# Why does my pixel camera still jitter even after rounding positions?

**URL:** https://forum.kirupa.com/t/why-does-my-pixel-camera-still-jitter-even-after-rounding-positions/680200
**Category:** web dev
**Created:** [April 8, 2026, 9:00am UTC](https://forum.kirupa.com/t/why-does-my-pixel-camera-still-jitter-even-after-rounding-positions/680200 "2026-04-08T09:00:11Z")
**Posts on this page:** 2
**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 8, 2026, 9:00am UTC](https://forum.kirupa.com/t/why-does-my-pixel-camera-still-jitter-even-after-rounding-positions/680200/1 "2026-04-08T09:00:12Z")

</div>

Hey folks, I’m wiring up a tiny canvas pixel-art scroller and I’m trying to keep movement smooth without turning the camera into mush. If I round everything, motion feels chunky, but if I keep subpixel values, the background and sprites start to shimmer.

```js
const scale = 4;
let camX = 0;
let playerX = 10;

function draw(ctx) {
  camX += 0.35;
  playerX += 0.35;

  ctx.setTransform(scale, 0, 0, scale, 0, 0);
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  const screenX = Math.round(playerX - camX);
  const tileOffset = Math.round(-camX);

  drawTilemap(ctx, tileOffset, 0);
  drawSprite(ctx, player, screenX, 8);
}

```

What should I snap here so the camera scroll stays crisp but the motion does not look like it is randomly vibrating?

WaffleFries 😊

---

<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 8, 2026, 10:07am UTC](https://forum.kirupa.com/t/why-does-my-pixel-camera-still-jitter-even-after-rounding-positions/680200/2 "2026-04-08T10:07:36Z")

</div>

@WaffleFries yup, the jitter is from snapping twice. `Math.round(playerX - camX)` and `Math.round(-camX)` can land on different pixels on neighboring frames, so the map and sprite fall out of sync by 1px.

Round the camera once per frame, then use that same snapped value everywhere:

```auto

js
function draw(ctx) {
  camX += 0.35;
  playerX += 0.35;

  ctx.setTransform(scale, 0, 0, scale, 0, 0);
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  const camPixelX = Math.round(camX);

  drawTilemap(ctx, -camPixelX, 0);
  drawSprite(ctx, player, playerX - camPixelX, 8);
}

```

So: keep sim values as floats, but only snap the camera during render. If it still shimmers after that, check `drawTilemap()` and `drawSprite()` for extra rounding or smoothing.

Yoshiii
