Skip to content

Decorated interiors pass 2: neighbour-aware & rule-bearing tiles (#36) - #41

Merged
Dibujaron merged 20 commits into
mainfrom
feat/decorated-interiors-pass2
Jul 21, 2026
Merged

Decorated interiors pass 2: neighbour-aware & rule-bearing tiles (#36)#41
Dibujaron merged 20 commits into
mainfrom
feat/decorated-interiors-pass2

Conversation

@Dibujaron

Copy link
Copy Markdown
Owner

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. stairs tiles 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-deck mask4 bitmask for autotiling + a pure interior_hash(deck,x,y) for variation — never Time/RNG/load-order, so nothing reshuffles on relog (headless self-test pins this).

  • f fountain — adjacent fountains merge into one pool.
  • l flowerbed — plants, with trees on interior cells of a large bed (density is a named lever).
  • t table — adjacent tables merge; a seat e next to a table turns to face it.
  • g hydroponic garden — aesthetic (reuses flowerbed machinery, never trees); leaves a #food production hook.

Slice C — wall-mounted consoles. Consoles move from tile centres to wall fixtures (EdgeSpec gained an optional console kind); 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 centre h/c/b glyphs are removed. Brokers need no seat; Q airlock stays a floor tile.

Slice D — wall bunk. Edge d = wall bunk (distinct from centre d = 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, so d=bunk would have clobbered d=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 in docs/deckplan-format.md.

Please eyeball in-engine (the screenshot harness is red on main, so I couldn't auto-verify the look)

  1. Wall-console art: console_helm/cargo/broker.png are 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.
  2. The migrated maps (Mockingbird helm/cargo, Highport/Ring brokers) — placement is mechanically correct and position-preserving, but worth your eye.
  3. Test decor: a few f/l tiles 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 --check clean.
  • Headless GDScript self-test (interior_selftest.tscn): PASS (determinism + autotile + neighbour logic).
  • Render probe runs error-free headless for every new tile.
  • harness/test_m2_interior.py has 4 pre-existing failures on main (stale-geometry, unrelated) — flagged separately, not touched here.

Notes

🤖 Generated with Claude Code

Dibujaron and others added 20 commits July 19, 2026 19:30
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.
@Dibujaron
Dibujaron merged commit 0f64914 into main Jul 21, 2026
1 check passed
@Dibujaron
Dibujaron deleted the feat/decorated-interiors-pass2 branch July 21, 2026 00:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Aesthetic interior tiles (pass 2): neighbor-aware & rule-bearing tiles

1 participant