Agent Skills: React Three Fiber v9 + drei v10

|

UncategorizedID: testacode/llm-toolkit/r3f

Install this agent skill to your local

pnpm dlx add-skill https://github.com/testacode/llm-toolkit/tree/HEAD/skills/r3f

Skill Files

Browse the full folder contents for r3f.

Download Skill

Loading file tree…

skills/r3f/SKILL.md

Skill Metadata

Name
r3f
Description
|

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

  • R3F Docs: https://r3f.docs.pmnd.rs/
  • drei Docs: https://drei.docs.pmnd.rs/
  • drei GitHub: https://github.com/pmndrs/drei
  • R3F GitHub: https://github.com/pmndrs/react-three-fiber
  • three-bvh-csg: https://github.com/gkjohnson/three-bvh-csg
React Three Fiber v9 + drei v10 Skill | Agent Skills