Tilemaps: compact cell storage in the project file, check total 1017 (#134)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
adminandClaude Opus 5 committed 2026-09-18 09:17:49 +02:00
1 parent 60be8d9aff
commit a0f279a031
3 files changed
+21 -5

No files matched your search

+1 -1
@@ -71,7 +71,7 @@ src/core/graph/ graph model, NodeRegistry/NodeContext/values, interpreter
lookup (what a node may look up: behaviors, state machines), keyRepeat; nodes/{events,flow,data,action,variable}/<Name>.ts
src/core/particles/ nodes (the catalogue), compile (a graph → one function per output),
emission (which particles are alive at a second — a pure rule, no state)
src/core/store/ serialize (untrusted JSON → Project), http (one API call), ProjectStore/HttpProjectStore,
src/core/store/ serialize (untrusted JSON → Project), tilemapCells (the compact form of a layer's cells in the file), http (one API call), ProjectStore/HttpProjectStore,
FileStore (what the server holds of one kind) + HttpFileStore (one generic client over the three
file collections) — TextureStore, FontStore and SoundStore are its type parameters, nothing else
src/core/time.ts the global clock: one scaled step a frame, shared by the world, the particles, the shaders and the animation preview
+2 -2
@@ -12,7 +12,7 @@ npm run check # typecheck + lint + format:check + tests, the gate CI runs
# code is lost (tail's is reported), so a red run reads as green
npm run build # writes dist/ and regenerates index.html
./build.sh # the same under `set -o pipefail`, for callers that pipe the output
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1013 editor checks, screenshots in /tmp/gm-e2e-*.png
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1017 editor checks, screenshots in /tmp/gm-e2e-*.png
GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step
./e2e.sh start [GM_STEPS] # the same run detached, see below
./e2e.sh status # live progress, or the last run's result
@@ -232,4 +232,4 @@ widths to find click points. The **render device is not in this repo** — `/dev
and a 1 GB `/dev/shm` come from `container.options` in the runner's own `config.yaml`, which
applies to every job on that runner. Without them chromium falls back to llvmpipe, which gets
WebGL 1.0 only. Measured in the job container: `ANGLE (Intel, Vulkan 1.3.230, HD Graphics 630)`,
WebGL 2.0, and the same 1013 checks as here.
WebGL 2.0, and the same 1017 checks as here.
+18 -2
@@ -67,10 +67,26 @@ tile is on the same step, so animated water does not run out of phase between tw
Drawing is done with **one mesh per tile and layer** rather than one sprite per cell, so a map of a
thousand cells costs as many draw calls as it has tiles on that layer.
## In the project file
While you edit, a layer holds its cells as a map from `"x,y"` to a tile. The project file stores
them more compactly (#134): per layer the tiles it uses **once**, the top-left painted cell, and
then **one line per row** as runs of `index*count`. `index` counts from 1 into the tile list, `0`
is an empty cell, and a single cell drops the count:
```json
"tiles": ["grass", "path"],
"origin": { "x": 0, "y": 0 },
"rows": ["1*40 0*3 2", "1*44"]
```
Cells outside the grid are stored as well, so a map that was made smaller gets them back when it
grows again. Measured: a full map of 100 × 100 cells on two layers went from 736 KB to 11 KB.
**Older projects** still load — their cells are read as they are and written in the new form on
the next save.
## What it does not do yet
- **No collision.** A tilemap is a picture; figures walk through it. Whether it should contribute
colliders is a question of its own and is not decided.
- Nothing fills an area by flooding it, and there is no picking up a tile off the map.
- The cells are stored one entry per painted cell (`"x,y"` → tile), uncompressed. Big maps
therefore make big project files; the format leaves room to pack them later.