useAnimationFrame example: Step-by-step

Matt PerryMatt Perry

In this tutorial, we'll build the useAnimationFrame example step-by-step.

This example is rated 1/5 difficulty, which means we'll spend some time explaining the Motion APIs that we've chosen to use (and why), and also any browser JavaScript APIs we encounter that might be unfamiliar to beginners.

Introduction

The useAnimationFrame example shows how to create complex continuous animations using Motion's useAnimationFrame hook. This hook provides a way to run a function on every frame, perfect for creating dynamic, math-based animations that need to run continuously.

Get started

Let's start with the basic structure of our 3D cube:

export default function UseAnimationFrame() {
    return (
        <div className="container">
            <div className="cube">
                <div className="side front" />
                <div className="side left" />
                <div className="side right" />
                <div className="side top" />
                <div className="side bottom" />
                <div className="side back" />
            </div>
        </div>
    )
}

Let's animate!

Import from Motion

First, we'll import the necessary hooks:

import { useAnimationFrame } from "motion/react"
import { useRef } from "react"

Setting up direct DOM manipulation

For this animation, we're calculating our own transform values every animation frame. So we can directly assign the transform property to the DOM element.

For this, we need a reference to our cube element:

export default function UseAnimationFrame() {
    const ref = useRef<HTMLDivElement>(null)
 
    return (
        <div className="container">
            <div className="cube" ref={ref}>
                {/* ... cube sides ... */}
            </div>
        </div>
    )
}

Creating the continuous animation

Now, let's add the frame-by-frame animation using useAnimationFrame. This hook runs a function on every animation frame, providing a timestamp we can use to create smooth continuous motion:

useAnimationFrame((t) => {
    if (!ref.current) return
 
    const rotate = Math.sin(t / 10000) * 200
    const y = (1 + Math.sin(t / 1000)) * -50
    ref.current.style.transform = `translateY(${y}px) rotateX(${rotate}deg) rotateY(${rotate}deg)`
})

The timestamp, t, increases continuously, allowing us to create cyclical motion. We use Math.sin to create smooth oscillating values between -1 and 1.

For rotation: t / 10000 creates a slow cycle, multiplied by 200 for a -200° to 200° range.

For vertical movement (y): t / 1000 creates a faster cycle, transformed to move between 0 and -100px.

Conclusion

In this tutorial, we learned how to:

Tutorial Project

We're currently working on adding a tutorial for every example on the Motion Examples website. So far, 12% of examples have a tutorial.