mcpField
R
react-three-fiber

react-three-fiber

github.com/freshtechbro開発1.2k3.8k 回インストール49 週間前に更新
リポジトリ

react-three-fiber について

React Three Fiberを使ってReactアプリに3D体験を構築するためのスキルです。Three.jsの宣言的レンダラーを扱い、シーン構成、フック、アセット読み込み、操作、パフォーマンス、再利用可能なスターター素材を解説します。

主な機能

  1. 01JSXでThree.jsシーンを構成
  2. 02Reactフックで3D状態を扱う
  3. 03アセットの読み込みとキャッシュ
  4. 04操作可能な3Dオブジェクトの作成
  5. 05レンダリング最適化の適用
  6. 06コンポーネントとシーンのひな形生成

活用シーン

  1. 01Reactアプリへの3Dシーン追加
  2. 02操作可能な製品展示の制作
  3. 03Reactでのゲームやシミュレーション開発
  4. 04再利用可能な3Dコンポーネントの開発

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/freshtechbro/claudedesignskills --skill react-three-fiber

インストール後、Claude Code で/react-three-fiberを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/examples/
README.md
assets/starter_r3f/
index.html
package.json
README.md
vite.config.js
assets/starter_r3f/src/
App.jsx
Experience.jsx
main.jsx
assets/starter_r3f/src/components/
Box.jsx
Sphere.jsx
references/
api_reference.md
scripts/
component_generator.py
scene_setup.py

詳細

React Three Fiber

概要

React Three Fiber(R3F)は Three.js 用の React レンダラーで、宣言的なコンポーネントベースの 3D 開発を React アプリケーションにもたらします。Three.js オブジェクトを命令的に作成・管理する代わりに、Three.js オブジェクトに直接対応する JSX コンポーネントを使って 3D シーンを構築します。

このスキルを使用する場面:

  • React アプリケーション内で 3D 体験を構築する場合
  • インタラクティブな製品コンフィギュレーターやショーケースを作成する場合
  • 3D ポートフォリオ、ギャラリー、ストーリーテリング体験を開発する場合
  • React でゲームやシミュレーションを構築する場合
  • 既存の React プロジェクトに 3D 要素を追加する場合
  • 3D グラフィックスで状態管理や React フックが必要な場合
  • React フレームワーク(Next.js、Gatsby、Remix)を使用する場合

主なメリット:

  • 宣言的:React コンポーネントのように 3D シーンを記述できます
  • React との統合:フック、コンテキスト、状態管理をすべて利用できます
  • 再利用性:3D コンポーネントライブラリを作成して共有できます
  • パフォーマンス:レンダリングの最適化と差分調整が自動で行われます
  • エコシステム:Drei ヘルパー、Zustand、Framer Motion などと連携します
  • TypeScript のサポート:Three.js オブジェクトの型安全性を完全に確保できます

基本概念

1. Canvas コンポーネント

<Canvas> コンポーネントは、Three.js のシーン、カメラ、レンダラー、レンダーループをセットアップします。

import { Canvas } from '@react-three/fiber'

function App() {
  return (
    <Canvas
      camera={{ position: [0, 0, 5], fov: 75 }}
      gl={{ antialias: true }}
      dpr={[1, 2]}
    >
      {/* 3D content goes here */}
    </Canvas>
  )
}

Canvas のプロパティ:

  • camera - カメラの設定(位置、fov、near、far)
  • gl - WebGL レンダラーの設定
  • dpr - デバイスのピクセル比(デフォルト:[1, 2])
  • shadows - シャドウマッピングを有効にします(デフォルト:false)
  • frameloop - 「always」(デフォルト)、「demand」、または「never」
  • flat - よりシンプルな色にするため、カラー管理を無効にします
  • linear - sRGB の代わりにリニアカラースペースを使用します
2. 宣言的な 3D オブジェクト

Three.js オブジェクトは、ケバブケースのプロパティを使った JSX で作成します。

// THREE.Mesh + THREE.BoxGeometry + THREE.MeshStandardMaterial
<mesh position={[0, 0, 0]} rotation={[0, Math.PI / 4, 0]}>
  <boxGeometry args={[1, 1, 1]} />
  <meshStandardMaterial color="hotpink" />
</mesh>

プロパティの対応関係:

  • position → object.position.set(x, y, z)
  • rotation → object.rotation.set(x, y, z)
  • scale → object.scale.set(x, y, z)
  • args → ジオメトリ/マテリアルのコンストラクター引数
  • attach → 親のプロパティにアタッチします(例:attach="material")

