Skip to main content

r3f-animation

React Three Fiber animation - useFrame, useAnimations, spring physics, keyframes. Use when animating objects, playing GLTF animations, creating procedural motion, or implementing physics-based movement.

Quellinformationen

Repository
zebbern/claude-code-guide
Letzte Quellaktivität
31. Mai 2026 um 15:44
Erkannte Sprache von SKILL.md
Englisch
Sterne
4.696
Forks
470

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
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 ```tsx 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 ```tsx 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 ```tsx 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 ```tsx // 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 ```tsx 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 ```tsx 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 ```tsx 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 ```tsx 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 ```tsx 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 ```tsx 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 ```bash npm install @react-spring/three ``` ### Basic Spring ```tsx 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 ```tsx 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 ```tsx 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 ```tsx 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 ```tsx 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 />
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen