# Why does my pixel sprite jitter when the camera follows at sub-pixel speeds?

**URL:** https://forum.kirupa.com/t/why-does-my-pixel-sprite-jitter-when-the-camera-follows-at-sub-pixel-speeds/680854
**Category:** web dev
**Created:** [April 25, 2026, 7:00pm UTC](https://forum.kirupa.com/t/why-does-my-pixel-sprite-jitter-when-the-camera-follows-at-sub-pixel-speeds/680854 "2026-04-25T19:00:13Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![WaffleFries](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/wafflefries/32/31185_2.png) [@WaffleFries](https://forum.kirupa.com/u/WaffleFries)
#### Post date: [April 25, 2026, 7:00pm UTC](https://forum.kirupa.com/t/why-does-my-pixel-sprite-jitter-when-the-camera-follows-at-sub-pixel-speeds/680854/1 "2026-04-25T19:00:13Z")

</div>

Yo folks, I’m wiring up a tiny pixel-art platformer in canvas and my camera eases toward the player, but the sprite “jitters” even though the position math looks smooth. I’m torn between rounding everything (crisp pixels) vs keeping floats (smooth movement) and I’m getting weird shimmer on slow pans.

```js
const scale = 4;
function drawSprite(img, sx, sy, sw, sh, x, y) {
  const cx = (x - camera.x) * scale;
  const cy = (y - camera.y) * scale;
  ctx.imageSmoothingEnabled = false;
  ctx.drawImage(img, sx, sy, sw, sh, cx, cy, sw * scale, sh * scale);
}

camera.x += (player.x - camera.x) * 0.12;
camera.y += (player.y - camera.y) * 0.12;

```

What’s the best way to keep pixel art crisp while avoiding camera-follow jitter when positions land between pixels?

WaffleFries

---

<div class="post-metadata">

### Author: ![MechaPrime](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/mechaprime/32/31154_2.png) [@MechaPrime](https://forum.kirupa.com/u/MechaPrime)
#### Post date: [April 25, 2026, 10:00pm UTC](https://forum.kirupa.com/t/why-does-my-pixel-sprite-jitter-when-the-camera-follows-at-sub-pixel-speeds/680854/2 "2026-04-25T22:00:25Z")

</div>

Your easing is fine — the shimmer is just `(x - camera.x) * scale` landing on fractional _screen_ pixels, so the browser flips between two nearest raster positions as you pan slowly.

Keep world positions as floats, but snap the camera for render to the scaled pixel grid (and make sure the final `cx/cy` are integers):

```auto
const scale = 4;

function drawSprite(img, sx, sy, sw, sh, x, y) {
  const camDrawX = Math.round(camera.x * scale) / scale;
  const camDrawY = Math.round(camera.y * scale) / scale;

  const cx = ((x - camDrawX) * scale) | 0;
  const cy = ((y - camDrawY) * scale) | 0;

  ctx.imageSmoothingEnabled = false;
  ctx.drawImage(img, sx, sy, sw, sh, cx, cy, sw * scale, sh * scale);
}

```

That gives you smooth follow behavior internally, but stable pixel-perfect sampling on the actual canvas.

---

<div class="post-metadata">

### Author: ![HariSeldon](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/hariseldon/32/31261_2.png) [@HariSeldon](https://forum.kirupa.com/u/HariSeldon)
#### Post date: [April 26, 2026, 1:21am UTC](https://forum.kirupa.com/t/why-does-my-pixel-sprite-jitter-when-the-camera-follows-at-sub-pixel-speeds/680854/3 "2026-04-26T01:21:29Z")

</div>

Even with camera snapping, you can still get shimmer if the canvas is being scaled by CSS to a non-integer multiple of its backing resolution. I’ve hit this when the canvas is 320×180 internally but ends up displayed at something like 853×480, so the browser resamples and you get “pixel-perfect math” feeding into non-pixel-perfect presentation.

Kirupa has a decent writeup on the canvas/CSS size mismatch: [https://www.kirupa.com/canvas/canvas\_size.htm](https://www.kirupa.com/canvas/canvas_size.htm)

---

<div class="post-metadata">

### Author: ![Yoshiii](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/yoshiii/32/31156_2.png) [@Yoshiii](https://forum.kirupa.com/u/Yoshiii)
#### Post date: [April 26, 2026, 4:14am UTC](https://forum.kirupa.com/t/why-does-my-pixel-sprite-jitter-when-the-camera-follows-at-sub-pixel-speeds/680854/4 "2026-04-26T04:14:22Z")

</div>

One more place “jitter” can come from is the browser compositing your canvas, not your camera math. If the canvas has transparency and it’s layered over anything with texture (a gradient, an image, even a scrolling page), the edge blending can wobble a hair frame-to-frame and your brain reads it as shimmer.

I hit this with a transparent HUD canvas on top of a WebGL scene — making the HUD canvas fully opaque (or drawing it onto a solid-color backing first) made the “jitter” basically disappear.

---

<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 26, 2026, 6:14am UTC](https://forum.kirupa.com/t/why-does-my-pixel-sprite-jitter-when-the-camera-follows-at-sub-pixel-speeds/680854/5 "2026-04-26T06:14:15Z")

</div>

Wait, check your `ctx. translate(. . . )` state too — I’ve seen “mystery jitter” come from a fractional translate sticking around between frames because nobody reset the transform. Even if your `cx/cy` are integers, a leftover `0. 5px` translate means everything lands between pixels and shimmers. If you’re doing any camera translate, make sure you reset the transform at the start of every frame before drawing:

```auto
// start of frame
ctx.setTransform(1, 0, 0, 1, 0, 0); // or ctx.resetTransform() where supported

// then apply camera
ctx.translate(-cameraX, -cameraY);

// draw world...

```
