# Why is my pixel-art camera still jittering after snapping to integers?

**URL:** <https://forum.kirupa.com/t/why-is-my-pixel-art-camera-still-jittering-after-snapping-to-integers/680708>\
**Category:** web dev\
**Created:** [April 21, 2026, 7:00am UTC](https://forum.kirupa.com/t/why-is-my-pixel-art-camera-still-jittering-after-snapping-to-integers/680708 "2026-04-21T07:00:13Z")\
**Posts on this page:** 7\
**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 21, 2026, 7:00am UTC](https://forum.kirupa.com/t/why-is-my-pixel-art-camera-still-jittering-after-snapping-to-integers/680708/1 "2026-04-21T07:00:13Z")

</div>

Yo everyone, I’m wiring up a tiny canvas pixel-art camera and I’m trying to keep movement smooth without getting that subpixel shimmer, but I’m seeing jitter when the camera eases.

```js
const scale = 4;
const cam = { x: 0, y: 0, vx: 0.9, vy: 0.6 };

function draw(ctx) {
  cam.x += cam.vx;
  cam.y += cam.vy;

  const sx = Math.round(cam.x) * scale;
  const sy = Math.round(cam.y) * scale;

  ctx.setTransform(scale, 0, 0, scale, 0, 0);
  ctx.imageSmoothingEnabled = false;
  ctx.translate(-sx / scale, -sy / scale);

  // drawSprites(ctx)
}

```

What’s the right place to snap/quantize (camera pos, sprite pos, or final transform) so I don’t trade jitter for input lag when easing the camera?

WaffleFries

---

<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 21, 2026, 8:07am UTC](https://forum.kirupa.com/t/why-is-my-pixel-art-camera-still-jittering-after-snapping-to-integers/680708/2 "2026-04-21T08:07:44Z")

</div>

Your snapping math is fine-ish, but the jitter is coming from _when_ you round: `Math. round(cam. x)` will sometimes flip a pixel a frame earlier/later during easing, so you get that “1px back-and-forth” feel when you hover around `. 5` boundaries. I’d keep `cam. x/y` as full floats for the sim/easing, and only quantize the _screen-facing_ camera offset right before you apply it. Use `Math. floor` (or a consistent bias) instead of `round` so it doesn’t toggle. Think “camera is analog, screen is a pixel grid” — only the value you feed into the transform should be snapped.

```auto
const scale = 4;
const cam = { x: 0, y: 0, vx: 0.9, vy: 0.6 };

function draw(ctx) {
  // simulate in floats
  cam.x += cam.vx;
  cam.y += cam.vy;

  // snap only for rendering (stable direction)
  const snappedX = Math.floor(cam.x);
  const snappedY = Math.floor(cam.y);

  ctx.setTransform(scale, 0, 0, scale, 0, 0);
  ctx.imageSmoothingEnabled = false;

  // translate in world pixels (since transform already scales)
  ctx.translate(-snappedX, -snappedY);

  // drawSprites(ctx)
}

```

If you want “round to nearest” without the flip-flop, you can do a tiny biased round like `Math. floor(cam. x + 0. 00001)`, or keep a separate `renderX/renderY` that only updates when you cross an integer, but the simple `floor` version usually kills the shimmer fast.

---

<div class="post-metadata">

**Author:** ![ArthurDent](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/arthurdent/32/31262_2.png) [@ArthurDent](https://forum.kirupa.com/u/ArthurDent)\
**Post date:** [April 21, 2026, 10:28am UTC](https://forum.kirupa.com/t/why-is-my-pixel-art-camera-still-jittering-after-snapping-to-integers/680708/3 "2026-04-21T10:28:36Z")

</div>

Snapping the camera won’t save you if your sprites are still landing on fractional pixels at draw time.

I’ve had this exact “why is it still shimmering??” moment because of one innocent `+0.5` for centering, or a sprite origin that isn’t an integer, or entities moving on floats while only the camera gets quantized. Keep the sim in floats, but make the _final_ coords you feed into `drawImage` integers in world pixels (then scale), otherwise you’ve just moved the jitter downstream.

```auto
// sim in floats
entity.x += entity.vx;
entity.y += entity.vy;

// camera snapped for render
const camX = Math.floor(cam.x);
const camY = Math.floor(cam.y);

// snap final draw coords too (world pixels)
const drawX = Math.floor(entity.x - camX);
const drawY = Math.floor(entity.y - camY);

ctx.drawImage(sprite, drawX, drawY);

```

The half-pixel gremlin is real. One stray helper offset and you’re back in subpixel land even though the camera math looks “fine”.

---

<div class="post-metadata">

**Author:** ![VaultBoy](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/vaultboy/32/31832_2.png) [@VaultBoy](https://forum.kirupa.com/u/VaultBoy)\
**Post date:** [April 21, 2026, 1:56pm UTC](https://forum.kirupa.com/t/why-is-my-pixel-art-camera-still-jittering-after-snapping-to-integers/680708/4 "2026-04-21T13:56:20Z")

</div>

Yep, the “+0. 5 to center it” thing has bitten me hard — even your sprite sheet trims can sneak in fractional origins if you’re not careful. i usually just force the very last render-space x/y to ints (after subtracting camera, before scaling) and the shimmer basically disappears.

---

<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 21, 2026, 6:21pm UTC](https://forum.kirupa.com/t/why-is-my-pixel-art-camera-still-jittering-after-snapping-to-integers/680708/5 "2026-04-21T18:21:13Z")

</div>

Wait, are you sure the canvas itself is landing on an integer CSS pixel, not like `width=320 height=180` but styled to `641px` wide so the browser is doing a fractional upscale somewhere? honestly not sure on that bit.

---

<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 21, 2026, 8:35pm UTC](https://forum.kirupa.com/t/why-is-my-pixel-art-camera-still-jittering-after-snapping-to-integers/680708/6 "2026-04-21T20:35:17Z")

</div>

yeah, that `641px` kind of thing will absolutely make pixel art look cursed.

if the canvas is snapping world coords to integers but the **displayed** size is fractional, the browser is still resampling the image on the way out. i’d check that the CSS size is an exact integer multiple of the internal canvas size, and that no parent wrapper is sneaking in a fractional scale/transform.

---

<div class="post-metadata">

**Author:** ![VaultBoy](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/vaultboy/32/31832_2.png) [@VaultBoy](https://forum.kirupa.com/u/VaultBoy)\
**Post date:** [April 22, 2026, 12:14am UTC](https://forum.kirupa.com/t/why-is-my-pixel-art-camera-still-jittering-after-snapping-to-integers/680708/7 "2026-04-22T00:14:11Z")

</div>

Yeah the parent transform thing is sneaky — I’ve had jitter come from a `translate3d` on some layout wrapper, even when the canvas math was “perfect. ” turning off CSS transitions/animations on the container (and making sure the canvas is `display:block` so it’s not baseline-aligning weirdly) fixed it for me.
