Convert Figma logo to code with AI

pmndrs logoreact-three-fiber

🇨🇭 A React renderer for Three.js

27,091
1,545
27,091
70

Top Related Projects

101,622

JavaScript 3D Library.

Babylon.js is a powerful, beautiful, simple, and open game and rendering engine packed into a friendly JavaScript framework.

7,123

glTF – Runtime 3D Asset Delivery

9,523

JavaScript game engine built on WebGL, WebGPU, WebXR and glTF

React component for Spline scenes.

✌️ A spring physics based React animation library

Quick Overview

React Three Fiber is a popular React renderer for Three.js, a powerful 3D graphics library for the web. It allows developers to create and manipulate 3D scenes using React's declarative syntax, making it easier to integrate 3D graphics into React applications.

Pros

  • Seamless integration with React ecosystem and components
  • Simplified 3D scene creation using declarative syntax
  • Automatic performance optimizations and efficient rendering
  • Large and active community with extensive documentation and examples

Cons

  • Steep learning curve for developers new to 3D graphics
  • Performance limitations for complex scenes compared to vanilla Three.js
  • Potential compatibility issues with some Three.js plugins and extensions
  • Requires understanding of both React and Three.js concepts

Code Examples

  1. Creating a simple 3D scene with a rotating cube:
import React, { useRef } from 'react'
import { Canvas, useFrame } from '@react-three/fiber'

function RotatingCube() {
  const meshRef = useRef()
  useFrame(() => (meshRef.current.rotation.x += 0.01))
  return (
    <mesh ref={meshRef}>
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color="orange" />
    </mesh>
  )
}

function App() {
  return (
    <Canvas>
      <ambientLight />
      <pointLight position={[10, 10, 10]} />
      <RotatingCube />
    </Canvas>
  )
}
  1. Adding user interaction with mouse events:
import { useThree } from '@react-three/fiber'

function InteractiveSphere() {
  const { viewport } = useThree()
  return (
    <mesh
      onClick={(e) => console.log('clicked')}
      onPointerOver={(e) => console.log('hovered')}
      onPointerOut={(e) => console.log('unhovered')}
    >
      <sphereGeometry args={[1, 32, 32]} />
      <meshStandardMaterial color="royalblue" />
    </mesh>
  )
}
  1. Using hooks for animation:
import { useFrame } from '@react-three/fiber'

function AnimatedTorus() {
  const meshRef = useRef()
  useFrame((state, delta) => {
    meshRef.current.rotation.x += delta
    meshRef.current.position.y = Math.sin(state.clock.elapsedTime) * 2
  })
  return (
    <mesh ref={meshRef}>
      <torusGeometry args={[1, 0.4, 16, 100]} />
      <meshNormalMaterial />
    </mesh>
  )
}

Getting Started

To start using React Three Fiber, follow these steps:

  1. Install the required packages:

    npm install three @react-three/fiber
    
  2. Create a basic 3D scene in your React component:

    import React from 'react'
    import { Canvas } from '@react-three/fiber'
    
    function App() {
      return (
        <Canvas>
          <ambientLight />
          <mesh>
            <boxGeometry />
            <meshStandardMaterial />
          </mesh>
        </Canvas>
      )
    }
    
    export default App
    
  3. Run your React application and you should see a 3D cube rendered on the screen.

Competitor Comparisons

101,622

JavaScript 3D Library.

Pros of three.js

  • Lower-level API providing more control and flexibility
  • Wider ecosystem and community support
  • Can be used with any JavaScript framework or vanilla JS

Cons of three.js

  • Steeper learning curve for beginners
  • More verbose code, requiring manual setup of scenes, cameras, and renderers
  • Less integration with React's component-based architecture

Code Comparison

three.js:

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

react-three-fiber:

import { Canvas } from '@react-three/fiber'

function App() {
  return (
    <Canvas>
      {/* Scene contents */}
    </Canvas>
  )
}