省略記法:

// Full notation
<mesh position={[1, 2, 3]} />

// Axis-specific (dash notation)
<mesh position-x={1} position-y={2} position-z={3} />
3. useFrame フック

毎フレーム(アニメーションループ)でコードを実行します。

import { useFrame } from '@react-three/fiber'
import { useRef } from 'react'

function RotatingBox() {
  const meshRef = useRef()

  useFrame((state, delta) => {
    // Rotate mesh on every frame
    meshRef.current.rotation.x += delta
    meshRef.current.rotation.y += delta * 0.5

    // Access scene state
    const time = state.clock.elapsedTime
    meshRef.current.position.y = Math.sin(time) * 2
  })

  return (
    <mesh ref={meshRef}>
      <boxGeometry />
      <meshStandardMaterial color="orange" />
    </mesh>
  )
}

useFrame のパラメーター:

  • state - シーンの状態(camera、scene、gl、clock など)
  • delta - 前回のフレームからの経過時間(フレームレートに依存しない処理に使用)
  • xrFrame - XR フレームデータ(VR/AR 用)

重要:useFrame 内では setState を使用しないでください。不要な再レンダリングが発生します。

4. useThree フック

シーンの状態とメソッドにアクセスします。

import { useThree } from '@react-three/fiber'

function CameraInfo() {
  const { camera, gl, scene, size, viewport } = useThree()

  // Selective subscription (only re-render on size change)
  const size = useThree((state) => state.size)

  // Get state non-reactively
  const get = useThree((state) => state.get)
  const freshState = get() // Latest state without triggering re-render

  return null
}

利用可能な状態:

  • camera - デフォルトのカメラ
  • scene - Three.js のシーン
  • gl - WebGL レンダラー
  • size - Canvas の寸法
  • viewport - 3D 単位でのビューポートの寸法
  • clock - Three.js のクロック
  • pointer - 正規化されたマウス座標
  • invalidate() - レンダリングを手動でトリガーします
  • setSize() - Canvas のサイズを手動で変更します
5. useLoader フック

自動キャッシュと Suspense との連携により、アセットを読み込みます。

import { Suspense } from 'react'
import { useLoader } from '@react-three/fiber'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { TextureLoader } from 'three'

function Model() {
  const gltf = useLoader(GLTFLoader, '/model.glb')
  return <primitive object={gltf.scene} />
}

function TexturedMesh() {
  const texture = useLoader(TextureLoader, '/texture.jpg')
  return (
    <mesh>
      <boxGeometry />
      <meshStandardMaterial map={texture} />
    </mesh>
  )
}

function App() {
  return (
    <Canvas>
      <Suspense fallback={<LoadingIndicator />}>
        <Model />
        <TexturedMesh />
      </Suspense>
    </Canvas>
  )
}

複数のアセットの読み込み:

const [texture1, texture2, texture3] = useLoader(TextureLoader, [
  '/tex1.jpg',
  '/tex2.jpg',
  '/tex3.jpg'
])

ローダーの拡張:

import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'

useLoader(GLTFLoader, '/model.glb', (loader) => {
  const dracoLoader = new DRACOLoader()
  dracoLoader.setDecoderPath('/draco/')
  loader.setDRACOLoader(dracoLoader)
})

事前読み込み:

// Pre-load assets before component mounts
useLoader.preload(GLTFLoader, '/model.glb')

よく使われるパターン

パターン 1:基本的なシーンのセットアップ
import { Canvas } from '@react-three/fiber'

function Scene() {
  return (
    <>
      {/* Lights */}
      <ambientLight intensity={0.5} />
      <spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} />

      {/* Objects */}
      <mesh position={[0, 0, 0]}>
        <boxGeometry args={[1, 1, 1]} />
        <meshStandardMaterial color="hotpink" />
      </mesh>
    </>
  )
}

function App() {
  return (
    <Canvas camera={{ position: [0, 0, 5], fov: 75 }}>
      <Scene />
    </Canvas>
  )
}
パターン 2:インタラクティブなオブジェクト(クリック、ホバー)
import { useState } from 'react'

