@react-three/drei vs react-three-fiber vs three
Building 3D Web Experiences: Core Engine vs React Renderer vs Helper Library
@react-three/dreireact-three-fiberthreeSimilar Packages:

Building 3D Web Experiences: Core Engine vs React Renderer vs Helper Library

three is the foundational WebGL library that provides low-level access to graphics primitives like scenes, cameras, and geometries. react-three-fiber is a React renderer for three, allowing developers to build 3D scenes using declarative React components instead of imperative code. @react-three/drei is a collection of useful helpers and common abstractions built on top of react-three-fiber, offering ready-to-use components for controls, environments, and interactions to speed up development.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
@react-three/drei09,8251.75 MB10924 days agoMIT
react-three-fiber031,827-535 years agoMIT
three0114,92523.2 MB3792 months agoMIT

three vs react-three-fiber vs @react-three/drei: Architecture and DX Compared

Building 3D experiences on the web usually involves one of three layers: the core engine, the React renderer, or a helper library. three gives you raw power, react-three-fiber connects that power to React, and @react-three/drei provides the common tools you need to finish the job. Let's compare how they handle everyday tasks.

🏗️ Scene Setup: Manual Boilerplate vs Declarative Canvas

three requires you to manually create the scene, camera, and renderer, then append the canvas to the DOM.

  • You must handle the render loop and resizing logic yourself.
  • This offers maximum control but involves significant boilerplate code.
// three: Manual setup
import * as THREE from 'three';

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);

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate();

react-three-fiber wraps the setup in a <Canvas> component.

  • It automatically handles the renderer, loop, and resize events.
  • You just drop components inside the canvas to build your scene.
// react-three-fiber: Declarative setup
import { Canvas } from '@react-three/fiber';

function App() {
  return (
    <Canvas>
      {/* Scene content goes here */}
    </Canvas>
  );
}

@react-three/drei builds on the <Canvas> from react-three-fiber.

  • It doesn't replace the canvas but adds environment helpers inside it.
  • You can instantly add skies or stars without manual lighting setup.
// @react-three/drei: Enhanced setup
import { Canvas } from '@react-three/fiber';
import { Stars } from '@react-three/drei';

function App() {
  return (
    <Canvas>
      <Stars /> {/* Instant background */}
    </Canvas>
  );
}

🧊 Creating Objects: Imperative Classes vs JSX Primitives

three uses constructor classes for geometries and materials.

  • You create a mesh by combining geometry and material instances.
  • Memory management and disposal are your responsibility.
// three: Imperative objects
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial({ color: 'orange' });
const mesh = new THREE.Mesh(geometry, material);

scene.add(mesh);

react-three-fiber maps three.js classes to JSX elements.

  • You use lowercase tags like <mesh> and <boxGeometry>.
  • The library handles disposal and updates automatically when props change.
// react-three-fiber: JSX primitives
function Box() {
  return (
    <mesh>
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color="orange" />
    </mesh>
  );
}

@react-three/drei provides high-level components that wrap primitives.

  • Components like <Box> include geometry and material in one tag.
  • This reduces verbosity for common shapes and adds extra features.
// @react-three/drei: High-level components
import { Box } from '@react-three/drei';

function Box() {
  return <Box args={[1, 1, 1]} color="orange" />;
}

🎬 Animation: RequestAnimationFrame vs Hooks vs Helpers

three relies on the standard requestAnimationFrame loop.

  • You must manually update object positions inside the function.
  • This gives you precise timing control but requires more code.
// three: Manual loop
function animate() {
  requestAnimationFrame(animate);
  mesh.rotation.x += 0.01;
  renderer.render(scene, camera);
}
animate();

react-three-fiber provides the useFrame hook.

  • It runs on every frame but keeps logic inside React components.
  • You get access to state and delta time without global variables.
// react-three-fiber: useFrame hook
import { useFrame } from '@react-three/fiber';
import { useRef } from 'react';

function RotatingBox() {
  const ref = useRef();
  useFrame((state, delta) => {
    ref.current.rotation.x += delta;
  });
  return <mesh ref={ref}><boxGeometry /></mesh>;
}

