3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「誰でもコードが書ける」の次に来るのは、コンテキスト設計の標準化だと思う話

3
Last updated at Posted at 2026-03-18

AIコーディングの話をネットで読んでいると、よくこういう言葉を見ます。

「これで誰でもプログラムが書けるようになる」

私はこの言葉を聞くたびに、こう読み替えてしまいます。

「誰でも書ける」と言われたとき、それは普及ではなく"名前の変更"のサインである。

かつて、同じことがありました。

1950年代の初期、プログラムを書くことは、今よりはるかに機械都合の作業でした。人間が機械に合わせて、ほとんど機械語そのままの形で記述する——決して人間にやさしいものではなかったのです。

その後、アセンブラやFORTRAN、COBOLといった言語が登場し、人間が読める形で記述できるように、抽象度が一段ずつ引き上げられていきます。

そして1970年代後半、ひとつの象徴的な出来事が起きます。

「BASIC」という言語が、個人向けコンピュータとともに広く普及し始めたことです。

BASICは「より高度な言語」だったから広まったわけではありません。それまでプログラムを書いていなかった人たちが、初めて自分でプログラムを書き始めたという点が決定的でした。

だからこそ、こう言われたのです。

「これで誰でもプログラムが書けるようになる」

あのとき何が起きたか。

プログラムを書くという行為が、限られた専門家の作業から、より多くの人が関わる行為へと変わった。

そしてそれと前後して、人々が中心だと感じる行為の名前も変わっていきました。もはや中心にあったのは「バイナリコードの生成/入力」ではなく、コードを書くこと——すなわちコーディングだったのです。

そして今、LLMが現れ、また同じ言葉が聞こえます。

「これで誰でもコードが書けるようになる」

おそらくこれは、コーディングの主戦場がコードそのものから移り、例えば、「コンテキスト設計」という新しい名前が前面に出る前兆です。

この記事は、その変化が何をもたらすかを考える思考実験です。

歴史の話でいえば、ビル・ゲイツとスティーブ・ジョブズにヒントがあるように思えます。

1. 行為はなくならない。名前が変わる。

「誰でもできる」という言葉が出たとき、その行為はなくなりません。抽象度が上がって、別の名前に変わる。

時代 行為の名前 何をしているか
1950年代 バイナリコードの入力 コンピュータを直接動かす
1975年 コーディング 論理をコードで記述する
2025年? コンテキスト設計? 文脈と意図を組み立て、AIに実行させる

コンテキスト設計とは、簡単に言えば

「AIにどう考えさせるかを設計する行為」

です。それは単にプロンプトを書くことではなく、参照させる資料、守らせる制約、途中成果物の保存方法、レビューの観点、やり直し方まで含めて、AIが働く作業環境そのものを設計することです。

重要なのは、この変化のたびに「新しい土台」が必要になったことです。

BASICが生まれた後、人々はすぐに気づきました。

「誰でも書けるようになった。でも、大きなものは作れない。」

  • 複数人で開発できない
  • 再現性がない
  • 製品として出荷できない

もちろん、フロッピーディスクやCP/MのようなOSは存在していました。ただ、それでも環境はまだ統一されていなかった。

機種ごとにBASICの方言が違う。ファイル形式が違う。動作環境が違う。「あのマシンで動いたものがこのマシンでも動く」という保証がなかった。

つまり「書ける」と「標準として作れる」は別の話でした。

もちろん 現実の歴史はもっと入り組んでいます。ただ、大づかみに見れば「誰でも書けるようになった」後に必要になったのは、個人技を製品や産業に変えるための標準化でした。

そして、それを押さえたのが、MS-DOSでした。そのレイヤーを制したのが、ビル・ゲイツでした。

2. ゲイツが見ていたもの:新しい行為を支える"土台"

ゲイツは「BASICが普及した」という事実に乗ったのではありません。

「BASICの次に何が必要になるか」を見ていた。

そして重要なのは、「次に必要になった」MS-DOSをゲイツは自分で書いていないことです。

Tim PatersonというエンジニアがSeattle Computer Productsで書いた「QDOS」を買い取り、IBMにライセンスして「PC-DOS」として出荷した。互換機メーカーには「MS-DOS」として別途ライセンスした。

書いたのではなく、価値を見抜いて、誰よりも早く押さえた。

MS-DOSが勝った理由は3つです。

  • IBM PCだけでなく、互換機でも動いた → 標準になった
  • その上にコンパイラ・ツール・ソフトが積み重なった → 開発者の足場になった
  • 「とりあえずDOSで作ればいい」という状況が生まれた → ネットワーク効果

ゲイツの本質は技術力ではありません。

「次に必要になるレイヤーを見抜き、標準として押さえる」

という目利きと動きの速さでした。

3. ジョブズが見ていたもの:"Apple"というもの

一方でジョブズは、別の角度から同じ変化を見ていました。

アップルIIを買った人は、CPUを買ったわけでも、OSを買ったわけでもない。

「Apple II」というものを買った。

キーボードもモニタもBASICも、ぜんぶ最初から入っていた。技術者でなくても、箱を開ければ使えた。

ゲイツが「MS-DOS」というソフトを売ったとすれば、ジョブズが売ったのは、部品ではなく、最初からひとつに統合された体験でした。

中に何が入っているかは関係ない。ユーザーは「Appleを持っている」という事実だけを受け取った。

ジョブズが見ていたのも「BASICの普及」ではありません。

「BASICの次に、誰もが手に取れる"もの"が必要になる」

という未来でした。

4. 二人は何が違ったのか

まず歴史の話として整理します。

1970〜80年代の実像:

観点 ゲイツ(MS-DOS) ジョブズ(アップルII)
やったこと 価値を見抜いて標準を押さえた(買って転売) 全部ひとつにまとめて"もの"にした
対象 開発者・企業 一般ユーザー・クリエイター
核心 「次のレイヤーを誰よりも早く標準化する」 「中身を隠した、使えるもの」

ただし、ここで歴史を正確に振り返る必要があります。

二人はそれほど綺麗に分かれていたわけではありません。

ジョブズがMacintoshで作ったのは、OS込みの統合製品でした。ジョブズは「もの」を作ると同時に、ゲイツ的な「OS=土台」のレイヤーも最初から取りに行っていた。逆にゲイツも、WindowsやOfficeを「誰もが使える製品」として磨き続けました。

つまり、二人は最終的に同じ領域で戦うことになった。ただし入口が違った。

  • ゲイツは「標準」側から入って、後から「もの」を作った
  • ジョブズは「もの」側から入って、最初からOSを内包していた

どちらが正しかったかではなく、どちらも「行為の変化」の次を見ていた。そして、どちらも最終的にはお互いの領域に踏み込んでいった——これが重要です。

この「入口は違えど、結局は両方必要になった」という歴史の教訓を、AI時代に重ねてみます。

2025年への類比:

観点 ゲイツ型 ジョブズ型
目指すもの コンテキストOSを標準として押さえる コンテキスト設計を隠した"もの"を作る
対象 開発者・企業・チーム 一般ユーザー・非エンジニア
核心 「再現性・標準化・プラットフォーム化」 「名前のついた、すぐ使えるもの」

5. コンテキスト設計の時代に必要になるもの

今、コーディングの主戦場はコンテキスト設計へ移ろうとしています。

そしてここで問題が生まれています。

LLMは強力ですが、「同じことをもう一度やらせる」のが驚くほど難しい。

昨日うまくいった指示が、今日は違う結果を返す。
チームの別の人が同じことを試しても、再現できない。
「なんかうまくいった」が積み重なるだけで、工業化できない。

これはコンテキストが管理されていない問題です。

だからこそ、コンテキストOSが必要になります。

コンテキストOSとは、コードではなく「コンテキスト(文脈・意図・状態)そのもの」を管理・再実行する層である。

たとえば、こんな仕組みです。

  • 「この機能を追加せよ」というコンテキストがそのままファイルとして保存される
  • そのコンテキストを別の環境・別のモデルで再実行できる
  • 結果の差分が「コードの差分」ではなく「コンテキストの差分」として見える

「Gitみたいなもの?」と思った人、正解に近いです。ただしGitは成果物のバージョン管理であって、「なぜその変更が生まれたか」「どの指示・モデル・参照資料で生成したか」——つまり生成プロセスのバージョン管理ではありません。部品はあっても、それらを束ねて再実行可能にする層がまだない。

やりたいこと Git コンテキストOS
コードの差分を見る
「なぜこの変更をしたか」を追跡する △(コミットメッセージ) ○(指示・制約・参照資料を丸ごと記録)
同じ機能を別のモデルで再生成する ×
チームのコンテキスト設計ルールを強制する ×
結果の差分を「コンテキストの差分」として比較する ×

Gitが「コードの履歴」を管理するインフラだとすれば、コンテキストOSは 「意図と生成プロセスの履歴」を管理するインフラです。コードより一段上——コードを生み出す行為そのものを管理する層です。

実は、その原型はすでに存在しています。

Cursorのルールファイル、エージェントのスキル定義、プロンプトのテンプレート群——
これらはすでにコンテキストOSの最初の部品と言えます。

