Namespaced asset API + spritesheet/atlas with named cells #81

Closed
opened 2026-09-02 04:52:41 +02:00 by orkun · 2 comments
Owner

Sprite loading is a bare png_load("assets/sprites/floor0.png") — unnamespaced, and one file per 16x16 sprite. There is no general (non-Tiled) spritesheet/atlas API: you cannot load one sheet and address a cell by grid coords or by name.

Proposal: a namespaced API, e.g. Sprite.sheet(path, cellw, cellh) -> handle, Sprite.cell(sheet, col, row) / Sprite.define(name, sheet, col, row) -> id, plus Assets.* for load/lookup. Loading many individual PNGs is slower and clutters the project.

Seen in an external game that had to pre-slice the 0x72 atlas into individual PNG files.

Sprite loading is a bare `png_load("assets/sprites/floor0.png")` — unnamespaced, and one file per 16x16 sprite. There is no general (non-Tiled) spritesheet/atlas API: you cannot load one sheet and address a cell by grid coords or by name. Proposal: a namespaced API, e.g. `Sprite.sheet(path, cellw, cellh)` -> handle, `Sprite.cell(sheet, col, row)` / `Sprite.define(name, sheet, col, row)` -> id, plus `Assets.*` for load/lookup. Loading many individual PNGs is slower and clutters the project. Seen in an external game that had to pre-slice the 0x72 atlas into individual PNG files.
Author
Owner

Please beware that some sprites may or may not cover more than 1 cell.

Please beware that some sprites may or may not cover more than 1 cell.
Author
Owner

Shipped in f3f1336 (full suite 114/0, goldens byte-identical, fixpoint intact).

A namespaced spritesheet / atlas API over the variable-size image loader, so a cell is a sub-rect of the kept image — sprites are no longer restricted to the 16x16 sprite table:

  • Sprite.sheet(path, cellw, cellh) -> handle — load one sheet, remember its cell grid
  • Sprite.cell(sheet, col, row) -> id — a cell by grid coords
  • Sprite.cell_span(sheet, col, row, cols, rows) -> id — a sprite spanning more than one cell (per your note that some sprites cover >1 cell — a tall character, a wide object)
  • Sprite.define(name, sheet, col, row) / Sprite.named(name) — name a cell and look it up (content data can drive rendering with no hard-coded ids)
  • Sprite.draw(id, x, y) / Sprite.draw_scaled(id, x, y, scale) — blit through the camera / zoom / clip, exactly like Screen.sprite
  • Sprite.width(id) / Sprite.height(id)
  • Assets.image(path) -> id (whole file as one sprite) / Assets.load (alias) / Assets.get(name) (alias of Sprite.named)

Spliced on demand, so a program that uses neither Sprite.sheet nor Assets.* is byte-identical. Verified by examples/library/atlas.ludic against a real 12x11 Kenney sheet (tilemap_packed.png): single cell (16x16), a 2x3 multi-cell span (32x48), named define/lookup, Assets.image, and a pixel-readback that the sprite drew — prints 16 16 32 48 1 1 1 16 1. 14 docs pages added.

Note: this atlas id-space is distinct from the Sprite engine component (#85), which draws png_load ids via the 16x16 table; wiring atlas ids into that component's auto-draw is a natural follow-up.

Shipped in f3f1336 (full suite 114/0, goldens byte-identical, fixpoint intact). A namespaced spritesheet / atlas API over the variable-size image loader, so a cell is a **sub-rect of the kept image** — sprites are no longer restricted to the 16x16 sprite table: - `Sprite.sheet(path, cellw, cellh) -> handle` — load one sheet, remember its cell grid - `Sprite.cell(sheet, col, row) -> id` — a cell by grid coords - `Sprite.cell_span(sheet, col, row, cols, rows) -> id` — **a sprite spanning more than one cell** (per your note that some sprites cover >1 cell — a tall character, a wide object) - `Sprite.define(name, sheet, col, row)` / `Sprite.named(name)` — name a cell and look it up (content data can drive rendering with no hard-coded ids) - `Sprite.draw(id, x, y)` / `Sprite.draw_scaled(id, x, y, scale)` — blit through the camera / zoom / clip, exactly like `Screen.sprite` - `Sprite.width(id)` / `Sprite.height(id)` - `Assets.image(path) -> id` (whole file as one sprite) / `Assets.load` (alias) / `Assets.get(name)` (alias of `Sprite.named`) Spliced on demand, so a program that uses neither `Sprite.sheet` nor `Assets.*` is byte-identical. Verified by `examples/library/atlas.ludic` against a real 12x11 Kenney sheet (tilemap_packed.png): single cell (16x16), a 2x3 multi-cell span (32x48), named define/lookup, Assets.image, and a pixel-readback that the sprite drew — prints `16 16 32 48 1 1 1 16 1`. 14 docs pages added. Note: this atlas id-space is distinct from the `Sprite` engine *component* (#85), which draws png_load ids via the 16x16 table; wiring atlas ids into that component's auto-draw is a natural follow-up.
orkun closed this issue 2026-09-02 06:58:29 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: workshopsoft/ludic#81
No description provided.