@react-three/drei offers declarative animation components.

  • Components like <Float> animate objects without writing loop logic.
  • This is perfect for idle animations like hovering or breathing effects.
// @react-three/drei: Declarative animation
import { Float } from '@react-three/drei';

function FloatingBox() {
  return (
    <Float speed={2} rotationIntensity={1}>
      <Box args={[1, 1, 1]} color="orange" />
    </Float>
  );
}

🎮 Camera Controls: Manual Wiring vs Drop-in Components

three requires importing controls and wiring them to the camera and DOM.

  • You must update controls in the render loop.
  • This is flexible but easy to get wrong if you miss a step.
// three: Manual controls
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

const controls = new OrbitControls(camera, renderer.domElement);

function animate() {
  requestAnimationFrame(animate);
  controls.update(); // Must call update
  renderer.render(scene, camera);
}

react-three-fiber allows manual control integration via hooks.

  • You can access the camera and GL context using useThree.
  • This is rare now since helpers exist, but it shows the capability.
// react-three-fiber: Manual integration
import { useThree } from '@react-three/fiber';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { useEffect } from 'react';

function Controls() {
  const { camera, gl } = useThree();
  useEffect(() => {
    const controls = new OrbitControls(camera, gl.domElement);
    return () => controls.dispose();
  }, [camera, gl]);
  return null;
}

@react-three/drei exports ready-to-use control components.

  • You just drop <OrbitControls /> into the scene.
  • It handles disposal, updates, and props automatically.
// @react-three/drei: Ready-made controls
import { OrbitControls } from '@react-three/drei';

function Scene() {
  return (
    <>
      <OrbitControls makeDefault />
      <Box />
    </>
  );
}

🌍 Similarities: Shared Foundations

While these packages serve different roles, they share a tight connection.

1. 🔗 Same Underlying Engine

  • react-three-fiber and @react-three/drei both rely on three.
  • Any three object can be used within the React ecosystem.
// All three can access core THREE objects
import * as THREE from 'three';
const color = new THREE.Color('red');

2. 🔄 Reactive Updates

  • react-three-fiber and @react-three/drei react to prop changes.
  • three requires manual setting of properties.
// react-three-fiber / drei
<meshStandardMaterial color={isActive ? 'blue' : 'red'} />

// three
material.color.set(isActive ? 'blue' : 'red');

3. 🛠️ Extensible Ecosystem

  • All three support custom shaders and extensions.
  • You can mix imperative three code inside React components when needed.
// react-three-fiber: Mixing imperative code
useFrame((state) => {
  mesh.current.material.uniforms.time.value = state.clock.elapsedTime;
});

📊 Summary: Key Differences

Featurethreereact-three-fiber@react-three/drei
Style⚙️ Imperative JS⚛️ Declarative JSX🧩 Pre-built Components
Setup📝 Manual Boilerplate📦 <Canvas> Wrapper🚀 Helpers inside Canvas
Animation⏱️ requestAnimationFrame🪝 useFrame Hook🎈 <Float> Components
Controls🔌 Manual Wiring🪝 Hook Integration🎮 <OrbitControls />
Best For🎮 Custom Engines🌐 React Apps⚡ Rapid Prototyping

💡 The Big Picture

three is the engine under the hood — it powers everything but requires you to build the car yourself. Use it for maximum control or non-React projects.

react-three-fiber is the steering wheel and dashboard — it lets you drive the engine using React patterns. Use it to integrate 3D into your modern web app.

@react-three/drei is the GPS and comfort features — it gives you navigation and luxury tools so you don't have to build them. Use it to ship faster with standard features.

Final Thought: You rarely choose just one. Most professional React 3D apps use all three together — three for the core types, react-three-fiber for the scene graph, and @react-three/drei for the heavy lifting.

