# Why does my sprite animation skip frames when the tab lags?

**URL:** https://forum.kirupa.com/t/why-does-my-sprite-animation-skip-frames-when-the-tab-lags/680196
**Category:** web dev
**Created:** [April 8, 2026, 7:00am UTC](https://forum.kirupa.com/t/why-does-my-sprite-animation-skip-frames-when-the-tab-lags/680196 "2026-04-08T07:00:10Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![BobaMilk](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/bobamilk/32/31157_2.png) [@BobaMilk](https://forum.kirupa.com/u/BobaMilk)
#### Post date: [April 8, 2026, 7:00am UTC](https://forum.kirupa.com/t/why-does-my-sprite-animation-skip-frames-when-the-tab-lags/680196/1 "2026-04-08T07:00:10Z")

</div>

Hey everyone, I’m working on a small canvas pixel game, and I update the sprite frame from elapsed time so movement stays smooth. It mostly works, but if the tab stalls for a moment, the animation can jump 2 or 3 frames and the walk cycle looks broken.

```js
let last = performance.now();
let frame = 0;
let acc = 0;
const frameMs = 100;

function loop(now) {
  acc += now - last;
  last = now;

  if (acc >= frameMs) {
    frame = (frame + Math.floor(acc / frameMs)) % 6;
    acc %= frameMs;
  }

  draw(frame);
  requestAnimationFrame(loop);
}

requestAnimationFrame(loop);

```

What is the usual fix here if I want timing to stay honest but I also do not want sprite frames to visibly skip after a lag spike?

BobaMilk

---

<div class="post-metadata">

### Author: ![Quelly](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/quelly/32/31386_2.png) [@Quelly](https://forum.kirupa.com/u/Quelly)
#### Post date: [April 8, 2026, 7:28am UTC](https://forum.kirupa.com/t/why-does-my-sprite-animation-skip-frames-when-the-tab-lags/680196/2 "2026-04-08T07:28:47Z")

</div>

@BobaMilk yup, it’s skipping because `Math.floor(acc / frameMs)` fast-forwards the walk cycle after a hitch. If the tab pauses for 300ms, you add 3 frames in one paint, which is honest to elapsed time but looks bad for a sprite loop.

The usual fix is to separate gameplay time from visual animation time. Let movement/physics use real `dt`, but cap the animation side so it only advances one pose per render, or clamp the animation `dt` before it hits the sprite accumulator.

```auto

js
let last = performance.now();
let frame = 0;
let animAcc = 0;
const frameMs = 100;
const maxAnimDt = 100; // don't let a hitch dump multiple frames into animation

function loop(now) {
  const dt = now - last;
  last = now;

  // use full dt for gameplay if you want timing to stay honest
  // updateMovement(dt);

  // but soften hitches for visual animation
  animAcc += Math.min(dt, maxAnimDt);

  if (animAcc >= frameMs) {
    frame = (frame + 1) % 6; // at most one visible pose change this render
    animAcc -= frameMs; // keep leftover time instead of zeroing it out
  }

  draw(frame);
  requestAnimationFrame(loop);
}

requestAnimationFrame(loop);

```

Small but important detail: use `animAcc -= frameMs`, not `animAcc %= frameMs`, if you’re intentionally limiting animation to one step. `%=` would throw away the extra whole-frame time and make the animation drift more than you probably want.

Quelly
