@react-three/fiber


react-three-fiber is a React renderer for threejs.
Build your scene declaratively with re-usable, self-contained components that react to state, are readily interactive and can participate in React's ecosystem.
yarn install three @types/three @react-three/fiber
[!WARNING]
Three-fiber is a React renderer, it must pair with a major version of React, just like react-dom, react-native, etc. @react-three/fiber@8 pairs with react@18, @react-three/fiber@9+ pairs with react@19.
Does it have limitations?
None. Everything that works in Threejs will work here without exception.
Is it slower than plain Threejs?
No. There is no overhead. Components render outside of React. It outperforms Threejs in scale due to React's scheduling abilities.
Can it keep up with frequent feature updates to Threejs?
Yes. It merely expresses Threejs in JSX, <mesh /> dynamically turns into new THREE.Mesh(). If a new Threejs version adds, removes or changes features, it will be available to you instantly without depending on updates to this library.
Does it support WebGPU?
Yes. In v10 it is the default: <Canvas> from @react-three/fiber renders with three's WebGPURenderer, which falls back to a WebGL2 backend where the browser has no WebGPU, and the hooks are typed for it. Node materials and TSL work out of the box, with our own hooks in @react-three/tsl. Scenes that need WebGLRenderer (GLSL ShaderMaterials, onBeforeCompile, postprocessing) import from @react-three/fiber/legacy.
Upgrading to v10?
v10 is in alpha (npm install @react-three/fiber@alpha). Read the migration guide and the list of breaking changes. The short version:
@react-three/fiber renders with WebGPU; WebGL is @react-three/fiber/legacy, chosen by the import.
useThree, useFrame and onCreated are typed for the import's renderer, so state.renderer.compute(...) needs no cast. Libraries that run on both renderers type against @react-three/fiber/extension.
state.gl is state.renderer (deprecated), state.clock is gone (state.elapsed, state.delta), and shadows and the color props moved into renderer={{ ... }} / gl={{ ... }}.
- The TSL hooks live in
@react-three/tsl; the physics frame phase runs on a fixed timestep.
What does it look like?
| Let's make a re-usable component that has its own state, reacts to user-input and participates in the render-loop. (live demo). |
|
import { createRoot } from 'react-dom/client'
import React, { useRef, useState } from 'react'
import { Canvas, useFrame } from '@react-three/fiber'
function Box(props) {
const ref = useRef()
const [hovered, hover] = useState(false)
const [clicked, click] = useState(false)
useFrame(({ delta }) => (ref.current.rotation.x += delta))
return (
<mesh
{...props}
ref={ref}
scale={clicked ? 1.5 : 1}
onClick={(event) => click(!clicked)}
onPointerOver={(event) => hover(true)}
onPointerOut={(event) => hover(false)}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
</mesh>
)
}
createRoot(document.getElementById('root')).render(
<Canvas>
<ambientLight intensity={Math.PI / 2} />
<spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} decay={0} intensity={Math.PI} />
<pointLight position={[-10, -10, -10]} decay={0} intensity={Math.PI} />
<Box position={[-1.2, 0, 0]} />
<Box position={[1.2, 0, 0]} />
</Canvas>,
)
Show TypeScript example
npm install @types/three
import * as THREE from 'three'
import { createRoot } from 'react-dom/client'
import React, { useRef, useState } from 'react'
import { Canvas, useFrame, ThreeElements } from '@react-three/fiber'
function Box(props: ThreeElements['mesh']) {
const ref = useRef<THREE.Mesh>(null!)
const [hovered, hover] = useState(false)
const [clicked, click] = useState(false)
useFrame((state, delta) => (ref.current.rotation.x += delta))
return (
<mesh
{...props}
ref={ref}
scale={clicked ? 1.5 : 1}
onClick={(event) => click(!clicked)}
onPointerOver={(event) => hover(true)}
onPointerOut={(event) => hover(false)}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
</mesh>
)
}
createRoot(document.getElementById('root') as HTMLElement).render(
<Canvas>
<ambientLight intensity={Math.PI / 2} />
<spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} decay={0} intensity={Math.PI} />
<pointLight position={[-10, -10, -10]} decay={0} intensity={Math.PI} />
<Box position={[-1.2, 0, 0]} />
<Box position={[1.2, 0, 0]} />
</Canvas>,
)
Live demo: https://codesandbox.io/s/icy-tree-brnsm?file=/src/App.tsx
Show React Native example
This example uses expo-cli, but you can create a bare project with their template or with the react-native CLI.
npm install expo-cli -g
expo init my-app
cd my-app
npm install three @react-three/native
expo start
Some configuration may be required to tell the Metro bundler about your assets if you use useLoader or Drei abstractions like useGLTF and useTexture:
module.exports = {
resolver: {
sourceExts: ['js', 'jsx', 'json', 'ts', 'tsx', 'cjs'],
assetExts: ['glb', 'png', 'jpg'],
},
}
import React, { useRef, useState } from 'react'
import { Canvas, useFrame } from '@react-three/native'
function Box(props) {
const mesh = useRef(null)
const [hovered, setHover] = useState(false)
const [active, setActive] = useState(false)
useFrame((state, delta) => (mesh.current.rotation.x += delta))
return (
<mesh
{...props}
ref={mesh}
scale={active ? 1.5 : 1}
onClick={(event) => setActive(!active)}
onPointerOver={(event) => setHover(true)}
onPointerOut={(event) => setHover(false)}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
</mesh>
)
}
export default function App() {
return (
<Canvas>
<ambientLight intensity={Math.PI / 2} />
<spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} decay={0} intensity={Math.PI} />
<pointLight position={[-10, -10, -10]} decay={0} intensity={Math.PI} />
<Box position={[-1.2, 0, 0]} />
<Box position={[1.2, 0, 0]} />
</Canvas>
)
}
Documentation, tutorials, examples
Visit docs.pmnd.rs | Awesome React Three Fiber
First steps
You need to be versed in both React and Threejs before rushing into this. If you are unsure about React consult the official React docs, especially the section about hooks. As for Threejs, make sure you at least glance over the following links:
- Make sure you have a basic grasp of Threejs. Keep that site open.
- When you know what a scene is, a camera, mesh, geometry, material, fork the demo above.
- Look up the JSX elements that you see (mesh, ambientLight, etc), all threejs exports are native to three-fiber.
- Try changing some values, scroll through our API to see what the various settings and hooks do.
How to contribute
See the Development Guide for setup, workflow, and contributing standards.
All contributions are welcome as well as donations to Open Collective.
Backers
Thank you to all our backers! 🙏
Contributors
This project exists thanks to all the people who contribute.