Skip to content

Introduction

Fresh

Build your scene declaratively with re-usable, self-contained components that react to state, are readily interactive and can participate in React's ecosystem.

bash
npm install three @types/three @react-three/fiber

Version Pairing

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 three.js will work here without exception.

Is it slower than plain three.js?

No. There is no overhead. Components render outside of React. It outperforms three.js in scale due to React's scheduling abilities.

Can it keep up with frequent feature updates to three.js?

Yes. It merely expresses three.js in JSX — <mesh /> dynamically turns into new THREE.Mesh(). If a new three.js version adds, removes or changes features, it will be available to you instantly without depending on updates to this library.

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:

tsx
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 meshRef = useRef<THREE.Mesh>(null!)
  const [hovered, setHover] = useState(false)
  const [active, setActive] = useState(false)
  useFrame((state, delta) => (meshRef.current.rotation.x += delta))
  return (
    <mesh
      {...props}
      ref={meshRef}
      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' : '#2f74c0'} />
    </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>,
)

React Native

For installation instructions see the React Native installation guide.

jsx
import React, { useRef, useState } from 'react'
import { Canvas, useFrame } from '@react-three/fiber/native'

function Box(props) {
  const meshRef = useRef(null)
  const [hovered, setHover] = useState(false)
  const [active, setActive] = useState(false)
  useFrame((state, delta) => (meshRef.current.rotation.x += delta))
  return (
    <mesh
      {...props}
      ref={meshRef}
      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>
  )
}

First Steps

You need to be versed in both React and three.js before rushing into this. If you are unsure about React, consult the official React docs, especially the section about hooks. As for three.js, make sure you at least glance over the following:

  1. Make sure you have a basic grasp of three.js. Keep the docs open.
  2. When you know what a scene is, a camera, mesh, geometry, material — fork the demo above.
  3. Look up the JSX elements that you see (mesh, ambientLight, etc). All three.js exports are native to R3F.
  4. Try changing some values, scroll through the API to see what the various settings and hooks do.

Ecosystem

There is a vibrant and extensive ecosystem around R3F:

  • @react-three/drei — useful helpers, this is an ecosystem in itself
  • @react-three/gltfjsx — turns GLTFs into JSX components
  • @react-three/postprocessing — post-processing effects
  • @react-three/test-renderer — for unit tests in node
  • @react-three/flex — flexbox for react-three-fiber
  • @react-three/xr — VR/AR controllers and events
  • @react-three/csg — constructive solid geometry
  • @react-three/rapier — 3D physics using Rapier
  • @react-three/cannon — 3D physics using Cannon
  • @react-three/p2 — 2D physics using P2
  • @react-three/a11y — real a11y for your scene
  • @react-three/gpu-pathtracer — realistic path tracing
  • create-r3f-app next — Next.js starter
  • lamina — layer based shader materials
  • zustand — flux based state management
  • jotai — atoms based state management
  • valtio — proxy based state management
  • react-spring — spring-physics-based animation library
  • framer-motion-3d — framer motion for 3D
  • use-gesture — mouse/touch gestures
  • leva — create GUI controls in seconds
  • maath — a kitchen sink for math helpers
  • miniplex — ECS (entity management system)