The model — a hexagram is a ground type, in every runtime
ground-types/001 · created 2026-08-17 · updated 2026-08-18
What to do
Put the hexagram at the centre of the code, the way the spec asks, before any storage or
rendering exists. Read land-of-lor/docs/specs/GROUND_TYPES.md first (it is human-owned;
read, don’t edit).
Step 0 — fix the world file. game/content/spellgrove.world.json is invalid today: a
world-editor session on 2026-08-16 (05fcdd0) shrank beginner-arena to 20×10 and left two
portals out of bounds (village-to-arena toCell (0,10), arena-to-badlands fromCell (19,19)).
validateWorldContent returns two errors and npm run load-world refuses the file. Everything
in this epic rides on the loader. Assumption: keep the 20×10 and move both portals to the
bottom edge — (0,9) and (19,9). Say so in the session report.
Then the model, in three runtimes from one table:
game/shell/elements.js— addgroundto each of the eightLOR_TRIGRAMSentries ({ name, kind: "flat"|"sunken"|"mountain", passable, colour, pattern }; earth = Grass, wind = Sand, thunder = Snow/Ice, water = Water (sunken), fire = Lava (sunken), mountain = Mountain (impassable), lake = Deep Water (impassable), heaven = Stone/tiles) andgroundVariant({ label, colour, pattern }) to each of the 64LOR_ELEMENTS(the Earth-upper one is the plain variant; kw 56, Fire over Mountain, is the volcano). Inside the two existing globals, not a third one —card-editor.htmlregenerates this file from exactlyLOR_TRIGRAMSandLOR_ELEMENTS. Placeholder colours are fine; task 006 tunes them.game/sync-elements.shalso writesgame/director/src/data/elements.json; the director’sbuildscript copiessrc/dataintodist/the way it already copiesschema.sql.- New
game/world/ground_types.gdat the project root (pureRefCounted,preload-only, loads the sameelements.jsonviaload()— no hand-copied tables):kw_of(upper, lower),lower_of(kw),variant_index(kw),is_passable(kw),is_sunken(kw),is_mountain(kw),DEFAULT_KW = 2,plain_kw_for(lower).client/ui/element_db.gdgainsground_type(kw)/ground_variant(kw)and documented stubs for the spec’s other getters (getCreatureModel,getSize,getColour,getBrain,getNature,howManyStackInCell,getSpellKind,getPowerValue,rarity) — the shape is visible, no values are invented. - New
game/director/src/groundTypes.tswith the same API, readingdata/elements.json. game/world/grid.gd—CELL_TERRAIN_BLOCK = 4;ground: PackedInt32Arrayfilled with 2 in_init;ground_at(),apply_ground(PackedInt32Array) -> bool(length must match; setsCELL_TERRAIN_BLOCKfor impassable hexagrams but never overwritesCELL_PORTAL);decode_ground()as the one codec function;from_area_payloadreadsground;permits_squeeze()is false for a terrain block;set_portalwarns if it lands on one. Retire the “an authored area is open ground (no ground types yet)” test line.- Write the ground content-file format into
game/README.mdnow, so tasks 005–007 can start from it:game/content/areas/<slug>.ground.json={ "$comment", "slug", "width", "height", "layers", "rows": ["02 02 20 02 …", …] }—height × layersrow strings, two-character zero-padded, space-separated, one row per line.
Definition of done
test_runner.gd: kw ↔ (upper, lower) is a bijection matchingelements.json;apply_groundrespects portal precedence and rejects a wrong length;is_walkable/permits_squeezeon terrain blocks;from_area_payloadwith, without and with a shortground.npm test:groundTypes.test.ts(64 → 8 × 8, kind rules) and the loader suite green again after step 0.sync-elements.shwrites both JSON copies; both are committed.- Committed and pushed in
land-of-lor.
Where the work lands
land-of-lor — game/shell/, game/director/src/, game/world/, game/README.md.
What was done (2026-08-17, laptop session)
- Step 0:
spellgrove.world.json— beginner-arena’s two portals moved to (0,5) and (19,9);validateWorldContentis clean again. Assumption: the 20×10 resize was intended; the portals were moved, not the size restored. elements.js:groundon all eight trigrams,groundVarianton all 64 elements (placeholder colours; task 006 tunes them).sync-elements.shwrites the director copy;npm run buildcarries it intodist/.director/src/groundTypes.ts+test/groundTypes.test.ts(5 tests).world/ground_types.gd(root, pure),element_db.gdgetters and stubs,grid.gd(ground,CELL_TERRAIN_BLOCK,set_ground,apply_ground,decode_ground,ground_at,is_sunken,is_mountain;from_area_payloadreadsgroundbefore portals).test_runner.gd: 143 checks green.game/README.md: “The ground — every cell is a hexagram”, incl. the content-file format.
View source in repository · also available as raw markdown.