ludic/docs/language/camera/camera-zoom.md
Orkuncakilkaya 6a83c28e05
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 22s
ci / build-and-test (push) Successful in 2m15s
commit-lint / conventional-commits (push) Successful in 4s
docs / build-and-deploy (push) Successful in 28s
feat(camera): #78 deterministic Camera.zoom (Q16.16 render-time zoom)
The #78 investigation rejected hardware f32/f64 for the coordinate types
(they would desync lockstep/replay/save) and identified camera zoom as the
one genuinely-missing render feature. Ship it: Camera.zoom(scale) scales the
whole view about the screen centre by a Q16.16 factor, threaded through the
same two framebuffer chokepoints (rt_put_px/rt_fill_rect) that carry the
camera offset, so it composes with Camera.set/follow/shake. Gated by an
internal rt_cam_zoomed flag so a game that never zooms renders byte-for-byte
identically (golden renders unchanged); Camera.zoom(1.0) turns it back off.
The world coordinate types stay integer px + Q16.16 velocity, so it's a pure
render-time transform and itself deterministic.

Example examples/library/camera_zoom.ludic (pixel-readback verified),
docs page, RFC updated (docs/RFC-POSITION-TYPES.md). Full suite 105/0,
fixpoint holds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 06:55:37 +03:00

1.4 KiB

id name category kind tokens sig tip order ns member
camera-zoom Camera.zoom camera namespace-method Camera.zoom Camera.zoom(scale) Scale the whole view about the screen centre by a Q16.16 factor (1.0 = none). 4 Camera zoom

Sets a render-time zoom: every draw is scaled about the screen centre by scale, a Q16.16 fixed factor. 1.0 is no zoom (and turns the zoom path back off, restoring the byte-identical un-zoomed blit); 2.0 is 2x in; 0.5 is 2x out. It composes with Camera.set / Camera.follow (which move the view) and Camera.shake.

Zoom is a render-time transform, not a change to the world coordinate types — those stay integer pixels + Q16.16 velocity so lockstep, replay and world_save hold (see the position-types RFC, #78). Because it rides on fixed-point, the zoom is itself deterministic: the same scale produces the same pixels on every machine and headless.

Parameters:

  • scale — the zoom factor (fixed); 1.0 = no zoom, >1 zooms in, <1 zooms out
program Demo {
  property Cam { z: fixed = 1.0 }
  model View { Cam }
  handler DrawWorld phase Render {
    Camera.zoom(2.0)
    Screen.fill_rectangle(150, 110, 20, 20, 0xffcc00)
    Screen.show()
  }
}