requestAnimationFrame : How To Stop, Pause & Restart?

In this guide, we will look at how to stop, pause and restart an animation on a webpage using requestAnimationFrame.

This gets a little tricky because of the way animations are done with requestAnimationFrame. As you probably know, requestAnimationFrame does the animation using “recursion”. So, in order to stop the animation, we need to stop the “recursion”.

A Working Demo With Stop / Pause, Play And Reset

Below is a simple animation made with a box rotating using CSS rotate.

See the Pen
requestAnimationFrame How To Stop & Play
by Khoj Badami (@livefiredev)
on CodePen.

The Usual Structure Of A requestAnimationFrame Animation

Usually, the structure of the code has 4 parts:

  1. Set up the state of the animation: For example: Current angle of rotation of a box & if the animation is currently running
  2. Create a function which moves the animation into the next frame
  3. Call “requestAnimationFrame” from inside the function IF the animation needs to continue.
  4. Start the animation from outside the function by calling requestAnimationFrame the first time.

Let’s look at all the 4 parts in the code snippet below. I have written comments to mark the 4 parts.

// 1: Set up the animation intial state
let angle = 0;
let animate = true;

// 2: A function that moves the animation into the next frame
let updateBoxAngle = () => {
    angle += 1;
    document.getElementById("box").style.transform = `rotate(${angle}deg)`;

    // 3: Calling requestAnimationFrame from inside the function
    // if the animation needs to continue
    if (animate == true) { 
        requestAnimationFrame(updateBoxAngle) 
    }
}

// 4: Get the animation started by calling requestAnimationFrame first time
requestAnimationFrame(updateBoxAngle);

As you can see in the above on line 3, we have defined a variable called “animate”. This is a boolean that holds the value which decides if we should continue the animation or not.

The Key To Understanding How To Pause / Stop requestAnimationFrame

If you see the MDN page on requestAnimationFrame you will see the following note highlighted..

Note from MDN about requestAnimationFrame that helps with stop / pause & play

As you can see, if you want to continue the animation, you need to call requestAnimationFrame yourself again. And so, all you need to do to stop the animation is NOT call requestAnimationFrame.

let updateBoxAngle = () => {
    angle += 1;
    document.getElementById("box").style.transform = `rotate(${angle}deg)`;

    // Calling requestAnimationFrame from inside the function
    // if the animation needs to continue
    if (animate == true) { 
        requestAnimationFrame(updateBoxAngle) 
    }
}

The condition on line 7 is to do just that. We just need to play with the value to “animate” in order to pause and play the animation.

How To Pause / Stop The Animation Recursion?

document.getElementById("pauseButton").addEventListener('click', () => {
    animate = false;
});

It’s simple, we will just update the value of “animate” to false.

How To Resume The Animation Recursion?

document.getElementById("playButton").addEventListener('click', () => {
    if (animate == false) {
        animate = true;
        requestAnimationFrame(updateBoxAngle);
    }
});

All we do here is check to see if the animation is really paused and then if it is, we set “animate” to true again and kick off the animation using requestAnimationFrame.

IMPORTANT NOTE: If you do not check if the animation is already running, you will double up the speed of the animation because requestAnimationFrame will start to get called twice.

How To Reset The Animation Recursion

We set the “state” of the animation back to the original state. Then just to give the user a little bit of visual feedback, we wait for a second (1000 milliseconds) and then we kick off the animation again…

document.getElementById("resetButton").addEventListener('click', () => {
    angle = 0;
    animate = false;

    setTimeout(function() {
        animate = true;
        requestAnimationFrame(updateBoxAngle);
    }, 1000)
});

Hope you found this useful!