# JS Tip of the Day: Animations With requestAnimationFrame

**URL:** <https://forum.kirupa.com/t/js-tip-of-the-day-animations-with-requestanimationframe/643100>\
**Category:** web dev\
**Created:** [May 6, 2020, 12:35pm UTC](https://forum.kirupa.com/t/js-tip-of-the-day-animations-with-requestanimationframe/643100 "2020-05-06T12:35:56Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![senocular](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/senocular/32/7217_2.png) [@senocular](https://forum.kirupa.com/u/senocular)\
**Post date:** [May 6, 2020, 12:35pm UTC](https://forum.kirupa.com/t/js-tip-of-the-day-animations-with-requestanimationframe/643100/1 "2020-05-06T12:35:56Z")

</div>

**Animations With requestAnimationFrame**  
Level: Intermediate

CSS can provide a lot when it comes to adding animations to your website or web app. Whether through CSS Animations or CSS Transitions, it will generally be your preferred approach for adding motion to your content. But when it comes to those special cases where CSS just isn’t able cut it, you will have JavaScript to rely on.

When animating with JavaScript, you’ll be responsible for each frame of the animation. To best sync your animation frames with the rendering of the browser window, the Web API provides you with the function `requestAnimationFrame()`. `requestAnimationFrame()` accepts a callback that will run each time before the browser will render the screen. In this callback you would put the code needed to drive your animations. It receives one argument, a timestamp from when the page was first loaded.

```javascript
function callback (timestamp) {
    // animate stuff
}
requestAnimationFrame(callback);

```

Unlike `setInterval()`, `requestAnimationFrame()` doesn’t continuously call your callback over and over again. It only calls it once for the next time there’s a render (making it closer to `setTimeout()`). If you want to keep animating over time, you need to keep requesting a new animation frame with your callback. You would do this by calling `requestAnimationFrame()` again inside the callback.

```javascript
function callback (timestamp) {
    // animate stuff
    
    // keep animating
    requestAnimationFrame(callback);
}
requestAnimationFrame(callback);

```

If you want to stop animating, you can stop calling `requestAnimationFrame()`, or, much in the way `setInterval()` and `setTimeout()` can be stopped, you can capture the return value from `requestAnimationFrame()` and cancel it using `cancelAnimationFrame()`.

```javascript
function callback (timestamp) {
    // animate stuff
    
    // keep animating
    requestId = requestAnimationFrame(callback);
}
let requestId = requestAnimationFrame(callback);
cancelAnimationFrame(requestId); // cancels animation

```

The following is a more complete example, using an HTML “cat” element that follows the mouse using `requestAnimationFrame()`. It shows two ways of stopping the animation, one by not calling `requestAnimationFrame()` again if a certain condition is met, and the other by canceling the request id with `cancelAnimationFrame()` when the user clicks.

```auto
<span id="cat" style="position: absolute">cat</span>

<script>
let cat = document.getElementById('cat');
let catSpeed = 2;
let catPos = {x:0, y:0};
let mousePos = {x:200, y:200};

function updateCatPos () {
    let {x, y} = catPos;
    let dx = mousePos.x - x;
    let dy = mousePos.y - y;
    let isCaught = dx < catSpeed && dy < catSpeed;
    let angle = Math.atan2(dy, dx);
    x += catSpeed * Math.cos(angle);
    y += catSpeed * Math.sin(angle);
    cat.style.transform = `translate(${x}px, ${y}px)`;
    catPos = {x, y};
    return isCaught;
}

function updateMousePos (event) {
    mousePos = {x: event.clientX, y: event.clientY};
}
addEventListener('mousemove', updateMousePos);

function stopChase (event) {
    cancelAnimationFrame(chaseId);
}
addEventListener('click', stopChase);

function chaseLoop (timestamp) {
    let isCaught = updateCatPos();
    if (isCaught) {
        document.documentElement.style.cursor = 'none';
    } else {
        chaseId = requestAnimationFrame(chaseLoop);
    }
}
let chaseId = requestAnimationFrame(chaseLoop);
</script>

```

More info:

- [requestAnimationFrame on MDN](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame)
