r3f

Installation
SKILL.md

React Three Fiber v9 + drei v10

Escenas 3D declarativas en React. Complementa la skill threejs (vanilla Three.js imperativo).

Modelo Mental

React y Three.js manejan dominios distintos que se comunican via refs:

  • React es dueño del scene graph: monta, desmonta, reconcilia componentes JSX → objetos Three.js
  • Three.js es dueño del render loop: useFrame corre cada frame, muta refs directamente
  • Regla de oro: React para estado y estructura, refs para mutaciones per-frame
React tree (JSX, state, props)
      ↕ refs / props
useFrame callbacks (per-frame mutations)
      ↕ escribe en Three.js objects
WebGLRenderer (render en priority 0)

Cuando Usar Esta Skill vs threejs

Escenario Skill
Proyecto React + JSX para 3D r3f (esta)
Vanilla Three.js imperativo threejs
Conceptos de materiales, luces, shadows threejs (aplican igual)
Hooks: useFrame, useThree, useLoader r3f
drei helpers: controls, staging, text r3f
CSG con @react-three/csg r3f

Quick Start

import { Canvas } from '@react-three/fiber'
import { OrbitControls, Environment } from '@react-three/drei'

function Box() {
  return (
    <mesh castShadow>
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color="orange" roughness={0.4} />
    </mesh>
  )
}

export function Scene() {
  return (
    <Canvas shadows camera={{ position: [3, 3, 3], fov: 50 }}>
      <ambientLight intensity={0.4} />
      <directionalLight position={[5, 5, 5]} castShadow />
      <Box />
      <OrbitControls makeDefault />
      <Environment preset="studio" />
    </Canvas>
  )
}

Learning Path

Nivel 1: Core R3F

  • Canvas y Hooks: references/01-canvas-hooks.md — Canvas props, useThree, useFrame, useLoader, useGraph
  • JSX y Eventos: references/02-jsx-system.md — mapeo JSX→Three.js, args, attach, extend, primitive, eventos

Nivel 2: drei Ecosystem

  • Controls: references/03-drei-controls.md — OrbitControls, CameraControls, PivotControls, TransformControls, Keyboard/Scroll
  • Staging: references/04-drei-staging.md — Environment, shadows, Sky, materiales especiales
  • Abstractions: references/05-drei-abstractions.md — Text, Html, Billboard, Image, Clone, loaders, animaciones

Nivel 3: Performance y Patrones

  • Performance: references/06-drei-performance.md — Bvh, Instances, LOD, PerformanceMonitor, dispose, FBO
  • Zustand Bridge: references/07-zustand-integration.md — getState() en useFrame, invalidate(), demand rendering

Nivel 4: Especializado

  • CSG Operations: references/08-csg-operations.md — @react-three/csg, three-bvh-csg, boolean geometry
  • TypeScript v9: references/09-typescript-v9.md — ThreeElements, ThreeElement, module augmentation, migracion
  • Patterns y Gotchas: references/10-patterns-gotchas.md — anti-patterns, disposal, Suspense, portals

10 Core Rules

  1. Nunca setState en useFrame — causa re-render a 60fps. Usar refs o useStore.getState()
  2. useThree con selectoruseThree(s => s.camera), no useThree() desnudo (re-render en cada cambio de state)
  3. extend() obligatorio para custom objects — v9 no auto-descubre. extend({ MyClass }) antes del JSX
  4. Suspense boundary alrededor de loadersuseGLTF, useTexture, useLoader suspenden el componente
  5. frameloop="demand" para escenas estaticasinvalidate() desde useThree o store para triggerear frames
  6. args como constanteargs={[1,1,1]} inline recrea cada render. Hoistear o useMemo
  7. dispose={null} para recursos compartidos — R3F auto-dispone en unmount; prevenir con dispose={null}
  8. makeDefault en controls — registra en state.controls para que drei components lo accedan
  9. primitive no clona<primitive object={obj}/> usa la misma referencia. Usar <Clone> de drei para reusar
  10. Eventos solo en meshes con geometryonClick en <group> sin geometry no dispara

Anti-Patterns

Anti-pattern Problema Fix
setState(x) en useFrame Re-renders 60fps Refs o Zustand getState()
useThree() sin selector Re-render en cualquier cambio useThree(s => s.camera)
new THREE.Vector3() en render GC pressure per-frame Hoistear o useMemo
args={[w,h,d]} inline Reconstruye geometry cada render useMemo(() => [w,h,d], [w,h,d])
1000 <mesh> individuales Reconciliacion lenta <Instances> de drei
useEffect para animar Fuera del render loop useFrame con refs

Checklist Pre-Deploy

[ ] frameloop="demand" si la escena no se anima constantemente
[ ] <Suspense> alrededor de componentes con loaders
[ ] dispose={null} en <primitive> de recursos compartidos
[ ] <Bvh> wrapper si hay muchos meshes clickeables
[ ] dpr={[1, 2]} en Canvas para DPR adaptativo
[ ] OrbitControls con makeDefault
[ ] Sin setState en ningun useFrame
[ ] gl={{ preserveDrawingBuffer: true }} solo si necesitas screenshots

Resources

Related skills

More from testacode/llm-toolkit

Installs
3
First Seen
Mar 30, 2026