Appearance
Basic Animations
FreshThis tutorial will assume some React knowledge. We will build a small, continuous animation loop — the basic building block of more advanced animations.
useFrame
useFrame is a Fiber hook that lets you execute code on every frame of Fiber's render loop.
WARNING
Fiber hooks can only be called inside a <Canvas /> parent!
jsx
import { useFrame } from '@react-three/fiber'
function MyAnimatedBox() {
useFrame(() => {
console.log("Hey, I'm executing every frame!")
})
return (
<mesh>
<boxGeometry />
<meshBasicMaterial color="royalblue" />
</mesh>
)
}The callback we pass to useFrame will be executed every frame and passed an object containing the state of our Fiber scene.
We can extract time information from the clock parameter:
jsx
useFrame(({ clock }) => {
const a = clock.elapsedTime
console.log(a) // grows each frame from 0 at scene initialization
})clock is a three.js Clock object. We get the total elapsed time, which is key for our animations.
Animating with Refs
Instead of routing updates through React state (which is slow), directly mutate the mesh each frame. First, get a reference to it via useRef:
jsx
import React from 'react'
function MyAnimatedBox() {
const myMesh = React.useRef()
return (
<mesh ref={myMesh}>
<boxGeometry />
<meshBasicMaterial color="royalblue" />
</mesh>
)
}myMesh will now hold a reference to the actual three.js object, which we can freely mutate in useFrame:
jsx
useFrame(({ clock }) => {
myMesh.current.rotation.x = clock.elapsedTime
})What is happening here:
- We destructure
clockfrom the argument passed touseFrame - We access the
rotation.xproperty ofmyMesh.current— a reference to our actual mesh object - We assign a time-dependent value to the rotation on the x axis
- Our object will now infinitely rotate based on elapsed time
Exercise
Try Math.sin(clock.elapsedTime) and see how your animation changes — the mesh will oscillate back and forth instead of continuously rotating.
Using Delta Time
Always use frame deltas instead of fixed values so your app runs at the same speed on all devices:
jsx
useFrame((state, delta) => {
myMesh.current.rotation.x += delta
})This ensures the animation speed is consistent regardless of the user's display refresh rate (60fps, 120fps, etc).
Next Steps
Now that you understand the basic technique for animating in Fiber, learn how events work in the Events and Interaction tutorial.
For deeper animation work:
- react-spring — spring-physics-based animations that integrate with R3F
- framer-motion-3d — framer motion for three.js scenes