mcpField
T
threejs-impl-drei

threejs-impl-drei

github.com/impertio-studioDevelopment23145 installsUpdated 30w ago
Repository

About threejs-impl-drei

An implementation reference skill for React Three Fiber developers, covering Drei components and hooks for controls, environments, shadows, text, materials, and model loading. It also documents instancing, performance tools, and scene-layout helpers.

Key features

  1. 01Camera controls and scene-staging components
  2. 02Environment, lighting, and shadow tools
  3. 03Text, HTML, and material components
  4. 04Model, texture, and animation loading hooks
  5. 05Instancing and performance helpers

Use cases

  1. 01Build a product viewer or architectural walkthrough
  2. 02Load GLTF models and play animations
  3. 03Add text or a HUD to a 3D scene
  4. 04Optimize rendering of many meshes or complex models

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/impertio-studio/three.js-claude-skill-package --skill threejs-impl-drei

After installing, type/threejs-impl-dreiin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
anti-patterns.md
examples.md
methods.md

Details

From the project README

threejs-impl-drei

Quick Reference

Installation
npm install @react-three/drei @react-three/fiber three
Critical Warnings

ALWAYS wrap components that use loader hooks (useGLTF, useTexture, useFBX, useKTX2, useFont) in <Suspense fallback={...}>. Omitting Suspense causes the entire React tree to crash.

ALWAYS add makeDefault to your primary camera controls (<OrbitControls makeDefault />). Without makeDefault, Drei controls do NOT integrate with R3F's event system and pointer events break.

NEVER use an invalid Environment preset name. The ONLY valid presets are: apartment, city, dawn, forest, lobby, night, park, studio, sunset, warehouse.

NEVER forget to call .preload() for critical assets. Use useGLTF.preload('/model.glb') at module scope to start loading before component mount.

ALWAYS use <Instances> for rendering more than 100 identical meshes. Individual meshes cause one draw call each; instances batch them into one.


Controls

OrbitControls

The most common camera control. Orbit, zoom, and pan around a target.

import { OrbitControls } from '@react-three/drei'

<OrbitControls
  makeDefault           // ALWAYS add — integrates with R3F events
  enableDamping         // smooth movement
  dampingFactor={0.05}
  minDistance={2}
  maxDistance={20}
  minPolarAngle={0}
  maxPolarAngle={Math.PI / 2}  // prevent going below ground
/>
Other Controls
ComponentUse Case
CameraControlsFull-featured camera (recommended for complex scenes)
MapControlsTop-down map navigation (orbit restricted to vertical axis)
PresentationControlsDrag-to-rotate with spring physics (product viewers)
ScrollControlsScroll-driven animation (pages prop sets scroll length)
TransformControlsTranslate/rotate/scale gizmo on selected objects
DragControlsDrag objects in 3D space
KeyboardControlsKeyboard input as React context
FaceControlsFace-tracking camera movement
ScrollControls Pattern
import { ScrollControls, useScroll } from '@react-three/drei'

<ScrollControls pages={3} damping={0.1}>
  <ScrollScene />
</ScrollControls>

function ScrollScene() {
  const scroll = useScroll()
  useFrame(() => {
    const offset = scroll.offset // 0 to 1
  })
  return <mesh />
}

Environment and Staging

Environment

Loads HDR environment maps for realistic reflections and lighting.

import { Environment } from '@react-three/drei'

// Preset (downloads from polyhaven CDN)
<Environment preset="city" background blur={0.5} />

// Custom HDR file
<Environment files="/env.hdr" background />

// Custom environment with Lightformers
<Environment background>
  <Lightformer form="rect" intensity={2} position={[0, 5, -5]} scale={[10, 5, 1]} />
</Environment>

Valid presets: apartment, city, dawn, forest, lobby, night, park, studio, sunset, warehouse.

Stage

Complete lighting and shadow setup in one component. Ideal for product viewers.

import { Stage } from '@react-three/drei'

<Stage preset="rembrandt" intensity={0.5} environment="city" adjustCamera>
  <Model />
</Stage>
Shadow Components
ComponentUse CaseKey Props
ContactShadowsSoft ground shadows (no light needed)opacity, scale, blur, far, resolution, color
AccumulativeShadowsHigh-quality baked soft shadowsframes, alphaTest, scale, opacity
RandomizedLightChild of AccumulativeShadowsamount, radius, intensity, position
BakeShadowsBake shadow maps once, stop updating—
SoftShadowsPCSS soft shadows for real-time lights—
AccumulativeShadows Pattern
<AccumulativeShadows temporal frames={100} scale={10} position={[0, -0.5, 0]}>
  <RandomizedLight amount={8} radius={4} position={[5, 5, -10]} />
