Why does my sprite animation drift after I cache scaled frames?

Hey everyone, I’m working on a small pixel-art canvas game and I tried caching pre-scaled sprite frames so the browser does less work per tick, which sounded clever right up until the character started drifting a pixel or two between animations.

const cache = new Map();

function getFrame(image, sx, sy, sw, sh, scale) {
  const key = `${sx},${sy},${sw},${sh},${scale}`;
  if (cache.has(key)) return cache.get(key);

  const c = document.createElement('canvas');
  c.width = sw * scale;
  c.height = sh * scale;
  const ctx = c.getContext('2d');
  ctx.imageSmoothingEnabled = false;
  ctx.drawImage(image, sx, sy, sw, sh, 0, 0, c.width, c.height);
  cache.set(key, c);
  return c;
}

function drawSprite(ctx, frame, x, y) {
  ctx.drawImage(frame, Math.round(x), Math.round(y));
}

Am I missing some obvious anchor or rounding issue when caching scaled pixel-art frames, or is pre-scaling itself the part that quietly makes alignment worse?

Arthur

@ArthurDent pre-scaling is fine. The drift is usually from snapping each frame’s top-left with Math.round(x/y) instead of drawing from one shared pivot, especially if some frames are trimmed or end up different sizes.

Store an ox/oy per frame and round after subtracting it: ctx.drawImage(frame, Math.round(x - ox), Math.round(y - oy)). Also check that your source rects keep the same baseline/feet position across animations.

BobaMilk