How to Choose: @react-three/drei vs react-three-fiber vs three

  • @react-three/drei:

    Choose @react-three/drei if you are already using react-three-fiber and want to avoid reinventing common wheels like camera controls, loading states, or complex materials. It is the standard utility belt for production-ready React 3D apps, saving time on boilerplate while maintaining flexibility.

  • react-three-fiber:

    Choose react-three-fiber if you are working within a React application and want to manage your 3D scene graph using components and hooks. It is ideal when you need to sync 3D state with DOM state, leverage React's ecosystem for state management, or prefer declarative syntax over imperative boilerplate.

  • three:

    Choose three if you are building a non-React application or need complete low-level control over the WebGL rendering pipeline without the overhead of a React reconciliation layer. It is the best fit for custom game engines, heavy data visualizations, or projects where React is not part of the stack.

README for @react-three/drei

Storybook Version Downloads Discord Shield Open in GitHub Codespaces

logo

A growing collection of useful helpers and fully functional, ready-made abstractions for @react-three/fiber.

If you make a component that is generic enough to be useful to others, think about CONTRIBUTING!

npm install @react-three/drei

[!IMPORTANT] this package is using the stand-alone three-stdlib instead of three/examples/jsm.

Basic usage

import { PerspectiveCamera, PositionalAudio, ... } from '@react-three/drei'

React-native

import { PerspectiveCamera, PositionalAudio, ... } from '@react-three/drei/native'

The native route of the library does not export Html or Loader. The default export of the library is web which does export Html and Loader.

Documentation

https://pmndrs.github.io/drei

Old doc

[!WARNING] Below is an archive of the anchors links with their new respective locations to the documentation website. Do not update the links below, they are for reference only.

Cameras

PerspectiveCamera

Documentation has moved here

OrthographicCamera

Documentation has moved here

CubeCamera

Documentation has moved here

Controls

CameraControls

Documentation has moved here

ScrollControls

Documentation has moved here

PresentationControls

Documentation has moved here

KeyboardControls

Documentation has moved here

FaceControls

Documentation has moved here

MotionPathControls

Documentation has moved here

Gizmos

GizmoHelper

Documentation has moved here

PivotControls

Documentation has moved here

DragControls

Documentation has moved here

TransformControls

Documentation has moved here

Grid

Documentation has moved here

Helper / useHelper

Documentation has moved here

Shapes

Plane, Box, Sphere, Circle, Cone, Cylinder, Tube, Torus, TorusKnot, Ring, Tetrahedron, Polyhedron, Icosahedron, Octahedron, Dodecahedron, Extrude, Lathe, Shape

Documentation has moved here

RoundedBox

Documentation has moved here

ScreenQuad

Documentation has moved here

Line

Documentation has moved here

QuadraticBezierLine

Documentation has moved here

CubicBezierLine

Documentation has moved here

CatmullRomLine

Documentation has moved here

Facemesh

Documentation has moved here

Abstractions

Image

Documentation has moved here

Text

Documentation has moved here

Text3D

Documentation has moved here

Effects

Documentation has moved here

PositionalAudio

Documentation has moved here

Billboard

Documentation has moved here

ScreenSpace

Documentation has moved here

ScreenSizer

Documentation has moved here

GradientTexture

Documentation has moved here

Edges

Documentation has moved here

Outlines

Documentation has moved here

Trail

Documentation has moved here

Sampler

Documentation has moved here

ComputedAttribute

Documentation has moved here

Clone

Documentation has moved here

useAnimations

Documentation has moved here

MarchingCubes

Documentation has moved here

Decal

Documentation has moved here

Svg

Documentation has moved here

AsciiRenderer

Documentation has moved here

Splat

Documentation has moved here

Shaders

MeshReflectorMaterial

Documentation has moved here

MeshWobbleMaterial

Documentation has moved here

MeshDistortMaterial

Documentation has moved here

MeshRefractionMaterial

Documentation has moved here

MeshTransmissionMaterial

Documentation has moved here

MeshDiscardMaterial

Documentation has moved here

PointMaterial

Documentation has moved here

SoftShadows

Documentation has moved here

shaderMaterial

Documentation has moved here

Modifiers

CurveModifier

Documentation has moved here

Misc

useContextBridge

Documentation has moved here

Example

Documentation has moved here

Html

Documentation has moved here

CycleRaycast

Documentation has moved here

Select

Documentation has moved here

Sprite Animator

Documentation has moved here

Stats

Documentation has moved here

StatsGl

Documentation has moved here

Wireframe

Documentation has moved here