コンテキストOSが整備されると、コンテキスト設計は 職人技 → 工業 に変わります。


一方、ジョブズ的な視点からはこう問われます。

コンテキスト設計を、名前のついた"もの"として渡せるか?

  • LLM・IDE・コンテキストOSをひとつに統合する
  • 中身は見せない。「○○を使えばいい」という名前を渡す
  • ユーザーが「AIを使っている」ではなく「○○を使っている」と言う状態を作る

この"もの"が生まれると、コンテキスト設計は 専門家のもの → 誰でも使えるもの に変わります。

6. LLM時代の覇者になる条件

ゲイツ的な存在が現れるなら、こういう動きをするはずです。

  • すでにある技術を組み合わせて、コンテキストOSとして標準を先に押さえる
  • モデル非依存(GPT・Claude・Geminiどれでも動く)
  • IDE非依存(Cursor・VSCode・CLI・Webどこでも使える)
  • 組織で使えるコンテキスト管理の作法を「名前のついた標準」にする

ジョブズ的な存在が現れるなら、こういうものを作るはずです。

  • コンテキストOSの複雑さをすべて裏側に隠す
  • LLM・IDE・コンテキストOSを一体の"もの"として提供する
  • 「○○を使えばいい」という名前を世界に渡す

ただし、ここがこの記事で一番重要なポイントです。

AI時代は、「ゲイツ」と「ジョブズ」を分業できないかもしれない。

先に見たように、歴史上の二人も最終的にはお互いの領域に踏み込んでいきました。標準だけでも、"もの"だけでも、勝ちきれなかった。しかしマイコン時代は、少なくとも**「まず片方から始める」**ことが許されていました。

AI時代は、その猶予がないかもしれない。なぜか。

従来のコンピュータはこうでした。

OS(土台)
  └ アプリ(もの)

この二層は明確に分かれていた。
ゲイツはOS側で勝ち、ジョブズはOS込みの"もの"として勝った——戦い方は違うが、レイヤーの区別自体は存在していた。

でもAIでは、この境界が消えます。

「どんなコンテキストを渡すか」がそのまま「何を使っているか」になる。

コンテキスト設計がOSでもあり、アプリでもある。コンテキストOSと"もの"が一体化していく。

だから、どちらか片方だけを作っても、もう片方に侵食されます。

7. 今はまだ"1975年"

もしこの仮説が正しいなら、今はこの辺の時代です。

1975  Altair 8800 ← 「誰でもコンピュータが使える」熱狂
1977  アップルII  ← 最初の"もの"
1980  MS-DOS     ← 最初の標準OS
1984  Macintosh  ← "もの"の再発明

「誰でもAIでコードが書ける」という熱狂は、1975年の熱狂と重なります。

コンテキストOSはまだない。名前のついた"もの"もまだない。

でも、誰かがその次を静かに作り始めているはずです。

まとめ

「誰でも書ける」という言葉は、単なる普及の宣言ではありません。

行為が別の名前に変わる、前兆です。

機械語の入力 → コーディング → コンテキスト設計

この変化のたびに、新しい土台(OS)と新しい"もの"が生まれてきました。

そして今、またその変化の入り口に立っています。必要になるのはコンテキストOSと、それを包んだ名前のある"もの"です。


もしあなたが今、AIを使ってコードを書いているなら、もう一歩だけ視点を上げてみるのもいいかもしれません。

あなたが書いているものの重心は、コードそのものではなく、「コンテキストOSの最初の部品」 かもしれない。

そしてそれは、後から見たときに 「最初の一行」 になる可能性があります。

あなたはどっちに賭ける?

  • ゲイツ側:コンテキストを管理・再実行するOSを標準として押さえる(再現性・チーム運用・プラットフォーム化)
  • ジョブズ側:「○○を使えばいい」という名前のついた"もの"を作る(統合・コンテキストを隠す)
  • 両方やる:コンテキストOSも"もの"も、一人で全部取りにいく

気づいた人から、もうどちらかを始めています。
あなたは、どこに賭けますか。

おまけ: 例えばこんなのが「コンテキストOS」で生成・管理されるもの?

※ 解説すると重いので、手元にあるとある「システム」(ルール・スキルやスクリプトの集合体)の成果物を「なんとなく」陳列だけしてみます。興味のある方は開いてみてください。

  • AI(LLM)が何かを調査したり、ユーザーの指示に従って作成した「メモ」
クリックしてファイルの内容を表示

※ エージェント向け: 本メモ根拠の変更依頼時は、INV-03 厳守のうえ MAINT経路・DSC経路を検討してから実施すること。(メモを参照した依頼でも、通常どおり承認・手順を踏みます)

メモ: リサージュ図形(Lissajous figure)

互いに直交する2つの単振動を合成して得られる平面図形。周波数測定・オシロスコープでの同期合わせなどに用いられる。


定義

  • リサージュ図形(リサジュー図形): 直交する2つの単振動を合成した軌跡。
  • 媒介変数表示の例: (x = A\cos(at)), (y = B\sin(bt + \delta))
    • (A, B): 各方向の振幅
    • (a, b): 角振動数
    • (\delta): 初期位相

周波数との関係

  • 比較法: 基準波を横軸、被測定波を縦軸に入力すると、上下の山の数と左右の山の数が周波数比になる。
  • オシロスコープで周波数測定・信号の同期確認に利用される。

周波数比と形状

振動数比 形状の例
1:1 楕円(位相で円や直線にも)
1:2 8の字型
整数比 閉じた曲線
無理数比 閉じずに矩形領域を稠密に埋めるパターン

歴史・出典

  • 1855年、フランスの物理学者ジュール・アントワーヌ・リサジュー(Jules Antoine Lissajous)により考案。
  • 出典: 日本語Wikipedia「リサジュー図形」、解説サイト(Open Insight 等)。

更新履歴

  • 2026-03-18 05:56 作成(リサージュ図形の調査内容を追記)
  • AI(LLM)が実装に向けて後続モデルに対する指示を書いた「実装指示書」
クリックしてファイルの内容を表示

id: DSC-20260318-01-lissajous-vite-demo
title: リサージュ図形の振動数比アニメーションデモ(Vite + TypeScript)
status: Ready
created_at: "2026-03-18"
tags: [demo, lissajous, vite, browser]
locale: ja-JP
quality_refresh_hash_at_created: "2026-03-18T06:02:18.561+09:00 2c0c9ec5f3395d3db3ea127db00045bd1ad148108b49c18fa231f714b081562b"
quality_refresh_hash_before_impl: "" " # PRE-IMPL (npx tsx gradient-driven/scripts/qualities/pre-common-auto-check.ts --pre-impl) の出力を記録する"
quality_refresh_hash_at_reviewed: "" " # レビュー直前(status を Reviewed に変更する直前)に pre-review チェック の出力を記録する"
impl_approval_phrase: ""
mmtm_refs: []
context: null
role: Architect / Implementer / Reviewer
input_files: [gradient-driven/contexts/memos/202603/20260318/MEMO-20260318-01-lissajous-figure.md]
output_targets: [gradient-driven/contexts/descents/202603/20260318/DSC-20260318-01-lissajous-vite-demo.md, index.html, vite.config.ts, src/main.ts]


リサージュ図形の振動数比アニメーションデモ(Vite + TypeScript)

ブラウザでリサージュ図形を描画し、振動数比のアニメーション・残像・振幅 A/B の時間に対する非線形変化をデモする TypeScript プログラムを Vite で実行可能にする。

未確定事項

なし(本DSCで方針を確定する。)

差し戻し記録(差し戻し時のみ記入)

(該当時のみ記入)

背景 / 文脈

  • リサージュ図形は直交する2つの単振動の合成軌跡。振動数比・位相・振幅で形状が変わる(MEMO-20260318-01-lissajous-figure 参照)。
  • ユーザー要望: 振動数比のアニメーション、残像効果、振幅 A・B を時間に対してリニアでなく変化させて視覚的に面白いデモにすること。
  • 本リポジトリは package.json に vite を既に持つが、vite.config およびブラウザ用エントリ(index.html / src エントリ)は未整備のため、本DSCで新規追加する。

目的(Goals)

  • ブラウザでリサージュ図形を描画する TypeScript プログラムを追加する。
  • 振動数比(例: a:b)を時間経過で変化させるアニメーションを実装する。
  • 軌跡の残像(過去フレームの描画を薄く残す)を実装する。
  • 振幅 A と B を時間に対して非線形に変化させる(例: サインカーブ・パルス的な変化)。
  • Vite の dev / build / preview で実行・確認できるようにする。

非目標(Non-Goals)

  • 本番プロダクトの機能拡張ではない。デモ用途に限定する。
  • テストの自動化・E2E は本DSCの範囲外とする(手動動作確認で足りる)。

