From 9dd37a9b25beaadff32866105cc73119e2200007 Mon Sep 17 00:00:00 2001 From: Axel Meyer Date: Sat, 9 May 2026 21:55:04 +0200 Subject: [PATCH] feat: P.0.lib.camera 2D camera state + begin/finish wrapper --- .gitignore | 2 ++ README.md | 33 +++++++++++++++++++++++++++++ init.lua | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ manifest.lib | 1 + 4 files changed, 95 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 init.lua create mode 100644 manifest.lib diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..41ae811 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +*.log diff --git a/README.md b/README.md new file mode 100644 index 0000000..938b185 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# lib-core.camera + +P.0 2D camera state + begin/finish wrapper. Holds `target = {x, y}` + `zoom`, +wraps `engine.render.camera_2d_begin/end` with current state. + +- Lib-ID: `lib-core.camera` +- Version: `0.1.0` +- Spec: `meta/docs/superpowers/specs/2026-05-09-p0-lib-camera-design.md` + +Forward-compat stubs (DEPRECATED-MVP) for follow, set_bounds, lerp_to, shake, +set_rotation. See `meta/docs/architecture/render-pipeline.md` and +`meta/docs/architecture/map-topology.md §7.3` for full target context. + +## API +- `camera.set_target(x, y)` — set world-coords for screen-center +- `camera.set_zoom(z)` — set zoom (positive number) +- `camera.target() → {x, y}` — current target +- `camera.zoom() → number` — current zoom +- `camera.begin()` — push camera transform (must be inside render hook) +- `camera.finish()` — pop camera transform (`end` is Lua keyword) + +## Consumer pattern +```lua +local camera = require("lib-core.camera") +camera.set_target(256, 256) -- world-coords +camera.set_zoom(1.0) +function render(ctx) + engine.render.clear_color(...) + camera.begin() + -- draw world here + camera.finish() +end +``` diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..0ba06a5 --- /dev/null +++ b/init.lua @@ -0,0 +1,59 @@ +-- ===================================================================== +-- lib-core.camera — 2D Camera State (P.0) +-- See: meta/docs/superpowers/specs/2026-05-09-p0-lib-camera-design.md +-- +-- Scope: target + zoom state + begin/finish wrapper. +-- Forward-compat stubs (DEPRECATED-MVP): +-- - follow(entity) -- lib-core.actor slice +-- - set_bounds(map_id) -- when map-bounds matter +-- - lerp_to(target, dt) -- smooth-follow / animation slice +-- - shake(intensity, dur) -- effects/juice slice +-- - set_rotation(deg) -- closed-topology slice +-- ===================================================================== + +local target_x = 0 +local target_y = 0 +local zoom_v = 1.0 + +local M = {} + +function M.set_target(x, y) + if type(x) ~= "number" or type(y) ~= "number" then + error("camera.set_target: x and y must be numbers") + end + target_x = x + target_y = y +end + +function M.set_zoom(z) + if type(z) ~= "number" or z <= 0 then + error(string.format("camera.set_zoom: zoom must be a positive number, got %s", + tostring(z))) + end + zoom_v = z +end + +function M.target() + return { x = target_x, y = target_y } +end + +function M.zoom() + return zoom_v +end + +function M.begin() + engine.render.camera_2d_begin(target_x, target_y, zoom_v) +end + +function M.finish() + engine.render.camera_2d_end() +end + +-- DEPRECATED-MVP: forward-compat stubs for later slices +-- function M.follow(entity) -- lib-core.actor slice +-- function M.set_bounds(map_id) -- bounds-clamping slice +-- function M.lerp_to(target, dt) -- smooth-follow slice +-- function M.shake(intensity, dur) -- effects/juice slice +-- function M.set_rotation(deg) -- closed-topology slice + +return M diff --git a/manifest.lib b/manifest.lib new file mode 100644 index 0000000..fc57e22 --- /dev/null +++ b/manifest.lib @@ -0,0 +1 @@ +{"id":"lib-core.camera","version":"0.1.0","api_min":"0.1"}