function InteractiveBox() {
  const [hovered, setHovered] = useState(false)
  const [active, setActive] = useState(false)

  return (
    <mesh
      scale={active ? 1.5 : 1}
      onClick={() => setActive(!active)}
      onPointerOver={() => setHovered(true)}
      onPointerOut={() => setHovered(false)}
    >
      <boxGeometry />
      <meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
    </mesh>
  )
}
パターン 3:useFrame を使ったアニメーションコンポーネント
import { useRef } from 'react'
import { useFrame } from '@react-three/fiber'

function AnimatedSphere() {
  const meshRef = useRef()

  useFrame((state, delta) => {
    // Rotate
    meshRef.current.rotation.y += delta

    // Oscillate position
    const time = state.clock.elapsedTime
    meshRef.current.position.y = Math.sin(time) * 2
  })

  return (
    <mesh ref={meshRef}>
      <sphereGeometry args={[1, 32, 32]} />
      <meshStandardMaterial color="cyan" />
    </mesh>
  )
}
パターン 4:GLTF モデルの読み込み
import { Suspense } from 'react'
import { useLoader } from '@react-three/fiber'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'

function Model({ url }) {
  const gltf = useLoader(GLTFLoader, url)

  return (
    <primitive
      object={gltf.scene}
      scale={0.5}
      position={[0, 0, 0]}
    />
  )
}

function App() {
  return (
    <Canvas>
      <Suspense fallback={<LoadingPlaceholder />}>
        <Model url="/model.glb" />
      </Suspense>
    </Canvas>
  )
}

function LoadingPlaceholder() {
  return (
    <mesh>
      <boxGeometry />
      <meshBasicMaterial wireframe />
    </mesh>
  )
}
パターン 5:複数のライト
function Lighting() {
  return (
    <>
      {/* Ambient light for base illumination */}
      <ambientLight intensity={0.3} />

      {/* Directional light with shadows */}
      <directionalLight
        position={[5, 5, 5]}
        intensity={1}
        castShadow
        shadow-mapSize-width={2048}
        shadow-mapSize-height={2048}
      />

      {/* Point light for accent */}
      <pointLight position={[-5, 5, -5]} intensity={0.5} color="blue" />

      {/* Spot light for focused illumination */}
      <spotLight
        position={[10, 10, 10]}
        angle={0.3}
        penumbra={1}
        intensity={1}
      />
    </>
  )
}
パターン 6:インスタンシング(多数のオブジェクト)
import { useMemo, useRef } from 'react'
import * as THREE from 'three'
import { useFrame } from '@react-three/fiber'

function Particles({ count = 1000 }) {
  const meshRef = useRef()

  // Generate random positions
  const particles = useMemo(() => {
    const temp = []
    for (let i = 0; i < count; i++) {
      const t = Math.random() * 100
      const factor = 20 + Math.random() * 100
      const speed = 0.01 + Math.random() / 200
      const x = Math.random() * 2 - 1
      const y = Math.random() * 2 - 1
      const z = Math.random() * 2 - 1
      temp.push({ t, factor, speed, x, y, z, mx: 0, my: 0 })
    }
    return temp
  }, [count])

  const dummy = useMemo(() => new THREE.Object3D(), [])

  useFrame(() => {
    particles.forEach((particle, i) => {
      let { t, factor, speed, x, y, z } = particle
      t = particle.t += speed / 2
      const a = Math.cos(t) + Math.sin(t * 1) / 10
      const b = Math.sin(t) + Math.cos(t * 2) / 10
      const s = Math.cos(t)

      dummy.position.set(
        x + Math.cos((t / 10) * factor) + (Math.sin(t * 1) * factor) / 10,
        y + Math.sin((t / 10) * factor) + (Math.cos(t * 2) * factor) / 10,
        z + Math.cos((t / 10) * factor) + (Math.sin(t * 3) * factor) / 10
      )
      dummy.scale.set(s, s, s)
      dummy.updateMatrix()
      meshRef.current.setMatrixAt(i, dummy.matrix)
    })
    meshRef.current.instanceMatrix.needsUpdate = true
  })

  return (
    <instancedMesh ref={meshRef} args={[null, null, count]}>
      <sphereGeometry args={[0.05, 8, 8]} />
      <meshBasicMaterial color="white" />
    </instancedMesh>
  )
}
パターン 7:グループ化とネスト
function Robot() {
  return (
    <group position={[0, 0, 0]}>
      {/* Body */}
      <mesh position={[0, 0, 0]}>
        <boxGeometry args={[1, 2, 1]} />
        <meshStandardMaterial color="gray" />
      </mesh>

      {/* Head */}
      <mesh position={[0, 1.5, 0]}>
        <sphereGeometry args={[0.5, 32, 32]} />
        <meshStandardMaterial color="silver" />
      </mesh>

      {/* Arms */}
      <group position={[-0.75, 0.5, 0]}>
        <mesh>
          <cylinderGeometry args={[0.1, 0.1, 1.5]} />
          <meshStandardMaterial color="darkgray" />
        </mesh>
      </group>

      <group position={[0.75, 0.5, 0]}>
        <mesh>
          <cylinderGeometry args={[0.1, 0.1, 1.5]} />
          <meshStandardMaterial color="darkgray" />
        </mesh>
      </group>
    </group>
  )
}