改変許可範囲

  • 定義: 本DSCを実施するときに編集してよい範囲の SoT。context.output_targets と整合させる。
  • 新規作成予定ファイル一覧(必須・正本): index.html, vite.config.ts, src/main.ts
  • 実施指示対象と改変許可範囲の一致チェック: [x] 確認済み(Ready 遷移直前にエージェントが記入)
  • 対象範囲: gradient-driven/contexts/descents/202603/20260318/DSC-20260318-01-lissajous-vite-demo.md, index.html, vite.config.ts, src/main.ts
  • 許可する変更: 上記ファイルの新規作成、DSC の実施結果節・status の更新。
  • 禁止する変更: qualities/** の編集、上記以外の既存ファイルの意図しない変更。
  • 改変非許可範囲(既定): qualities/, descent_driven/, .cursor/。本DSCでは qualities/ は改変対象外とする。
  • 依存の追加・更新: 禁止(既存の vite / typescript のみ使用)。
  • 互換性方針: 既存の npm run build / dev / preview / check を壊さない。

リスク

  • Vite のルートがリポジトリルートと異なる場合、既存の typecheck/lint との整合を要する。対策: vite.config の root をリポジトリルートにし、entry を index.html に合わせる。
  • 残像の描画負荷。対策: 残像フレーム数に上限を設け、requestAnimationFrame で描画する。

設計構想(Design Concept)

  • 描画: Canvas 2D を使用。x = A(t) cos(a t + φ), y = B(t) sin(b t + δ) の媒介変数表示。A(t), B(t) は時間 t の非線形関数(例: 基準振幅 × (0.5 + 0.5 sin(ωt)) や短いパルス)。
  • 残像: 毎フレームで直前のバッファを少し暗くしてから現在フレームを描画する(globalAlpha または fillRect で半透明でクリア)。
  • 振動数比のアニメーション: a, b を時間とともに変化させる(例: 整数比 1:1 → 1:2 → 2:3 をループ)。
  • 責務: main.ts にエントリとループを置き、Canvas の取得・リサイズ・描画ロジックを一ファイルにまとめてよい(デモのため分割は最小限でよい)。
  • 防止すべき状況: (1) file:// で開く前提にしない (2) CORS/モジュール未解決で白画面にしない (3) 無限ループで UI を止めない (4) 型 any や as unknown as で逃げない (5) default export を乱用しない (6) 制御構造の直前にコメントを欠く (7) 境界由来を unknown で受けずに as で流す (8) 残像バッファのメモリを無制限に増やさない (9) 振幅が 0 で除算や NaN を起こさない (10) リサイズ時に Canvas が崩れない。

用語 / 境界

  • リサージュ図形: x = A cos(at + φ), y = B sin(bt + δ) で表される曲線。a, b は角振動数、A, B は振幅、φ, δ は位相。
  • 残像: 過去数フレームの軌跡を半透明で重ねて表示する効果。
  • 責務境界: ブラウザで動作する単一ページのデモ。バックエンド・永続化は行わない。

公開インタフェース

  • 本DSCはブラウザ用エントリのみ追加する。公開 API は持たない。
  • エントリ: index.html が script type="module" で src/main.ts を読み込む。

型設計

  • 振幅・角振動数・位相は number。Canvas は HTMLCanvasElement。requestAnimationFrame のコールバックは number を受け取る。

例外・エラー方針

  • Canvas やコンテキストの取得失敗時はコンソールにログを出して早期 return。ユーザー向けメッセージは最小限でよい。

セキュリティ影響(任意)

該当なし。ローカルで動作するデモであり、認証・秘密・外部入力は扱わない。

セキュリティ / パフォーマンス / 可観測性

  • スレットモデル: ローカル表示のみ。入力検証は不要。
  • パフォーマンス: 60fps 程度を目安に、残像フレーム数で調整可能にする。
  • ログ: デバッグ用に必要最小限(取得失敗時のみ)。

ドキュメンテーション方針

  • README の更新は本DSCの範囲外とする。DSC の「動作確認手順」で起動方法を明示する。
  • コメント: main.ts 内で制御構造の直前に意図コメントを入れる(docs 品質コンテキスト準拠)。locale は ja-JP に合わせる。

品質ゲート(このDSCの定義)

  • 実行順序(必須): [docs/PLAYBOOK/PRE-IMPL.md] に従い、npm run -s preflight(少なくとも1回成功)→ npm run checknode gradient-driven/tests/rules-skills-consistency/run-from-optional-consistency-suites.mjs の順とする。
  • 実行(npm): npm run check
  • 追加ゲート: なし。
  • 測定指標/閾値: なし。

受け入れ条件(Acceptance Criteria)

受け入れ条件(UI・UX)

  • ブラウザで開発サーバ(npm run dev)を起動し、指定 URL を開くとリサージュ図形が描画されること。
  • 振動数比が時間とともに変化するアニメーションが見えること。
  • 軌跡に残像(過去の線が薄く残る)が付いていること。
  • 振幅 A および B が時間に対して非線形に変化していることが分かること(リニアな一定振幅ではないこと)。

受け入れ不可条件(UI・UX)

  • 初期表示から白画面のまま何も描画されないこと。
  • file:// で開くことを前提とした手順のみで動作確認とすること。
  • クリックやキー操作を前提にしないと描画が始まらないこと(ページ読み込みでアニメーション開始でよい)。

受け入れ条件(UI・UX以外)

  • npm run check が成功すること。
  • 本DSCの「品質ゲート(このDSCの定義)」で定義したゲートを満たすこと。
  • TypeScript は strict および qualities の型・lint ルールに従うこと。

受け入れ不可条件(UI・UX以外)

  • CORS やモジュール読み込みエラーでコンソールに恒常的にエラーが出ていること。
  • 型エラーを抑止コメントで隠すこと。
  • eslint-disable で品質ゲートを無効化すること。

品質ゲート宣言(必読)

本DSCの実装を行う際は、以下を単一情報源かつ必達目的として扱うこと。

  • ゲート実行の参照設定の SoT は qualities/**
  • コード生成時に参照する品質コンテキストの SoT は gradient-driven/contexts/qualities/**/context.md。編集時は該当 context.md を厳守し、矛盾する編集をしないこと。
  • 実装は必ず npm run check を通過すること。実行順序は PRE-IMPL.md に従い、preflight を少なくとも1回成功させてから check を実行する。
  • DSC は後続モデルが単体で実装できるだけの情報を自己完結的に記述する。

ステータス運用

  • 状態: Draft → Ready → Implemented → Reviewed。差し戻し時は Ready に戻す。
  • Implemented の定義: npm run check を成功させ、DSC の「実施結果 / レビュワー向けコメント」を確定した状態。
  • Reviewed の定義: descent-impl-review に従いレビュー完了した状態。
  • 差し戻し後の再実施: 当該 DSC に impl_approval_phrase が記録済みであれば再承認不要(INV-17)。

モメンタム整合

  • expansion_policy: 本DSCの改変許可範囲を超えない。必要十分な範囲に限定し、skill cap を超えない。
  • done_criteria: 上記受け入れ条件をすべて満たし、npm run check 通過および動作確認手順に従ったブラウザ確認が完了していること。

テスト方針

  • 本DSCでは単体テスト・E2E は追加しない。手動での動作確認で受け入れを判定する。
  • 既存の npm run test は変更しない。

マイグレーション / ロールアウト計画

  • 新規ファイルの追加のみ。既存機能の移行はなし。

実施方式

