with-canvas
Canvas作業は、見た目はきれいだがカクカクするビジュアルコードと、最適化されているが保守不可能またはアクセシブルでないコード、という2つの異なる方法で失敗します。すべてのタスクを、描画呼び出しを書く前のレンダリングアーキテクチャの決定として扱ってください。現在のフェーズで指定された参照のみを読み込み、すべての参照を事前に読み込まないでください。
フェーズ1 - Canvasジョブの分類
APIを選択する前に、支配的なワークロードを特定します。
- Canvasを却下: シーンが主にテキスト、アクセシブルなコントロール、ドキュメントレイアウト、シンプルなアイコン、CSSアニメーション、メディア再生、または少数のスケーラブルなベクター形状である場合は、DOM/CSS/SVG/ビデオを優先します。
- 装飾アニメーション: 非インタラクティブな雰囲気、背景パーティクル、星、鳥、プロシージャルループ。
- データレンダリング: チャート、マップ、ヒートマップ、大規模な点群、頻繁に更新される測定値。
- ジェネレーティブアート: シード付き/ランダム描画、クリエイティブスケッチ、プロシージャルシステム、エクスポート可能な画像。
- インタラクティブツール: ポインター/キーボード入力、選択、ドラッグ、編集可能オブジェクト、ヒットテスト。
- ゲーム/シミュレーション: 固定更新ループ、動的エンティティ、衝突/物理、レイヤードシーン。
- WebGL/エンジンCanvas: Three.js/Babylon.js/その他のレンダラーがGPUリソースを所有。
必須: ワークロードが装飾アニメーションまたはジェネレーティブアートの場合は、references/visual-quality.mdを読んでください。これらの2つのジョブでは、見た目を良くすることがタスクであり、パフォーマンスとアクセシビリティの衛生管理だけでは凡庸な出力になります。データレンダリング、ツール、ゲーム、エンジンCanvasには読み込まないでください。
終了条件: ワークロード、Canvasが適切なプリミティブである理由、目標フレームレート、予想オブジェクト数、インタラクションモデル、およびCanvasが装飾的か意味的に意味があるかを記述します。
フェーズ2 - レンダリングモデルの選択
シーンが主にイミディエイトモード描画、ピクセルワーク、スプライト、シンプルなアニメーション、またはバンドルサイズが重要な場合は、生のCanvas 2Dを使用します。
アプリが編集可能なオブジェクト、選択、ドラッグ/ドロップ、レイヤードシーングラフ、イベント委譲、またはシリアライゼーションを必要とする場合は、リテインドモードライブラリを使用します。
スケッチ、ジェネレーティブアート、教育/プロトタイピング、またはセットアップ/描画のエルゴノミクスがフレームワーク統合よりも重要なクリエイティブコーディングには、p5.jsを使用します。
ベクター編集ワークフロー(パス、セグメント、ベジェジオメトリ、ヒットテスト、SVGインポート/エクスポート、レイヤードベクタードキュメント)にはPaper.jsを使用します。
アプリUI用のCanvas(React/Vue/Svelte統合、ドラッグ可能な形状、レイヤー、キャッシュされた形状、イベントリスニングコントロール)にはKonvaを使用します。
軽量なシーン/コンポーネント抽象化には、そのコンポーネントモデルが適合し、依存関係の新しさがプロジェクトにとって許容できる場合にPencil.jsを使用します。
支配的なコストが3D/GPUレンダリング、シェーダー、カメラ、マテリアル、または大規模なメッシュ/スプライトワークロードである場合は、Three.js/Babylon.js、または直接WebGLを使用します。
必須: ライブラリを選択するか、ライブラリの選択をレビューする場合は、references/library-selection.mdを読んでください。タスクがそれらのフェーズに達しない限り、パフォーマンスやレビューの参照を読み込まないでください。
Canvasライブラリをインストールする前、または重要ではないライブラリAPIコードを書く前に、利用可能な場合はContext7で現在のドキュメントを確認し、そうでない場合は公式ドキュメントを使用してください。p5.js、Paper.js、Pencil.js、Konva、ZIM、Three.js、Babylon.jsについては、記憶したAPIに依存しないでください。
終了条件: モデルと、拒否された代替案を一行の理由とともに挙げます。
フェーズ3 - ループと状態の設計
Canvasコードを、ライフサイクル、状態更新、レンダリング、入力、リサイズ、後片付けに分離します。フレームワークコンポーネントの場合、命令型Canvasエンジンを1つのマウント/初期化境界の背後に保ちます。
表示中のアニメーションにはrequestAnimationFrameを使用します。シミュレーション速度をリフレッシュレート間で安定させる必要がある場合は、RAFタイムスタンプからdeltaを追跡します。後片付け時にRAFをキャンセルし、非表示時には一時停止または作業を減らし、prefers-reduced-motionを尊重します。
以下の再描画戦略から1つを選択します。
- 全再描画: シンプルさが勝る小規模/装飾的なシーンで許容されます。
- ダーティ矩形: 境界変更が小さく、背景が安定している移動オブジェクト。
- レイヤードCanvas: 静的/低速な背景、動的エンティティ、UI/インタラクションオーバーレイ。
- スプライト/キャッシュブロット: 繰り返される高コストな形状、テキスト、マーカー、拡大縮小画像、パーティクル。
- ワーカーOffscreenCanvas: 入力/メインスレッドと競合する高負荷な描画またはシミュレーション。
必須: アニメーション、大規模シーン、パーティクル、チャート、画像拡大縮小、高DPI出力、またはワーカーレンダリングを最適化する前に、references/performance.mdを読んでください。ライブラリを追加/置換しない限り、library-selectionを読み込まないでください。
終了条件: フレームパイプラインを順序に従って記述します: 入力サンプリング -> 更新 -> クリア/再描画戦略 -> 描画 -> 次のフレームをスケジュール。
フェーズ4 - Canvasの衛生管理の実装
CanvasのサイズはCSSだけでなくバッキングストアで設定します。鮮明な出力を得るには、CSSサイズを個別に設定し、canvas.width/height = cssSize * devicePixelRatioを設定し、ctx.setTransform(dpr, 0, 0, dpr, 0, 0)で変換を正規化します。パフォーマンス重視のシーンでは、意図的にDPRを下げます。
シーンに合ったオプションでコンテキストを初期化します。不透明なCanvasには{ alpha: false }を使用します。willReadFrequently: trueは頻繁なgetImageData読み取りの場合にのみ使用します。バッキング戦略が変わる可能性があるためです。
入力の場合、ポインター座標をgetBoundingClientRect()とCanvasスケールで変換します。clientX/clientYをCanvas座標として信頼しないでください。
アクセシビリティのために、装飾的なCanvasにはaria-hidden="true"を付け、インタラクティブハンドラーを付けません。意味のあるCanvasインタラクションには、DOMコントロール、キーボードパス、フォーカス管理、ラベル、または同等の非Canvas表現が必要です。
終了条件: リサイズ、DPR、コンテキストオプション、イベント座標マッピング、モーション設定、後片付けがすべて明示的に行われていること。
フェーズ5 - レビューと検証
Canvasコードをホットループとリソースライフサイクルとしてレビューします。視覚的な正しさだけで止まらないでください。
必須: 既存のCanvasコードをレビューするとき、または新しい実装を最終決定する前に、references/review-checklist.mdを読んでください。レビューに依存関係の適合性が含まれない限り、library-selectionを読み込まないでください。
タスクに適した少なくとも1つのランタイムシグナルで検証します: Chromeパフォーマンスパネル、FPSメーター、メモリスナップショット、インタラクション遅延、モーション削減パス、非表示タブの動作、または低スペック/モバイルスロットリング。
例
- ユーザーが「パーティクル背景を作って」と依頼: 装飾アニメーションとして分類し、パーティクル数またはプロシージャル描画がCanvasを正当化する場合のみDOM/SVGを却下し、見た目については
references/visual-quality.mdを、ループについてはreferences/performance.mdを読む。 - ユーザーが「選択機能付きのドラッグ可能な図形を作って」と依頼: インタラクティブツールとして分類し、
references/library-selection.mdを読み、オブジェクトモデルに基づいてKonva/Paper.js/生のCanvas 2Dを選択する可能性が高い。 - ユーザーが「このCanvasループをレビューして」と依頼: 既存のワークロードを分類し、
references/review-checklist.mdを読み、カクツキ、高オブジェクト数、またはホットパスの懸念がある場合のみreferences/performance.mdを読む。 - ユーザーが「p5スケッチを追加して」と依頼:
references/library-selection.mdを読み、APIコードの前に現在のp5ドキュメントを確認し、フレームワークのライフサイクル境界を明示的に保つ。
禁止事項
-
描画済みCanvasのリサイズをCSSのみで行わないこと 代わりに: バッキングストアの寸法とCSS寸法を意図的に設定し、リサイズ後にDPR変換を一度適用する。 理由: CSSのみの拡大縮小は出力をぼやけさせ、Retinaディスプレイで悪化するバッキングストアの不一致を隠します。
-
後片付けパスなしでRAFループを開始しないこと 代わりに: フレームIDを保存し、アンマウント/破棄時にキャンセルし、可視性またはメディアクエリの変更後に二重起動を防ぐ。 理由: 孤立したループは切り離されたCanvasへの描画を続け、メモリ/CPUリークを作成し、スナップショットはしばしばブラウザ内部に誤って帰属させます。
-
高コストな静的内容を、視覚的にシーンの一部だからという理由で毎フレーム再描画しないこと 代わりに: オフスクリーンCanvas、ImageBitmap、レイヤーCanvas、Path2D、またはライブラリ形状キャッシュにキャッシュする。 理由: Canvasはイミディエイトモードです。明示的にキャッシュまたはレイヤー化しない限り、変更されていないビジュアルでも完全な描画コストがかかります。
-
Canvasのみのインタラクションを唯一のアクセシブルなコントロールとして使用しないこと 代わりに: DOMコントロール/セマンティクス、またはラベルとフォーカス動作を備えたキーボード操作可能なリテインドオブジェクトモデルを提供する。 理由: Canvasピクセルは、ロール、名前、状態、またはヒットターゲットを支援技術に公開しません。
-
パフォーマンスが悪いからといって、Canvas作業をOffscreenCanvasに移行しないこと 代わりに: 最初にボトルネックが描画呼び出し、状態チャーン、オーバードロー、画像拡大縮小、ピクセル読み取り、またはシミュレーションのいずれであるかを特定し、メインスレッドの競合が問題である場合にワーカーを使用する。 理由: ワーカーは転送、バンドル、DOMアクセスの制約を追加します。悪い描画アーキテクチャを修正しません。
-
リテインドモードライブラリのパフォーマンスルールをオプションと見なさないこと 代わりに: 非アクティブなレイヤーでのリスニングを無効にし、高コストな形状をキャッシュし、レイヤー数を最小限に抑え、ライブラリのライフサイクルを通じてノード/ステージを破棄する。 理由: ライブラリはシーングラフとイベント機構を追加します。それらのスイッチを無視すると、生のCanvasよりも遅くなる可能性があります。