Drei ヘルパーとの統合

Drei は R3F に欠かせないヘルパーライブラリで、そのまま使えるコンポーネントを提供します。

OrbitControls
import { OrbitControls } from '@react-three/drei'

<Canvas>
  <OrbitControls
    makeDefault
    enableDamping
    dampingFactor={0.05}
    minDistance={3}
    maxDistance={20}
  />
  <Box />
</Canvas>
環境とライティング
import { Environment, ContactShadows } from '@react-three/drei'

<Canvas>
  {/* HDRI environment map */}
  <Environment preset="sunset" />

  {/* Or custom */}
  <Environment files="/hdri.hdr" />

  {/* Soft contact shadows */}
  <ContactShadows
    opacity={0.5}
    scale={10}
    blur={1}
    far={10}
    resolution={256}
  />

  <Model />
</Canvas>
テキスト
import { Text, Text3D } from '@react-three/drei'

// 2D Billboard text
<Text
  position={[0, 2, 0]}
  fontSize={1}
  color="white"
  anchorX="center"
  anchorY="middle"
>
  Hello World
</Text>

// 3D extruded text
<Text3D
  font="/fonts/helvetiker_regular.typeface.json"
  size={1}
  height={0.2}
>
  3D Text
  <meshNormalMaterial />
</Text3D>
useGLTF フック(Drei)
import { useGLTF } from '@react-three/drei'

function Model() {
  const { scene, materials, nodes } = useGLTF('/model.glb')

  return <primitive object={scene} />
}

// Pre-load
useGLTF.preload('/model.glb')
Center と Bounds
import { Center, Bounds, useBounds } from '@react-three/drei'

// Auto-center objects
<Center>
  <Model />
</Center>

// Auto-fit camera to bounds
<Bounds fit clip observe margin={1.2}>
  <Model />
</Bounds>
HTML オーバーレイ
import { Html } from '@react-three/drei'

<mesh>
  <boxGeometry />
  <meshStandardMaterial />

  <Html
    position={[0, 1, 0]}
    center
    distanceFactor={10}
  >
    <div className="annotation">
      This is a box
    </div>
  </Html>
</mesh>
スクロールコントロール
import { ScrollControls, Scroll, useScroll } from '@react-three/drei'
import { useFrame } from '@react-three/fiber'

function AnimatedScene() {
  const scroll = useScroll()
  const meshRef = useRef()

  useFrame(() => {
    const offset = scroll.offset // 0-1 normalized scroll position
    meshRef.current.position.y = offset * 10
  })

  return <mesh ref={meshRef}>...</mesh>
}

<Canvas>
  <ScrollControls pages={3} damping={0.5}>
    <Scroll>
      <AnimatedScene />
    </Scroll>

    {/* HTML overlay */}
    <Scroll html>
      <div style={{ height: '100vh' }}>
        <h1>Scrollable content</h1>
      </div>
    </Scroll>
  </ScrollControls>
</Canvas>

他のライブラリとの統合

GSAP との連携
import { useRef, useEffect } from 'react'
import { useFrame } from '@react-three/fiber'
import gsap from 'gsap'

function AnimatedBox() {
  const meshRef = useRef()

  useEffect(() => {
    // GSAP timeline animation
    const tl = gsap.timeline({ repeat: -1, yoyo: true })

    tl.to(meshRef.current.position, {
      y: 2,
      duration: 1,
      ease: 'power2.inOut'
    })
    .to(meshRef.current.rotation, {
      y: Math.PI * 2,
      duration: 2,
      ease: 'none'
    }, 0)

    return () => tl.kill()
  }, [])

  return (
    <mesh ref={meshRef}>
      <boxGeometry />
      <meshStandardMaterial color="orange" />
    </mesh>
  )
}
Framer Motion との連携
import { motion } from 'framer-motion-3d'

