Pryne フロントエンドデバッグプレイブック は何をしますか?
Pryne のバニラ JavaScript デモビルド向け症状→トリアージガイド:単一ファイル HTML ページで、window.Roll モジュールスパイン(design-demos/js/roll-*.js)、WebGL グレインシェーダー(2D フォールバック付き)、1 つの rAF レンダリングループ、ベンダリングされた Lenis スムーススクロール、非同期 CDN からロードされる GSAP(プログレッシブエンハンスメントとして)を使用。
必須の背景知識: superpowers:systematic-debugging が一般的な根本原因の規律(調査なしに修正しない)を担当します。これに従い、このスキルはプロジェクト固有の症状テーブルと落とし穴のみを提供します。
ツール: ブラウザの操作方法、コンソールの取得、モーション削減のエミュレート、トレースの取得については、pryne-browser-lab を使用してください。このスキルは、それらのコマンドを既に実行できることを前提としています。
最初にヘッドコメントを読む
すべての v4 デモ(design-demos/ 内の v4-a から v4-d)は、ファイルの先頭に HTML コメントとして監査履歴を保持しています — 何が壊れていたか、何が修正されたか、その理由。2026-07-22 時点で全 4 ファイルで確認済み。再診断する前に、デバッグ対象のデモの先頭 30 行を確認してください。 見つける「バグ」のいくつかは、既に修正済みの回帰として文書化されています。もし再発した場合、新しい原因を探すのではなく、何がそれを元に戻したのかを調査してください。
また、ビルド構成(2026-07-22 時点)も理解してください:共有の roll-*.js モジュールを使用しているのは v4-d-hybrid.html のみです。v4-a/b/c はスコープを縮小した比較用ビルドで、独自のインライン JS を持っています — このテーブルの Roll 固有のチェックはそれらには適用されませんが、同じ障害クラスは適用されます。
コンソールエラーゼロが定常状態
基準はコンソールエラーゼロです(design-demos/DECISIONS.md の CRITIQUE ルーブリックで要求)。v3 はプロジェクトステータスログに従ってゼロが確認済み。v4 バリアントは方向性キャンペーン(pryne-design-direction-decision)が完了するまで未認定です。コンソールエラーはすべてトリアージすべき欠陥であり、無視してスクロールする周辺ノイズではありません。
症状 → トリアージテーブル
| 症状 | 考えられる原因 | 判別チェック |
|---|---|---|
| アニメーション/開発プレートが、そのセクションがスクロールされて表示される前に実行(または終了)する | 可視性ゲーティングの回帰。v4-d のヘッドコメントはこれを単一最高優先度の監査修正として記録:フィーチャープレートが「ページロードから無条件にティックし、誰もスクロールして到達する前に解決を終えていた」。開発はパネルの .in クラスでゲートする必要がある。 | 下記の実験 1 |
| リビールアニメーションが誤ってクリップされる、ジャンプする、またはトリガーされない | IntersectionObserver が監視する要素自体に clip-path が適用されている(内部ラッパーではなく)。コンセプト C の修正(v4-d に引き継がれ、ヘッドコメントに記載):リビールクリップパスは内部ラッパーに配置し、決して監視対象要素には配置しない。 | 要素を検査:監視対象ノードとクリップ対象ノードが同じか? |
| OS カーソルが消え、カスタムカーソルに置き換わらない | 再発しないはず — 2026-07-22 修正(コールドテスト監査で発見、同日修正):イベントハンドラ(roll-cursor.js:17-20)とその pointermove 呼び出し箇所(roll-core.js:26-29)が、元のセットアップ時キャッチに加えて、両方ともキャッチ&リストア(null の Roll.cursorUpdate、.custom-cursor を削除)するようになった;#cur/#ring の z-index を #flash(60) より上の 50→70 に引き上げ、クライマックスパルスがカーソルを塗りつぶせないようにした。症状が再発した場合、これらのガードのいずれかが後退したか、新しいコードがこの契約外でカーソルを非表示にしている。 | document.body.classList.contains('custom-cursor') と Roll.cursorUpdate — true/null の組み合わせが壊れた状態。両方とも正常に見える場合、getComputedStyle(cur).opacity を確認し、クライマックスフラッシュでのみ消えるかどうか確認 |
| WebGL ゴースト/軌跡、または色がページに対して誤ってブレンドされる | フレームごとのクリアがない、またはプリマルチプライドアルファの不一致。roll-shader.js は毎フレーム gl.clear(gl.COLOR_BUFFER_BIT) を呼び出し、{ alpha: true, premultipliedAlpha: false } でコンテキストを作成(両方とも監査修正、v4-d ヘッドコメントに記載)。 | roll-shader.js を git で差分:git diff HEAD -- design-demos/js/roll-shader.js |
| シェーダーキャンバスが真っ白、グレインがまったく表示されない | (a) モーション削減 — GL は意図的にセットアップされない(useGL = !Roll.reduced && setupGL());(b) WebGL コンテキストロスト — webglcontextlost ハンドラがキャンバスの opacity を 0 に設定し、静かに失敗する;(c) WebGL の前に 2D コンテキストが取得された(1 キャンバスにつき 1 コンテキストのみ、永遠に — roll-shader.js の先頭に文書化)。 | まず Roll.reduced。コンテキストロストの場合、ハンドラの観測可能な効果を確認:getComputedStyle(document.getElementById('tone')).opacity === '0'。注意:Roll.shader.useGL はセットアップ時のスナップショット(roll-shader.js:120-121) — webglcontextlost ハンドラはクロージャ変数(roll-shader.js:130-132)のみを変更するため、コンテキストロスト後も Roll.shader.useGL は true のまま。これを使用してロストを除外しないこと。 |
| スクロールコレオグラフィが停止しているが、ページはレンダリングされスクロールも正常 | スクリプトのロード順序または window.Roll 名前空間の破損。スクリプトの順序は重要 — チェーンとチェックコマンドは pryne-frontend-architecture に記載。各モジュールは IIFE で、window.Roll を介してのみ状態を共有;初期モジュールで 1 つのエラーがスローされると、後続のすべてが枯渇する。 | 下記の実験 2;コンソールに Roll.X is undefined と表示され、枯渇したモジュールが特定される |
| 1 ユーザーから「すべてのモーションが停止」という報告があり、自分のマシンでは正常 | ユーザーで prefers-reduced-motion が有効。これは 正しい動作であり、バグではない:roll-core.js がメディアクエリから Roll.reduced を設定し、すべてのモジュールがこれでゲートする(カバー削除、プレートは完全に展開されて即座に表示、Lenis スキップ、シェーダーオフ)。「修正」しないこと。 | 下記の実験 3 |
| トラックパッド/ホイール/タッチ間でスクロール感が一貫しない | 生のスクロールデルタのばらつき — Lenis をベンダリングした文書化された理由(design-demos/DECISIONS.md 参照)。Lenis はネイティブスクロールをラップするため window.scrollY は有効のまま;これは感触のアップグレードのみで、モーション削減時は null。 | typeof Lenis(ロードされたか?)、次にデモがスクロールモジュールで Lenis を構築しているか確認 |
| ベースラインは動作するが、ホバー/キネティック/カーソルの装飾がない | GSAP CDN が失敗したかブロックされた。GSAP は jsdelivr(SRI ピン留め)から async でロードされ、到着したときのみ Roll.upgradeMotion() を介して Roll.enhanced = true を切り替える。プログレッシブエンハンスメントは設計による:ベースラインのコレオグラフィはこれなしでも動作しなければならない。ベースラインも壊れている場合、これが原因ではない。 | 下記の実験 4 |
| 音声が無音 | ミュートがデフォルト:roll-audio.js はミュートで開始し、localStorage['ch001_muted'] に選択を永続化し、#mute-toggle のクリック(ユーザージェスチャー、自動再生ポリシーを満たす)からのみアンビエントハムを開始する。すべての合成は try/catch でラップされ、アセットは不要。コードを疑う前に SND トグル状態を確認。 | Roll.audio.muted、および localStorage.getItem('ch001_muted') |
| 固定 HUD がフッターと重なる/隠す | フッターフェード修正の回帰:footer の IntersectionObserver がビートメーターとミュートボタンに .faded クラスをトグルする(roll-scroll.js)。 | フッターまでスクロール;#beatmeter に .faded が表示されるか確認 |
判別実験
これらの実験をページコンソールまたは evaluate_script(pryne-browser-lab 参照)で実行してください。各実験は、コードに触れる前に 1 つの質問に答えます。
1 — プレート開発は可視性で正しくゲートされているか?
({ workVisible: document.getElementById('work').classList.contains('in'),
plate1: { d: Roll.featurePlate.d, done: !!Roll.featurePlate.done },
plate2: { d: Roll.featurePlate2.d, done: !!Roll.featurePlate2.done } })
新規ロード時、work セクションまでスクロールする前:workVisible: false かつ両方の d 値が 0 付近。workVisible が false の間に d が上昇している(または done: true)場合、ゲーティングが後退している。
2 — Roll スパインは無傷か?
({ core: !!window.Roll, reduced: Roll?.reduced, enhanced: Roll?.enhanced,
shader: !!Roll?.shader, audio: !!Roll?.audio, plates: !!Roll?.plates,
cursorUpdate: Roll?.cursorUpdate === null ? 'null' : typeof Roll?.cursorUpdate })
cursorUpdate について:これは 初期化 時に null(roll-core.js:23)であり、GSAP ロード前や pointer: fine ではないデバイスでも null — null だけでは何の証明にもならない。「フェイルセーフ」は、document.body.classList.contains('custom-cursor') が true かつ cursorUpdate が null の場合のみ示される(トリアージテーブルのカーソル行を参照)。
false/undefined がある場合、完了しなかったモジュールを特定 — コンソールでスローされたエラーを確認し、HTML 内のスクリプト順序を上記の負荷依存順序と照合。
3 — 「すべてのモーションが停止」は単なるモーション削減か?
({ mediaQuery: matchMedia('(prefers-reduced-motion: reduce)').matches, roll: Roll.reduced })
両方 true → 設計通りに動作;モーション削減をエミュレートして(pryne-browser-lab)レポートを再現。mediaQuery: true だが roll: false(または逆)→ モジュールが間違った真実のソースを読んでいる。
4 — GSAP エンハンスメントレイヤーはロードされたか?
({ gsapLoaded: !!window.gsap, enhanced: Roll.enhanced, reduced: Roll.reduced })
gsapLoaded: false → CDN がブロック/失敗(ネットワークパネルで jsdelivr リクエストを確認;SRI 不一致もここに該当)。gsapLoaded: true, enhanced: false, reduced: false → upgradeMotion() が実行されていない — スクリプトタグの onload フックを確認。
実際の時間を浪費する落とし穴
| 落とし穴 | ストーリー(一行) | フェンス |
|---|---|---|
| 「確認済み動作」≠正しい方向 | v3 NIGHT DRIVE は完全に構築され、コンソールエラーゼロ、確認済み — その後、統一コンセプトが間違っていたため置き換えられた(詳細:pryne-failure-archaeology)。 | コンセプトが現在の方向として確認されていないビルドの修正/デバッグに努力を費やさない。最初に DECISIONS.md とボールトステータスを確認。 |
| 文書化済み修正を再診断する | 各 v4 ヘッドコメントは、既に発見・修正された欠陥の変更履歴。 | devtools を開く前にヘッドコメントを読む。リストされた修正が壊れているように見える場合、症状ではなく、それを戻した原因を調査。 |
| モーション削減を「修正」する | すべてのモーションオフは、prefers-reduced-motion ユーザー向けの設計された動作であり、1 か所(Roll.reduced)でゲートされている。 | モーションなしのレポートを欠陥として扱う前に実験 3 を実行。 |
| 「何かをテストする」ために 2D コンテキストを取得する | キャンバスは 1 つのコンテキストタイプしか持てない;最初に 2D を取得すると、そのキャンバスで WebGL が永久に不可能になる(roll-shader.js に文書化)。 | コンソール実験で #tone に対して getContext('2d') を絶対に呼び出さない。 |
このスキルを使用すべきでない場合
- 一般的なデバッグ規律(仮説、最小限の変更、修正前の根本原因) → superpowers:systematic-debugging。
- ブラウザの操作方法/測定方法(MCP ツールの構造、トレース、Lighthouse、スクリーンショット) → pryne-browser-lab。
- 動作がデザイン不変条件に違反するかどうかの判断(モーション削減ゲーティング、ささやきレベルのパーソナリティ、ベンダリング) → pryne-frontend-architecture。
- 何かが構築/元に戻された全履歴 → pryne-failure-archaeology。
- その他のスタック(React/フレームワークビルド、Pryne 以外のプロジェクト):上記のテーブルは
window.Rollデモファミリーに固有;汎用の規律のみが転用可能。
出典とメンテナンス
scripts/verify.sh(このスキルのディレクトリ内)を実行して、以下のすべてを一度に確認してください。
事実は 2026-07-22 時点のもので、リポジトリ ~/Documents/Coding Folder/Portfolio (test) のコミット 457868a で確認済み。信頼する前に再確認:
- モジュールリストとサイズ:
wc -l design-demos/js/*.js - スクリプトロード順序:
grep -n "<script" design-demos/v4-d-hybrid.html - 共有モジュールを使用するデモ:
grep -l "roll-core.js" design-demos/*.html - ヘッドコメント規則がまだ有効か:
for f in design-demos/v4-*.html; do echo "== $f"; head -5 "$f"; done - モーション削減ゲート:
grep -n "prefers-reduced-motion\|Roll.reduced" design-demos/js/*.js - プレート可視性ゲーティング:
grep -n "classList.contains('in')" design-demos/js/roll-scroll.js - Lenis ベンダリング&配線:
ls design-demos/js/vendor/ && grep -n "new Lenis" design-demos/js/roll-scroll.js - GSAP エンハンスメントフック:
grep -n "upgradeMotion" design-demos/js/roll-core.js design-demos/v4-d-hybrid.html - オーディオミュートデフォルトとストレージキー:
grep -n "ch001_muted" design-demos/js/roll-audio.js - コンソールエラーゼロ基準:
grep -n "console errors" design-demos/DECISIONS.md