
R3f Best Practices
Apply React Three Fiber performance and pattern rules so 3D scenes stay smooth and do not tank React re-renders.
Overview
r3f-best-practices is an agent skill for the Build phase that enforces React Three Fiber performance, Canvas setup, Drei usage, and interaction patterns across prioritized rule sections.
Install
npx skills add https://github.com/emalorenzo/three-agent-skills --skill r3f-best-practicesWhat is this skill?
- 8 priority rule sections from Performance & Re-renders through Events & Interaction
- Critical perf gates: never setState in useFrame, isolate state, Zustand selectors, transient subscriptions
- useFrame guidance: priorities, delta time, render-on-demand, avoid heavy work per frame
- Canvas setup rules: container sizing, gl config, frameloop, shadows, linear/flat color
- Drei patterns: useGLTF, Environment, Instances, Bounds, Center, Float, and loading with Suspense
- 8 priority rule sections in the skill outline
- Critical Priority 1–2 sections cover performance and useFrame
- Named rule groups include perf-r3f-perf and loading-suspense
Adoption & trust: 605 installs on skills.sh; 26 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your R3F scene works in a demo but re-renders, useFrame misuse, and missing disposal make it slow or leaky in production.
Who is it for?
Solo front-end builders adding 3D heroes, configurators, or interactive WebGL to React apps who want opinionated R3F guardrails.
Skip if: Projects with no Three.js stack, pure 2D React UIs, or teams that only need Blender asset pipeline docs without in-app R3F code.
When should I use this skill?
You are writing or reviewing React Three Fiber components, Canvas, Drei helpers, or scene state and need prioritized anti-jank rules applied.
What do I get? / Deliverables
Your agent refactors the scene toward isolated state, correct useFrame habits, and documented R3F/Drei patterns aligned with the eight priority sections.
- Refactored R3F components following named rules
- Documented fixes for perf, useFrame, and loading patterns
Recommended Skills
Journey fit
Build → frontend is the canonical shelf because every rule governs R3F components, Canvas setup, and in-scene interaction code. The skill is explicitly about JSX/R3F component patterns, useFrame loops, and Drei helpers—not backend APIs or ship-time QA automation.
How it compares
Use this rule pack while authoring components—not generic React lint rules or a one-off Three.js tutorial that ignores Fiber’s render loop.
Common Questions / FAQ
Who is r3f-best-practices for?
Indie developers and small teams building React Three Fiber experiences who want an agent to apply prioritized performance and component rules during coding.
When should I use r3f-best-practices?
During Build frontend work when creating or reviewing Meshes, Canvas, useFrame animations, Drei loaders, and Zustand-driven scene state.
Is r3f-best-practices safe to install?
Check the Security Audits panel on this Prism page for published audit data; the skill is procedural guidance and does not by itself require shell or network access.
SKILL.md
READMESKILL.md - R3f Best Practices
# Rule Sections ## Priority 1: Performance & Re-renders (CRITICAL) - perf-never-set-state-in-useframe - perf-isolate-state - perf-zustand-selectors - perf-transient-subscriptions - perf-memo-components - perf-keys-for-lists - perf-avoid-inline-objects - perf-dispose-auto - perf-visibility-toggle - perf-r3f-perf ## Priority 2: useFrame & Animation (CRITICAL) - frame-priority - frame-delta-time - frame-conditional-subscription - frame-destructure-state - frame-render-on-demand - frame-avoid-heavy-computation ## Priority 3: Component Patterns (HIGH) - component-jsx-elements - component-attach-prop - component-primitive - component-extend - component-forwardref - component-dispose-null ## Priority 4: Canvas & Setup (HIGH) - canvas-size-container - canvas-camera-default - canvas-gl-config - canvas-shadows - canvas-frameloop - canvas-events - canvas-linear-flat ## Priority 5: Drei Helpers (MEDIUM-HIGH) - drei-use-gltf - drei-use-texture - drei-environment - drei-orbit-controls - drei-html - drei-text - drei-instances - drei-use-helper - drei-bounds - drei-center - drei-float ## Priority 6: Loading & Suspense (MEDIUM-HIGH) - loading-suspense - loading-preload - loading-use-progress - loading-lazy-components - loading-error-boundary ## Priority 7: State Management (MEDIUM) - state-zustand-store - state-avoid-objects-in-store - state-subscribeWithSelector - state-persist - state-separate-concerns ## Priority 8: Events & Interaction (MEDIUM) - events-pointer-events - events-stop-propagation - events-cursor-pointer - events-raycast-filter - events-event-data ## Priority 9: Post-processing (MEDIUM) - postpro-effect-composer - postpro-common-effects - postpro-selective-bloom - postpro-custom-shader - postpro-performance ## Priority 10: Physics Rapier (LOW-MEDIUM) - physics-setup - physics-body-types - physics-colliders - physics-events - physics-api-ref - physics-performance ## Priority 11: Leva Debug GUI (LOW) - leva-basic - leva-folders - leva-conditional # drei-use-gltf **Use useGLTF for model loading with preloading.** ## Why It Matters `useGLTF` from Drei provides: - Suspense integration (automatic loading states) - Caching (same model loaded once) - Preloading capability - Draco decompression support ## Basic Example ```jsx import { useGLTF } from '@react-three/drei'; function Model() { const { scene, nodes, materials } = useGLTF('/model.glb'); return <primitive object={scene} />; } ``` ## Preloading (Critical for UX) ```jsx import { useGLTF } from '@react-three/drei'; function Model() { const { scene } = useGLTF('/model.glb'); return <primitive object={scene} />; } // Preload at module level - starts loading immediately useGLTF.preload('/model.glb'); // Or preload multiple models useGLTF.preload(['/model1.glb', '/model2.glb', '/model3.glb']); ``` ## With Draco Compression ```jsx function DracoModel() { // Second argument is the Draco decoder path const { scene } = useGLTF('/model.glb', '/draco/'); return <primitive object={scene} />; } useGLTF.preload('/model.glb', '/draco/'); ``` ## Accessing Nodes and Materials ```jsx function Character() { const { nodes, materials } = useGLTF('/character.glb'); return ( <group> <mesh geometry={nodes.Body.geometry} material={materials.Skin} /> <mesh geometry={nodes.Clothes.geometry} material={materials.Fabric} /> </group> ); } ``` ## Clone for Multiple Instances ```jsx function Tree({ position }) { const { scene } = useGLTF('/tree.glb'); // Clone to avoid sharing state between instances return <primitive object={scene.clone()} position={position} />; } function Forest() { return ( <> <Tree position={[0, 0, 0]} /> <Tree position={[5, 0, 0]} /> <Tree position={[10, 0, 0]} /> </> ); } ``` ## With Suspense ```jsx import { Suspense } from 'react'; import { useGLTF } from '@react-three/drei'; function Model() { const { scene } = useGLTF('/model.gl