Quick answer: A CanvasLayer ignores the camera by design. For world-anchored or parallax content, set follow_viewport_enabled = true and use follow_viewport_scale for the parallax factor.

A background CanvasLayer is meant to parallax-scroll behind the world, but it stays locked to the screen — or the offset is wrong when the camera moves.

CanvasLayers Are Screen-Space by Default

A CanvasLayer renders independently of the 2D camera — that’s the point for HUDs. But it means a background layer won’t move with the world unless you tell it to.

Enable Follow Viewport

$BackgroundLayer.follow_viewport_enabled = true
$BackgroundLayer.follow_viewport_scale = 0.5   # half-speed parallax

Or Use Parallax2D / ParallaxBackground

For multi-layer scrolling backgrounds, the dedicated Parallax2D (Godot 4.3+) or ParallaxBackground nodes handle the math — you set a scroll scale per layer and they follow the camera automatically.

Keep HUD Layers As-Is

Your HUD CanvasLayer should keep follow_viewport off — it’s meant to be screen-locked. Only enable following on layers that represent world content.

Verifying

Move the camera. Background layers scroll at their parallax rates; the HUD stays put. No drift, no wrong offset.

“CanvasLayers ignore the camera on purpose. Opt in with follow_viewport for world-anchored layers.”

For anything beyond one parallax layer, reach for Parallax2D — hand-rolling follow_viewport_scale per layer gets fiddly fast.