function AnimatedSphere() {
  return (
    <motion.mesh
      initial={{ scale: 0 }}
      animate={{ scale: 1 }}
      transition={{ duration: 1 }}
    >
      <sphereGeometry />
      <meshStandardMaterial color="hotpink" />
    </motion.mesh>
  )
}
Zustand との連携(状態管理)
import create from 'zustand'

const useStore = create((set) => ({
  color: 'orange',
  setColor: (color) => set({ color })
}))

function Box() {
  const color = useStore((state) => state.color)
  const setColor = useStore((state) => state.setColor)

  return (
    <mesh onClick={() => setColor('hotpink')}>
      <boxGeometry />
      <meshStandardMaterial color={color} />
    </mesh>
  )
}

パフォーマンスの最適化

1. オンデマンドレンダリング
<Canvas frameloop="demand">
  {/* Only renders when needed */}
</Canvas>

// Manually trigger render
function MyComponent() {
  const invalidate = useThree((state) => state.invalidate)

  return (
    <mesh onClick={() => invalidate()}>
      <boxGeometry />
      <meshStandardMaterial />
    </mesh>
  )
}
2. インスタンシング

同一のオブジェクトを多数レンダリングするには、<instancedMesh>を使用します。

function Particles({ count = 10000 }) {
  const meshRef = useRef()

  useEffect(() => {
    const temp = new THREE.Object3D()

    for (let i = 0; i < count; i++) {
      temp.position.set(
        Math.random() * 10 - 5,
        Math.random() * 10 - 5,
        Math.random() * 10 - 5
      )
      temp.updateMatrix()
      meshRef.current.setMatrixAt(i, temp.matrix)
    }

    meshRef.current.instanceMatrix.needsUpdate = true
  }, [count])

  return (
    <instancedMesh ref={meshRef} args={[null, null, count]}>
      <sphereGeometry args={[0.1, 8, 8]} />
      <meshBasicMaterial color="white" />
    </instancedMesh>
  )
}
3. フラスタムカリング

カメラの視界外にあるオブジェクトは自動的にカリングされます。

// Disable for always-visible objects
<mesh frustumCulled={false}>
  <boxGeometry />
  <meshStandardMaterial />
</mesh>
4. LOD(詳細度)
import { Detailed } from '@react-three/drei'

<Detailed distances={[0, 10, 20]}>
  {/* High detail - close to camera */}
  <mesh geometry={highPolyGeometry} />

  {/* Medium detail */}
  <mesh geometry={mediumPolyGeometry} />

  {/* Low detail - far from camera */}
  <mesh geometry={lowPolyGeometry} />
</Detailed>
5. パフォーマンスの適応
import { AdaptiveDpr, AdaptiveEvents, PerformanceMonitor } from '@react-three/drei'

<Canvas>
  {/* Reduce DPR when performance drops */}
  <AdaptiveDpr pixelated />

  {/* Reduce raycast frequency */}
  <AdaptiveEvents />

  {/* Monitor and respond to performance */}
  <PerformanceMonitor
    onIncline={() => console.log('Performance improved')}
    onDecline={() => console.log('Performance degraded')}
  >
    <Scene />
  </PerformanceMonitor>
</Canvas>
6. 選択的な再レンダリング

不要な再レンダリングを避けるには、useThreeセレクターを使用します。

// ❌ Re-renders on any state change
const state = useThree()

// ✅ Only re-renders when size changes
const size = useThree((state) => state.size)

// ✅ Only re-renders when camera changes
const camera = useThree((state) => state.camera)

よくある落とし穴と解決策

❌ 落とし穴 1:useFrame内でのsetState
// ❌ BAD: Triggers React re-renders every frame
const [x, setX] = useState(0)
useFrame(() => setX((x) => x + 0.1))
return <mesh position-x={x} />

✅ 解決策:refを直接変更する

// ✅ GOOD: Direct mutation, no re-renders
const meshRef = useRef()
useFrame((state, delta) => {
  meshRef.current.position.x += delta
})
return <mesh ref={meshRef} />
❌ 落とし穴 2:レンダー中にオブジェクトを作成する
// ❌ BAD: Creates new Vector3 every render
<mesh position={new THREE.Vector3(1, 2, 3)} />

✅ 解決策:配列またはuseMemoを使用する

