PluginBench
Skill
Review
Audit score 70

r3f-animation

enzed/r3f-skills

Animate React Three Fiber objects with useFrame, damping, and GLTF clips.

What is r3f-animation?

Skill for animating 3D objects in React Three Fiber using useFrame hooks, damping functions, and GLTF animation clips. Use for procedural motion, transitions, demand-loop rendering, or physics-driven movement in interactive 3D scenes.

  • Animate object transforms and uniforms with useFrame and refs for continuous motion
  • Apply exponential damping to smoothly transition between target states
  • Play authored GLTF animation clips with independent instances and cleanup
  • Integrate velocity-based motion with delta-time for frame-rate-independent movement
  • Coordinate animations with physics simulations via Rapier kinematic targets
  • Optimize performance with demand rendering and selective invalidation

How to install r3f-animation

npx skills add https://github.com/enzed/r3f-skills --skill r3f-animation
Prerequisites
  • React Three Fiber 9+ and React 19+ installed
  • Three.js and Drei libraries available in the project
  • Understanding of useFrame hook and ref-based object manipulation
Claude Code
Cursor
Windsurf
Cline

How to use r3f-animation

  1. 1.Install the skill via npx skills add
  2. 2.Import useFrame from @react-three/fiber and useAnimations from Drei as needed
  3. 3.Create a ref to your mesh and use useFrame to update position, rotation, or other properties each frame
  4. 4.Use MathUtils.damp or exponential smoothing with delta time for smooth transitions
  5. 5.Call invalidate() when animation starts to enable demand rendering
  6. 6.For GLTF clips, use Drei's useAnimations hook to load and play named animation actions
  7. 7.Test animations at different frame rates and verify cleanup on component unmount

Use cases

Good for
  • Smoothly animate a 3D box between two positions when clicked, returning to idle
  • Play multiple character animations (walk, run, idle) from a single GLTF model
  • Implement physics-driven ragdoll or collision-based object movement
  • Create demand-loop animations that only render when motion is active
  • Transition between discrete UI states (open/closed panels, selected items) with easing
Who it's for
  • React Three Fiber developers building interactive 3D web experiences
  • Game developers needing character or object animation in WebGL
  • Creative technologists implementing motion design in 3D scenes
  • Performance-conscious developers optimizing frame rendering on demand

r3f-animation FAQ

When should I use useFrame vs. a spring/tween library?

Use useFrame for continuous transforms and refs when React state describes discrete goals (selected, open, active). Use the project's existing spring/tween library for coordinated transitions if it's already installed; avoid adding a state manager just for animation.

How do I prevent animation from jumping when switching targets?

Call invalidate() when the target changes to wake the frame loop, and use MathUtils.damp or exponential smoothing (1 - exp(-lambda * delta)) to smoothly interpolate. Cap delta time to avoid large jumps: Math.min(delta, 0.1).

Can I use useFrame with demand rendering (frameloop='demand')?

Yes. Mount the animated component below Canvas and call invalidate() whenever motion is active. Stop calling invalidate() when the animation reaches its goal to pause rendering.

How do I animate multiple GLTF clips independently?

Use Drei's useAnimations hook to load clips from a model. Each instance gets its own mixer and actions; read the clip playback reference to manage cleanup and prevent memory leaks.

Should I use delta-time-based lerp or a fixed lerp fraction?

Use delta-time: integrate velocity as position += velocity * delta, or use MathUtils.damp. Fixed lerp fractions depend on refresh rate and can overshoot; delta * speed is frame-rate-independent.

Full instructions (SKILL.md)

Source of truth, from enzed/r3f-skills.


name: r3f-animation description: Animate React Three Fiber objects with useFrame, damping, and GLTF clips. Use for procedural motion, animation transitions, or demand-loop animation; use physics guidance for collision-driven movement.

React Three Fiber animation

Check installed Fiber, Drei, and React versions first. These examples target Fiber 9 / React 19. Keep the project's animation library when it already meets the task.

Choose an owner

  • Use useFrame and refs for continuous transforms/uniforms; React state describes discrete goals such as selected, open, or active.
  • Use Drei useAnimations for authored GLTF clips. Read clip playback for independent animated instances and cleanup.
  • Use the project's spring/tween library for coordinated transitions; check its React peer dependencies before adding it. Do not introduce a state manager merely to animate a mesh.
  • Let Rapier own simulated body transforms. Animate kinematic targets through physics APIs rather than fighting the simulation with mesh positions.

Damping that can return to idle

Mount below Canvas; this also works with frameloop="demand". Click the box to change its target.

import { useEffect, useRef, useState } from 'react'
import { useFrame, useThree } from '@react-three/fiber'
import { MathUtils, type Mesh } from 'three'

export default function Example() {
  const mesh = useRef<Mesh>(null)
  const [active, setActive] = useState(false)
  const invalidate = useThree((state) => state.invalidate)
  const target = active ? 1 : -1
  useEffect(() => { invalidate() }, [target, invalidate])

  useFrame((_, delta) => {
    if (!mesh.current) return
    // Cap a visual transition's resume jump, not a physics simulation step.
    const x = MathUtils.damp(mesh.current.position.x, target, 6, Math.min(delta, 0.1))
    const moving = Math.abs(x - target) > 0.001
    mesh.current.position.x = moving ? x : target
    if (moving) invalidate()
  })

  return (
    <mesh ref={mesh} name="moving-box" onClick={() => setActive((value) => !value)}>
      <boxGeometry />
      <meshStandardMaterial color={active ? 'orange' : 'coral'} />
    </mesh>
  )
}

Timing and performance

  • delta is seconds. Integrate velocity as position += velocity * delta; use MathUtils.damp or lerp with 1 - exp(-lambda * delta) for exponential smoothing. A fixed lerp fraction depends on refresh rate; delta * speed can overshoot.
  • Reuse vectors/quaternions; avoid allocating them in every frame. Use quaternion interpolation for orientation instead of independently lerping Euler angles across wrap boundaries.
  • Use one timeline/clock owner. Fiber 9 still supplies state.clock; do not replace Fiber internals because Three.js deprecated new standalone Clock instances. For independent Three.js timing, consult Timer in the installed release.
  • On demand, external animation systems need invalidation while active. Invalidate before starting a synchronous animation and arrange the start on the next frame if the first frame would otherwise jump.
  • Read fast external state directly in the frame callback when supported (e.g. a store's getState()); subscribe React only to UI-relevant changes. Clean up external subscriptions.
  • Do not claim a normal React re-render stops animation. Profile actual work and subscription frequency before memoizing components.
  • Hiding an object does not stop its frame callback or mixer. Pause expensive animation explicitly when appropriate; respect reduced-motion preferences for decorative motion.
  • Repeated oscillations and shader motion can derive phase from elapsed time; simulations needing reproducibility require a fixed-step design, not arbitrary delta clamping.

Verify

Compare motion at different frame rates, background/resume behavior, and repeated target changes. On demand, confirm the object wakes, reaches its goal, and stops requesting frames. For clips, test two instances playing different actions.

Sources