</AccumulativeShadows>
Atmosphere
ComponentPurposeKey Props
SkyProcedural sky domesunPosition, turbidity, rayleigh
StarsParticle starfieldradius, count, factor, fade
SparklesFloating particlescount, size, speed, color
CloudVolumetric cloudsopacity, speed, segments, bounds

Text and HTML

Text (SDF)

High-quality 2D text rendered with signed distance fields via troika-three-text.

import { Text } from '@react-three/drei'

<Text
  fontSize={0.5}
  color="white"
  anchorX="center"
  anchorY="middle"
  maxWidth={2}
  font="/fonts/Inter-Bold.woff"
>
  Hello World
</Text>
Text3D

Extruded 3D geometry text. Requires a JSON font file (use facetype.js to convert).

import { Text3D, Center } from '@react-three/drei'

<Center>
  <Text3D font="/fonts/Inter_Bold.json" size={0.75} height={0.2} bevelEnabled bevelSize={0.02}>
    Hello
    <meshStandardMaterial color="orange" />
  </Text3D>
</Center>
Html

Renders DOM elements positioned in 3D space.

import { Html } from '@react-three/drei'

<mesh position={[0, 2, 0]}>
  <Html
    transform            // transforms with 3D position
    distanceFactor={10}  // scales with distance
    occlude              // hides behind 3D objects
    center               // centers the HTML element
    className="label"
  >
    <div style={{ color: 'white' }}>Annotation</div>
  </Html>
</mesh>
Billboard

ALWAYS faces the camera. Use for labels and sprites.

import { Billboard, Text } from '@react-three/drei'

<Billboard follow={true} lockX={false} lockY={false} lockZ={false}>
  <Text fontSize={0.5}>Always Visible</Text>
</Billboard>
Hud

Renders a heads-up display in a separate orthographic scene.

import { Hud, OrthographicCamera } from '@react-three/drei'

<Hud renderPriority={1}>
  <OrthographicCamera makeDefault position={[0, 0, 5]} />
  <Text position={[0, 0, 0]} fontSize={0.1}>HUD Text</Text>
</Hud>

Materials

ComponentPurpose
MeshReflectorMaterialReflective floors with blur, distortion, resolution
MeshTransmissionMaterialGlass with chromatic aberration, distortion, thickness
MeshRefractionMaterialRefraction using environment cube map
MeshWobbleMaterialAnimated wobble on MeshStandardMaterial
MeshDistortMaterialPerlin noise distortion on MeshStandardMaterial
MeshDiscardMaterialRenders nothing (shadow-only objects)
shaderMaterialHelper to create custom ShaderMaterial as JSX
MeshReflectorMaterial Example
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.5, 0]}>
  <planeGeometry args={[50, 50]} />
  <MeshReflectorMaterial
    blur={[300, 100]}
    resolution={1024}
    mixBlur={1}
    mixStrength={50}
    roughness={1}
    depthScale={1.2}
    minDepthThreshold={0.4}
    maxDepthThreshold={1.4}
    color="#151515"
    metalness={0.5}
  />
</mesh>
shaderMaterial Helper
import { shaderMaterial } from '@react-three/drei'
import { extend } from '@react-three/fiber'

const WaveMaterial = shaderMaterial(
  { uTime: 0, uColor: new THREE.Color(0.2, 0.0, 0.1) },
  /* vertex */ `varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }`,
  /* fragment */ `uniform float uTime; uniform vec3 uColor; varying vec2 vUv; void main() { gl_FragColor = vec4(vUv * uColor, 1.0); }`
)
extend({ WaveMaterial })
// Usage: <waveMaterial uTime={clock.elapsedTime} />

Loaders

ALWAYS wrap loader-consuming components in <Suspense>.

HookReturnsPreload
useGLTF(url){ nodes, materials, scene, animations }useGLTF.preload(url)
useTexture(url)THREE.Texture or map objectuseTexture.preload(url)
useFBX(url)THREE.GroupuseFBX.preload(url)
useKTX2(url)Compressed textureuseKTX2.preload(url)
useFont(url)Font data for Text3DuseFont.preload(url)
useAnimations(clips, ref){ actions, names, mixer, ref }—
useVideoTexture(url)THREE.VideoTexture—
useGLTF Pattern
import { useGLTF } from '@react-three/drei'