本セクション(実施方式)は必須であり、削除・改変してはならない(追記のみ可)。output-policy 参照トリガー(review_request_notice / followup_task_complete / subtask_complete)は必ず残置する。
本DSCの実施は、該当する Skill を適用タイミングに応じて発動し、各 Skill の SoT である PLAYBOOK に従う。(1) 設計前: prompting-run。 (2) Ready→IMPL 移行時: impl-approval-prompt により承認ブロックを1回提示。承認フレーズ送信後に pre-impl-run を適用し、実装開始。 (3) 実装完了前: 結果記録・status 更新。実装完了後は post-impl-record に従い、review_request_notice を1回のみ出力してよい。

  • プロンプティングフェーズの一時コードは tmp/** および scripts/tmp/** に限定する。

AI実装指針

  • コメントは本DSCの locale(ja-JP)に合わせる。
  • 責務境界(実施前後): 「後続が単体で実施するための実施指示」には実施前情報のみを記載する。実施済み事実は「実施結果 / レビュワー向けコメント」節にのみ記録する。

後続が単体で実施するための実施指示

実施指示に記載した編集対象は、改変許可範囲の「新規作成予定ファイル一覧」および対象範囲にすべて含まれること。ゲート実行順は PRE-IMPL.md に従い、preflight → check → node gradient-driven/tests/rules-skills-consistency/run-from-optional-consistency-suites.mjs の順で記載する。

  • 前提となる調査結果: MEMO-20260318-01-lissajous-figure にリサージュ図形の定義(x = A cos(at), y = B sin(bt + δ)、振動数比・整数比で閉じた曲線・残像は本DSCで独自実装)を記載済み。
  • 対象別の具体的改修内容:
    • 対象: index.html
    • 挿入・置換の位置: 新規作成。ルートに配置する。
    • 追加・変更する内容の要約: Vite のエントリとして、DOCTYPE、html、head、body を用意する。body 内に canvas 要素を1つ置く。script は type="module" で src を /src/main.ts とする(Vite が解決する)。
    • 参照すべき既存記述: なし。Vite の公式ドキュメントの HTML エントリの慣例に従う。
    • 対象: vite.config.ts
    • 挿入・置換の位置: 新規作成。ルートに配置する。
    • 追加・変更する内容の要約: Vite の設定を export default で定義する。root はプロジェクトルート、build.outDir は dist、エントリは index.html をルートに置く前提とする。TypeScript のビルドに必要な最小設定(build.target 等)を含める。
    • 参照すべき既存記述: package.json の "build": "vite build", "dev": "vite" を利用する。qualities/infra/tsconfig の include に vite.config.ts が含まれることを確認する。
    • 対象: src/main.ts
    • 挿入・置換の位置: 新規作成。src/main.ts として配置する。
    • 追加・変更する内容の要約: (1) DOMContentLoaded または window.onload で document から canvas を取得し、2D コンテキストを取得する。取得失敗時は console.error で return。(2) リサージュのパラメータ: 振幅 A(t), B(t) は時間 t の非線形関数(例: 基準値 × (0.5 + 0.5 * Math.sin(t * 0.001)) や矩形波に近い変化)とする。角振動数 a, b は時間で変化させてよい(例: 整数比をループ)。(3) 毎フレーム: 残像用に直前の描画を薄く残す(例: fillStyle で半透明の黒で全体を fillRect する、または globalAlpha で上書き描画)。(4) 現在の A(t), B(t), a, b で媒介変数 θ を 0 から 2π まで刻んで x, y を計算し、Canvas 座標に変換して lineTo で結ぶ。(5) requestAnimationFrame でループする。(6) ウィンドウリサイズ時に canvas の width/height を更新する。制御構造(if/for 等)の直前に意図コメントを入れる(docs 品質コンテキスト準拠)。
    • 参照すべき既存記述: 品質コンテキストの core(no-default-export、import 規律)、types(no-explicit-any、no_unknown_double_cast)、boundary-guards(境界直後は assert/parse)の各説明を参照する。編集対象外。DOM 由来の canvas は境界扱いとしないが、取得失敗時は早期 return する。
    • 対象: gradient-driven/contexts/descents/202603/20260318/DSC-20260318-01-lissajous-vite-demo.md
    • 挿入・置換の位置: 「実施結果 / レビュワー向けコメント」節および front matter の quality_refresh_hash_before_impl と status。
    • 追加・変更する内容の要約: 実装完了後に post-impl-record に従い、実施概要・作業ログ・実装詳細(ファイル別)・品質に関するコメントを記録する。status を Implemented に更新する。実施指示節には実施済み事実を書かず、実施結果節にのみ書く。

実装時設計ログ(逐次追記)

(実装中に追記)

実施結果 / レビュワー向けコメント

(実装完了後に post-impl-record に従い記入)

トラブルシューティング・動作確認手順

本セクションはユーザーが実施する際の動作確認とトラブルシューティング手順を記載する。

動作確認手順

  1. 起動方法:
    npm run dev
    
  2. アクセス方法: ターミナルに表示されるローカル URL(例: http://localhost:5173)をブラウザで開く。file:// で index.html を直接開かないこと(モジュール解決のため開発サーバ必須)。
  3. 確認項目:
    • リサージュ図形が描画されていること。
    • 振動数比が時間とともに変化するアニメーションであること。
    • 軌跡に残像が付いていること。
    • 振幅 A および B が時間に対して非線形に変化していること(一定でないこと)。
    • ウィンドウリサイズ後も描画が継続すること。
  4. 品質ゲート(本DSCの定義と対応):
    • npm run -s preflight を少なくとも1回成功させる。
    • npm run check を実行して成功すること。
    • node gradient-driven/tests/rules-skills-consistency/run-from-optional-consistency-suites.mjs を実行して通過すること。

トラブルシューティング

Step 1: エラーメッセージの収集

  • ブラウザの開発者ツールのコンソールに表示されるエラーを確認する。
  • ターミナルで npm run dev 実行時のエラーを確認する。

Step 2: 基本的な確認事項

  • npm install は正常に完了したか。
  • npm run check は成功しているか。
  • npm run dev で開発サーバが起動し、表示された URL を開いているか(file:// ではないか)。

Step 3: AIへの報告フォーマット

(テンプレートは _DSC-template の通り)

よくある問題(実装後に追記)

(実装完了後に追記。特になければ「特記すべき問題は発生しませんでした。」と記載する。)

参考リンク

  • MEMO-20260318-01-lissajous-figure.md(リサージュ図形の定義・周波数比)
  • Vite 公式ドキュメント(エントリ・設定)
  • 別コンテキスト(別エージェント)が上記「実装指示書」をレビューした結果の記録
クリックしてファイルの内容を表示

id: GRAD-20260318-01-dsc-20260318-01-lissajous-vite-demo-virtual
title: DSC-20260318-01 リサージュViteデモ 仮実施勾配観測
created_at: "2026-03-18"
updated_at: "2026-03-18"
model_identity: 【非公開】
mmtm_refs: []
linked_dsc_paths: [gradient-driven/contexts/descents/202603/20260318/DSC-20260318-01-lissajous-vite-demo.md]


DSC-20260318-01 リサージュViteデモ 仮実施勾配観測

仮定状態の定義

  • 対象 DSC(DSC-20260318-01-lissajous-vite-demo)を実施済みと仮定した。
  • 成果物(index.html, vite.config.ts, src/main.ts)が存在し、受け入れ条件を満たした状態を前提に観測した。

対象

  • 対象ファイル/スコープ: リポジトリ全体。補助対象: 実装(index.html, vite.config.ts, src/main.ts および当該 DSC)。
  • 観測モード: 実施済み仮定
  • 観測軸: 不整合, 矛盾, 曖昧さ, 抜け, セキュリティ, DSCの背景・方針に照らし合わせて実施内容が網羅性を持つか, DSCの背景・目的に照らし合わせて実施内容が合目的か(背景・目的との整合)

観測実施内容

  • 基準 DSC の本文(目的・背景・改変許可範囲・設計構想・実施指示・受け入れ条件・リスク)を読み、観測軸に沿って実施済み仮定で残りうる問題を確認した。
  • 既存の tsconfig include を確認し、vite.config.ts が含まれることを確認した(qualities/infra/tsconfig/types/tsconfig.json に含まれる)。

未確定事項(対象DSCからの反映)

  • 該当なし

MMTM 状態観点

  • 確認元: 本観測の決定には MMTM の状態は不要のため未参照。
  • 次アクション: 特になし

観測された勾配

  1. 残像フレーム数上限の実施指示での記載不足(抜け・曖昧さ)
    • 検出内容: 設計構想・リスクでは「残像フレーム数に上限を設け」「残像バッファのメモリを無制限に増やさない」とあるが、実施指示の main.ts 要約には「残像用に直前の描画を薄く残す」とのみで、フレーム数上限の具体的な値や変数名の指示がない。実施者が解釈に迷うか、上限なしで実装してメモリリスクに触れる可能性がある。
    • 対応案A: 実施指示の main.ts 要約に「残像は直近 N フレーム分のみ保持する(N は例: 30 など定数でよい)」を追記する。メリット: 後続が単体で実施する際の一意性が増す。デメリット: 実施指示がやや長くなる。
    • 対応案B: 現状のままとする。メリット: 実装の自由度が残る。デメリット: 受け入れ条件や防止すべき状況との対応が読み手に伝わりにくく、メモリ無制限実装の可能性が残る。
    • 推奨: 対応案A。DSC の自己完結性と防止すべき状況(残像バッファのメモリを無制限に増やさない)との整合のため、実施指示に上限の目安を明記する。

対応案・推奨のまとめ

項目 推奨
1 対応案A(実施指示の main.ts 要約に残像フレーム数上限の目安を追記)

既知の未実施差分(ノイズ扱い)

  • 実施済み仮定のため、未着手なら当然発生する差分(index.html, vite.config.ts, src/main.ts の未作成)は観測勾配の主項目に含めない。本観測時点では該当なしとして扱った。

基準からの反転経緯

  • なし(基準から作成時点までの区間において、反転は観測されなかった)

次アクション

  • 観測勾配 1 件の推奨を対応案Aとした。指摘を DSC に反映するのは DSC実施前の流れで行う。DSC 作成/更新チャットで、当該 GRAD の指摘のうち妥当なものを DSC に反映するよう依頼してください。

更新履歴

  • 2026-03-18 作成 | DSC-20260318-01 仮実施勾配観測(実施済み仮定、観測軸に網羅性・合目的性を追加)
  • チーム規約としての「品質コンテキスト」(一部)
クリックしてファイルの内容を表示 # docs Quality Context

Why(なぜこの品質ゲートが必要か)

ドキュメント・コメント系の品質を無視すると、意図不明な分岐・冗長コメント・ロケール混在・JSDoc 重複が残り、可読性と保守性が低下する。手戻りとして、制御構造コメントの追加・類似度しきい値の調整・comment_locale 違反の一括修正が発生する。

成果物品質への影響

  • 意図の明示: if/for/while/switch/try 等の直前に意図を表すコメントを要求し、分岐の意図を後続が把握できるようにする。
  • 類似度検査: 直前コメントと then/else/catch ブロックの内容が似すぎる場合に警告し、差別化を促す。連続する行コメントの類似度も閾値(既定 0.75)で検査する。
  • ロケール: 日本語ロケール時は JSDoc を ASCII のみにしない(comment_locale)。JSDoc の隣接重複を禁止(jsdoc_no_duplicate)。

品質ゲートでの手戻りコスト

  • トークン消費: 制御構造へのコメント追加・類似度違反の修正。
  • 認知負荷: require-comments-on-control-structures の targets / similarityThreshold / requireSectionComments 等のオプション理解。

Where(どこに適用されるか)

監視範囲: qualities/eslint/03-documentation/docs/config.mjs が参照するプラグイン(qualities/eslint/plugins/docs/)、qualities/policy/comment_locale/docs/、qualities/policy/jsdoc_no_duplicate/docs/。対象ファイルは ESLint の docs 設定で指定された .ts/.tsx/.js/.jsx(.d.ts は除外想定)。

グロブ・対象ファイル例

  • プラグイン・設定: qualities/eslint/plugins/docs/**/*.js, qualities/eslint/03-documentation/docs/**/*.mjs
  • ポリシー実体: qualities/policy/comment_locale/docs/**, qualities/policy/jsdoc_no_duplicate/docs/**
  • lint 対象(設定依存): 本番ゲートで docs を有効にしたときの対象は config の files/ignores に従う(例: src/**/*.{ts,tsx}, qualities/**/*.{js,mjs} 等)

