<< All versions
Skill v1.0.1
currentAutomated scan100/100emalorenzo/three-agent-skills/r3f-best-practices
4 files
──Details
PublishedMay 15, 2026 at 03:06 AM
Content Hashsha256:07ef389848b071e0...
Git SHAf950f95ae3b1
Bump Typepatch
──Files
Files (1 file, 7.9 KB)
SKILL.md7.9 KBactive
SKILL.md · 263 lines · 7.9 KB
version: "1.0.1" name: r3f-best-practices description: React 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. license: MIT metadata: author: three-agent-skills version: "1.1.0"
React Three Fiber Best Practices
Comprehensive guide for React Three Fiber and the Poimandres ecosystem. Contains 70+ rules across 12 categories, prioritized by impact.
Sources & Credits
Additional tips from 100 Three.js Tips by Utsubo
When to Apply
Reference these guidelines when:
- Writing new R3F components
- Optimizing R3F performance (re-renders are the #1 issue)
- Using Drei helpers correctly
- Managing state with Zustand
- Implementing post-processing or physics
Ecosystem Coverage
- @react-three/fiber - React renderer for Three.js
- @react-three/drei - Useful helpers and abstractions
- @react-three/postprocessing - Post-processing effects
- @react-three/rapier - Physics engine
- zustand - State management
- leva - Debug GUI
Rule Categories by Priority
| Priority | Category | Impact | Prefix | |
|---|---|---|---|---|
| 1 | Performance & Re-renders | CRITICAL | perf- | |
| 2 | useFrame & Animation | CRITICAL | frame- | |
| 3 | Component Patterns | HIGH | component- | |
| 4 | Canvas & Setup | HIGH | canvas- | |
| 5 | Drei Helpers | MEDIUM-HIGH | drei- | |
| 6 | Loading & Suspense | MEDIUM-HIGH | loading- | |
| 7 | State Management | MEDIUM | state- | |
| 8 | Events & Interaction | MEDIUM | events- | |
| 9 | Post-processing | MEDIUM | postpro- | |
| 10 | Physics (Rapier) | LOW-MEDIUM | physics- | |
| 11 | Leva (Debug GUI) | LOW | leva- |
Quick Reference
1. Performance & Re-renders (CRITICAL)
perf-never-set-state-in-useframe- NEVER call setState in useFrameperf-isolate-state- Isolate components that need React stateperf-zustand-selectors- Use Zustand selectors, not entire storeperf-transient-subscriptions- Use transient subscriptions for continuous valuesperf-memo-components- Memoize expensive componentsperf-keys-for-lists- Use stable keys for dynamic listsperf-avoid-inline-objects- Avoid creating objects/arrays in JSXperf-dispose-auto- Understand R3F auto-dispose behaviorperf-visibility-toggle- Toggle visibility instead of remountingperf-r3f-perf- Use r3f-perf for performance monitoring
2. useFrame & Animation (CRITICAL)
frame-priority- Use priority for execution orderframe-delta-time- Always use delta for animationsframe-conditional-subscription- Disable useFrame when not neededframe-destructure-state- Destructure only what you needframe-render-on-demand- Use invalidate() for on-demand renderingframe-avoid-heavy-computation- Move heavy work outside useFrame
3. Component Patterns (HIGH)
component-jsx-elements- Use JSX for Three.js objectscomponent-attach-prop- Use attach for non-standard propertiescomponent-primitive- Use primitive for existing objectscomponent-extend- Use extend() for custom classescomponent-forwardref- Use forwardRef for reusable componentscomponent-dispose-null- Set dispose={null} on shared resources
4. Canvas & Setup (HIGH)
canvas-size-container- Canvas fills parent containercanvas-camera-default- Configure camera via propcanvas-gl-config- Configure WebGL contextcanvas-shadows- Enable shadows at Canvas levelcanvas-frameloop- Choose appropriate frameloop modecanvas-events- Configure event handlingcanvas-linear-flat- Use linear/flat for correct colors
5. Drei Helpers (MEDIUM-HIGH)
drei-use-gltf- useGLTF with preloadingdrei-use-texture- useTexture for texture loadingdrei-environment- Environment for realistic lightingdrei-orbit-controls- OrbitControls from Dreidrei-html- Html for DOM overlaysdrei-text- Text for 3D textdrei-instances- Instances for optimized instancingdrei-use-helper- useHelper for debug visualizationdrei-bounds- Bounds to fit cameradrei-center- Center to center objectsdrei-float- Float for floating animation
6. Loading & Suspense (MEDIUM-HIGH)
loading-suspense- Wrap async components in Suspenseloading-preload- Preload assets with useGLTF.preloadloading-use-progress- useProgress for loading UIloading-lazy-components- Lazy load heavy componentsloading-error-boundary- Handle loading errors
7. State Management (MEDIUM)
state-zustand-store- Create focused Zustand storesstate-avoid-objects-in-store- Be careful with Three.js objectsstate-subscribeWithSelector- Fine-grained subscriptionsstate-persist- Persist state when neededstate-separate-concerns- Separate stores by concern
8. Events & Interaction (MEDIUM)
events-pointer-events- Use pointer events on meshesevents-stop-propagation- Prevent event bubblingevents-cursor-pointer- Change cursor on hoverevents-raycast-filter- Filter raycastingevents-event-data- Understand event data structure
9. Post-processing (MEDIUM)
postpro-effect-composer- Use EffectComposerpostpro-common-effects- Common effects referencepostpro-selective-bloom- SelectiveBloom for optimized glowpostpro-custom-shader- Create custom effectspostpro-performance- Optimize post-processing
10. Physics Rapier (LOW-MEDIUM)
physics-setup- Basic Rapier setupphysics-body-types- dynamic, fixed, kinematicphysics-colliders- Choose appropriate collidersphysics-events- Handle collision eventsphysics-api-ref- Use ref for physics APIphysics-performance- Optimize physics
11. Leva (LOW)
leva-basic- Basic Leva usageleva-folders- Organize with foldersleva-conditional- Hide in production
How to Use
Read individual rule files for detailed explanations and code examples:
rules/perf-never-set-state-in-useframe.mdrules/drei-use-gltf.mdrules/state-zustand-selectors.md
Full Compiled Document
For the complete guide with all rules expanded: ../R3F_BEST_PRACTICES.md
Critical Patterns
NEVER setState in useFrame
jsx
// BAD - 60 re-renders per second!function BadComponent() {const [position, setPosition] = useState(0);useFrame(() => {setPosition(p => p + 0.01); // NEVER DO THIS});return <mesh position-x={position} />;}// GOOD - Mutate refs directlyfunction GoodComponent() {const meshRef = useRef();useFrame(() => {meshRef.current.position.x += 0.01;});return <mesh ref={meshRef} />;}
Zustand Selectors
jsx
// BAD - Re-renders on ANY store changeconst store = useGameStore();// GOOD - Only re-renders when playerX changesconst playerX = useGameStore(state => state.playerX);// BETTER - No re-renders, direct mutationuseFrame(() => {const { value } = useStore.getState();ref.current.position.x = value;});
Drei useGLTF
jsx
import { useGLTF } from '@react-three/drei';function Model() {const { scene } = useGLTF('/model.glb');return <primitive object={scene} />;}// Preload for instant loadinguseGLTF.preload('/model.glb');
Suspense Loading
jsx
function App() {return (<Canvas><Suspense fallback={<Loader />}><Model /></Suspense></Canvas>);}
r3f-perf Monitoring
jsx
import { Perf } from 'r3f-perf';function App() {return (<Canvas><Perf position="top-left" /><Scene /></Canvas>);}
Toggle Visibility (Not Remounting)
jsx
// BAD: Remounting destroys and recreates{showModel && <Model />}// GOOD: Toggle visibility, keeps instance alive<Model visible={showModel} />