function Model(props) {
  const { nodes, materials } = useGLTF('/model.glb')
  return (
    <group {...props}>
      <mesh geometry={nodes.Body.geometry} material={materials.Metal} />
    </group>
  )
}
useGLTF.preload('/model.glb')
useTexture with Multiple Maps
const textures = useTexture({
  map: '/color.jpg',
  normalMap: '/normal.jpg',
  roughnessMap: '/roughness.jpg',
  aoMap: '/ao.jpg',
})
// Spread directly onto material
<meshStandardMaterial {...textures} />
useAnimations Pattern
function AnimatedModel() {
  const group = useRef()
  const { nodes, animations } = useGLTF('/character.glb')
  const { actions } = useAnimations(animations, group)

  useEffect(() => {
    actions['Walk']?.play()
    return () => actions['Walk']?.stop()
  }, [actions])

  return <group ref={group}><primitive object={nodes.Scene} /></group>
}

Performance

Instances

ALWAYS use for large numbers of identical meshes (>100). Reduces draw calls from N to 1.

import { Instances, Instance } from '@react-three/drei'

<Instances limit={1000} range={1000}>
  <boxGeometry />
  <meshStandardMaterial />
  {positions.map((pos, i) => (
    <Instance key={i} position={pos} color="orange" />
  ))}
</Instances>
Merged

Merges different geometries into a single draw call.

import { Merged } from '@react-three/drei'

function Furniture({ nodes }) {
  return (
    <Merged meshes={[nodes.Chair, nodes.Table, nodes.Lamp]}>
      {(Chair, Table, Lamp) => (
        <>
          <Chair position={[0, 0, 0]} />
          <Table position={[2, 0, 0]} />
          <Lamp position={[1, 1, 0]} />
        </>
      )}
    </Merged>
  )
}
Performance Helpers
ComponentPurpose
DetailedLOD — switches geometry based on camera distance
BakeShadowsBakes shadows once, stops updating
AdaptiveDprLowers device pixel ratio during performance drops
AdaptiveEventsReduces event frequency during performance drops
PerformanceMonitorMonitors FPS, triggers regression callbacks
BvhBVH-accelerated raycasting for complex meshes
meshBoundsFast bounding-box raycasting (replaces per-triangle)
PerformanceMonitor Pattern
<PerformanceMonitor
  onIncline={() => setDpr(2)}
  onDecline={() => setDpr(1)}
  flipflops={3}
  onFallback={() => setDpr(0.5)}
/>

Staging and Layout

ComponentPurposeKey Props
CenterCenters children at origintop, right, bottom, left, front, back
FloatFloating hover animationspeed, rotationIntensity, floatIntensity
BoundsAuto-fit camera to contentfit, clip, observe, margin
ResizeNormalizes children to unit sizewidth, height, depth

Abstractions and Effects

ComponentPurpose
EdgesRenders wireframe edges
OutlinesScreen-space outlines
TrailMotion trail behind objects
DecalProject texture onto mesh surface
SplatGaussian splatting renderer
CloneDeep clone with shared geometry/materials
ImageTexture-mapped plane with shader effects
MeshPortalMaterialPortal — renders scene inside mesh surface
GradientTextureProcedural gradient texture

Gizmos

ComponentPurpose
GizmoHelperViewport orientation widget
PivotControlsInteractive pivot gizmo (translate/rotate/scale)
TransformControlsThree.js TransformControls wrapper
GridInfinite configurable grid plane
Helper / useHelperVisualize light/camera helpers

Component Selection Guide

ScenarioComponent
Product viewerStage + OrbitControls + Environment
Architectural walkthroughCameraControls + Environment + ContactShadows
Scrolling experienceScrollControls + useScroll
Data visualizationInstances + Html + Billboard
Text labels in 3DText (2D) or Text3D (extruded) + Billboard
Glass/transparent objectsMeshTransmissionMaterial + Environment
Reflective floorsMeshReflectorMaterial
Large identical meshesInstances (>100) or Merged (mixed geometries)
Model loadinguseGLTF + Suspense + .preload()
HUD / overlayHud or Html with fullscreen

Reference Links

Official Sources

Comments

Markdown supported