// ✅ GOOD: Use array notation
<mesh position={[1, 2, 3]} />

// Or useMemo for complex objects
const position = useMemo(() => new THREE.Vector3(1, 2, 3), [])
<mesh position={position} />
❌ 落とし穴 3:useLoaderのキャッシュを使用しない
// ❌ BAD: Loads texture every render
function Component() {
  const [texture, setTexture] = useState()
  useEffect(() => {
    new TextureLoader().load('/texture.jpg', setTexture)
  }, [])
  return texture ? <meshBasicMaterial map={texture} /> : null
}

✅ 解決策:useLoaderを使用する(自動的にキャッシュされます)

// ✅ GOOD: Cached and reused
function Component() {
  const texture = useLoader(TextureLoader, '/texture.jpg')
  return <meshBasicMaterial map={texture} />
}
❌ 落とし穴 4:条件付きマウント(コストが高い)
// ❌ BAD: Unmounts and remounts (expensive)
{stage === 1 && <Stage1 />}
{stage === 2 && <Stage2 />}
{stage === 3 && <Stage3 />}

✅ 解決策:visibilityプロパティを使用する

// ✅ GOOD: Components stay mounted, just hidden
<Stage1 visible={stage === 1} />
<Stage2 visible={stage === 2} />
<Stage3 visible={stage === 3} />

function Stage1({ visible, ...props }) {
  return <group {...props} visible={visible}>...</group>
}
❌ 落とし穴 5:Canvasの外でuseThreeを使用する
// ❌ BAD: Crashes - useThree must be inside Canvas
function App() {
  const { size } = useThree()
  return <Canvas>...</Canvas>
}

✅ 解決策:Canvasの子要素内でフックを使用する

// ✅ GOOD: useThree inside Canvas child
function CameraInfo() {
  const { size } = useThree()
  return null
}

function App() {
  return (
    <Canvas>
      <CameraInfo />
    </Canvas>
  )
}
❌ 落とし穴 6:リソースを破棄しない
// ❌ BAD: Memory leak - textures not disposed
const texture = useLoader(TextureLoader, '/texture.jpg')

✅ 解決策:R3Fはリソースを自動的に破棄しますが、Three.jsのオブジェクトを手動で扱う場合は注意してください

// ✅ GOOD: Manual cleanup when needed
useEffect(() => {
  const geometry = new THREE.SphereGeometry(1)
  const material = new THREE.MeshBasicMaterial()

  return () => {
    geometry.dispose()
    material.dispose()
  }
}, [])

ベストプラクティス

1. コンポーネントの構成

シーンを再利用可能なコンポーネントに分割します。

function Lights() {
  return (
    <>
      <ambientLight intensity={0.5} />
      <spotLight position={[10, 10, 10]} angle={0.15} />
    </>
  )
}

function Scene() {
  return (
    <>
      <Lights />
      <Model />
      <Ground />
      <Effects />
    </>
  )
}

<Canvas>
  <Scene />
</Canvas>
2. 重いアセットをSuspendする

非同期処理は必ずSuspenseでラップします。

<Canvas>
  <Suspense fallback={<Loader />}>
    <Model />
    <Environment />
  </Suspense>
</Canvas>
3. TypeScriptを使用する
import { ThreeElements } from '@react-three/fiber'

function Box(props: ThreeElements['mesh']) {
  return (
    <mesh {...props}>
      <boxGeometry />
      <meshStandardMaterial />
    </mesh>
  )
}
4. 機能ごとに整理する
src/
  components/
    3d/
      Scene.tsx
      Lights.tsx
      Camera.tsx
    models/
      Robot.tsx
      Character.tsx
    effects/
      PostProcessing.tsx
5. React DevTools Profilerでテストする

再レンダリングを監視し、パフォーマンスの問題を引き起こしているコンポーネントを最適化します。


リソース

リファレンス
  • references/api_reference.md - R3FとDreiのAPIドキュメント一式
  • references/hooks_guide.md - フックの使用方法とパターンの詳細
  • references/drei_helpers.md - Dreiライブラリの包括的なガイド
スクリプト
  • scripts/component_generator.py - R3Fコンポーネントのボイラープレートを生成します
  • scripts/scene_setup.py - 一般的なパターンを使用してR3Fシーンを初期化します
アセット
  • assets/starter_r3f/ - R3FとViteを使用したスターターテンプレート一式
  • assets/examples/ - 実際のR3Fコンポーネントの例
外部リソース

コメント