threejs-interaction について
3D 入力、ピッキング、カメラ操作、選択状態を実装する Three.js 開発者向けスキルです。キャンバス基準の座標計算、明示的な対象指定、インタラクション状態の確実な解放を重視します。
主な機能
- 01ポインターやタッチ入力のレイキャスト
- 02カメラとオブジェクト操作の設定
- 03空間間のポインター座標変換
- 04ホバーと選択状態の管理
- 05レイキャストの抑制とリスナーの解放
活用シーン
- 01ポインターやタッチによるシーンオブジェクトの選択
- 02位置やサイズが変わったキャンバスでのピッキング不具合の修正
- 03オービット、ドラッグ、変形操作の追加
- 04古いホバー状態やポインター状態の解消
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ akillness/ jeo-skills --skill threejs-interactionインストール後、Claude Code で/threejs-interactionを入力して読み込まれたか確認します。
同梱ファイルSKILL.toonevals/evals.json
詳細
Three.js のインタラクション
直接的な 3D 入力、オブジェクトのピッキング、カメラ操作、選択状態には、このスキルを使用してください。セマンティックな HTML コントロール、キーボードアクセシビリティ、フォーカス管理については web-accessibility に、ゲーム入力のアーキテクチャについては web-game-development に振り分けてください。
このスキルを使う場面
- 選択可能なシーンオブジェクトに対して、ポインターやタッチをレイキャストする
- カメラコントロール、オブジェクトのドラッグ、トランスフォームハンドル、またはポインターロックを追加または修正する
- クライアント座標、正規化デバイス座標、ワールド座標、スクリーン座標の間で座標を変換する
- クリックの取りこぼし、古いホバー状態、ポインターキャプチャの問題、または過剰なレイキャストを修正する
手順
Step 1: インタラクションの境界を定義する
- キャンバス要素とその
getBoundingClientRect()を特定します。キャンバスがウィンドウ内でオフセットされているか、サイズ変更されている場合は、ポインター座標をウィンドウ全体に対して正規化しないでください。 - ピッキング可能なコレクションまたはレイヤーを明示的に定義します。境界を設けずに
scene.childrenをレイキャストすると、意図しないターゲットに当たり、シーンの規模に応じてコストが増大します。 - 入力イベントと視覚状態の変更を分離し、ホバーや選択の状態を個別にテストして解除できるようにします。
Step 2: 実際のキャンバスからレイキャストする
const pointer = new THREE.Vector2();
const raycaster = new THREE.Raycaster();
function pick(event) {
const rect = renderer.domElement.getBoundingClientRect();
pointer.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
pointer.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
raycaster.setFromCamera(pointer, camera);
return raycaster.intersectObjects(pickables, true)[0] ?? null;
}
ネストされたヒットを、すべての子メッシュを製品レベルの別個のターゲットにするのではなく、意味上の選択可能なルートに解決します。キャンバスのサイズがゼロの場合は処理をガードし、キャンバスの境界外のイベントは無視してください。
Step 3: コントロールと入力動作を意図的に選ぶ
| 要件 | 適切なツール |
|---|---|
| ターゲットの周囲をオービットする | OrbitControls |
| ブラウザーでの一人称視点 | PointerLockControls |
| マップの制約/パン | MapControls |
| オブジェクトのトランスフォームを操作する | TransformControls |
| 既知のオブジェクトをドラッグする | DragControls または明示的なレイと平面のロジック |
| アクセシブルなコマンド/UI アクション | DOM コントロールと web-accessibility |
インストール済みの Three.js アドオンのパスからコントロールをインポートし、キャンバス/シーンのアンマウント時に破棄してください。複数のレンダーループでコントロールを更新しないでください。
Step 4: 処理を抑制し、状態をクリーンアップする
ホバーが必要な場合にのみ、ポインターの移動時にレイキャストします。大規模なシーンでは、より複雑な加速構造を検討する前に、レイヤー、境界、ブロードフェーズフィルタリング、またはターゲットリストを使用してください。pointerleave、キャプチャの喪失、オブジェクトの削除、シーンのティアダウン時にはホバー状態を解除してください。
Step 5: 入力動作を検証する
- マウス、タッチ、キーボードで操作する代替手段、およびサイズ変更/オフセットされたキャンバスをテストします。
- 空白部分のクリック、ネストされたメッシュ、遮蔽されたオブジェクト、頻繁なエンター/リーブイベントをテストします。
- ティアダウン時にコントロールがリスナーを解放し、ポインターロック/ドラッグ状態を解除することを確認します。
- ポインターなしでも操作できる必要があるすべてのアクションについて、フォーカス可視の DOM アフォーダンスを確認します。
例
マテリアルを破損せずにホバーする
各選択可能オブジェクトの基本的な視覚状態をマップに保持します。ホバーが変わったら、次のハイライトを適用する前に古い選択状態を復元します。ハイライト表示するメッシュが 1 つだけの場合、共有マテリアルの色を変更しないでください。クローンを作成するか、サポートされているオブジェクトごとのシグナルを使用します。
オブジェクトを地面に配置する
THREE.Plane を作成し、ポインターからレイを飛ばして、ray.intersectPlane を使用します。スクリーン座標から深度を推測するよりも予測しやすく、どのカメラでも動作します。
ベストプラクティス
window.innerWidthとinnerHeightではなく、キャンバスの矩形に対して正規化します。- 意味上のピッキング対象を明示し、子オブジェクトとの交差をルートオブジェクトに解決します。
- ドラッグ操作には、マウスとタッチを別々に実装するのではなく、ポインターイベントとポインターキャプチャを使用します。
- シーンのライフサイクルに合わせてコントロールを破棄し、カスタムリスナーを削除します。
- 必要な製品アクションを有効にする唯一の方法として、レイキャストを使わないでください。