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.
Use the skills CLI to install this skill with one command. Auto-detects all installed AI assistants.
Method 1 - skills CLI
npx skills i emalorenzo/three-agent-skills/skills/r3f-best-practicesMethod 2 - openskills (supports sync & update)
npx openskills install emalorenzo/three-agent-skillsAuto-detects Claude Code, Cursor, Codex CLI, Gemini CLI, and more. One install, works everywhere.
Installation Path
Download and extract to one of the following locations:
No setup needed. Let our cloud agents run this skill for you.
Select Provider
Select Model
Best for coding tasks
Environment setup included
Comprehensive guide for React Three Fiber and the Poimandres ecosystem. Contains 70+ rules across 12 categories, prioritized by impact.
Additional tips from 100 Three.js Tips by Utsubo
Reference these guidelines when:
| 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- |
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 monitoringframe-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 useFramecomponent-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= on shared resourcescanvas-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 colorsdrei-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 animationloading-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 errorsstate-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 concernevents-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 structurepostpro-effect-composer - Use EffectComposerpostpro-common-effects - Common effects referencepostpro-selective-bloom - SelectiveBloom for optimized glowpostpro-custom-shader - Create custom effectspostpro-performance - Optimize post-processingphysics-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 physicsleva-basic - Basic Leva usageleva-folders - Organize with foldersleva-conditional - Hide in productionRead individual rule files for detailed explanations and code examples:
rules/perf-never-set-state-in-useframe.md
rules/drei-use-gltf.md
rules/state-zustand-selectors.md
For the complete guide with all rules expanded: ../R3F_BEST_PRACTICES.md
// 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
// BAD - Re-renders on ANY store change
const store = useGameStore();
// GOOD - Only re-renders when playerX changes
const playerX = useGameStore(state => state.playerX);
// BETTER - No re-renders, direct mutation
useFrame(() => {
const { value } = useStore.getState();
ref.current.position.x = value;
import { useGLTF } from '@react-three/drei';
function Model() {
const { scene } = useGLTF('/model.glb');
return <primitive object={scene} />;
}
// Preload for instant loading
useGLTF.preload('/model.glb');function App() {
return (
<Canvas>
<Suspense fallback={<Loader />}>
<Model />
</Suspense>
</Canvas>
);
}import { Perf } from 'r3f-perf';
function App() {
return (
<Canvas>
<Perf position="top-left" />
<Scene />
</Canvas>
);
}// BAD: Remounting destroys and recreates
{showModel && <Model />}
// GOOD: Toggle visibility, keeps instance alive
<Model visible={showModel} />| 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- |