r3f-interaction について
React Three Fiber 開発者向けのインタラクションスキルです。ポインター、ドラッグ、カメラ、キーボード入力を扱い、イベントの動作や入力の所有権、例外ケースの検証を説明します。
主な機能
- 01R3F ポインターイベントの動作
- 02オブジェクトのドラッグと操作制御
- 03キーボードと連続入力の処理
- 04タッチ、キャプチャ、キャンセルの処理
- 05インタラクションの例外テスト
活用シーン
- 01選択可能な 3D オブジェクトの実装
- 02ドラッグとカメラ操作の競合回避
- 03タッチやキャンバス外のドラッグ処理
- 04キーボード入力とフォーカスの検証
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ enzed/ r3f-skills --skill r3f-interactionインストール後、Claude Code で/r3f-interactionを入力して読み込まれたか確認します。
詳細
React Three Fiber の操作
まず、インストールされている Fiber、Drei、入力ライブラリのバージョンを確認してください。例は Fiber 9/React 19 を対象としています。ハンドラーを接続する前に、カメラの移動、オブジェクトの移動、UI 入力をそれぞれどの機能が担うか決めてください。
選択可能なオブジェクト
Canvas の下にマウントしてください。重要な操作には、Canvas の外側にアクセス可能な DOM コントロールを用意してください。メッシュのポインターハンドラーだけではキーボードから操作できません。
import { useState } from 'react'
import { OrbitControls } from '@react-three/drei'
export default function Example() {
const [selected, setSelected] = useState(false)
return (
<>
<mesh
name="selectable-box"
onClick={(event) => {
event.stopPropagation()
setSelected((value) => !value)
}}
>
<boxGeometry />
<meshStandardMaterial color={selected ? 'gold' : 'coral'} />
</mesh>
<OrbitControls makeDefault />
</>
)
}
イベントのセマンティクス
- R3F はハンドラーを持つオブジェクトにレイキャストし、距離順にヒットを通知してから、祖先へバブリングします。
event.objectはヒットしたオブジェクト、event.eventObjectはハンドラーを持つオブジェクトです。 stopPropagation()は、より遠くにあるヒットオブジェクトと祖先への通知をブロックします。イベントの通知方法を変更するものであり、すでに実行されたレイキャストを回避するものではありません。呼び出すと、ヒット対象の背後にある、以前ホバーされていたオブジェクトで直ちに pointerout が発生する場合があります。event.pointはワールド空間の座標です。保持する値はクローンし、ローカルトランスフォームに割り当てる前に親のローカル空間へ変換してください。2D のドラッグを 3D に対応させるには、平面との交差点または深度の基準が必要です。- 背景をクリックしたときに選択を解除するには、Canvas の
onPointerMissedを処理してください。イベントの移動情報とアプリケーションのジェスチャーポリシーを使って、クリックとドラッグを区別してください。 - R3F のポインタキャプチャはヒットテストに追加される動作です。
event.target.setPointerCapture(event.pointerId)と対応する解除メソッドでキャプチャと解除を行い、キャンセルやキャプチャ喪失も処理してください。 - ポインタが静止した状態でカメラを動かす場合、ホバー結果を更新するために
state.events.update()が必要になることがあります。必要な場合にのみ呼び出し、毎フレーム余分なレイキャストを行うような使い方は避けてください。 - ピッキングの負荷が高い場合は、より単純なヒットプロキシやレイヤーフィルタリングを使用してください。見た目が透明であることだけを理由に、交差しないと想定しないでください。
コントロールとドラッグの担当範囲
- 周回操作には OrbitControls を使用してください。スクリプトによる遷移や、より高度なカメラ動作が必要な場合は CameraControls を使用してください。プロパティやメソッドをコピーする前に、インストール済みの Drei/基盤となるコントロールのバージョンを確認してください。
- Drei のコントロールはフレーム更新と需要に応じた無効化を管理します。明示的な連携なしに、同じカメラで複数のアクティブなコントロールをマウントするのは避けてください。
makeDefaultを使うと、コントロールインスタンスを連携するヘルパーから参照できるようになります。ドラッグ中、TransformControls はデフォルトのコントロールを一時停止できます。カスタムコントロールも正しく無効化・復元されることを確認してください。- オブジェクトのドラッグには、必要な制約に応じて Drei の DragControls/PivotControls/TransformControls を選択してください。制御される行列と自動トランスフォームを区別し、同じオブジェクトに両方を適用しないでください。
- カスタムドラッグでは、初期トランスフォームを保存し、ポインタをキャプチャし、選択した平面に投影してください。また、pointerup、キャンセル、アンマウント時にカメラコントロールを復元してください。実際のイベントターゲットに必要な touch-action の要件を満たしてください。
- 共有 DOM イベントソースでは、イベントターゲットと Canvas の矩形に合った座標プレフィックスが必要です。スクロールやオーバーレイをテストしてください。何も考えずに
client座標を選ぶと、オフセットが生じることがあります。
キーボードと連続入力
- Drei の KeyboardControls では、名前付きアクションを定義できます。移動には
useFrame内で getter を読み取ってください。離散イベントには購読を使い、購読を解除してください。 - 速度を一定に保つ必要がある場合は、斜め移動を正規化してください。視覚的な移動量には delta を掛けてください。物理ボディでは、メッシュを直接動かすのではなく、物理ステップのロジックに入力を渡してください。
- フォーカス喪失時には押下中の入力をクリアし、テキストフィールドにフォーカスがある場合はそれを考慮してください。ポインターロック/フルスクリーン/オーディオの開始には、明示的なユーザー操作が必要な場合があります。
- 高頻度のポインタ位置には refs を使い、意味のあるイベントには React state を使ってください。1 つのハンドラーをスロットリングするだけのために lodash やストアを追加するのは避けてください。スロットリングが必要な場合はタイマーをクリーンアップしてください。
- ScrollControls はスクロールコンテキストを作成します。
useScrollはその下で使用してください。正規化された offset/delta はピクセル単位の距離ではありません。
検証
重なり合うメッシュ、ネストされたグループ、背景の選択解除、キャンバス外へのドラッグ、タッチ、キャンセル、フォーカス喪失、キーボードによる代替操作をテストします。ドラッグ後にカメラ操作が復帰することを確認します。
参考資料
コメント
Markdown 対応