react-three-fiber provides a more declarative approach, abstracting away the boilerplate setup required in three.js. It allows for easier integration with React components and state management, making it more suitable for React-based projects. However, three.js offers more granular control and can be used in a wider range of JavaScript environments.

Babylon.js is a powerful, beautiful, simple, and open game and rendering engine packed into a friendly JavaScript framework.

Pros of Babylon.js

  • More comprehensive and feature-rich 3D engine
  • Better documentation and learning resources
  • Larger community and ecosystem

Cons of Babylon.js

  • Steeper learning curve for beginners
  • Less integration with React ecosystem
  • More verbose code for simple scenes

Code Comparison

Babylon.js:

const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.FreeCamera("camera", new BABYLON.Vector3(0, 5, -10), scene);
const sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {diameter: 2}, scene);

React Three Fiber:

function Scene() {
  return (
    <Canvas>
      <perspectiveCamera position={[0, 5, -10]} />
      <mesh>
        <sphereGeometry args={[1, 32, 32]} />
        <meshStandardMaterial />
      </mesh>
    </Canvas>
  );
}

React Three Fiber provides a more declarative and React-like approach to creating 3D scenes, making it easier for React developers to integrate 3D graphics into their applications. However, Babylon.js offers a more powerful and feature-complete 3D engine with better performance for complex scenes and games. The choice between the two depends on the specific project requirements and the developer's familiarity with React and 3D graphics programming.

7,123

glTF – Runtime 3D Asset Delivery

Pros of glTF

  • Industry-standard 3D file format with wide adoption and support
  • Efficient, compact representation of 3D scenes and models
  • Extensible format allowing for custom data and features

Cons of glTF

  • Primarily a file format, not a rendering or interaction library
  • Requires additional tools or libraries for rendering and manipulation
  • Less focused on React integration compared to react-three-fiber

Code Comparison

glTF (JSON representation):

{
  "asset": { "version": "2.0" },
  "scene": 0,
  "scenes": [{ "nodes": [0] }],
  "nodes": [{ "mesh": 0 }],
  "meshes": [{ "primitives": [{ "attributes": { "POSITION": 0 } }] }]
}

react-three-fiber:

function Scene() {
  return (
    <mesh>
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color="hotpink" />
    </mesh>
  )
}

Summary

glTF is a file format for 3D content, while react-three-fiber is a React renderer for Three.js. glTF excels in standardization and efficient 3D representation, but requires additional tools for rendering. react-three-fiber provides a more integrated solution for React developers working with 3D graphics, offering a declarative approach to creating and manipulating 3D scenes within React applications.

9,523

JavaScript game engine built on WebGL, WebGPU, WebXR and glTF

Pros of PlayCanvas Engine

  • Complete game engine with built-in physics, audio, and animation systems
  • Visual editor for scene creation and asset management
  • Better performance for complex 3D applications and games

Cons of PlayCanvas Engine

  • Steeper learning curve for developers new to game engines
  • Less flexibility for integration with existing React applications
  • More opinionated structure, which may limit customization options

Code Comparison

React Three Fiber:

function Box(props) {
  const mesh = useRef()
  return (
    <mesh {...props} ref={mesh}>
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color={'orange'} />
    </mesh>
  )
}

PlayCanvas Engine:

var entity = new pc.Entity();
entity.addComponent('model', {
    type: 'box'
});
entity.addComponent('material', {
    type: 'phong'
});
app.root.addChild(entity);

Summary

React Three Fiber is ideal for React developers looking to add 3D graphics to their web applications, offering a more familiar syntax and easier integration with existing React projects. PlayCanvas Engine, on the other hand, is better suited for full-fledged 3D game development, providing a comprehensive set of tools and features at the cost of a steeper learning curve and less flexibility for web application integration.

React component for Spline scenes.

Pros of react-spline

  • Simplified workflow for importing and using 3D scenes created in Spline
  • Easier integration of interactive 3D elements for designers and non-developers
  • Automatic handling of scene loading and optimization

