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.
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):
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.
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.
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:
// 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...