react-three-fiber
React Three Fiber (R3F) is React for Three.js: scene graph as JSX, hooks for animation and state, Suspense for loaders, declarative components for everything. Combined with @react-three/drei helpers it’s the most productive way to ship 3D in a React app.
Canvas, useFrame, drei, loaders
EXAMPLE
// 1) Install
// npm install three @react-three/fiber @react-three/drei @react-three/postprocessing
import { Canvas, useFrame, useThree } from '@react-three/fiber';
import { OrbitControls, Environment, useGLTF, ContactShadows, Html, Text, Stage } from '@react-three/drei';
import { Suspense, useRef, useState } from 'react';
import * as THREE from 'three';
// 2) Minimal scene
function Box(props) {
const ref = useRef();
const [hovered, setHover] = useState(false);
const [active, setActive] = useState(false);
useFrame((state, dt) => {
ref.current.rotation.x += dt;
ref.current.rotation.y += dt * 0.5;
});
return (
<mesh
{...props}
ref={ref}
scale={active ? 1.5 : 1}
onClick={() => setActive((s) => !s)}
onPointerOver={() => setHover(true)}
onPointerOut={() => setHover(false)}
>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={hovered ? 'orange' : '#4f46e5'} />
</mesh>
);
}
// 3) Canvas — the root that mounts Three.js inside React
export function App() {
return (
<Canvas
camera={{ position: [3, 3, 5], fov: 50 }}
shadows
gl={{ antialias: true, outputColorSpace: THREE.SRGBColorSpace }}
>
<ambientLight intensity={0.3} />
<directionalLight position={[5, 5, 5]} castShadow intensity={1.2} />
<Box position={[-1, 0, 0]} />
<Box position={[1, 0, 0]} />
<OrbitControls />
</Canvas>
);
}
// 4) Loading a glTF — Suspense + drei
function Model({ url }) {
const { scene } = useGLTF(url);
return <primitive object={scene} />;
}
<Canvas>
<Suspense fallback={<Html>Loading…</Html>}>
<Model url="/helmet.glb" />
<Environment preset="sunset" />
<ContactShadows position={[0, -1, 0]} opacity={0.5} scale={10} blur={2.5} far={4} />
</Suspense>
</Canvas>
// useGLTF preloads — call useGLTF.preload(url) outside of render.
// 5) Drei staples
// • OrbitControls / TrackballControls / FlyControls
// • Environment (HDRI lighting)
// • Sky / Stars / Cloud — natural backdrops
// • Stage — pre-configured lighting + ground
// • Float / Center / Bounds — auto-fit and gentle motion
// • Html — render React UI inside the 3D scene
// • Text — 3D text via troika
// • PerspectiveCamera / OrthographicCamera — camera primitives
// • Outlines / Edges — visual effects
// • Sparkles / Trail / Lightformer — fancy helpers
// 6) useFrame — runs every frame; sync state, animate, update
function Spinner() {
const ref = useRef();
useFrame((state, dt) => {
ref.current.rotation.y += dt * 0.5;
ref.current.position.y = Math.sin(state.clock.elapsedTime) * 0.3;
});
return <mesh ref={ref}><torusGeometry args={[0.6, 0.2, 16, 100]} /><meshStandardMaterial color="violet" /></mesh>;
}
// 7) Pointer events
// onClick, onContextMenu, onDoubleClick, onPointerUp/Down/Over/Out/Move/Cancel, onWheel
// Events are raycasted automatically. Use 'stopPropagation' to prevent bubbling.
// 8) useThree — access the underlying Three.js renderer/scene/camera/etc.
function Logger() {
const { camera, gl, scene, viewport, size } = useThree();
console.log('camera position', camera.position);
return null;
}
// 9) Resize-friendly + viewport scaling
<Canvas dpr={[1, 2]} /* device pixel ratio clamp */
resize={{ scroll: true, debounce: { scroll: 50, resize: 0 } }}>
{/* … */}
</Canvas>
// 10) Performance modes
<Canvas frameloop="demand"> {/* renders only when invalidated */}
<RotatingBox onUpdate={() => invalidate()} />
</Canvas>
// Or 'frameloop="never"' and call invalidate() manually for snapshot-style scenes.
// 11) Post-processing (bloom, DOF, etc.)
import { EffectComposer, Bloom, Vignette } from '@react-three/postprocessing';
<Canvas>
{/* scene */}
<EffectComposer>
<Bloom intensity={0.6} luminanceThreshold={0.7} />
<Vignette eskil={false} offset={0.1} darkness={1.1} />
</EffectComposer>
</Canvas>
// 12) Physics (Rapier / Cannon)
import { Physics, RigidBody, CuboidCollider } from '@react-three/rapier';
<Canvas>
<Physics gravity={[0, -9.8, 0]}>
<RigidBody>
<Box position={[0, 5, 0]} />
</RigidBody>
<RigidBody type="fixed">
<CuboidCollider args={[10, 0.1, 10]} />
<mesh position={[0, -0.1, 0]} receiveShadow>
<boxGeometry args={[20, 0.2, 20]} />
<meshStandardMaterial color="#88aa66" />
</mesh>
</RigidBody>
</Physics>
</Canvas>
// 13) Custom shaders
import { shaderMaterial } from '@react-three/drei';
import { extend } from '@react-three/fiber';
const MyMaterial = shaderMaterial(
{ uTime: 0, uColor: new THREE.Color('orange') },
/* vertex */ `varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }`,
/* frag */ `uniform float uTime; uniform vec3 uColor; varying vec2 vUv;
void main() { gl_FragColor = vec4(uColor * (0.5 + 0.5 * sin(uTime + vUv.x * 5.0)), 1.0); }`,
);
extend({ MyMaterial });
function WavyPlane() {
const ref = useRef();
useFrame(({ clock }) => { ref.current.uTime = clock.elapsedTime; });
return <mesh><planeGeometry args={[2, 2, 64, 64]} /><myMaterial ref={ref} /></mesh>;
}
// 14) Common bugs
// • Forgot Canvas → throwing 'R3F: Hooks can only be used within the Canvas component'
// • Setting mesh ref but no children → empty render; check JSX nesting
// • useGLTF without preload + Suspense → tearing / blank flashes
// • shadows but no castShadow/receiveShadow set on meshes
// • Heavy useFrame closures cause GC pauses → memoise references with useRef + useCallback
// • Multiple <Canvas> on a page sharing state — keep one per scene
// • Pointer events firing for hidden meshes — use raycast={null} or layer filtering
// • HMR on non-React Three code — refresh required
Why it matters
React Three Fiber turns 3D into idiomatic React: components for objects, useFrame for per-frame logic, Suspense + drei loaders for models and HDRIs, optional Rapier physics, and post-processing as JSX. frameloop="demand" + render-on-change keeps cost low for static or sporadic scenes.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
import { Canvas } from '@react-three/fiber';
import { OrbitControls } from '@react-three/drei';
<Canvas><OrbitControls /><mesh /></Canvas>
Try it Yourself »
Discussion
Loading…