Stats
Actions
Tags
From example-skills
Build interactive 3D scenes in React using react-three-fiber, drei helpers, animations, reusable components, and performance patterns like instanced meshes.
How this skill is triggered — by the user, by Claude, or both
Slash command
/example-skills:react-three-fiber-patternsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Build 3D scenes declaratively with React using react-three-fiber.
Build 3D scenes declaratively with React using react-three-fiber.
npm install three @react-three/fiber @react-three/drei
npm install -D @types/three
import { Canvas } from '@react-three/fiber'
import { OrbitControls, Environment } from '@react-three/drei'
export function Scene() {
return (
<Canvas camera={{ position: [0, 2, 5], fov: 60 }}>
<ambientLight intensity={0.5} />
<directionalLight position={[10, 10, 5]} intensity={1} />
<mesh position={[0, 1, 0]}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="hotpink" />
</mesh>
<mesh rotation={[-Math.PI / 2, 0, 0]}>
<planeGeometry args={[10, 10]} />
<meshStandardMaterial color="#333" />
</mesh>
<OrbitControls />
<Environment preset="sunset" />
</Canvas>
)
}
import { useRef } from 'react'
import { useFrame } from '@react-three/fiber'
import * as THREE from 'three'
interface SpinningBoxProps {
position: [number, number, number]
color: string
speed?: number
}
export function SpinningBox({ position, color, speed = 1 }: SpinningBoxProps) {
const meshRef = useRef<THREE.Mesh>(null!)
useFrame((state, delta) => {
meshRef.current.rotation.y += delta * speed
meshRef.current.position.y = Math.sin(state.clock.elapsedTime) * 0.5 + 1
})
return (
<mesh ref={meshRef} position={position}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={color} />
</mesh>
)
}
import { useRef, useMemo } from 'react'
import { useFrame } from '@react-three/fiber'
import * as THREE from 'three'
export function ParticleField({ count = 1000 }) {
const meshRef = useRef<THREE.InstancedMesh>(null!)
const dummy = useMemo(() => new THREE.Object3D(), [])
const particles = useMemo(() =>
Array.from({ length: count }, () => ({
position: [
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20,
] as [number, number, number],
speed: 0.5 + Math.random() * 2,
})),
[count]
)
useFrame((state) => {
particles.forEach((p, i) => {
dummy.position.set(...p.position)
dummy.position.y += Math.sin(state.clock.elapsedTime * p.speed) * 0.5
dummy.updateMatrix()
meshRef.current.setMatrixAt(i, dummy.matrix)
})
meshRef.current.instanceMatrix.needsUpdate = true
})
return (
<instancedMesh ref={meshRef} args={[undefined, undefined, count]}>
<sphereGeometry args={[0.05, 8, 8]} />
<meshStandardMaterial color="#88ccff" />
</instancedMesh>
)
}
import { useSpring, animated } from '@react-spring/three'
export function AnimatedBox({ active }: { active: boolean }) {
const springs = useSpring({
scale: active ? 1.5 : 1,
color: active ? '#ff6b6b' : '#4ecdc4',
})
return (
<animated.mesh scale={springs.scale}>
<boxGeometry />
<animated.meshStandardMaterial color={springs.color} />
</animated.mesh>
)
}
import { useRef, useEffect } from 'react'
import gsap from 'gsap'
import * as THREE from 'three'
export function GSAPMesh() {
const meshRef = useRef<THREE.Mesh>(null!)
useEffect(() => {
gsap.to(meshRef.current.rotation, {
y: Math.PI * 2,
duration: 4,
repeat: -1,
ease: 'none',
})
gsap.to(meshRef.current.position, {
y: 2,
duration: 2,
yoyo: true,
repeat: -1,
ease: 'power1.inOut',
})
}, [])
return (
<mesh ref={meshRef}>
<torusKnotGeometry args={[1, 0.3, 128, 32]} />
<meshStandardMaterial color="gold" metalness={0.8} roughness={0.2} />
</mesh>
)
}
import {
Text, Html, Float, MeshDistortMaterial,
useGLTF, useTexture, Sparkles,
} from '@react-three/drei'
// 3D Text
<Text fontSize={0.5} color="white" anchorX="center">
Hello World
</Text>
// HTML overlay in 3D space
<Html position={[0, 2, 0]} center>
<div className="tooltip">Score: 42</div>
</Html>
// Floating animation
<Float speed={2} rotationIntensity={0.5} floatIntensity={1}>
<mesh><sphereGeometry /><meshStandardMaterial /></mesh>
</Float>
// Distortion material
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<MeshDistortMaterial color="#8b5cf6" speed={2} distort={0.3} />
</mesh>
// Particle sparkles
<Sparkles count={200} scale={5} size={2} speed={0.5} />
import { shaderMaterial } from '@react-three/drei'
import { extend, useFrame } from '@react-three/fiber'
import * as THREE from 'three'
const WaveMaterial = shaderMaterial(
{ uTime: 0, uColor: new THREE.Color('#4ecdc4') },
// Vertex shader
`varying vec2 vUv;
uniform float uTime;
void main() {
vUv = uv;
vec3 pos = position;
pos.z += sin(pos.x * 4.0 + uTime) * 0.2;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}`,
// Fragment shader
`varying vec2 vUv;
uniform vec3 uColor;
void main() {
gl_FragColor = vec4(uColor * vUv.y, 1.0);
}`
)
extend({ WaveMaterial })
export function WavePlane() {
const materialRef = useRef<any>(null!)
useFrame((state) => {
materialRef.current.uTime = state.clock.elapsedTime
})
return (
<mesh rotation={[-Math.PI / 2, 0, 0]}>
<planeGeometry args={[10, 10, 64, 64]} />
<waveMaterial ref={materialRef} />
</mesh>
)
}
| Technique | When | Savings |
|---|---|---|
useFrame with delta | Always | Framerate-independent |
InstancedMesh | >100 same geometry | 90%+ draw calls |
useMemo for geometry | Static data | Prevents re-creation |
<Suspense> + useGLTF | Asset loading | Non-blocking |
<Leva> debug controls | Development | Easy parameter tuning |
gl={{ antialias: false }} | Mobile | GPU savings |
npx claudepluginhub a-organvm/a-i--skills --plugin document-skillsProvides a checklist for code reviews covering functionality, security, performance, maintainability, tests, and quality. Use for pull requests, audits, team standards, and developer training.