監視範囲の代表パス

  • qualities/eslint/plugins/docs/require-comments-on-control-structures.js(制御構造直前コメント・節コメント・類似度)
  • qualities/eslint/plugins/docs/require-comments-similarity.js(then/else/catch と直前コメントの類似度)
  • qualities/eslint/plugins/docs/consecutive-line-comments-similarity.js(連続行コメントの類似度、similarityThreshold 0.25〜1.0、既定 0.75)
  • qualities/eslint/plugins/docs/block-comment-formatting.js、eslint-directive-rules.js、export-jsdoc-required.js 等
  • qualities/policy/comment_locale/docs/run.mjs、qualities/policy/jsdoc_no_duplicate/docs/run.mjs

What(何をチェックするか)

コマンド/役割 設定 監視範囲 閾値/禁止事項
npm run lint (docs) qualities/eslint/03-documentation/docs/config.mjs 設定で指定された files require-comments-on-control-structures(if/for/while/do/switch/try/ternary の直前コメント)、similarityThreshold、requireSectionComments
docs/consecutive-line-comments-similarity plugins/docs/consecutive-line-comments-similarity.js 行コメント連続 類似度しきい値(既定 0.75)、超過で報告
comment_locale policy/comment_locale/docs/run.mjs JSDoc 日本語ロケール時は ASCII のみの JSDoc 禁止
jsdoc_no_duplicate policy/jsdoc_no_duplicate/docs/run.mjs 隣接 JSDoc 同一キー・タグ重複禁止

How(どうやって守るか)

設定閾値一覧

  • require-comments-on-control-structures: targets(if/for/while/do/switch/try/ternary)、similarityThreshold、requireSectionComments(always/falls-through-only/boolean)、allowBlankLine、ignoreElseIf/ignoreCatch。出典: require-comments-on-control-structures.js の meta.schema。
  • consecutive-line-comments-similarity: similarityThreshold 0.25〜1.0、既定 0.75。出典: consecutive-line-comments-similarity.js。
  • 制御構造の節コメント: sectionCommentLocations(before-if/block-head/trailing)、allowSectionAsPrevious。出典: require-comments-on-control-structures.internals.js および require-comments-sections.js。

成功パターン

// 認証済みの場合のみ処理を続ける
if (user.authenticated) {
  proceed();
} else {
  // 未認証の場合はログイン画面へリダイレクト
  redirectToLogin();
}
  • if/for/while/switch/try の直前に意図を説明するコメントを1行以上置く。
  • then/else/catch のコメントが直前コメントと似すぎないように差別化する(similarityThreshold 以下に収める)。
  • 連続する行コメントの内容が似すぎないようにする(単一行化または文言を変える)。
  • JSDoc はロケールに合わせ、隣接重複を避ける。

失敗パターン

if (user.authenticated) {
  proceed();  // 認証済みなら処理
} else {
  redirectToLogin();  // 認証済みでないならリダイレクト → 直前コメントと類似度超
}
// 制御構造直前にコメントなしも違反
for (const x of list) { doSomething(x); }
  • 制御構造の直前にコメントがない、またはパターン不一致。
  • 直前コメントと then/else/catch のコメントが類似度しきい値超。
  • 連続行コメントが類似度しきい値超。
  • 日本語ロケールで JSDoc が ASCII のみ、または隣接 JSDoc が重複。

LLM典型NGパターン(最低5件)

  1. 制御構造の直前にコメントなし — if/for/while/switch/try の直前に意図コメントを必ず置く。
  2. then/else のコメントが直前と似すぎ — similarityThreshold を超えないよう文言を差別化する。
  3. 連続行コメントが似すぎ — 単一行にまとめるか、内容を変える。
  4. JSDoc が ASCII のみ(ja ロケール) — comment_locale に合わせる。
  5. 隣接 JSDoc の重複 — jsdoc_no_duplicate に従い重複を削除する。
  6. 節コメントの不足 — requireSectionComments が有効な場合は block-head 等に節コメントを入れる。

事前チェックリスト(コード生成前)

  • 制御構造の直前に意図コメントがあるか
  • 類似度しきい値(0.75 等)を超えていないか
  • 連続行コメントを単一行化または差別化したか

修正方針(違反発見時)

  1. 制御構造直前コメントなし — if/for/while/switch/try の直前に意図を1行以上追加する。
  2. 類似度超過 — then/else/catch のコメントを直前コメントと差別化する(具体化・別観点で書く)。連続行コメントは単一行にまとめるか文言を変える。
  3. comment_locale 違反 — 日本語ロケール時は JSDoc を日本語またはロケールに合わせた表記に変更する。
  4. jsdoc_no_duplicate 違反 — 隣接する重複 JSDoc を1つに統合する。
  5. 節コメント不足 — requireSectionComments が有効な場合は block-head 等に節コメントを追加する。
  • DSCを「実施」して作成されたソースコード
クリックしてファイルの内容を表示
/**
 * @file リサージュ図形の振動数比アニメーションデモ エントリポイント
 * @consoleHandler
 * 備考: 特記事項なし
 * - default export を禁止し named export のみで統一する
 * - 同一モジュールの重複 import を避け import 直後に空行を挿入する
 * - any を使用せず具体型または unknown と型ガードで型安全性を確保する
 * - 二重キャスト(unknown 経由の型変換)を禁止し assert で型を確定する
 * - 制御構造の直前に意図を明示するコメントを必ず配置する
 * - コメント言語は日本語ロケールに統一し ASCII のみの記述を避ける
 * - 空 catch や trivial catch を禁止し適切にエラーを処理する
 * - strict-boolean-expressions に従い真偽値の暗黙変換を避ける
 * - eslint-disable 指令による品質ゲートの無効化を禁止する
 */

// --- 定数定義 ---

/** 振動数比パターンで使用する角振動数(3以上の整数) */
const FREQ_3 = 3;
const FREQ_4 = 4;
const FREQ_5 = 5;
const FREQ_6 = 6;

/** 振動数比の整数比パターン(a, b)の配列 */
const FREQUENCY_RATIOS: ReadonlyArray<readonly [number, number]> = [
  [1, 2],
  [2, FREQ_3],
  [FREQ_3, FREQ_4],
  [FREQ_3, 2],
  [FREQ_4, FREQ_3],
  [1, FREQ_3],
  [FREQ_5, FREQ_4],
  [FREQ_5, FREQ_6],
];

/** 残像効果の不透明度(低いほど残像が長く残る) */
const TRAIL_ALPHA = 0.05;

/** 位相オフセットの分母(π/QUARTER_DIVISOR でδを計算する) */
const QUARTER_DIVISOR = 4;

/** リサージュの位相オフセット δ */
const PHASE_DELTA = Math.PI / QUARTER_DIVISOR;

/** 媒介変数 θ の分割数 */
const THETA_STEPS = 2000;

/** 振動数比1パターンの表示時間(ミリ秒) */
const RATIO_DURATION_MS = 5000;

/** 遅い振幅変動の周波数係数 */
const SLOW_FREQUENCY = 0.0003;

/** 速い振幅変動の周波数係数 */
const FAST_FREQUENCY = 0.001;

/** 振幅の基礎成分(定常成分) */
const AMPLITUDE_BASE = 0.5;

/** 振幅の遅い変動成分の重み */
const AMPLITUDE_SLOW_WEIGHT = 0.3;

