improve-threejs について
improve-threejsは、Three.jsおよびReact Three Fiberのコードベースを監査・改善するスキルです。React Doctorのスキャンに、描画ループを考慮した優先順位付けと根拠に基づく視覚検査を組み合わせ、性能、リソース管理、シーンの問題を特定します。
主な機能
- 01描画ループと操作のホットパスを把握
- 02React Doctorのスキャンを実行
- 03フレームループへの影響で問題を優先付け
- 04視覚チェック項目に沿ってシーンを検査
- 05性能とGPUリソースの問題を修正
- 06コード変更と描画動作を検証
活用シーン
- 01Three.jsまたはR3Fアプリの監査
- 02フレームコールバック内の割り当てや状態更新の特定
- 03シーンの根拠に基づく視覚的な問題の診断
- 04修正後の回帰と描画動作の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ millionco/ react-doctor --skill improve-threejsインストール後、Claude Code で/improve-threejsを入力して読み込まれたか確認します。
詳細
Three.js の改善
Three.js または React Three Fiber(R3F)のコードベースを監査し、最も影響の大きい問題を修正します。毎フレーム実行される処理、破棄されない GPU リソース、レンダリングのたびに再構築されるシーングラフオブジェクト、ユーザーが目にする視覚的な不具合が対象です。React Doctor は機械検証済みのコードスキャンを提供し、このスキルは一般的な React スキャナーでは対応できない、フレームループの評価と視覚的な確認を行います。
基本原則は、重大度はレンダーループに応じて決まるということです。useFrame 内や requestAnimationFrame のコールバック内のコードは毎秒 60 回実行されるため、そこでの軽微な非効率は、設定パネルにある重大な問題よりも優先されます。各指摘は、ルールの既定の重大度ではなく、どこで実行されるかに基づいて順位付けしてください。
ワークフロー
Step 1: 調査
スキャンの前にスタックを特定します。Three.js のみか R3F か、どのヘルパーライブラリ(drei、postprocessing、rapier)を使用しているか、レンダーループがどこにあるか(useFrame フック、requestAnimationFrame、<Canvas frameloop> の設定)を確認します。
ホットパスマップを作成します。すべての useFrame 本体、すべての RAF コールバック、すべてのポインター移動ハンドラーを記録してください。これらのファイルは Step 3 で最も厳しく確認します。
Step 2: スキャン
React Doctor を読み取り専用で実行し、構造化された証拠を収集します。
npx react-doctor@latest --verbose
変更後の回帰チェックでは、--scope changed を指定して実行し、スコアが下がっていないことを確認します。
Step 3: フレームループへの影響に基づくトリアージ
ホットパスマップを使ってスキャナーの指摘を再度順位付けし、続いてスキャナーでは検出できない Three.js 固有の問題を探します。報告する前に、すべての指摘について file:line を確認してください。
重大度:高。毎フレーム実行される、または GPU メモリをリークする問題:
useFrame内での割り当て:毎フレームnew Vector3()、new Color()を呼び出したり、新しい配列を Three.js API に渡したりする問題です。修正方法:スクラッチオブジェクトをモジュールスコープまたはuseMemoに置き、インプレースで変更しますuseFrame内でのsetState:フレームごとに React ツリーを再レンダリングします。修正方法:ref を直接変更し、状態は選択や表示状態など、個別の変更に限って使います- 破棄処理の不足:命令型に作成したジオメトリ、マテリアル、テクスチャ、レンダーターゲットが破棄されない問題です。修正方法:クリーンアップ関数で
dispose()を呼び出すか、オブジェクトを R3F の宣言的なツリーに移してライフサイクルを管理させます - レンダリング中のオブジェクト再構築:
useMemoを使わずにジオメトリやマテリアルのインスタンスを作成したり、インラインのargs配列の参照がレンダリングごとに変わったりして、R3F が内部オブジェクトを再構築する問題です
重大度:中。レンダリングごと、または操作ごとの無駄:
- 安定しないシーングラフの props:インラインの
new THREE.Vector3()や新しいマテリアルオブジェクトを props として渡す問題です(position={[x, y, z]}のような通常の配列は問題ありません。R3F が処理します) - インスタンシングの不足:同一のメッシュを数百個個別にレンダリングしており、
<Instances>やInstancedMeshを使っていない問題です - 無駄なフレーム:操作時にしか変化しないシーンで
frameloop="always"を指定している問題です。修正方法:frameloop="demand"とinvalidate()を使います - アセット読み込みのキャッシュ不足:
useLoader、useTexture、useGLTFを使わずにテクスチャやモデルを読み込み、キャッシュと Suspense との連携が失われる問題です
重大度:低。コードの健全性に関する問題: キャンバス以外の UI コードに関する React Doctor の指摘、<Preload> の不足、テクスチャサイズの過大。
Step 4: 視覚的な監査
シーンが実際にどのようにレンダリングされるかを確認します。視覚的な指摘にはすべて、スクリーンショット、フレームキャプチャ、または再現した観察結果といった証拠が必要です。ソースコードを読んだだけの推測は認められません。開発サーバーとブラウザーを利用できる場合は、アプリを読み込み、最初の安定したフレームをキャプチャしてから、カメラを動かして操作した後のフレームもキャプチャします。ブラウザーを利用できない場合は、以下に挙げるコード上の原因を確認し、各指摘にソースからの推定であることを明記します。
簡易評価基準を適用します。証拠が不具合の条件を示している場合に限り、その行を不合格とします。
| 領域 | チェック項目 | 失敗となる条件 |
|---|---|---|
| レンダリングの健全性 | ロード後にシーンが安定したフレームに到達する | 黒いキャンバス、WebGL コンテキストエラー、またはコンテンツがまったく表示されない |
| ジオメトリ | 継ぎ目、エッジ、境界に沿ってカメラを移動する | 隙間、欠落した面、見えてしまう裏面、または同じ深度で2つのサーフェスがちらつく(z-fighting) |
| 透明度と深度 | 重なり合うサーフェスまたは透過サーフェスで深度順序の境界を越える | 誤ったソート順、ハロー、透過すべきなのに不透明なサーフェス、または浅い角度でのちらつき |
| テクスチャ | マッピングされたサーフェスを近く、遠く、浅い角度から表示する | テクスチャの欠落、引き伸ばし、継ぎ目、モアレ、シマー、または誤った色空間による色あせ |
| マテリアルとライティング | ライティングされたサーフェスで光と視線の方向を変える | 光の方向を無視するサーフェス、または反射する環境のない反射性金属 |
| シャドウ | キャスター、レシーバー、ライトをその範囲内で移動する | アクネ、分離したまたは浮遊する影、静止時のちらつき、またはキャスターより長く残る影 |
| カメラ | 移動とトランジションを通じて主要な被写体を追う | 被写体がフレーム外に出る、カメラがジオメトリにクリップする、または前景がプレイエリアを遮る |
| スケールと接触 | オブジェクトのスケールと接地状態を周囲と比較する | オブジェクトが支持面の上に浮く、めり込む、交差する、または不自然なスケールで配置されている |
| 画像の安定性 | サポートされている解像度でカメラをゆっくりパンする | シルエット、薄いジオメトリ、またはハイライトが這う、スパークル、ゴースト化する |
| リサイズと DPR | ビューポートサイズ、ズーム、デバイスピクセル比を変更する | 歪み、ぼやけ、引き伸ばされた出力、またはビューポートからはみ出すコンテンツ |
ルーブリックの各行には、通常のコードレベルの原因が少数あります。行が失敗した場合は、まずこれらを確認してください。
- 色あせた、または暗すぎる色:
renderer.outputColorSpaceがSRGBColorSpaceに設定されていない、カラーテクスチャにtexture.colorSpace = SRGBColorSpaceがない、またはデータテクスチャ(ノーマル、ラフネス)が誤って sRGB としてマークされている - Z-fighting:
polygonOffsetまたは位置の微調整が必要な同一平面上のジオメトリ、またはシーンのスケールに対してニアプレーンが小さすぎる - シャドウアクネまたは浮遊する影:
shadow.biasとshadow.normalBiasが調整されていない、またはシーンよりはるかに大きいシャドウカメラの錐台 - ぼやけた、または引き伸ばされたキャンバス: レンダラーサイズがキャンバスの CSS サイズと同期していない、
setPixelRatioが呼ばれていない、またはリサイズハンドラーでcamera.updateProjectionMatrix()を忘れている - 黒い金属:
scene.environmentが設定されていない状態でのmetalness: 1 - 透明度のソートの不具合:
depthWrite: false、手動のrenderOrder、またはより小さなメッシュへの分割が必要な大きな透明メッシュ - シマーと這い: テクスチャ異方性の欠落、アンチエイリアスの無効化、またはより厚い形状が必要な薄いジオメトリ
ステップ 5: 修正
重大度順に修正します。まず HIGH のパフォーマンス所見と失敗した視覚的行からです。所見が React Doctor ルールに対応する場合は、その場で考えるのではなく、正規のレシピを取得してください。
https://www.react.doctor/prompts/rules/<plugin>/<rule>.md
Three.js 固有の所見については、トリアージリストまたは上記の原因リストで示された修正を適用してください。
ステップ 6:検証
npx react-doctor@latest --verbose --scope changed を実行し、スコアが低下していないことを確認します。不合格だったビジュアル評価項目をすべて、元の証拠と同じ視点・操作で再確認し、合格していることを確認します。その後、動作を検証します。シーンが描画され、アニメーションが再生され、操作に応答することを確認します。ブラウザーの開発者ツールが使える場合は、アイドル状態のシーンを回転させながらメモリプロファイルを監視します。アイドル中にヒープが増加する場合は、リソースの解放漏れが残っています。
スキャナーが常に見落とすチェック項目
監査のたびに、以下を手動で確認してください。
- 命令的に作成したすべての GPU リソースに対する
dispose()の網羅性 useFrameと RAF コールバック内での割り当てとsetState- クリーンアップなしでキャンバスまたはウィンドウに登録されたイベントリスナーと
ResizeObserver - 絞り込んだ対象リストを使わず、ポインターを動かすたびにシーン全体をレイキャストしていないか
- シーンの一部だけで必要な場合に、シャドウやポストプロセッシングが全体で有効になっていないか
- レンダラーおよびすべてのカラー テクスチャの色空間設定