r3f-fundamentals
enzed/r3f-skills
Set up React Three Fiber scenes, Canvas, typed JSX, hooks, and resource ownership.
What is r3f-fundamentals?
React Three Fiber fundamentals covers scene architecture and render-loop setup for 3D web applications. Use this skill to establish Canvas components, manage typed JSX elements, implement animation hooks, and handle resource lifecycle—not for detailed materials or effects.
- Create minimal Canvas scenes with typed JSX and Three.js objects
- Implement per-frame animation using useFrame with delta time
- Manage component boundaries between Canvas and DOM UI
- Handle resource ownership and disposal for geometries and materials
- Configure render-loop behavior with frameloop modes and priorities
- Set up camera, lighting, and basic scene hierarchy
How to install r3f-fundamentals
npx skills add https://github.com/enzed/r3f-skills --skill r3f-fundamentals- React 19 and React Three Fiber 9 (or React 18 with Fiber 8)
- Three.js and Drei installed and matching your project versions
- A parent container with nonzero height for the Canvas component
How to use r3f-fundamentals
- 1.Inspect your project's package.json and lockfile to confirm Fiber and React versions
- 2.Create a Canvas component as the root of your 3D scene, setting camera and DPR props
- 3.Define scene components beneath Canvas using typed JSX (ThreeElements['mesh'], etc.) and useRef<Mesh>(null)
- 4.Implement per-frame updates with useFrame, mutating refs for animation and using delta in seconds
- 5.Use explicit attach props for non-child properties like buffer attributes
- 6.Configure frameloop ('always' or 'demand') and render priorities based on your animation needs
- 7.Test by rendering in a browser, checking the console, resizing, and unmounting/remounting components
Use cases
- Building the foundational structure for a 3D scene in a React application
- Setting up typed component props and refs for Three.js objects in Fiber 9
- Implementing continuous or on-demand rendering strategies for performance
- Managing animation state with refs and React state appropriately
- Configuring Canvas with proper DPR, tone mapping, and shadow settings
- React developers building 3D web experiences with Three.js
- Frontend engineers setting up scene architecture in React Three Fiber projects
- Developers migrating to Fiber 9 or React 19 and needing type-safe patterns
- Teams establishing render-loop and resource-management conventions
r3f-fundamentals FAQ
Use 'demand' for scenes that can rest between interactions. Animations must keep invalidating until settled, and imperative changes need invalidate() calls. 'always' is better for continuous animation.
R3F disposes declaratively owned objects when unmounted. Use <primitive object={...}> only for external resources you manage yourself. Cached assets and shared resources need an explicit owner; do not dispose them while another consumer uses them.
Use React state for discrete UI changes. For per-frame motion, mutate owned refs directly inside useFrame—it's more efficient and avoids re-renders. Reuse scratch vectors and use delta in seconds.
useFrame, useThree, and loader hooks must be called only in components beneath Canvas, never in the component creating Canvas or inside event callbacks. This ensures they run in the correct Three.js context.
Use ThreeElements['mesh'] for mesh props and useRef<Mesh>(null) for refs. Fiber 9 uses ThreeElement<typeof Class> for custom elements; avoid the removed Object3DNode or global JSX augmentation patterns.
Full instructions (SKILL.md)
Source of truth, from enzed/r3f-skills.
name: r3f-fundamentals description: Set up React Three Fiber scenes, Canvas, typed JSX, hooks, and resource ownership. Use for scene architecture and render-loop setup, rather than detailed materials or effects.
React Three Fiber fundamentals
Choose the right baseline
- Inspect the project's manifest and lockfile before selecting APIs. These examples target Fiber 9 / React 19; Fiber 8 pairs with React 18. Do not upgrade a project just to match a recipe.
- Check installed Three.js and Drei versions too. Use released documentation matching those versions; if unavailable, state the uncertainty instead of inventing props.
- Keep the existing renderer unless the task calls for changing it. For WebGPU, read renderer selection; Fiber 10 alpha APIs are not Fiber 9 APIs.
Minimal scene
This example owns its Canvas. Its parent must have a nonzero height.
import { useRef } from 'react'
import { Canvas, useFrame, type ThreeElements } from '@react-three/fiber'
import type { Mesh } from 'three'
function RotatingBox(props: ThreeElements['mesh']) {
const mesh = useRef<Mesh>(null)
useFrame((_, delta) => {
if (mesh.current) mesh.current.rotation.y += delta * 0.5
})
return (
<mesh {...props} ref={mesh}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="coral" />
</mesh>
)
}
export default function Example() {
return (
<Canvas camera={{ position: [0, 0, 5] }} dpr={[1, 2]}>
<ambientLight intensity={0.5} />
<directionalLight position={[3, 4, 5]} intensity={2} />
<RotatingBox />
</Canvas>
)
}
Scene and type boundaries
- Call
useThree,useFrame, and loader hooks in components beneath Canvas, never in the component creating that Canvas or inside an event callback. - Canvas children are Three.js objects. Place DOM UI outside it or use Drei
Html. A Suspense fallback inside Canvas must obey the same rule. - Use
ThreeElements['mesh']for mesh props anduseRef<Mesh>(null)for refs. Fiber 9 usesThreeElement<typeof Class>for custom elements; do not use removedObject3DNodeor globalJSX.IntrinsicElementsaugmentation. extend(Class)creates a locally typed component in Fiber 9. Useextend({ Class })plus module augmentation of@react-three/fiberwhen a shared lowercase JSX element is actually needed.argsare constructor arguments: changing them reconstructs the object. Update ordinary props or refs for animation; retain expensive shapes, arrays, and materials when their inputs have not changed.- Geometry/material children attach automatically. Use explicit
attachfor other properties, e.g.attach="attributes-position"for a buffer attribute. - Three.js uses radians and local transforms. Convert world-space input into the object's parent space before assigning it to
position.
Render-loop decisions
- Use React state for discrete UI changes; mutate owned refs for per-frame motion. Reuse scratch vectors and use
deltain seconds. Do not create a second animation loop for the same scene. useThree(state => state.camera)subscribes to camera replacement, not mutations ofcamera.position. Read transient values insideuseFrame; update the projection matrix after imperative camera projection changes.- Default
frameloop="always"fits continuous animation. Use"demand"for scenes that can rest: imperative changes needinvalidate(), and animations must keep invalidating until settled. Drei controls handle their own invalidation. - Negative frame priorities order updates without taking over rendering. A positive priority disables automatic rendering: its owner must render, and must coordinate with any composer. Callbacks run in ascending priority order.
- Do not reset transforms in JSX and animate the same values from another owner. Visibility changes do not automatically stop callbacks or release GPU resources.
Renderer and ownership pitfalls
- Default WebGL Canvas uses sRGB output and ACES filmic tone mapping.
flatselectsNoToneMapping;linearchanges output color space. Neither is a generic fix for washed-out assets. - On Three.js r182+, use
shadows="percentage"for PCF shadows. Bareshadowsin Fiber 9 selects deprecatedPCFSoftShadowMapon this baseline. - Start with defaults; add
preserveDrawingBuffer, larger DPR, or extra render passes only for an actual requirement and measure their cost. - R3F disposes declaratively owned objects when unmounted.
<primitive object={...}>does not dispose the supplied object. Cached loader assets and shared resources need an explicit owner; do not dispose them while another consumer uses them. dispose={null}opts a subtree out of automatic disposal; it is not a general performance switch. Manually allocated resources outside R3F's ownership need cleanup.- Effects, subscriptions, and imperative registrations must survive Strict Mode setup/cleanup. Profile before adding memoization; ordinary React renders do not inherently restart
useFrameanimation.
Verify
Type-check, render in a browser, check the console, resize, and unmount/remount. For demand rendering, verify both waking and returning to idle.
Sources
- Fiber 9 migration — version-sensitive types and renderer setup.
- Canvas, objects and disposal, hooks.
- Performance pitfalls, on-demand rendering.
Related skills
More from enzed/r3f-skills and the wider catalog.

r3f-geometry
Build React Three Fiber geometry, buffers, instanced meshes, and lines for shape construction and draw-call optimization.

r3f-interaction
Implement pointer events, picking, dragging, keyboard input, and camera controls in React Three Fiber scenes.

r3f-lighting
Light React Three Fiber scenes with direct lights, environment maps, and shadows.

r3f-loaders
Load and reuse 3D assets in React Three Fiber with caching, cloning, and error handling.

r3f-materials
Choose and configure React Three Fiber surface materials, PBR, transparency, and transmission.

r3f-physics
Add Rapier physics simulation to React Three Fiber with rigid bodies, colliders, forces, and joints.