Decorated interiors pass 2: neighbour-aware & rule-bearing tiles (#36) - #41
Merged
Conversation
Cohesive spec for the pass-2 tile zoo: neighbour-aware decor (fountain, flowerbed, table, hydroponic) on a deterministic hash, up/down hatchway art, wall-mounted consoles, the wall-bunk rule tile, and first-crack greyscale sprites. Slices A-E build internally; batched into one review. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
13 tasks across slices A-E: sprite scaffold, deterministic neighbour module, hatchway art, fountain/flowerbed/table/hydroponic, wall consoles + map migration, bunk rule tile, first-crack sprite pass. Batched to one PR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stairs tiles now render as stairs_up/stairs_down/stairs_updown greyscale sprites instead of plain floor, chosen by probing both vertical scan directions (ShipClassData.stairs_leads, a public wrapper over the existing _scan_stairs) rather than any authored direction. An isolated stairs tile that connects neither way falls back to plain floor. Pure client render pass (_draw_stairs, inserted between floor and decor in _draw()); server and wire protocol untouched. Extends tools/gen_interior_sprites.py with the three new sprite generators and adds a 3-deck stacked-stairs case to interior_render_probe.gd so the headless probe exercises all three direction branches.
Add centre glyph 'f' (fountain), a walkable floor decor tile. Adjacent fountain tiles merge visually into one larger pool via InteriorNeighbors' mask4 neighbour bitmask, routed through a new pure autotile_suffix helper (mask -> "" | "_n" | "_ew" | "_nesw" | ...). interior_view.gd's _draw_decor special-cases glyph "f" to build the sprite id from the neighbour mask, falling back to the base "fountain" piece when suffixed art is missing -- deterministic, no RNG/Time, proving the shared neighbour-aware module ahead of flowerbeds/trees/tables.
t merges with adjacent tables like fountains do (mask4 + autotile_suffix). A seat (e) adjacent to a table renders rotated to face it, via a new pure InteriorNeighbors.face_toward(deck, x, y, target_glyph) with fixed N,E,S,W priority. A new _draw_decor_tex helper carries the rotation for seats while leaving every other decor glyph's draw byte-identical (quarter 0). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ok) (#36) Add centre glyph 'g' (hydroponic), a walkable floor decor tile. Reuses the flowerbed neighbour-aware machinery (mask4/popcount/interior_hash + plant_variant) but calls plant_variant with allow_tree=false, so it renders only "hydro_plant" or base "hydroponic" trough art -- never a tree. Leaves a TODO(#food) hook marking the seam for a future fresh-food system to enumerate 'g' decor cells without touching render code. Extends gen_interior_sprites.py with hydroponic (trough/rack) and hydro_plant (sprout) sprites, documents the pass-2 decor glyphs (f/l/g/t) in docs/deckplan-format.md, and registers 'g' in the render probe's inline deck/registry so the branch runs headless.
Teach the glyph registry that a wall (edge) fixture can carry a console kind (EdgeSpec.console), add edge h/c/b entries alongside the existing centre h/c/b, and make scan_markers also scan a tile's own four edges for a console-bearing wall (guarded on the centre being Floor). Purely additive: centre h/c/b consoles keep working unchanged; maps still author the centre form until a later migration task.
T8 moved helm/cargo/broker consoles to edge fixtures, which already render on the wall strip via the existing fixture path with no client change. This was the one remaining piece: skip centre-drawing those three kinds in _draw_consoles so an edge-authored console shows once (on the wall) instead of doubled; dock stays a centre airlock pictogram. Also mirrors console_sprite ingest for edge entries in glyph_registry.gd (future-proofing sprite_for_console for wall-only console glyphs), and extends interior_render_probe.gd with an edge-console 'h' wall fixture + seat tile plus a matching "helm" consoles entry, exercising the new skip branch and the wall-console draw path headlessly. Verified headless: editor cache rebuild clean, interior_render_probe and interior_selftest both run with no SCRIPT/Parse errors, selftest reports PASS.
) (#36) Adds edge glyph `d`=bunk (Fixture, blocks like a wall, sprite "bunk"), distinct from centre `d`=floor bed. The rule that a bunk may only mount over a floor bed or another bunk (to stack bunks) is an authoring convention this pass, documented in docs/deckplan-format.md and the glyph registry description; enforcement is #24. Fixes GlyphRegistry (client) to keep centre and edge sprite-by-glyph maps separate: previously a single merged dict meant an edge entry could clobber a centre entry sharing the same char, which would have made every floor bed render as a wall bunk now that `d` means two different things by position.
Migrate the three authored maps from centre console glyphs to wall-mounted edge fixtures, each on an edge of its own tile so the derived console keeps its (deck,x,y) — sim/world/shipclass tests unchanged: - Mockingbird helm -> north wall + pilot seat; cargo -> hold west wall. - Highport two brokers -> north-edge counters; Ring broker -> south wall. Remove the now-unused centre h/c/b glyphs from glyphs.json + default(). Update glyphs_test / world_test / shipclass_test fixtures that authored centre consoles to the wall form. Add a few fountain/flowerbed decor tiles to the Highport concourse for in-game testing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#36) First-crack sprite polish for pass-2 decor: cargo_pallet base grey raised from 170 into the 185-205 band flagged by pass-1 review (plus wider slats + a cross-strap), the seat redesigned as a clear backrest+cushion (backrest on the south edge, matching the "front-facing north" convention documented in interior_view.gd), the rug border contrast bumped, and flowerbed sprigs enlarged and the fountain given a ripple highlight. Stdlib-only, greyscale, same dimensions/filenames/keys throughout. Adds a "Retuning interior sprites" hand-off section to docs/deckplan-format.md pointing at tools/gen_interior_sprites.py vs. in-place PNG replacement, noting the Highport test-decor tiles and that the console-migrated maps still need an in-engine eyeball since the screenshot harness is red. Verification: gleam test (244 passed, no failures), gleam format --check (clean), godot --editor import pass (clean), interior_selftest.tscn (SELFTEST: PASS), interior_render_probe.tscn (exit 0, no errors). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Consoles now render on the 64x14 wall strip (they moved from tile centres to wall fixtures), but the art was still the 44x44 centre-draw sprites and squished. Generate proper wall-strip panels: a dark screen with a per-kind mark (helm nav line, cargo crate slats, broker rising bars). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review feedback: everything rendered as white squares. Root cause: sprites filled the tile with a uniform light grey and no dark elements, so only the dark-shafted down-ladder read. Rework the generator around a design language — dark outline (~G55) for the silhouette, mid fill for the body/palette tint, light highlight — so each tile reads as an object (rug w/ medallion, chair, bed+pillow, round fountain, tree, ladder, wall panels) and still takes the colour multiply as shading. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review: uncoloured decor rendered pale/white because the palette tint only applies when a tile carries an NE-corner colour. Add a per-glyph DEFAULT colour (fountain→light_blue, flowerbed/tree→green, table/bed/rug→warm, etc.) used when the tile has none, so decor reads in colour. Wire it through the decor, stairs, and (newly tinted) wall-fixture draw paths via a shared _tile_tint helper. Defaults live in a client-side map for now — TODO(#36): promote to a `color` field in glyphs.json so they're authorable. Also redraw stairs_up as bold dark up-chevrons on a light panel (the inverse of the dark down-shaft) so "ascend" reads as clearly as "descend".
Review: beds defaulted to the same light_blue as windows. A two-tone bed can't come from the single-slot palette multiply, so bake red covers + white pillow into the bed and bunk sprites and drop their default palette slot (they draw untinted; an NE-corner colour still overrides). Distinct from windows, and a nod to Minecraft beds.
This was referenced Jul 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #36. Pass-2 interior tiles, each layering a mechanic on the pass-1 decor+colour pipeline, plus first-crack sprites. Built as internal slices, batched into this one PR for review.
What's in it
Slice A — hatchway art.
stairstiles render as up- / down- / both-hatchway, derived client-side from the vertically-adjacent deck (stairs_target). Pure render; server untouched.Slice B — neighbour-aware decor (deterministic). A small shared client module (
interior_neighbors.gd): a same-deckmask4bitmask for autotiling + a pureinterior_hash(deck,x,y)for variation — never Time/RNG/load-order, so nothing reshuffles on relog (headless self-test pins this).ffountain — adjacent fountains merge into one pool.lflowerbed — plants, with trees on interior cells of a large bed (density is a named lever).ttable — adjacent tables merge; a seatenext to a table turns to face it.ghydroponic garden — aesthetic (reuses flowerbed machinery, never trees); leaves a#foodproduction hook.Slice C — wall-mounted consoles. Consoles move from tile centres to wall fixtures (
EdgeSpecgained an optionalconsolekind); the interaction record derives at the floor tile the wall faces, so console positions — and all sim/world/shipclass behaviour — are unchanged. The three authored maps (Mockingbird, Highport, Ring) are migrated (each console mounted on an edge of its own tile), and the now-unused centreh/c/bglyphs are removed. Brokers need no seat;Qairlock stays a floor tile.Slice D — wall bunk. Edge
d= wall bunk (distinct from centred= floor bed); blocks like a wall; placement rule is an authoring convention this pass (enforcement is #24). This also uncovered + fixed a latent client bug: the registry previously merged centre/edge sprite ids in one dict, sod=bunk would have clobberedd=bed — now split into centre/edge sprite maps.Slice E — sprites. stdlib-only greyscale sprite generator (
tools/gen_interior_sprites.py) with first-crack art for every pass-1 + pass-2 tile; a legibility pass; retuning is documented indocs/deckplan-format.md.Please eyeball in-engine (the screenshot harness is red on main, so I couldn't auto-verify the look)
console_helm/cargo/broker.pngare 64×64 (authored for the old centre-draw) but now render on a 64×14 wall strip → they'll look squished. Correctness (position/interaction) is fine; the art wants a 64×14 wall pass — didn't want to overwrite your hand-authored console sprites without your call.f/ltiles were dropped into the Highport concourse so you can see the new decor live (rearrange freely — it's just data).Verification
gleam test: 244 passed,gleam format --checkclean.interior_selftest.tscn): PASS (determinism + autotile + neighbour logic).harness/test_m2_interior.pyhas 4 pre-existing failures onmain(stale-geometry, unrelated) — flagged separately, not touched here.Notes
edge.consoleon the glyph registry.DH_PORTisolation (so tests don't collide with a dev server) shipped separately as chore(harness): dedicated DH_PORT so tests never collide with a dev server #40.🤖 Generated with Claude Code