Pmndrs.docs

Installation

Learn how to install react-three-fiber

npm install three @react-three/fiber

Fiber is compatible with React v18.0.0+ and works with ReactDOM and React Native.

Getting started with React Three Fiber is not nearly as hard as you might have thought, but various frameworks may require particular attention.

We've put together guides for getting started with each popular framework:

  • Create React App
  • Next.js
  • CDN w/o build tools
  • React Native

If you just want to give it a try, fork this example on codesandbox!

Create React App

create-react-app will work out of the box, nothing special here!

# Create app
npx create-react-app my-app
cd my-app

# Install dependencies
npm install three @react-three/fiber

# Start
npm run start

Next.js

It should work out of the box but you will encounter untranspiled add-ons in the three.js ecosystem, in that case you can install the next-transpile-modules module:

npm install next-transpile-modules --save-dev

Then, add this to your next.config.js

const withTM = require('next-transpile-modules')(['three'])
module.exports = withTM()

Make sure to check out our official next.js starter, too!

Without build tools

You can use React Three Fiber with browser-ready ES Modules from esm.sh and a JSX-like syntax powered by htm.

import ReactDOM from 'https://esm.sh/react-dom'
import React, { useRef, useState } from 'https://esm.sh/react'
import { Canvas, useFrame } from 'https://esm.sh/@react-three/fiber'
import htm from 'https://esm.sh/htm'

const html = htm.bind(React.createElement)
ReactDOM.render(html`<${Canvas}>...<//>`, document.getElementById('root'))
Full example
import ReactDOM from 'https://esm.sh/react-dom'
import React, { useRef, useState } from 'https://esm.sh/react'
import { Canvas, useFrame } from 'https://esm.sh/@react-three/fiber'
import htm from 'https://esm.sh/htm'

const html = htm.bind(React.createElement)

function Box(props) {
  const mesh = useRef()
  const [hovered, setHover] = useState(false)
  const [active, setActive] = useState(false)
  useFrame(() => (mesh.current.rotation.x = mesh.current.rotation.y += 0.01))
  return html` <mesh
    ...${props}
    ref=${mesh}
    scale=${active ? 1.5 : 1}
    onClick=${() => setActive(!active)}
    onPointerOver=${() => setHover(true)}
    onPointerOut=${() => setHover(false)}
  >
    <boxGeometry args=${[1, 1, 1]} />
    <meshStandardMaterial color=${hovered ? 'hotpink' : 'orange'} />
  </mesh>`
}

ReactDOM.render(
  html` <${Canvas}>
    <ambientLight />
    <pointLight position=${[10, 10, 10]} />
    <${Box} position=${[-1.2, 0, 0]} />
    <${Box} position=${[1.2, 0, 0]} />
  <//>`,
  document.getElementById('root'),
)

React Native

R3F v8 adds support for react-native and can be imported from @react-three/fiber/native. We use expo-gl and expo-asset under the hood for WebGL2 bindings and ensuring interplay between Metro and threejs loaders.

To get started, create an app via expo or react-native:

# Create a managed/bare app
npx create-expo-app
cd my-app

# or

# Create and link bare app
npx react-native init my-app
npx install-expo-modules@latest
cd my-app

Then install dependencies (for manual installation or migration, see expo modules installation):

# Automatically install
expo install expo-gl

# Install NPM dependencies
npm install three @react-three/fiber

Some configuration may be required to tell the Metro bundler about your assets if you use useLoader or Drei abstractions like useGLTF and useTexture:

// metro.config.js
module.exports = {
  resolver: {
    sourceExts: ['js', 'jsx', 'json', 'ts', 'tsx', 'cjs'],
    assetExts: ['glb', 'gltf', 'png', 'jpg'],
  },
}

R3F's API is completely x-platform, so you can use events and hooks just as you would on the web.

Just make sure to import from @react-three/fiber/native or @react-three/drei/native to use their native targets.

import React, { useRef, useState } from 'react'
import { Canvas, useFrame } from '@react-three/fiber/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 += 0.01))
  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 />
      <pointLight position={[10, 10, 10]} />
      <Box position={[-1.2, 0, 0]} />
      <Box position={[1.2, 0, 0]} />
    </Canvas>
  )
}