useDepthBuffer

Documentation has moved here

Fbo / useFBO

Documentation has moved here

useCamera

Documentation has moved here

CubeCamera / useCubeCamera

Documentation has moved here

DetectGPU / useDetectGPU

Documentation has moved here

useAspect

Documentation has moved here

useCursor

Documentation has moved here

useIntersect

Documentation has moved here

useBoxProjectedEnv

Documentation has moved here

Trail / useTrail

Documentation has moved here

useSurfaceSampler

Documentation has moved here

FaceLandmarker

Documentation has moved here

Loading

Loader

Documentation has moved here

Progress / useProgress

Documentation has moved here

Gltf / useGLTF

Documentation has moved here

Fbx / useFBX

Documentation has moved here

Texture / useTexture

Documentation has moved here

Ktx2 / useKTX2

Documentation has moved here

CubeTexture / useCubeTexture

Documentation has moved here

VideoTexture / useVideoTexture

Documentation has moved here

TrailTexture / useTrailTexture

Documentation has moved here

useFont

Documentation has moved here

useSpriteLoader

Documentation has moved here

Performance

Instances

Documentation has moved here

Merged

Documentation has moved here

Points

Documentation has moved here

Segments

Documentation has moved here

Detailed

Documentation has moved here

Preload

Documentation has moved here

BakeShadows

Documentation has moved here

meshBounds

Documentation has moved here

AdaptiveDpr

Documentation has moved here

AdaptiveEvents

Documentation has moved here

Bvh

Documentation has moved here

PerformanceMonitor

Documentation has moved here

Portals

Hud

Documentation has moved here

View

Documentation has moved here

RenderTexture

Documentation has moved here

RenderCubeTexture

Documentation has moved here

Fisheye

Documentation has moved here

Mask

Documentation has moved here

MeshPortalMaterial

Documentation has moved here

Staging

Center

Documentation has moved here

Resize

Documentation has moved here

BBAnchor

Documentation has moved here

Bounds

Documentation has moved here

CameraShake

Documentation has moved here

Float

Documentation has moved here

Stage

Documentation has moved here

Backdrop

Documentation has moved here

Shadow

Documentation has moved here

Caustics

Documentation has moved here

ContactShadows

Documentation has moved here

RandomizedLight

Documentation has moved here

AccumulativeShadows

Documentation has moved here

SpotLight

Documentation has moved here

SpotLightShadow

Documentation has moved here

Environment

Documentation has moved here

Lightformer

Documentation has moved here

Sky

Documentation has moved here

Stars

Documentation has moved here

Sparkles

Documentation has moved here

Cloud

Documentation has moved here

useEnvironment

Documentation has moved here

MatcapTexture / useMatcapTexture

Documentation has moved here

NormalTexture / useNormalTexture

Documentation has moved here

ShadowAlpha

Documentation has moved here

Dev

INSTALL

Pre-requisites:

  • Install nvm, then:
    $ nvm install
    $ nvm use
    $ node -v # make sure your version satisfies package.json#engines.node
    
    nb: if you want this node version to be your default nvm's one: nvm alias default node
  • Install yarn, with:
    $ corepack enable
    $ corepack prepare --activate # it reads "packageManager"
    $ yarn -v # make sure your version satisfies package.json#engines.yarn
    
$ yarn install

Test

Local

Pre-requisites:

  • $ npx playwright install
    

To run visual tests locally:

$ yarn build
$ yarn test

To update a snapshot:

$ PLAYWRIGHT_UPDATE_SNAPSHOTS=1 yarn test

Docker

[!IMPORTANT] Snapshots are system-dependent, so to run playwright in the same environment as the CI:

$ docker run --init --rm \
    -v $(pwd):/app -w /app \
    ghcr.io/pmndrs/playwright:drei \
      sh -c "corepack enable && yarn install && yarn build && yarn test"

To update a snapshot:

$ docker run --init --rm \
    -v $(pwd):/app -w /app \
    -e PLAYWRIGHT_UPDATE_SNAPSHOTS=1 \
    ghcr.io/pmndrs/playwright:drei \
      sh -c "corepack enable && yarn install && yarn build && yarn test"