# lib-core.maps Single tile-grid map implementation. Loads JSON map + tilemap files, registers maps by id, and provides tile-fetch + walkability + size queries with current-map sugar. **Version:** 0.1.2 **Lib-ID:** lib-core.maps **Requires:** (none) **Tags:** maps, tile-grid, walkability, tilemap ## Topology ```mermaid graph LR this["lib-core.maps"] engine["engine.*"] this --> engine ``` ## API ### `maps.load(path)` **Syntax:** `maps.load(path: string) -> string` **Example:** ```lua local id = maps.load("maps/forest.json") maps.set_current(id) ``` **Description:** Loads a JSON map-file from disk, resolves + loads its referenced tilemap (local module-tilemap-id or fully-qualified), validates the map-table, and registers it. Returns the map-id. Errors if the id is already registered. ### `maps.create(t)` **Syntax:** `maps.create(t: {id: string, tilemap_table: table, ...}) -> string` **Example:** ```lua local id = maps.create({ id = "test-tiny", size = { w = 4, h = 4 }, tile_size = { w = 16, h = 16 }, tilemap_table = my_tilemap, tiles = { 0,0,0,0, 0,1,1,0, 0,1,1,0, 0,0,0,0 }, }) ``` **Description:** Programmatic creation for tests + procedural generators. Caller must supply a fully-built `tilemap_table` (not a path/id reference). Otherwise identical to `load`. ### `maps.size(map_id)` **Syntax:** `maps.size(map_id: string | nil) -> {w: integer, h: integer}` **Description:** Returns map-size in tiles. Falls back to current-map when `map_id` is nil. Errors if no current map. ### `maps.tile_size(map_id)` **Syntax:** `maps.tile_size(map_id: string | nil) -> {w: integer, h: integer}` **Description:** Returns tile-size in pixels. Falls back to current-map when nil. ### `maps.tile_at(a, b, c)` **Syntax:** `maps.tile_at(map_id: string, tx: integer, ty: integer) -> table | nil` *(also: `maps.tile_at(tx, ty)` uses current-map)* **Example:** ```lua local tile = maps.tile_at(5, 3) if tile then engine.print(tile.id) end ``` **Description:** Arity-flex sugar: `tile_at(tx, ty)` uses current-map; `tile_at(map_id, tx, ty)` is explicit. Returns the resolved tile-record from the tilemap, or `nil` if out-of-bounds. ### `maps.is_walkable(a, b, c)` **Syntax:** `maps.is_walkable(map_id: string, tx: integer, ty: integer) -> bool` *(also: `is_walkable(tx, ty)` uses current-map)* **Description:** Convenience: returns `true` iff the tile exists and has `walkable == true`. Out-of-bounds is `false`. ### `maps.tilemap_id(map_id)` **Syntax:** `maps.tilemap_id(map_id: string | nil) -> string` **Description:** Returns the fully-qualified tilemap-id referenced by a map. ### `maps.current()` **Syntax:** `maps.current() -> string | nil` **Description:** Returns the currently-active map-id, or `nil` if none. ### `maps.set_current(map_id)` **Syntax:** `maps.set_current(map_id: string) -> void` **Description:** Switches the current-map pointer. Errors if `map_id` is not registered. ### `maps.list()` **Syntax:** `maps.list() -> string[]` **Description:** Returns an array of all registered map-ids. ### `maps.load_textures(asset_aliases)` **Syntax:** `maps.load_textures(asset_aliases: {[string]: string}) -> void` **Example:** ```lua maps.set_current(map_id) maps.load_textures({ terrain = "lib-core.terrain-assets" }) ``` **Description:** Resolves the current tilemap's tile `texture` atlas-ids to texture-handles via the asset-lib indirection. `asset_aliases` maps the tilemap's `asset_pack` alias-key to a lib-id; the lib's `assets/atlas.json` is read to locate each texture file. Populates `tile.texture_handle` on each tile in-place. No-op if the tilemap has no `asset_pack`. Call once at module init after `set_current`; do not call repeatedly (texture handles are not auto-cached). ### `maps.draw_map()` **Syntax:** `maps.draw_map() -> void` **Description:** Draws the current map grid. Tiles with a resolved `texture_handle` render via `engine.render.draw_sprite_transform` with rotation about the tile center (using the map's optional `tile_rotations` parallel array). Tiles without a texture handle fall back to `engine.render.draw_rect` with `tile.color` (Phase 1 mode). No-op if no current map. ### `maps.state(map_id)` **Syntax:** `maps.state(map_id: string) -> string` **Description:** DEPRECATED-MVP stub. Always returns `"Active"` in v0.1.x. Full lifecycle (`Virgin`/`Inert`/`Passive`/`Active`/`Pinned`) lands in the multi-map slice. ### `maps.pin(map_id, reason)` **Syntax:** `maps.pin(map_id: string, reason: string) -> void` **Description:** DEPRECATED-MVP stub. Emits a warn in v0.1.x. Pinning prevents lifecycle-eviction in the multi-map slice. ## Conventions - Pixel-coords + tile-coords kept distinct: `size`/`tiles` index in tile-units; `tile_size` is the conversion to pixels. - Tilemap-ids may be local (`.`) or fully-qualified; `load()` resolves both. - `tile_at` is bounds-checked: out-of-bounds returns `nil` (not error). - Y-down-positive per ADR-0031. ## Consumer pattern ```lua local maps = require("lib-core.maps") local id = maps.load("maps/forest.json") maps.set_current(id) local sz = maps.size() for ty = 0, sz.h - 1 do for tx = 0, sz.w - 1 do if not maps.is_walkable(tx, ty) then -- mark blocked cell end end end ``` ## CHANGELOG ### v0.1.2 - Sprite-mode in draw_map: tilemap-tiles with `texture` atlas-id render via engine.render.draw_sprite_transform; tiles without `texture` fall back to color-rect render (Phase 1 mode). - Map-data tile_rotations parallel array support: per-cell 90-degree rotation in {0, 90, 180, 270}, applied at draw via rotation about the tile center. Optional; absent means all-zero. - New API: maps.load_textures(asset_aliases) resolves the current tilemap's tile atlas-ids to texture-handles via the asset-lib indirection. Mirrors the puppet.load_textures pattern. - Tilemap schema additions: tilemap.asset_pack (alias-key), tile.texture (atlas-id). - Backward-compat: existing Phase 1 color-only tilemaps render unchanged. ### v0.1.1 - Tilemap-id resolution handles module-ids with dots (prefix-match instead of first-dot split). ### v0.1.0 (P.0) - Initial release: load/create + tile_at + is_walkable + current-map management. ## References - Spec v0.1.0 (P.0): `meta/docs/superpowers/specs/2026-05-09-p0-lib-maps-design.md` - Architecture: `meta/docs/architecture/map-topology.md` - ADR-0001 (engine knows verbs, libs bring nouns) - ADR-0031 (pixel-convention: Y-down-positive) - ADR-0038 (API-Doc-Convention)