$npx -y skills add emalorenzo/three-agent-skills --skill r3f-best-practicesReact Three Fiber (R3F) and Poimandres ecosystem best practices. Use when writing, reviewing, or optimizing R3F code. Triggers on tasks involving @react-three/fiber, @react-three/drei, zustand, @react-three/postprocessing, @react-three/rapier, or leva.
| 1 | # React Three Fiber Best Practices |
| 2 | |
| 3 | Comprehensive guide for React Three Fiber and the Poimandres ecosystem. Contains 70+ rules across 12 categories, prioritized by impact. |
| 4 | |
| 5 | ## Sources & Credits |
| 6 | |
| 7 | > Additional tips from [100 Three.js Tips](https://www.utsubo.com/blog/threejs-best-practices-100-tips) by [Utsubo](https://www.utsubo.com) |
| 8 | |
| 9 | ## When to Apply |
| 10 | |
| 11 | Reference these guidelines when: |
| 12 | - Writing new R3F components |
| 13 | - Optimizing R3F performance (re-renders are the #1 issue) |
| 14 | - Using Drei helpers correctly |
| 15 | - Managing state with Zustand |
| 16 | - Implementing post-processing or physics |
| 17 | |
| 18 | ## Ecosystem Coverage |
| 19 | |
| 20 | - **@react-three/fiber** - React renderer for Three.js |
| 21 | - **@react-three/drei** - Useful helpers and abstractions |
| 22 | - **@react-three/postprocessing** - Post-processing effects |
| 23 | - **@react-three/rapier** - Physics engine |
| 24 | - **zustand** - State management |
| 25 | - **leva** - Debug GUI |
| 26 | |
| 27 | ## Rule Categories by Priority |
| 28 | |
| 29 | | Priority | Category | Impact | Prefix | |
| 30 | |----------|----------|--------|--------| |
| 31 | | 1 | Performance & Re-renders | CRITICAL | `perf-` | |
| 32 | | 2 | useFrame & Animation | CRITICAL | `frame-` | |
| 33 | | 3 | Component Patterns | HIGH | `component-` | |
| 34 | | 4 | Canvas & Setup | HIGH | `canvas-` | |
| 35 | | 5 | Drei Helpers | MEDIUM-HIGH | `drei-` | |
| 36 | | 6 | Loading & Suspense | MEDIUM-HIGH | `loading-` | |
| 37 | | 7 | State Management | MEDIUM | `state-` | |
| 38 | | 8 | Events & Interaction | MEDIUM | `events-` | |
| 39 | | 9 | Post-processing | MEDIUM | `postpro-` | |
| 40 | | 10 | Physics (Rapier) | LOW-MEDIUM | `physics-` | |
| 41 | | 11 | Leva (Debug GUI) | LOW | `leva-` | |
| 42 | |
| 43 | ## Quick Reference |
| 44 | |
| 45 | ### 1. Performance & Re-renders (CRITICAL) |
| 46 | |
| 47 | - `perf-never-set-state-in-useframe` - NEVER call setState in useFrame |
| 48 | - `perf-isolate-state` - Isolate components that need React state |
| 49 | - `perf-zustand-selectors` - Use Zustand selectors, not entire store |
| 50 | - `perf-transient-subscriptions` - Use transient subscriptions for continuous values |
| 51 | - `perf-memo-components` - Memoize expensive components |
| 52 | - `perf-keys-for-lists` - Use stable keys for dynamic lists |
| 53 | - `perf-avoid-inline-objects` - Avoid creating objects/arrays in JSX |
| 54 | - `perf-dispose-auto` - Understand R3F auto-dispose behavior |
| 55 | - `perf-visibility-toggle` - Toggle visibility instead of remounting |
| 56 | - `perf-r3f-perf` - Use r3f-perf for performance monitoring |
| 57 | |
| 58 | ### 2. useFrame & Animation (CRITICAL) |
| 59 | |
| 60 | - `frame-priority` - Use priority for execution order |
| 61 | - `frame-delta-time` - Always use delta for animations |
| 62 | - `frame-conditional-subscription` - Disable useFrame when not needed |
| 63 | - `frame-destructure-state` - Destructure only what you need |
| 64 | - `frame-render-on-demand` - Use invalidate() for on-demand rendering |
| 65 | - `frame-avoid-heavy-computation` - Move heavy work outside useFrame |
| 66 | |
| 67 | ### 3. Component Patterns (HIGH) |
| 68 | |
| 69 | - `component-jsx-elements` - Use JSX for Three.js objects |
| 70 | - `component-attach-prop` - Use attach for non-standard properties |
| 71 | - `component-primitive` - Use primitive for existing objects |
| 72 | - `component-extend` - Use extend() for custom classes |
| 73 | - `component-forwardref` - Use forwardRef for reusable components |
| 74 | - `component-dispose-null` - Set dispose={null} on shared resources |
| 75 | |
| 76 | ### 4. Canvas & Setup (HIGH) |
| 77 | |
| 78 | - `canvas-size-container` - Canvas fills parent container |
| 79 | - `canvas-camera-default` - Configure camera via prop |
| 80 | - `canvas-gl-config` - Configure WebGL context |
| 81 | - `canvas-shadows` - Enable shadows at Canvas level |
| 82 | - `canvas-frameloop` - Choose appropriate frameloop mode |
| 83 | - `canvas-events` - Configure event handling |
| 84 | - `canvas-linear-flat` - Use linear/flat for correct colors |
| 85 | |
| 86 | ### 5. Drei Helpers (MEDIUM-HIGH) |
| 87 | |
| 88 | - `drei-use-gltf` - useGLTF with preloading |
| 89 | - `drei-use-texture` - useTexture for texture loading |
| 90 | - `drei-environment` - Environment for realistic lighting |
| 91 | - `drei-orbit-controls` - OrbitControls from Drei |
| 92 | - `drei-html` - Html for DOM overlays |
| 93 | - `drei-text` - Text for 3D text |
| 94 | - `drei-instances` - Instances for optimized instancing |
| 95 | - `drei-use-helper` - useHelper for debug visualization |
| 96 | - `drei-bounds` - Bounds to fit camera |
| 97 | - `drei-center` - Center to center objects |
| 98 | - `drei-float` - Float for floating animation |
| 99 | |
| 100 | ### 6. Loading & Suspense (MEDIUM-HIGH) |
| 101 | |
| 102 | - `loading-suspense` - Wrap async components in Suspense |
| 103 | - `loading-preload` - Preload assets with useGLTF.preload |
| 104 | - `loading-use-progress` - useProgress for loading UI |
| 105 | - `loading-lazy-components` - Lazy load heavy components |
| 106 | - `loading-error-boundary` - Handle loading errors |
| 107 | |
| 108 | ### 7. State Management (MEDIUM) |
| 109 | |
| 110 | - `state-zustand-store` - Create focused Zustand stores |
| 111 | - `state-avoid-objects-in-store` - Be careful with Three.js objects |
| 112 | - `state-subscribeWithSelector` - Fine-grained subscriptions |
| 113 | - `state-persist` - Persist state when needed |
| 114 | - `st |