/** 振幅の速い変動成分の重み */
const AMPLITUDE_FAST_WEIGHT = 0.2;

/** Canvas に対するリサージュ曲線の描画領域比率 */
const CANVAS_RADIUS_RATIO = 0.35;

/** 振幅 B 側の周波数ファクタ(A 側と異なる値で非対称な動きを生む) */
const AMPLITUDE_B_FACTOR = 1.7;

/** 色相の回転速度(ミリ秒あたりの度数) */
const HUE_ROTATION_SPEED = 0.02;

/** 色相の最大値(度数) */
const HUE_MAX = 360;

/** 描画線の太さ */
const LINE_WIDTH = 1.5;

// --- 関数定義 ---

/**
 * Canvas 要素と 2D コンテキストを取得する。
 * 取得失敗時は console.error でログを出し null を返す。
 * @returns Canvas と 2D コンテキストのペア、または null
 */
function getCanvasContext(): {
  canvas: HTMLCanvasElement;
  ctx: CanvasRenderingContext2D;
} | null {
  const element = document.getElementById('lissajous-canvas');

  // Canvas 要素が DOM に存在しない、または HTMLCanvasElement でない場合は中止する
  if (!(element instanceof HTMLCanvasElement)) {
    console.error('Canvas 要素が見つかりません: #lissajous-canvas');
    return null;
  }

  const ctx = element.getContext('2d');

  // 2D コンテキストの取得に失敗した場合は中止する
  if (ctx === null) {
    console.error('Canvas 2D コンテキストの取得に失敗しました');
    return null;
  }

  return { canvas: element, ctx };
}

/**
 * Canvas のサイズをウィンドウサイズに合わせて更新する。
 * @param canvas - サイズを更新する Canvas 要素
 */
function resizeCanvas(canvas: HTMLCanvasElement): void {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
}

/**
 * 非線形振幅関数。
 * 遅い成分(サインカーブ)と速い成分(パルス的変化)を合成し、
 * 時間に対して非リニアに変化する振幅を返す。
 * @param baseAmplitude - 振幅の基準値(ピクセル)
 * @param timeMs - 経過時間(ミリ秒)
 * @param frequencyFactor - 周波数の倍率
 * @returns 計算された振幅値
 */
function computeAmplitude(
  baseAmplitude: number,
  timeMs: number,
  frequencyFactor: number,
): number {
  const slow = Math.sin(timeMs * SLOW_FREQUENCY * frequencyFactor);
  const fast = Math.sin(timeMs * FAST_FREQUENCY * frequencyFactor);

  // 遅い成分と速い成分の二乗を合成して滑らかかつ非線形な変化にする
  return baseAmplitude * (AMPLITUDE_BASE + AMPLITUDE_SLOW_WEIGHT * slow + AMPLITUDE_FAST_WEIGHT * fast * fast);
}

/**
 * 経過時間から現在の振動数比パターンのインデックスを算出する。
 * @param timeMs - 経過時間(ミリ秒)
 * @returns 振動数比配列のインデックス
 */
function getCurrentRatioIndex(timeMs: number): number {
  return Math.floor(timeMs / RATIO_DURATION_MS) % FREQUENCY_RATIOS.length;
}

/**
 * リサージュ曲線を1フレーム分描画する。
 * @param ctx - 描画先の 2D コンテキスト
 * @param width - Canvas の幅
 * @param height - Canvas の高さ
 * @param timeMs - 経過時間(ミリ秒)
 */
function drawLissajous(
  ctx: CanvasRenderingContext2D,
  width: number,
  height: number,
  timeMs: number,
): void {
  const ratioIndex = getCurrentRatioIndex(timeMs);
  const ratio = FREQUENCY_RATIOS[ratioIndex];

  // noUncheckedIndexedAccess により undefined の可能性があるため検査する
  if (ratio === undefined) {
    return;
  }

  const [a, b] = ratio;
  const centerX = width / 2;
  const centerY = height / 2;
  const baseRadius = Math.min(width, height) * CANVAS_RADIUS_RATIO;

  const amplitudeA = computeAmplitude(baseRadius, timeMs, 1);
  const amplitudeB = computeAmplitude(baseRadius, timeMs, AMPLITUDE_B_FACTOR);

  ctx.beginPath();
  ctx.strokeStyle = `hsl(${String((timeMs * HUE_ROTATION_SPEED) % HUE_MAX)}, 80%, 60%)`;
  ctx.lineWidth = LINE_WIDTH;

  // 媒介変数 θ を 0 〜 2π の範囲で刻み、リサージュ曲線の軌跡を描く
  for (let i = 0; i <= THETA_STEPS; i++) {
    const theta = (i / THETA_STEPS) * Math.PI * 2;
    const x = centerX + amplitudeA * Math.cos(a * theta);
    const y = centerY + amplitudeB * Math.sin(b * theta + PHASE_DELTA);

    // 最初の点では moveTo で開始し、以降は lineTo で線を接続する
    if (i === 0) {
      // 始点を設定する
      ctx.moveTo(x, y);
    } else {
      // 次の点へ直線を引く
      ctx.lineTo(x, y);
    }
  }

  ctx.stroke();
}

/**
 * 残像効果を適用する。
 * 半透明の黒で画面全体を塗り、過去フレームの軌跡を薄く残す。
 * @param ctx - 描画先の 2D コンテキスト
 * @param width - Canvas の幅
 * @param height - Canvas の高さ
 */
function applyTrailEffect(
  ctx: CanvasRenderingContext2D,
  width: number,
  height: number,
): void {
  ctx.fillStyle = `rgba(0, 0, 0, ${String(TRAIL_ALPHA)})`;
  ctx.fillRect(0, 0, width, height);
}

/**
 * アニメーションループを開始する。
 * @param canvas - 描画先の Canvas 要素
 * @param ctx - 描画先の 2D コンテキスト
 */
function startAnimation(
  canvas: HTMLCanvasElement,
  ctx: CanvasRenderingContext2D,
): void {
  // 初期状態で黒背景を描画しておく
  ctx.fillStyle = '#000000';
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  /**
   * requestAnimationFrame のコールバック。
   * @param timestamp - 現在のフレームタイムスタンプ
   */
  function frame(timestamp: number): void {
    applyTrailEffect(ctx, canvas.width, canvas.height);
    drawLissajous(ctx, canvas.width, canvas.height, timestamp);
    requestAnimationFrame(frame);
  }

  requestAnimationFrame(frame);
}

/** エントリポイント: DOM 読み込み完了後に Canvas を初期化しアニメーションを開始する */
function init(): void {
  const result = getCanvasContext();

  // Canvas またはコンテキストの取得に失敗した場合は起動を中止する
  if (result === null) {
    return;
  }

  const { canvas, ctx } = result;

  resizeCanvas(canvas);

  // ウィンドウリサイズ時に Canvas サイズを再設定する
  window.addEventListener('resize', () => {
    resizeCanvas(canvas);
  });

  startAnimation(canvas, ctx);
}

// DOMContentLoaded イベントで初期化を実行する
document.addEventListener('DOMContentLoaded', init);

ソースコード以前のファイルが 「ソースコンテキスト」 として、「プログラムのソースファイル」より重視される 世界も見えてきませんか・・・?(いや、どうなんでしょうね・・・)

ちなみに先ほどからの 「実装指示書」(DSC) ~ 「実施」までで作成されたプログラムは、見事にユーザー(私)の意図とはだいぶ異なる何か になってしまいました。(ホントはもっと「周波数比」が連続して変化するオシロスコープ的アニメーションになる予定が謎の未確認飛行物体風アニメに・・・笑)

ユーザーの意図とはだいぶ異なる実装完了したデモ
image.png

クリックするとアニメーションに飛びますが不思議なアニメなのであまり見続けない方が良いと思います。酔いやすい方等はご注意ください。

ただしここから先が「コンテキストが残っている」ことの一つの強みでもあります。 例えばAI(LLM)に下記のような指示をチャットで行うと、「修正のための実施指示書」 (DSC) がスムーズに作成され、それを「実施」することで、よりユーザーの意図に近いコードへと修正されます。

LLMへの指示: さっき DSC-20260318-01-lissajous-vite-demo.md でアニメ作成してもらったんだけどちょっと意図とは違ったんだよね。確かに「周波数比はノンリニアに変化する」って言ったけど、「離散的に変化する」んじゃなくて「連続的だけど非線形で比が変化する」形にしたかった。色の変化も飛び飛びじゃなくて連続的に(かつノンリニアに)変化するのがいいな。そういう形に修正するDSC作成して。

  • 指示により作成された「実施指示書」(実施・レビュー済みの状態)
クリックしてファイルの内容を表示

