React Three Fiber

Three.js のシーングラフを React のコンポーネントツリーとして書けるレンダラ。 DOM の代わりに THREE.MeshTHREE.Light を React reconciler が組み立てる。 略称 R3F。Poimandres チームによる。

これは何か

素の Three.js は命令的に書く: new Mesh() を作って scene.add()、 update ループで位置を更新、終わるときに dispose。R3F はこれを JSX で宣言するだけにする。

素の Three.js
const geom = new THREE.BoxGeometry()
const mat  = new THREE.MeshStandardMaterial({ color: "orange" })
const mesh = new THREE.Mesh(geom, mat)
scene.add(mesh)
renderer.setAnimationLoop(() => {
  mesh.rotation.y += 0.01
  renderer.render(scene, camera)
})
同じものを R3F
function Box() {
  const ref = useRef<THREE.Mesh>(null!)
  useFrame((_, dt) => { ref.current.rotation.y += dt })
  return (
    <mesh ref={ref}>
      <boxGeometry />
      <meshStandardMaterial color="orange" />
    </mesh>
  )
}

<Canvas>
  <ambientLight intensity={0.6} />
  <directionalLight position={[3, 5, 4]} />
  <Box />
</Canvas>

R3F が React にもたらす本質

R3F の本質は単に「JSX で書ける」だけではない。React のメンタルモデルがそのまま 3D に適用できる:

裏側: Reconciler が何をしているか

R3F は react-reconciler をカスタムレンダラとして実装している。 DOM の代わりに Three.js のオブジェクトを「ホスト」として扱う。

  1. JSX の type("mesh" など)を見て、対応する Three.js クラス(THREE.Mesh)を new する。
  2. props をインスタンスのフィールドに代入する(position={[1,2,3]}mesh.position.set(1,2,3))。
  3. 子要素は scene.add(child) または「attach」される。
  4. props が変わると、対応するフィールドが書き換えられる(再レンダリングの代わりにミューテーション)。
  5. JSX ツリーから外れたインスタンスは dispose() される(自動メモリ管理)。

この仕組みのおかげで、「Three.js のコードを React で書いている」のではなく「React の世界が Three.js を含んでいる」感覚になる。 逆に Three.js の概念(マテリアル・ジオメトリ・ライト)はそのまま頭に入っている必要がある。

30秒のメンタルモデル

  1. JSX 要素は Three.js のクラス<mesh> = new THREE.Mesh()<ambientLight> = new THREE.AmbientLight()。要素名の最初を小文字にしただけ。
  2. args がコンストラクタ引数<boxGeometry args={[2,1,1]} /> = new BoxGeometry(2,1,1)
  3. props はオブジェクトのプロパティposition / rotation / scale[x,y,z] の配列で渡せる。
  4. 子要素は add() される。geometry/material 等は attach 経由で親にぶら下がる(普通は自動)。
  5. 毎フレーム動かしたいときは useFrame。React の再レンダーは挟まず、ref を直接ミューテートする。
  6. イベントは普通の React イベントonClick / onPointerOver をメッシュに直接書ける。
  7. 非同期ロードは useLoader。Suspense と統合される。

R3F のエコシステム地図

R3F は単独で使うことはまずない。周辺ライブラリと組み合わせて「R3F スタック」になる。

ライブラリ役割
@react-three/drei定番ヘルパー集(OrbitControls, Environment, useGLTF, Html, Text 等)
@react-three/postprocessingBloom / DoF / Vignette などのポストエフェクト
@react-three/rapier物理シミュレーション(Rust 製の Rapier)
@react-three/cannon物理(Cannon.js)。レガシー対応で残る
@react-three/xrWebXR(VR/AR)対応
@react-three/csgブール演算(メッシュの union/subtract/intersect)
@react-three/uikit3D 空間内の UI(Yoga/Tailwind 風)
levaリアルタイム調整 UI(GUI で値を弄れる)
@react-spring/three宣言的バネアニメ
framer-motion-3dframer-motion の 3D 拡張
gltfjsxGLB → JSX 自動変換 CLI
zustandR3F と相性最高の状態管理

R3F vs 生 Three.js

R3F生 Three.js
記述スタイル宣言的(JSX)命令的(new / add / dispose)
状態管理との連携React の世界がそのまま自分で書く
HMR○(Vite/Next.js)シーンの再構築コスト大
非同期アセットSuspense と統合自分で進捗管理
ボイラープレート少ない多い(毎回 setup)
低レベル制御refs 経由で同等直接
学習コストThree.js + React + R3F 流儀Three.js だけ
世の中の参考実装増えてきた圧倒的に多い

使うと嬉しい場面

使わない方が良い場面

前提

R3F はあくまで Three.js の薄いラッパ。Three.js の基本概念(scene / camera / mesh / material / geometry / light)が頭に入っていることが土台。
土台の知識は Three.js のセクションを参照。

2026 春時点のバージョン感

導入

最小
npm install three @react-three/fiber

# よく使うヘルパー
npm install @react-three/drei

# TypeScript なら(最近の three は型同梱なので不要なケース増えてる)
npm install -D @types/three

Vite テンプレート

npm create vite@latest my-3d -- --template react-ts
cd my-3d
npm install three @react-three/fiber @react-three/drei
npm run dev

Next.js (App Router)

Canvas はクライアント専用なので "use client" が必須。詳しくは パフォーマンス・注意点

このノートの読み方

  1. 基本(Canvas)<Canvas> の役割と JSX→Three の対応を押さえる。
  2. フックuseFrame / useThree / useLoader を覚える。ここがR3Fの本体
  3. シーン構築 でライト・マテリアル・カメラを実用例で見る。
  4. 動かしたいなら アニメーション、当たり判定が要るなら インタラクション
  5. 表現を伸ばしたい時に シェーダ・ポストプロセス
  6. 物理が要るなら 物理シミュレーション
  7. Meta Quest など HMD で没入型を作るなら WebXR / VR / AR
  8. 定型は drei とアセットに揃っている。
  9. 本番投入前に パフォーマンス・注意点 を一通り読む。