Cons of react-spline

  • Limited to scenes created in Spline, less flexibility for custom 3D development
  • Smaller community and ecosystem compared to react-three-fiber
  • Potentially less performant for complex scenes or large-scale applications

Code Comparison

react-spline:

import Spline from '@splinetool/react-spline';

function App() {
  return <Spline scene="https://prod.spline.design/example.splinecode" />;
}

react-three-fiber:

import { Canvas } from '@react-three/fiber';
import { Box } from '@react-three/drei';

function App() {
  return (
    <Canvas>
      <Box position={[0, 0, 0]} />
    </Canvas>
  );
}

react-spline focuses on simplicity and ease of use for Spline-created scenes, while react-three-fiber offers more flexibility and control over custom 3D scenes. The choice between the two depends on the project's requirements, the team's expertise, and the desired level of customization.

✌️ A spring physics based React animation library

Pros of react-spring

  • Focuses on general-purpose animations and transitions
  • Easier to learn and implement for basic UI animations
  • Smaller bundle size and lighter performance impact

Cons of react-spring

  • Limited to 2D animations and transformations
  • Lacks advanced 3D rendering capabilities
  • Not optimized for complex, GPU-accelerated graphics

Code Comparison

react-spring:

import { useSpring, animated } from 'react-spring'

function AnimatedComponent() {
  const props = useSpring({ opacity: 1, from: { opacity: 0 } })
  return <animated.div style={props}>I will fade in</animated.div>
}

react-three-fiber:

import { Canvas, useFrame } from '@react-three/fiber'
import { useRef } from 'react'

function RotatingBox() {
  const meshRef = useRef()
  useFrame(() => (meshRef.current.rotation.x += 0.01))
  return <mesh ref={meshRef}><boxGeometry /></mesh>
}

function Scene() {
  return <Canvas><RotatingBox /></Canvas>
}

While react-spring excels in creating smooth, physics-based animations for UI elements, react-three-fiber is specifically designed for 3D rendering and complex WebGL-based graphics. react-spring is more accessible for general web development, whereas react-three-fiber offers powerful tools for creating immersive 3D experiences within React applications.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

@react-three/fiber

Version Downloads Twitter Discord Open Collective ETH BTC

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.

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

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.

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) {
  // This reference gives us direct access to the THREE.Mesh object
  const ref = useRef()
  // Hold state for hovered and clicked events
  const [hovered, hover] = useState(false)
  const [clicked, click] = useState(false)
  // Subscribe this component to the render-loop, rotate the mesh every frame
  useFrame((state, delta) => (ref.current.rotation.x += delta))
  // Return the view, these are regular Threejs elements expressed in JSX
  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 relies on react 18 and uses expo-cli, but you can create a bare project with their template or with the react-native CLI.

# Install expo-cli, this will create our app
npm install expo-cli -g
# Create app and cd into it
expo init my-app
cd my-app
# Install dependencies
npm install three @react-three/fiber@beta react@rc
# Start
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:

// metro.config.js
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/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 += 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

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:

  1. Make sure you have a basic grasp of Threejs. Keep that site 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 threejs exports are native to three-fiber.
  4. Try changing some values, scroll through our API to see what the various settings and hooks do.

Some helpful material:

Ecosystem

There is a vibrant and extensive eco system around three-fiber, full of libraries, helpers and abstractions.

Usage Trend of the @react-three Family

Who is using Three-fiber

A small selection of companies and projects relying on three-fiber.

How to contribute

If you like this project, please consider helping out. All contributions are welcome as well as donations to Opencollective, or in crypto BTC: 36fuguTPxGCNnYZSRdgdh6Ea94brCAjMbH, ETH: 0x6E3f79Ea1d0dcedeb33D3fC6c34d2B1f156F2682.

Backers

Thank you to all our backers! 🙏

Contributors

This project exists thanks to all the people who contribute.

NPM DownloadsLast 30 Days