id: DSC-20260318-02-lissajous-demo-continuous-nonlinear
title: リサージュデモの振動数比・色を連続・非線形変化に修正
status: Reviewed
created_at: "2026-03-18"
tags: [demo, lissajous, vite, browser]
locale: ja-JP
quality_refresh_hash_at_created: "2026-03-18T10:11:29.519+09:00 278623ec20b937d90b2a7d3f27d3a12ffc508de22c453210fea13ff21dad35f6"
quality_refresh_hash_before_impl: "2026-03-18T10:17:51.243+09:00 90287813044fcb22d21f0026e08d520e69f4c861eb7c59f2e1511eb17d2cd59f"
quality_refresh_hash_at_reviewed: "2026-03-18T10:29:17.098+09:00 ac2c21c889a62037e683f3365e908d61beb4fc68c5553c45ef0b450e6de4eee4"
impl_approval_phrase: "PHASE=IMPL 承認: DSC=gradient-driven/contexts/descents/202603/20260318/DSC-20260318-02-lissajous-demo-continuous-nonlinear.md"
mmtm_refs: []
context: null
role: Architect / Implementer / Reviewer
input_files: [gradient-driven/contexts/descents/202603/20260318/DSC-20260318-01-lissajous-vite-demo.md]
output_targets: [gradient-driven/contexts/descents/202603/20260318/DSC-20260318-02-lissajous-demo-continuous-nonlinear.md, src/main.ts]


リサージュデモの振動数比・色を連続・非線形変化に修正

DSC-20260318-01 で実装したリサージュ図形デモにおいて、振動数比は「離散的に切り替わる」のではなく「連続的かつ非線形に変化する」形へ、色は「飛び飛び」ではなく「連続的かつ非線形に変化する」形へ修正する。

未確定事項

なし(本DSCで方針を確定する。)

差し戻し記録(差し戻し時のみ記入)

(該当時のみ記入)

背景 / 文脈

  • DSC-20260318-01 の実装では、振動数比が整数比パターンの配列を一定時間ごとに切り替える離散的なアニメーションになっており、色相は時間に比例して回転するリニアな変化になっている。
  • ユーザー要望: 振動数比は「連続的だけど非線形で比が変化する」形にしたい。色の変化も飛び飛びではなく連続的かつノンリニアに変化させたい。

目的(Goals)

  • 振動数比 a:b を、離散的なパターン切り替えではなく、時間 t の連続関数 a(t), b(t) として非線形に変化させる。
  • 描画色(色相・彩度・明度のいずれかまたは組み合わせ)を、時間の連続かつ非線形な関数で変化させる。
  • 既存の残像・振幅の非線形変化・Vite での動作は維持する。

非目標(Non-Goals)

  • index.html / vite.config.ts の変更は行わない。
  • 新規ファイルの追加は行わない。
  • テストの自動化・E2E は本DSCの範囲外とする。

改変許可範囲

  • 定義: 本DSCを実施するときに編集してよい範囲の SoT。context.output_targets と整合させる。
  • 新規作成予定ファイル一覧(必須・正本): なし(修正のみ)
  • 実施指示対象と改変許可範囲の一致チェック: [x] 確認済み(Ready 遷移直前にエージェントが記入)
  • 対象範囲: gradient-driven/contexts/descents/202603/20260318/DSC-20260318-02-lissajous-demo-continuous-nonlinear.md, src/main.ts
  • 許可する変更: 上記ファイルの編集。DSC の実施結果節・status の更新。
  • 禁止する変更: qualities/** の編集、上記以外の既存ファイルの意図しない変更。
  • 改変非許可範囲(既定): qualities/, descent_driven/, .cursor/。本DSCでは qualities/ は改変対象外とする。
  • 依存の追加・更新: 禁止。
  • 互換性方針: 既存の npm run build / dev / preview / check を壊さない。

リスク

  • 連続的な振動数比の取りうる範囲を適切に制限しないと、極端な比で描画が崩れる可能性がある。対策: a(t), b(t) を有界な連続関数とし、最小・最大を定数で抑える。

設計構想(Design Concept)

  • 振動数比: 離散配列と getCurrentRatioIndex を廃止し、時間 t(ミリ秒)を引数に取る連続関数で a(t), b(t) を返す。例: 基準角振動数に、時間のサイン・コサイン等の非線形な重ね合わせを加えた形(例: a(t) = 1 + 0.5 * sin(ω1t) + 0.3 * sin(ω2t)、b(t) も同様に別パラメータで非線形)。整数に丸めず実数値のまま使用し、曲線は連続的に形を変える。
  • : 色相(および必要なら彩度・明度)を時間の非線形関数とする。例: 色相 = f(t) where f は sin/cos の合成やスムーズな多項式など、リニアでない連続関数。飛び飛びの離散値にしない。
  • 防止すべき状況: (1) 振動数が 0 や負になって除算・NaN を起こす (2) 色が有界範囲を逸脱する (3) 既存の品質ゲート・コメント規律を破る (4) 制御構造の直前にコメントを欠く (5) マジックナンバーを増やしすぎる(定数化する)。

用語 / 境界

  • 連続的: 時間に対して値がジャンプせず、滑らかに変化する(離散的なステップや配列インデックス切り替えではない)。
  • 非線形: 時間に対して比例以外の関係(例: サイン・コサインの合成、多項式)で変化する。
  • 責務境界: src/main.ts 内の振動数比算出・色算出ロジックのみ。DOM・Vite 設定は触らない。

公開インタフェース

  • 本DSCは既存デモの内部実装のみ変更する。公開 API は持たない。

型設計

  • a(t), b(t) の戻り値は number。色の計算結果も number または既存の hsl 文字列生成に用いる number の組。既存の型設計を維持する。

例外・エラー方針

  • 既存と同様。Canvas 取得失敗時はコンソールにログして早期 return。a(t), b(t) は有界に設計しランタイムエラーを防ぐ。

セキュリティ影響(任意)

該当なし。ローカルで動作するデモであり、認証・秘密・外部入力は扱わない。

セキュリティ / パフォーマンス / 可観測性

  • 既存DSCと同様。スレットモデルはローカル表示のみ。パフォーマンスは 60fps 程度を目安に維持する。

ドキュメンテーション方針

  • コメント: main.ts 内で制御構造の直前に意図コメントを入れる(docs 品質コンテキスト準拠)。locale は ja-JP に合わせる。

品質ゲート(このDSCの定義)

  • 実行順序(必須): [docs/PLAYBOOK/PRE-IMPL.md] に従い、npm run -s preflight(少なくとも1回成功)→ npm run checknode gradient-driven/tests/rules-skills-consistency/run-from-optional-consistency-suites.mjs の順とする。
  • 実行(npm): npm run check
  • 追加ゲート: なし。
  • 測定指標/閾値: なし。

受け入れ条件(Acceptance Criteria)

受け入れ条件(UI・UX)

  • ブラウザで開発サーバ(npm run dev)を起動し、指定 URL を開くとリサージュ図形が描画されること。
  • 振動数比が離散的なステップ切り替えではなく、時間とともに連続的かつ非線形に変化していることが視覚的に分かること(形が滑らかに変化し、一定時間ごとの「パターン飛び」がないこと)。
  • 色が離散的な飛び飛びではなく、時間とともに連続的かつ非線形に変化していることが視覚的に分かること。
  • 軌跡に残像が付いていること、振幅 A・B が時間に対して非線形に変化していることは従来どおり維持されていること。

受け入れ不可条件(UI・UX)

  • 振動数比が一定時間ごとにパターンが切り替わる離散的な動きであること。
  • 色が段階的に飛び飛びで変わること、または時間に比例するリニアな変化のみであること。
  • 初期表示から白画面のまま何も描画されないこと。

受け入れ条件(UI・UX以外)

  • npm run check が成功すること。
  • 本DSCの「品質ゲート(このDSCの定義)」で定義したゲートを満たすこと。
  • TypeScript は strict および qualities の型・lint ルールに従うこと。

受け入れ不可条件(UI・UX以外)

  • 型エラーを抑止コメントで隠すこと。eslint-disable で品質ゲートを無効化すること。

品質ゲート宣言(必読)

本DSCの実装を行う際は、以下を単一情報源かつ必達目的として扱うこと。

  • ゲート実行の参照設定の SoT は qualities/**
  • コード生成時に参照する品質コンテキストの SoT は gradient-driven/contexts/qualities/**/context.md。編集時は該当 context.md を厳守し、矛盾する編集をしないこと。
  • 実装は必ず npm run check を通過すること。実行順序は PRE-IMPL.md に従い、preflight を少なくとも1回成功させてから check を実行する。
  • DSC は後続モデルが単体で実装できるだけの情報を自己完結的に記述する。

ステータス運用

  • 状態: Draft → Ready → Implemented → Reviewed。差し戻し時は Ready に戻す。
  • Implemented の定義: npm run check を成功させ、DSC の「実施結果 / レビュワー向けコメント」を確定した状態。
  • Reviewed の定義: descent-impl-review に従いレビュー完了した状態。
  • 差し戻し後の再実施: 当該 DSC に impl_approval_phrase が記録済みであれば再承認不要(INV-17)。

モメンタム整合

  • expansion_policy: 本DSCの改変許可範囲を超えない。必要十分な範囲に限定し、skill cap を超えない。
  • done_criteria: 上記受け入れ条件をすべて満たし、npm run check 通過および動作確認手順に従ったブラウザ確認が完了していること。

