react-three-fiber by anthemflynn/ccmp
npx skills add https://github.com/anthemflynn/ccmp --skill react-three-fiberReact Three Fiber (R3F) 是 Three.js 的 React 渲染器。使用 JSX 编写声明式、基于组件的 3D 场景。
库版本 (2026)
- React Three Fiber: v9.5+
- @react-three/drei: v9.116+
- @react-three/rapier: v2+
- @react-three/postprocessing: v3+
- React: 19+ (支持并发特性)
你的应用已经是基于 React 的吗?
→ 是:使用 R3F(天然集成)
→ 否:考虑原生 Three.js
你需要 React 状态管理吗?
→ 是:使用 R3F(无缝状态集成)
→ 否:两者皆可
3D 场景是整个应用吗?
→ 是:两者皆可(R3F 有轻微开销)
→ 否,与 React UI 混合:使用 R3F
性能关键,有数百万个对象?
→ 考虑原生 Three.js 以获得最大控制权
→ R3F 适用于 99% 的用例
本地组件状态(单个网格颜色、悬停)?
→ useState / useRef
在少数组件间共享(选中的对象)?
→ React Context 或属性透传
全局游戏/应用状态(分数、库存、设置)?
→ Zustand(推荐用于 R3F)
具有动作/归约器的复杂状态?
→ 带切片的 Zustand 或 Redux Toolkit
需要状态持久化?
→ 带持久化中间件的 Zustand
需要相机控制?
├─ 围绕物体旋转 → OrbitControls
├─ 第一人称 → PointerLockControls
├─ 地图/俯视图 → MapControls
└─ 平滑过渡 → CameraControls
需要环境光照?
├─ 快速预设 → <Environment preset="sunset" />
├─ 自定义 HDR → <Environment files="/env.hdr" />
└─ 性能敏感 → <Environment blur={0.5} />
需要文本?
├─ 场景中的 3D 文本 → <Text3D />
├─ 2D 文本广告牌 → <Text />
└─ HTML 叠加层 → <Html />
需要加载?
├─ GLTF 模型 → useGLTF
├─ 纹理 → useTexture
├─ 进度 UI → useProgress
└─ 预加载 → <Preload all />
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
import { Canvas } from '@react-three/fiber'
function App() {
return (
<Canvas
camera={{ position: [0, 0, 5], fov: 75 }}
gl={{ antialias: true }}
shadows
>
<ambientLight intensity={0.5} />
<directionalLight position={[10, 10, 5]} castShadow />
<mesh>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="orange" />
</mesh>
</Canvas>
)
}
<Canvas
camera={{ position, fov, near, far }} // 相机配置
gl={{ antialias, alpha, powerPreference }} // WebGL 上下文
shadows // 启用阴影贴图
dpr={[1, 2]} // 设备像素比范围
frameloop="demand" // "always" | "demand" | "never"
style={{ width: '100%', height: '100vh' }}
onCreated={({ gl, scene, camera }) => {}} // 访问内部对象
/>
import { useFrame } from '@react-three/fiber'
import { useRef } from 'react'
function SpinningBox() {
const meshRef = useRef()
useFrame((state, delta) => {
// state: { clock, camera, scene, gl, pointer, ... }
meshRef.current.rotation.y += delta
meshRef.current.position.y = Math.sin(state.clock.elapsedTime)
})
return (
<mesh ref={meshRef}>
<boxGeometry />
<meshStandardMaterial />
</mesh>
)
}
import { useThree } from '@react-three/fiber'
function CameraLogger() {
const { camera, gl, scene, size, viewport, pointer } = useThree()
// viewport: Three.js 单位中的 { width, height }
// size: 像素单位中的 { width, height }
// pointer: 归一化的鼠标位置 (-1 到 1)
return null
}
import { useLoader } from '@react-three/fiber'
import { TextureLoader } from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
function Model() {
const gltf = useLoader(GLTFLoader, '/model.glb')
const texture = useLoader(TextureLoader, '/texture.jpg')
return <primitive object={gltf.scene} />
}
// Three.js 类 → 驼峰式 JSX 元素
// 构造函数参数 → args 属性(数组)
// 属性 → props
// THREE.Mesh
<mesh position={[0, 1, 0]} rotation={[0, Math.PI, 0]} scale={1.5}>
{/* THREE.BoxGeometry(1, 2, 1) */}
<boxGeometry args={[1, 2, 1]} />
{/* THREE.MeshStandardMaterial({ color: 'red' }) */}
<meshStandardMaterial color="red" roughness={0.5} />
</mesh>
// 嵌套属性使用短横线表示法
<directionalLight
position={[5, 5, 5]}
castShadow
shadow-mapSize={[2048, 2048]}
shadow-camera-far={50}
/>
// 附加到父级属性
<mesh>
<boxGeometry />
<meshStandardMaterial>
<texture attach="map" image={img} />
</meshStandardMaterial>
</mesh>
Drei 提供生产就绪的抽象。安装:@react-three/drei
import {
OrbitControls,
PerspectiveCamera,
Environment,
useGLTF,
useTexture,
Text,
Html,
Float,
Stage,
ContactShadows,
Sky,
Stars,
} from '@react-three/drei'
// 相机控制
<OrbitControls enableDamping dampingFactor={0.05} />
// 环境光照 (HDR)
<Environment preset="sunset" background />
// 预设:apartment, city, dawn, forest, lobby, night, park, studio, sunset, warehouse
// 加载支持 draco 的 GLTF
const { scene, nodes, materials } = useGLTF('/model.glb')
useGLTF.preload('/model.glb')
// 加载纹理
const [colorMap, normalMap] = useTexture(['/color.jpg', '/normal.jpg'])
// 3D 文本
<Text fontSize={1} color="white" anchorX="center" anchorY="middle">
Hello World
</Text>
// 3D 空间中的 HTML 叠加层
<Html position={[0, 2, 0]} center transform occlude>
<div className="label">点击我</div>
</Html>
// 浮动动画
<Float speed={2} rotationIntensity={0.5} floatIntensity={1}>
<mesh>...</mesh>
</Float>
// 快速工作室光照
<Stage environment="city" intensity={0.5}>
<Model />
</Stage>
// 地面上的柔和阴影
<ContactShadows position={[0, -0.5, 0]} opacity={0.5} blur={2} />
<mesh
onClick={(e) => {
e.stopPropagation()
console.log('clicked', e.point, e.face)
}}
onPointerOver={(e) => setHovered(true)}
onPointerOut={(e) => setHovered(false)}
onPointerMove={(e) => console.log(e.point)}
onPointerDown={(e) => {}}
onPointerUp={(e) => {}}
onDoubleClick={(e) => {}}
onContextMenu={(e) => {}}
>
事件对象包含:point, face, faceIndex, distance, object, eventObject, camera, ray。
import { create } from 'zustand'
const useStore = create((set) => ({
score: 0,
gameState: 'idle',
addScore: (points) => set((state) => ({ score: state.score + points })),
startGame: () => set({ gameState: 'playing' }),
}))
function ScoreDisplay() {
const score = useStore((state) => state.score)
return <Text>{score}</Text>
}
function GameLogic() {
const addScore = useStore((state) => state.addScore)
useFrame(() => {
// 调用 addScore 的游戏逻辑
})
return null
}
const GameContext = createContext()
function GameProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState)
return (
<GameContext.Provider value={{ state, dispatch }}>
{children}
</GameContext.Provider>
)
}
// 包裹 Canvas 内容
<Canvas>
<GameProvider>
<Scene />
</GameProvider>
</Canvas>
import { Instances, Instance } from '@react-three/drei'
function Boxes({ count = 1000 }) {
return (
<Instances limit={count}>
<boxGeometry />
<meshStandardMaterial />
{Array.from({ length: count }, (_, i) => (
<Instance
key={i}
position={[Math.random() * 100, Math.random() * 100, Math.random() * 100]}
color={`hsl(${Math.random() * 360}, 50%, 50%)`}
/>
))}
</Instances>
)
}
// 仅在需要时重新渲染
<Canvas frameloop="demand">
{/* 调用 invalidate() 来触发渲染 */}
</Canvas>
function Controls() {
const { invalidate } = useThree()
return <OrbitControls onChange={() => invalidate()} />
}
// 记忆化昂贵的组件
const ExpensiveModel = memo(function ExpensiveModel({ url }) {
const gltf = useGLTF(url)
return <primitive object={gltf.scene.clone()} />
})
// 在组件外部记忆化材质/几何体
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshStandardMaterial({ color: 'red' })
function Box() {
return (
<mesh geometry={geometry} material={material} />
)
}
import { PerformanceMonitor, AdaptiveDpr, AdaptiveEvents } from '@react-three/drei'
<Canvas>
<PerformanceMonitor
onDecline={() => setQuality('low')}
onIncline={() => setQuality('high')}
>
<AdaptiveDpr pixelated />
<AdaptiveEvents />
<Scene quality={quality} />
</PerformanceMonitor>
</Canvas>
| 当你需要... | 使用技能 |
|---|---|
| 原生 Three.js(无 React) | → threejs |
| 加载前优化资源 | → asset-pipeline-3d |
| 调试视觉/性能问题 | → graphics-troubleshooting |
每周安装量
143
代码仓库
GitHub 星标
3
首次出现
2026年1月24日
安全审计
安装于
opencode126
gemini-cli123
codex122
github-copilot114
cursor106
kimi-cli100
React Three Fiber (R3F) is a React renderer for Three.js. Write declarative, component-based 3D scenes using JSX.
Library Versions (2026)
- React Three Fiber: v9.5+
- @react-three/drei: v9.116+
- @react-three/rapier: v2+
- @react-three/postprocessing: v3+
- React: 19+ (concurrent features supported)
Is your app already React-based?
→ Yes: Use R3F (natural integration)
→ No: Consider vanilla Three.js
Do you need React state management?
→ Yes: Use R3F (seamless state integration)
→ No: Either works
Is the 3D scene the entire app?
→ Yes: Either works (R3F has slight overhead)
→ No, mixed with React UI: Use R3F
Performance-critical with millions of objects?
→ Consider vanilla Three.js for maximum control
→ R3F is fine for 99% of use cases
Local component state (single mesh color, hover)?
→ useState / useRef
Shared between few components (selected object)?
→ React Context or prop drilling
Global game/app state (score, inventory, settings)?
→ Zustand (recommended for R3F)
Complex state with actions/reducers?
→ Zustand with slices or Redux Toolkit
Need state persistence?
→ Zustand with persist middleware
Need camera controls?
├─ Orbit around object → OrbitControls
├─ First-person → PointerLockControls
├─ Map/top-down → MapControls
└─ Smooth transitions → CameraControls
Need environment lighting?
├─ Quick preset → <Environment preset="sunset" />
├─ Custom HDR → <Environment files="/env.hdr" />
└─ Performance-sensitive → <Environment blur={0.5} />
Need text?
├─ 3D text in scene → <Text3D />
├─ 2D text billboards → <Text />
└─ HTML overlay → <Html />
Need loading?
├─ GLTF models → useGLTF
├─ Textures → useTexture
├─ Progress UI → useProgress
└─ Preloading → <Preload all />
import { Canvas } from '@react-three/fiber'
function App() {
return (
<Canvas
camera={{ position: [0, 0, 5], fov: 75 }}
gl={{ antialias: true }}
shadows
>
<ambientLight intensity={0.5} />
<directionalLight position={[10, 10, 5]} castShadow />
<mesh>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="orange" />
</mesh>
</Canvas>
)
}
<Canvas
camera={{ position, fov, near, far }} // Camera config
gl={{ antialias, alpha, powerPreference }} // WebGL context
shadows // Enable shadow maps
dpr={[1, 2]} // Device pixel ratio range
frameloop="demand" // "always" | "demand" | "never"
style={{ width: '100%', height: '100vh' }}
onCreated={({ gl, scene, camera }) => {}} // Access internals
/>
import { useFrame } from '@react-three/fiber'
import { useRef } from 'react'
function SpinningBox() {
const meshRef = useRef()
useFrame((state, delta) => {
// state: { clock, camera, scene, gl, pointer, ... }
meshRef.current.rotation.y += delta
meshRef.current.position.y = Math.sin(state.clock.elapsedTime)
})
return (
<mesh ref={meshRef}>
<boxGeometry />
<meshStandardMaterial />
</mesh>
)
}
import { useThree } from '@react-three/fiber'
function CameraLogger() {
const { camera, gl, scene, size, viewport, pointer } = useThree()
// viewport: { width, height } in Three.js units
// size: { width, height } in pixels
// pointer: normalized mouse position (-1 to 1)
return null
}
import { useLoader } from '@react-three/fiber'
import { TextureLoader } from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
function Model() {
const gltf = useLoader(GLTFLoader, '/model.glb')
const texture = useLoader(TextureLoader, '/texture.jpg')
return <primitive object={gltf.scene} />
}
// Three.js class → camelCase JSX element
// Constructor args → args prop (array)
// Properties → props
// THREE.Mesh
<mesh position={[0, 1, 0]} rotation={[0, Math.PI, 0]} scale={1.5}>
{/* THREE.BoxGeometry(1, 2, 1) */}
<boxGeometry args={[1, 2, 1]} />
{/* THREE.MeshStandardMaterial({ color: 'red' }) */}
<meshStandardMaterial color="red" roughness={0.5} />
</mesh>
// Nested properties use dash notation
<directionalLight
position={[5, 5, 5]}
castShadow
shadow-mapSize={[2048, 2048]}
shadow-camera-far={50}
/>
// Attach to parent properties
<mesh>
<boxGeometry />
<meshStandardMaterial>
<texture attach="map" image={img} />
</meshStandardMaterial>
</mesh>
Drei provides production-ready abstractions. Install: @react-three/drei
import {
OrbitControls,
PerspectiveCamera,
Environment,
useGLTF,
useTexture,
Text,
Html,
Float,
Stage,
ContactShadows,
Sky,
Stars,
} from '@react-three/drei'
// Camera controls
<OrbitControls enableDamping dampingFactor={0.05} />
// Environment lighting (HDR)
<Environment preset="sunset" background />
// Presets: apartment, city, dawn, forest, lobby, night, park, studio, sunset, warehouse
// Load GLTF with draco support
const { scene, nodes, materials } = useGLTF('/model.glb')
useGLTF.preload('/model.glb')
// Load textures
const [colorMap, normalMap] = useTexture(['/color.jpg', '/normal.jpg'])
// 3D Text
<Text fontSize={1} color="white" anchorX="center" anchorY="middle">
Hello World
</Text>
// HTML overlay in 3D space
<Html position={[0, 2, 0]} center transform occlude>
<div className="label">Click me</div>
</Html>
// Floating animation
<Float speed={2} rotationIntensity={0.5} floatIntensity={1}>
<mesh>...</mesh>
</Float>
// Quick studio lighting
<Stage environment="city" intensity={0.5}>
<Model />
</Stage>
// Soft shadows on ground
<ContactShadows position={[0, -0.5, 0]} opacity={0.5} blur={2} />
<mesh
onClick={(e) => {
e.stopPropagation()
console.log('clicked', e.point, e.face)
}}
onPointerOver={(e) => setHovered(true)}
onPointerOut={(e) => setHovered(false)}
onPointerMove={(e) => console.log(e.point)}
onPointerDown={(e) => {}}
onPointerUp={(e) => {}}
onDoubleClick={(e) => {}}
onContextMenu={(e) => {}}
>
Event object includes: point, face, faceIndex, distance, object, eventObject, camera, ray.
import { create } from 'zustand'
const useStore = create((set) => ({
score: 0,
gameState: 'idle',
addScore: (points) => set((state) => ({ score: state.score + points })),
startGame: () => set({ gameState: 'playing' }),
}))
function ScoreDisplay() {
const score = useStore((state) => state.score)
return <Text>{score}</Text>
}
function GameLogic() {
const addScore = useStore((state) => state.addScore)
useFrame(() => {
// Game logic that calls addScore
})
return null
}
const GameContext = createContext()
function GameProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState)
return (
<GameContext.Provider value={{ state, dispatch }}>
{children}
</GameContext.Provider>
)
}
// Wrap Canvas content
<Canvas>
<GameProvider>
<Scene />
</GameProvider>
</Canvas>
import { Instances, Instance } from '@react-three/drei'
function Boxes({ count = 1000 }) {
return (
<Instances limit={count}>
<boxGeometry />
<meshStandardMaterial />
{Array.from({ length: count }, (_, i) => (
<Instance
key={i}
position={[Math.random() * 100, Math.random() * 100, Math.random() * 100]}
color={`hsl(${Math.random() * 360}, 50%, 50%)`}
/>
))}
</Instances>
)
}
// Only re-render when needed
<Canvas frameloop="demand">
{/* Call invalidate() to trigger render */}
</Canvas>
function Controls() {
const { invalidate } = useThree()
return <OrbitControls onChange={() => invalidate()} />
}
// Memoize expensive components
const ExpensiveModel = memo(function ExpensiveModel({ url }) {
const gltf = useGLTF(url)
return <primitive object={gltf.scene.clone()} />
})
// Memoize materials/geometries outside components
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshStandardMaterial({ color: 'red' })
function Box() {
return (
<mesh geometry={geometry} material={material} />
)
}
import { PerformanceMonitor, AdaptiveDpr, AdaptiveEvents } from '@react-three/drei'
<Canvas>
<PerformanceMonitor
onDecline={() => setQuality('low')}
onIncline={() => setQuality('high')}
>
<AdaptiveDpr pixelated />
<AdaptiveEvents />
<Scene quality={quality} />
</PerformanceMonitor>
</Canvas>
| When you need... | Use skill |
|---|---|
| Vanilla Three.js (no React) | → threejs |
| Optimize assets before loading | → asset-pipeline-3d |
| Debug visual/performance issues | → graphics-troubleshooting |
Weekly Installs
143
Repository
GitHub Stars
3
First Seen
Jan 24, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode126
gemini-cli123
codex122
github-copilot114
cursor106
kimi-cli100
Vue.js测试最佳实践:Vue 3组件、组合式函数、Pinia与异步测试完整指南
3,800 周安装