r3f-animation
React Three Fiber animation - useFrame, useAnimations, spring physics, keyframes
Install / Use
npx skills add zebbern/claude-code-guide --skill r3f-animationInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
DesignSupported Platforms
Our assessment of r3f-animation
r3f-animation scores 93/100 on our quality scale, 30th of 194 Design skills we index (top 16%).
Its SKILL.md is 21 KB long, well organised into 41 sections with 32 code examples: a thorough specification that gives an agent plenty to work with.
With 4,638 GitHub stars, it is one of the more widely adopted skills in the catalogue.
Maintenance, license and trust
- The repository was last updated yesterday, so r3f-animation is actively maintained.
- It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
Safety scan
No issues foundOur scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands.
Automated pattern scan on 2026-09-27. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.
r3f-animation compared with similar skills
All 4 of these similar skills score higher than r3f-animation; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| r3f-animation (this skill)by zebbern | 93 | 4.6k | 1d ago | SKILL.md |
| algorithmic-artby anthropics | 100 | 177.9k | 4d ago | SKILL.md |
| pptxby anthropics | 100 | 177.9k | 4d ago | SKILL.md |
| designby nextlevelbuilder | 100 | 130.2k | 5d ago | SKILL.md |
| ui-ux-pro-maxby nextlevelbuilder | 100 | 130.2k | 5d ago | SKILL.md |
Frequently asked questions
- How do I install r3f-animation?
- Run
npx skills add zebbern/claude-code-guide --skill r3f-animation. The install tabs above show the steps for each supported agent. - Which AI agents does r3f-animation work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is r3f-animation safe to use?
- Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. It is MIT-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is r3f-animation still maintained?
- The repository was last updated yesterday, so r3f-animation is actively maintained.
Skill content
View source on GitHubname: r3f-animation description: React Three Fiber animation - useFrame, useAnimations, spring physics, keyframes. Use when animating objects, playing GLTF animations, creating procedural motion, or implementing physics-based movement.
React Three Fiber Animation
Quick Start
import { Canvas, useFrame } from '@react-three/fiber'
import { useRef } from 'react'
function RotatingBox() {
const meshRef = useRef()
useFrame((state, delta) => {
meshRef.current.rotation.x += delta
meshRef.current.rotation.y += delta * 0.5
})
return (
<mesh ref={meshRef}>
<boxGeometry />
<meshStandardMaterial color="hotpink" />
</mesh>
)
}
export default function App() {
return (
<Canvas>
<ambientLight />
<RotatingBox />
</Canvas>
)
}
useFrame Hook
The core animation hook in R3F. Runs every frame.
Basic Usage
import { useFrame } from '@react-three/fiber'
import { useRef } from 'react'
function AnimatedMesh() {
const meshRef = useRef()
useFrame((state, delta) => {
// state contains: clock, camera, scene, gl, mouse, etc.
// delta is time since last frame in seconds
meshRef.current.rotation.y += delta
})
return (
<mesh ref={meshRef}>
<boxGeometry />
<meshStandardMaterial color="orange" />
</mesh>
)
}
State Object
useFrame((state, delta, xrFrame) => {
const {
clock, // THREE.Clock
camera, // Current camera
scene, // Scene
gl, // WebGLRenderer
mouse, // Normalized mouse position (-1 to 1)
pointer, // Same as mouse
viewport, // Viewport dimensions
size, // Canvas size
raycaster, // Raycaster
get, // Get current state
set, // Set state
invalidate, // Request re-render (when frameloop="demand")
} = state
// Time-based animation
const t = clock.getElapsedTime()
meshRef.current.position.y = Math.sin(t) * 2
})
Render Priority
// Lower numbers run first. Default is 0.
// Use negative for pre-render, positive for post-render
function PreRender() {
useFrame(() => {
// Runs before main render
}, -1)
}
function PostRender() {
useFrame(() => {
// Runs after main render
}, 1)
}
function DefaultRender() {
useFrame(() => {
// Runs at default priority (0)
})
}
Conditional Animation
function ConditionalAnimation({ isAnimating }) {
const meshRef = useRef()
useFrame((state, delta) => {
if (!isAnimating) return
meshRef.current.rotation.y += delta
})
return <mesh ref={meshRef}>...</mesh>
}
GLTF Animations with useAnimations
The recommended way to play animations from GLTF/GLB files.
Basic Usage
import { useGLTF, useAnimations } from '@react-three/drei'
import { useEffect, useRef } from 'react'
function AnimatedModel() {
const group = useRef()
const { scene, animations } = useGLTF('/models/character.glb')
const { actions, names } = useAnimations(animations, group)
useEffect(() => {
// Play first animation
actions[names[0]]?.play()
}, [actions, names])
return <primitive ref={group} object={scene} />
}
Animation Control
function Character() {
const group = useRef()
const { scene, animations } = useGLTF('/models/character.glb')
const { actions, mixer } = useAnimations(animations, group)
useEffect(() => {
const action = actions['Walk']
if (action) {
// Playback control
action.play()
action.stop()
action.reset()
action.paused = true
// Speed
action.timeScale = 1.5 // 1.5x speed
action.timeScale = -1 // Reverse
// Loop modes
action.loop = THREE.LoopOnce
action.loop = THREE.LoopRepeat
action.loop = THREE.LoopPingPong
action.repetitions = 3
action.clampWhenFinished = true
// Weight (for blending)
action.weight = 1
}
}, [actions])
return <primitive ref={group} object={scene} />
}
Crossfade Between Animations
import { useGLTF, useAnimations } from '@react-three/drei'
import { useState, useEffect, useRef } from 'react'
function Character() {
const group = useRef()
const { scene, animations } = useGLTF('/models/character.glb')
const { actions } = useAnimations(animations, group)
const [currentAnim, setCurrentAnim] = useState('Idle')
useEffect(() => {
// Fade out all animations
Object.values(actions).forEach(action => {
action?.fadeOut(0.5)
})
// Fade in current animation
actions[currentAnim]?.reset().fadeIn(0.5).play()
}, [currentAnim, actions])
return (
<group ref={group}>
<primitive object={scene} />
</group>
)
}
Animation Events
function AnimatedModel() {
const group = useRef()
const { scene, animations } = useGLTF('/models/character.glb')
const { actions, mixer } = useAnimations(animations, group)
useEffect(() => {
// Listen for animation events
const onFinished = (e) => {
console.log('Animation finished:', e.action.getClip().name)
}
const onLoop = (e) => {
console.log('Animation looped:', e.action.getClip().name)
}
mixer.addEventListener('finished', onFinished)
mixer.addEventListener('loop', onLoop)
return () => {
mixer.removeEventListener('finished', onFinished)
mixer.removeEventListener('loop', onLoop)
}
}, [mixer])
return <primitive ref={group} object={scene} />
}
Animation Blending
function CharacterController({ speed = 0 }) {
const group = useRef()
const { scene, animations } = useGLTF('/models/character.glb')
const { actions } = useAnimations(animations, group)
useEffect(() => {
// Start all animations
actions['Idle']?.play()
actions['Walk']?.play()
actions['Run']?.play()
}, [actions])
// Blend based on speed
useFrame(() => {
if (speed < 0.1) {
actions['Idle']?.setEffectiveWeight(1)
actions['Walk']?.setEffectiveWeight(0)
actions['Run']?.setEffectiveWeight(0)
} else if (speed < 5) {
const t = speed / 5
actions['Idle']?.setEffectiveWeight(1 - t)
actions['Walk']?.setEffectiveWeight(t)
actions['Run']?.setEffectiveWeight(0)
} else {
const t = Math.min((speed - 5) / 5, 1)
actions['Idle']?.setEffectiveWeight(0)
actions['Walk']?.setEffectiveWeight(1 - t)
actions['Run']?.setEffectiveWeight(t)
}
})
return <primitive ref={group} object={scene} />
}
Spring Animation (@react-spring/three)
Physics-based spring animations that integrate with R3F.
Installation
npm install @react-spring/three
Basic Spring
import { useSpring, animated } from '@react-spring/three'
function AnimatedBox() {
const [active, setActive] = useState(false)
const { scale, color } = useSpring({
scale: active ? 1.5 : 1,
color: active ? '#ff6b6b' : '#4ecdc4',
config: { mass: 1, tension: 280, friction: 60 }
})
return (
<animated.mesh
scale={scale}
onClick={() => setActive(!active)}
>
<boxGeometry />
<animated.meshStandardMaterial color={color} />
</animated.mesh>
)
}
Spring Config Presets
import { useSpring, animated, config } from '@react-spring/three'
function SpringPresets() {
const { position } = useSpring({
position: [0, 2, 0],
config: config.wobbly // Presets: default, gentle, wobbly, stiff, slow, molasses
})
// Or custom config
const { rotation } = useSpring({
rotation: [0, Math.PI, 0],
config: {
mass: 1,
tension: 170,
friction: 26,
clamp: false,
precision: 0.01,
velocity: 0,
}
})
return (
<animated.mesh position={position} rotation={rotation}>
<boxGeometry />
<meshStandardMaterial />
</animated.mesh>
)
}
Multiple Springs
import { useSprings, animated } from '@react-spring/three'
function AnimatedBoxes({ count = 5 }) {
const [springs, api] = useSprings(count, (i) => ({
position: [i * 2 - count, 0, 0],
scale: 1,
config: { mass: 1, tension: 280, friction: 60 }
}))
const handleClick = (index) => {
api.start((i) => {
if (i === index) return { scale: 1.5 }
return { scale: 1 }
})
}
return springs.map((spring, i) => (
<animated.mesh
key={i}
position={spring.position}
scale={spring.scale}
onClick={() => handleClick(i)}
>
<boxGeometry />
<meshStandardMaterial color="orange" />
</animated.mesh>
))
}
Gesture Integration
import { useSpring, animated } from '@react-spring/three'
import { useDrag } from '@use-gesture/react'
function DraggableBox() {
const [spring, api] = useSpring(() => ({
position: [0, 0, 0],
config: { mass: 1, tension: 280, friction: 60 }
}))
const bind = useDrag(({ movement: [mx, my], down }) => {
api.start({
position: down ? [mx / 100, -my / 100, 0] : [0, 0, 0]
})
})
return (
<animated.mesh {...bind()} position={spring.position}>
<boxGeometry />
<meshStandardMaterial color="hotpink" />
</animated.mesh>
)
}
Chain Animations
import { useSpring, animated, useChain, useSpringRef } from '@react-spring/three'
function ChainedAnimation() {
const scaleRef = useSpringRef()
const rotationRef = useSpringRef()
const { scale } = useSpring({
ref: scaleRef,
from: { scale: 0 },
to: { scale: 1 },
config: { tension: 200, friction: 20 }
})
const { rotation } = useSpring({
ref: rotationRef,
from: { rotation: [0, 0, 0] },
to: { rotation: [0, Math.PI * 2, 0] },
config: { tension: 100, friction: 30 }
})
// Scale first (0-0.5), then rotation (0.5-1)
useChain([scaleRef, rotationRef], [0, 0.5])
return (
<animated.mesh scale={scale} rotation={rotation}>
<boxGeometry />
<meshStandardMaterial color="cyan" />
</animated.mesh>
)
}
Morph Targets
Blend between different mesh shapes.
import { useGLTF } from '@react-three/drei'
import { useFrame } from '@react-three/fiber'
import { useRef } from 'react'
function MorphingFace() {
const { scene, nodes } = useGLTF('/models/face.glb')
const meshRef = useRef()
useFrame(({ clock }) => {
const t = clock.getElapsedTime()
// Access morph target influences
if (meshRef.current?.morphTargetInfluences) {
// Animate smile
const smileIndex = meshRef.current.morphTargetDictionary['smile']
meshRef.current.morphTargetInfluences[smileIndex] = (Math.sin(t) + 1) / 2
}
})
return (
<primitive ref={meshRef} object={nodes.Face} />
)
}
Controlled Morph Targets
function MorphControls({ morphInfluences }) {
const { nodes } = useGLTF('/models/face.glb')
const meshRef = useRef()
useFrame(() => {
if (meshRef.current?.morphTargetInfluences) {
Object.entries(morphInfluences).forEach(([name, value]) => {
const index = meshRef.current.morphTargetDictionary[name]
if (index !== undefined) {
meshRef.current.morphTargetInfluences[index] = value
}
})
}
})
return <primitive ref={meshRef} object={nodes.Face} />
}
// Usage
<MorphControls morphInfluences={{ smile: 0.5, blink: 1, angry: 0 }} />
Skeletal Animation
Accessing Bones
import { useGLTF } from '@react-three/drei'
import { useFrame } from '@react-three/fiber'
import { useEffect, useRef } from 'react'
function SkeletalCharacter() {
const { scene } = useGLTF('/models/character.glb')
const headBoneRef = useRef()
useEffect(() => {
// Find skeleton
scene.traverse((child) => {
if (child.isSkinnedMesh) {
const skeleton = child.skeleton
const headBone = skeleton.bones.find(b => b.name === 'Head')
headBoneRef.current = headBone
Truncated for display — read the full file on GitHub.
Related Skills
algorithmic-art
177.9kCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems.
pptx
177.9kUse this skill any time a .pptx or .potx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx or .potx file (even if the extracted content will be used elsewhere, like in an em…
design
130.2kComprehensive design skill: brand identity, design tokens, UI styling, logo generation (55 styles, Gemini, Atlas Cloud, or MuAPI AI), corporate identity program (50 deliverables, CIP mockups), HTML presentations (Chart.js), banner design (22 styles, social/ads/web/print), icon design (15 styles, SVG…
ui-ux-pro-max
130.2kUI/UX design intelligence for web, mobile, and desktop. This skill should be used when designing, building, reviewing, or fixing interfaces, including pages, components, design systems, accessibility, interaction, responsive layout, typography, color, charts, and stack-specific UI implementation.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