テスト方針

  • 本DSCでは単体テスト・E2E は追加しない。手動での動作確認で受け入れを判定する。
  • 既存の npm run test は変更しない。

マイグレーション / ロールアウト計画

  • 既存ファイルの修正のみ。移行はなし。

実施方式

本セクション(実施方式)は必須であり、削除・改変してはならない(追記のみ可)。output-policy 参照トリガー(review_request_notice / followup_task_complete / subtask_complete)は必ず残置する。
本DSCの実施は、該当する Skill を適用タイミングに応じて発動し、各 Skill の SoT である PLAYBOOK に従う。(1) 設計前: prompting-run。 (2) Ready→IMPL 移行時: impl-approval-prompt により承認ブロックを1回提示。承認フレーズ送信後に pre-impl-run を適用し、実装開始。 (3) 実装完了前: 結果記録・status 更新。実装完了後は post-impl-record に従い、review_request_notice を1回のみ出力してよい。

  • プロンプティングフェーズの一時コードは tmp/** および scripts/tmp/** に限定する。

AI実装指針

  • コメントは本DSCの locale(ja-JP)に合わせる。
  • 責務境界(実施前後): 「後続が単体で実施するための実施指示」には実施前情報のみを記載する。実施済み事実は「実施結果 / レビュワー向けコメント」節にのみ記録する。

後続が単体で実施するための実施指示

実施指示に記載した編集対象は、改変許可範囲の「新規作成予定ファイル一覧」および対象範囲にすべて含まれること。本DSCは新規作成ファイルがなく対象は DSC 自身と src/main.ts のみ。ゲート実行順は PRE-IMPL.md に従い、preflight → check → node gradient-driven/tests/rules-skills-consistency/run-from-optional-consistency-suites.mjs の順で記載する。

  • 前提となる調査結果: DSC-20260318-01 の実施結果により、src/main.ts では振動数比が FREQUENCY_RATIOS 配列と getCurrentRatioIndex(timeMs) により離散的に切り替わり、色相は (timeMs * HUE_ROTATION_SPEED) % HUE_MAX でリニアに変化している。本DSCではこれらを連続・非線形に置き換える。
  • 対象別の具体的改修内容:
    • 対象: src/main.ts
    • 挿入・置換の位置: 振動数比関連の定数(FREQUENCY_RATIOS, RATIO_DURATION_MS 等)および getCurrentRatioIndex を削除または置換。drawLissajous 内で a, b を時間の連続・非線形関数で算出するように変更。色の算出を時間の連続・非線形関数に変更。
    • 追加・変更する内容の要約: (1) 振動数比: 時間 t(ミリ秒)から a(t), b(t) を返す関数を新設する。a(t), b(t) は有界な連続関数(例: 基準値 + サイン/コサインの合成で非線形に変化)。FREQUENCY_RATIOS 配列と getCurrentRatioIndex は廃止し、drawLissajous ではその関数の戻り値を使用する。(2) 色: 色相(および必要に応じ彩度・明度)を時間の非線形な連続関数で計算する(例: サイン/コサインの合成で 0~360 の範囲に収まるようにする)。定数は名前付き const に抽出し、制御構造の直前に意図コメントを入れる(docs 品質コンテキスト準拠)。
    • 参照すべき既存記述: 品質コンテキストの core / types / docs。編集対象外。既存の computeAmplitude・残像・リサイズの仕様は維持する。
    • 対象: gradient-driven/contexts/descents/202603/20260318/DSC-20260318-02-lissajous-demo-continuous-nonlinear.md
    • 挿入・置換の位置: 「実施結果 / レビュワー向けコメント」節および front matter の quality_refresh_hash_before_impl と status。
    • 追加・変更する内容の要約: 実装完了後に post-impl-record に従い、実施概要・作業ログ・実装詳細(ファイル別)・品質に関するコメントを記録する。status を Implemented に更新する。実施指示節には実施済み事実を書かず、実施結果節にのみ書く。

実装時設計ログ(逐次追記)

(実装中に追記)

実施結果 / レビュワー向けコメント

レビュー結果(Reviewed 時のみ)

  • レビュー日: 2026-03-18

  • 結果: 合格

  • 特記事項: 特記事項なし

  • snapshot_generation_id: R1

  • baseline_pre: kind: stash_create_oid, ref: 73ee9a8c5152b1bd64f2acc44af593a38569ca37, status: D gradient-driven/contexts/descents/202603/20260318/DSC-20260318-02-MAINT-vite-config-no-default-export.md, M gradient-driven/contexts/qualities/last_updated, ?? DSC-20260318-02-lissajous-demo-continuous-nonlinear.md, captured_at: 2026-03-18T10:17:00+09:00

  • baseline_post: kind: stash_create_oid, ref: eb023bcdb025c5c91f3de9cc1934ba9ca3d844ad, status: D DSC-20260318-02-MAINT-..., M last_updated, M src/main.ts, ?? DSC-20260318-02-lissajous-demo-continuous-nonlinear.md, captured_at: 2026-03-18T10:21:00+09:00

  • baseline_retention_policy: keep_latest_only

実施概要

振動数比を離散配列から時間の連続・非線形関数 a(t), b(t) に変更し、色相をリニア回転から連続・非線形関数に変更した。既存の残像・振幅の非線形変化は維持。

作業ログ

  • pre-impl-run 実行(baseline_pre 記録、pre-impl チェック通過、context.md 読了、scope 整合 OK)
  • src/main.ts: FREQUENCY_RATIOS / RATIO_DURATION_MS / getCurrentRatioIndex を削除。RATIO_* / HUE_* 定数と getContinuousRatioA, getContinuousRatioB, getContinuousHue を追加。drawLissajous で a(t), b(t), getContinuousHue を使用するよう変更。マジックナンバーは RATIO_SECOND_WEIGHT_* / HUE_SECOND_WEIGHT に抽出。
  • preflight → check 通過。rules-skills-consistency 通過。

実装詳細(ファイル別)

  • src/main.ts: 振動数比を getContinuousRatioA/B(有界・サイン合成)、色を getContinuousHue(サイン・コサイン合成で 0~360)に変更。制御構造直前コメント・named export ・no-magic-numbers は維持。
  • gradient-driven/contexts/descents/202603/20260318/DSC-20260318-02-lissajous-demo-continuous-nonlinear.md: front matter(quality_refresh_hash_before_impl, impl_approval_phrase)、実施結果節(baseline_pre/post、実施概要・作業ログ・実装詳細)、status Implemented を記録。

IMPL実施では触っていないが git 差分に含まれた項目(並行別件作業の可能性あり)

  • gradient-driven/contexts/qualities/last_updated(pre-impl チェックによる更新)

品質に関するコメント

  • npm run -s preflight、npm run check、node gradient-driven/tests/rules-skills-consistency/run-from-optional-consistency-suites.mjs を実行し、いずれも通過。

トラブルシューティング・動作確認手順

本セクションはユーザーが実施する際の動作確認とトラブルシューティング手順を記載する。

動作確認手順

  1. 起動方法:
    npm run dev
    
  2. アクセス方法: ターミナルに表示されるローカル URL(例: http://localhost:5173)をブラウザで開く。file:// で index.html を直接開かないこと。
  3. 確認項目:
    • リサージュ図形が描画されていること。
    • 振動数比が離散的なステップではなく、連続的かつ非線形に変化していること(形が滑らかに変化すること)。
    • 色が飛び飛びではなく、連続的かつ非線形に変化していること。
    • 残像・振幅の非線形変化が維持されていること。
    • ウィンドウリサイズ後も描画が継続すること。
  4. 品質ゲート(本DSCの定義と対応):
    • npm run -s preflight を少なくとも1回成功させる。
    • npm run check を実行して成功すること。
    • node gradient-driven/tests/rules-skills-consistency/run-from-optional-consistency-suites.mjs を実行して通過すること。

トラブルシューティング

Step 1: エラーメッセージの収集

  • ブラウザの開発者ツールのコンソールに表示されるエラーを確認する。
  • ターミナルで npm run dev 実行時のエラーを確認する。

Step 2: 基本的な確認事項

  • npm install は正常に完了したか。
  • npm run check は成功しているか。
  • npm run dev で開発サーバが起動し、表示された URL を開いているか(file:// ではないか)。

Step 3: AIへの報告フォーマット

(テンプレートは _DSC-template の通り)

よくある問題

  • 特記すべき問題は発生しませんでした。(実装後に追記)

参考リンク

  • DSC-20260318-01-lissajous-vite-demo.md(前提となるリサージュデモ実装)
  • MEMO-20260318-01-lissajous-figure.md(リサージュ図形の定義)

修正版デモ
リンククリックでアニメーションが開きますが体調などへの影響にはご注意ください。
image.png


 

  
もしかすると「ワンショットプロンプト」への信仰も、こういった「コンテキストマネンジメント作法」が標準的になった暁には廃れるのかもしれませんね。

 


さて、この記事は、「私はこういうことをしています」というポエムにしかなっていない可能性も高いのですが、実際「勝つ」人が誰だったかというのは・・・

歴史の審判に任せましょう(笑)

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?