Quick answer: Smoothing creates fractional pixel positions; changing zoom multiplies those fractions into visible jitter. Set Camera2D process_callback to Physics, enable Snap 2D Transforms / Vertices To Pixel in project settings, and tune position_smoothing_speed to match the physics rate.
Here is how to fix Godot Camera2D smoothing that produces visible jitter especially when the camera zooms in or out. Player movement looks fine. Then you smooth-zoom toward an enemy and the entire scene shimmers, sprites wobble, pixel-art textures crawl. Smoothing math interacts badly with non-integer pixel positions, and zoom magnifies the effect.
The Symptom
Camera follows the player smoothly. When zoom changes — via tween or direct property assignment — the world wobbles for the duration of the zoom. Pixel-art games show particularly bad shimmer because individual texels jump between adjacent screen pixels.
What Causes This
Sub-pixel positions. Smoothed motion produces fractional positions like (125.37, 88.92). Without snap-to-pixel, those fractions render as anti-aliased borders. With pixel-art textures sized to specific pixel multiples, the result is shimmer.
Process callback mismatch. If smoothing runs on Idle (Process) but your physics movement runs on Physics, the two timelines drift relative to each other every frame.
Zoom amplifies jitter. A 0.5-pixel jitter at zoom 1 becomes 1 pixel of jitter at zoom 2. Zoom changes produce the most visible jitter.
Smoothing speed too low. A speed of 1 means the camera takes a full second to reach 63% of the target. During zoom this long lag is interpreted by the eye as smearing.
The Fix
Step 1: Enable snap-to-pixel. Open Project Settings → Rendering → 2D and enable both:
- Snap 2D Transforms To Pixel
- Snap 2D Vertices To Pixel
This forces all 2D transforms to round to integer pixel coordinates, eliminating sub-pixel shimmer regardless of smoothing.
Step 2: Use Physics process callback.
extends Camera2D
func _ready():
process_callback = Camera2D.CAMERA2D_PROCESS_PHYSICS
position_smoothing_enabled = true
position_smoothing_speed = 8.0
drag_horizontal_enabled = false
drag_vertical_enabled = false
Running smoothing in physics keeps the camera and physics objects in lockstep, eliminating drift.
Step 3: Tween zoom on physics tick.
func zoom_to(target_zoom: float, duration: float = 0.3):
var tween = create_tween()
tween.set_process_mode(Tween.TWEEN_PROCESS_PHYSICS)
tween.tween_property(self, "zoom", Vector2(target_zoom, target_zoom), duration)
The physics process mode keeps the zoom interpolation aligned with both physics and the camera’s smoothing.
Step 4: Tune smoothing speed. Start at 8.0 for responsive feel. Drop to 4.0 for floaty cinematic motion. Above 12 the camera snaps so quickly that smoothing is almost invisible — you may as well disable it.
Step 5: Round zoom to clean fractions. Pixel-art looks best at integer or simple-fraction zooms (0.5, 1.0, 2.0). Avoid arbitrary values like 1.7. If you must zoom continuously, snap to nearest 0.25 step:
var snapped_zoom = round(zoom_target * 4) / 4.0
For Pixel-Perfect Pixel Art
If you are making strict pixel art, consider rendering to a low-resolution viewport and upscaling. Set Project Settings → Display → Window → Stretch → Mode to viewport and Aspect to keep. Choose a base size like 320x180. This eliminates per-pixel jitter regardless of camera smoothing because the smoothing operates on the upscaled output, not on the source pixels.
When To Disable Smoothing
For ultra-tight platformers (Celeste-tier), some designers disable smoothing entirely and snap the camera to integer multiples of the player position. This eliminates all camera-related jitter but loses the cinematic feel. For most games, snap-to-pixel + physics callback + speed 8 is the right compromise.
“Smoothing wants float positions; pixels want integers. Snap settings reconcile the two. Physics process keeps everything in lockstep.”
Related Issues
For CanvasLayer parallax issues, see CanvasLayer Follow Viewport. For other Godot 2D issues, see CharacterBody2D Ghost Collision.
Snap 2D Transforms. Physics callback. Speed 8. The shimmer stops.