Skip to content

S3: The metro, by hand - #370

Merged
jamescrosswell merged 7 commits into
mainfrom
task/350-metro
Oct 22, 2026
Merged

jamescrosswell merged 7 commits into
mainfrom
task/350-metro

Conversation

@jamescrosswell

@jamescrosswell jamescrosswell commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

An abandoned metro station one level below the village, designed by hand: metro, the Old Metro. A stairway goes down from Banyan Row's river promenade through a door like any other, into a ticket hall, down to a platform with a dead train, along a service tunnel, and to a depot with the clinic. It has dark stretches, a maintenance plug, three locked places, three secrets and six places for salvage, each with a stable id for the tasks that build on it. Everything's painted in #329's revised cartoon, a little dirty.

Closes #350

Please look at

All from the real client, in the ?harness=side harness, at 80 px/m.

Taste calls:

  • A vaulted, tiled station. Cream tiles with a teal band, arches with empty poster frames, a tiled wall 4.6 m tall behind the platform with junk piled at its foot, and blurred rails in the foreground. The backdrop is the vault seen overhead, its ribs at the top of the view.
  • A little dirty. The style words are Style study 3: add pixel art and flat cartoon to the side-view comparison #329's revised cartoon with "a little worn and dirty, a few smudges, scuffs and stains" in place of "grime on every surface", so the sewers have somewhere to go.
  • The way in is on Banyan Row's river promenade (x 62), the lowest part of the village: a narrow papercraft iron-and-glass canopy with a train pictogram, between the news kiosk and the signpost, whose post stands clear of it. The signpost and prompt read "The Old Metro". The door can't move to the canopy's cell: next to the kiosk, E reads the news.
  • The service tunnel is the same hall past a tiled arch. It reads as a tunnel only once S4 darkens it.
  • Catwalks and steps are the metro's own, steel and tiled, drawn over the street's wooden ledges and stone steps. Its two ladders are still the street's wooden ones, which pass for something the tunnel dwellers put up.
  • The clinic is a 10-wide kiosk of cracked green tiles with two neon crosses, painted in one go so its roof has no seam. A faint light line runs down its left edge. Its room is bare for S7.
  • At night the metro takes the village's night tint, as the client lights every street by the time of day. Underground probably shouldn't (below).

For the tasks that build on it

Ids and cells are in simile.street.metro and content/street/README.md's The metro. No schema change.

Task Hook Id
S4 Dark stretches, in a new light layer metro_vault (over the platform, rows 0–11), metro_tunnel_west, metro_tunnel_east. Every other cell is in a lit one: metro_entrance, metro_platform, metro_maintenance, metro_depot.
S4 The maintenance plug, a machine metro_plug, stood at from (72, 15), in a lit alcove between the tunnel's two dark halves
S6 Places salvage can lie, in a new pickups layer metro_salvage_1 … _6: the train's roof, the west tunnel twice, the pipe ledge, the east tunnel, and the high ledge
S6 The scrap trader's stall the location scrap_stall and the spot metro_scrap_trader, standing, facing south
S7 The clinic and the doctor's stall spot clinic, an amenity on clinic_floor_0 (room clinic), and the spot clinic_doctor
S8 The high ledge, a machine metro_high_ledge, four cells at row 12, three rows above the floor
S8 The dead terminal, a machine metro_terminal, stood at from (104, 15)
S8, S9 The lift to the sewers, a machine metro_lift; its foot on the metro is (100, 15) (LIFT_FOOT), where a link down would end. No link leads from it yet.
  • The height assumed for the legs: the high ledge is LEGS_ROWS = 3 rows up. Today's jump is 2 rows (rise 2.3 tiles), so it's out of reach; the legs need at least 3 rows (a rise of about 3.2 tiles or more).
  • The locked places are interactables of kind machine, the only kind the client doesn't use on E. The ledge isn't really a machine: S8 may want a kind of its own.
  • Secrets are secret pickups holding money or an item: metro_secret_stairwell (25), metro_secret_catwalk (40), and metro_secret_alcove, a ration_pack (food, 0.5 kg). Each needs a run jump that walking and climbing don't replace.
  • light and pickups are new object layers on every map, empty outside the metro. TownMap doesn't read them yet; that's for S4 and S6 in simile.world.map.

What changed

  • The metro (server/simile/street/metro.py, 110 × 20): a landing and two three-row flights through the ticket hall to the platform; the scrap stall, benches and a dead train with a ladder up its end; a catwalk along the vault; the tunnel arch, the plug, and a ladder, a pipe ledge, a catwalk and an alcove up the tunnel wall; the clinic, the lift, the terminal and the high ledge. The door banyan_row_to_metro joins Banyan Row (62, 18) and the landing (2, 9). JUMPING now has the metro, and UNDERGROUND names it.
  • Tests (tests/street/test_metro.py): the way down and back on foot; every cell but the high ledge in reach of today's jump, and the ledge in reach with a three-row jump; the lift and terminal walked to but leading nowhere; the plug lit between dark stretches; light covering every cell once; secrets needing a jump; the stall spots; no resident with anywhere to go; and every hook's id and cell.
  • Art (server/simile/papercraft/): painter.cartoon and the cartoon references in content/papercraft/references/cartoon/; TUNNEL_LAYERS; furniture, a front Look and papers marked cartoon; sketches for the train, the catwalk, the steps and the lift. No village piece repainted.
    • Look gains plants, so the clinic has no potted plants, and whole, so it's painted in one go rather than as a terrace (Front.unit).
    • near-metro is cut as a ground piece keyed on its top row's colour (cut above, cutout.key's new bg), since the wall fills its sides.
  • positions.json has 94 metro cases: the client's sends down the stairway, on the three secrets' jumps and at the high ledge, and four places nobody could be.
  • The walk walks from Banyan Row through the metro into the clinic and back, jumps to the three secrets, and checks a run jump falls short of the high ledge. The generic legs pick up the metro's door, flights and ladders. 110 of 110 legs pass.

Notes

  • The gap behind the platform is closed at every camera height the metro has. The client puts mid-metro's foot 2.75 m above the feet, so near-metro, 4.5 m up from its foot, overlaps it by 1.75 m. In the metro the camera never rises: the highest place to stand is 8.8 m up, under the 9.9 m at which it starts to follow, and a jump keeps the height it left from. A rise would have to pass 4.4 m before the gap showed. The catwalk over the stairwell is the highest the camera gets.
  • Outside S3: The metro, by hand #350's Owns, each a list of maps, the walk, or one test line:
    • server/tests/world/test_paths.py lists the metro among the streets.
    • server/tests/papercraft/test_fronts.py: a unit can be wider than UNIT when the front is painted whole.
    • client/src/side/maps.test.ts counts the metro and the clinic's floor.
    • client/src/side/walk.e2e.ts and client/src/side/README.md: the metro's legs. A jump in the table can now land on another row (onto).
  • Residents' paths haven't changed. I ran test_simulate's day (seed 1, from 09:00) for 24 sim hours on main and on this branch, recording every EntityMoved: 48,616 moves on both, identical, with the same summary, none of them under the village.
  • The village is as it was. Every tile and object on main's maps is unchanged; Banyan Row only gains the door and the entrance's canopy.
  • Saves still load. On a copy of simile.db in a temp dir, all 11 residents came back on their saved tiles.
  • FLUX: 42 paintings at 8 bits, about 24 minutes:
    • 26 in 882 s, then the train (white under its bogies), the turnstiles (they looked like safes), the pipes (a valve wheel every metre once stretched), the entrance (stairs going up) and the new steps again in 143 s, and the catwalk once more in 28 s when formatting changed its sketch's source.
    • For the review, 291 s: the near wall, the mid wall without rails, the clinic whole and its glow, the narrower canopy, and the catwalk, steps and lift again when their sketches' docstrings were cut. Then the clinic and its glow at a new seed in 86 s, as the first whole one had a white sliver down its left edge.
    • Every repaint of an unchanged sketch came out byte for byte the same. content/papercraft/ is 9.4 MB of its 12.

Follow-ups

  • Underground ignores the time of day. The client tints the metro by the village's clock, so it's dark blue at night. Probably part of S4's darkness.
  • Per-street ledges, ladders and steps. The client draws one set for every street. The metro covers its ledges and steps with furniture; a street's own pieces in the manifest would be cleaner.
  • Lower ground draws as the river. The client draws any ground below a street's usual row as Banyan Row's promenade, so the metro has no pits. S9's sewers will want them.

🤖 Generated with Claude Code

jamescrosswell and others added 4 commits October 23, 2026 02:56
An abandoned station under the village, 110 wide: a landing and two flights down through the
ticket hall to the platform, a dead train with a catwalk above it, a service tunnel, and a depot
with the clinic, the lift down to the sewers, a dead terminal and a high ledge a row above today's
jump. Every map gains two object layers, light and pickups, for the dark stretches, salvage and
secrets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Six layers, the clinic's front, glow and room paper, and fifteen pieces of furniture, painted from
#329's cartoon references, plus a papercraft metro entrance on Banyan Row's promenade. The metro's
catwalks and steps are furniture over the street's own ledges and steps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It walks from Banyan Row down into the metro, through it into the clinic and back up, jumps up to
the metro's three secrets, and checks a run jump falls short of the high ledge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jamescrosswell

Copy link
Copy Markdown
Contributor Author

Changes requested. Two small ones. The map, the hooks and the tests are right.

Changes

  1. A gap behind the platform shows the vault's ribs.
    • What you see: between the foot of mid-metro and the top of near-metro's tiled wall there's a band about 1.5 m tall. Through it you see the metro-vault backdrop. Because of it the track floats at the height of the train's roof. It's in platform.jpg, train-roof.jpg, vault-catwalk.jpg, the tunnel shots and the GIFs.
    • Why: the client puts mid's foot 2.75 m above the feet (LAYER_PLACES), and near-metro is a short strip. Outdoors the gap shows sky.
    • Fix, inside Owns: paint near-metro as a solid wall tall enough to overlap mid's foot at every camera height, and take the rails off mid's foot. Or paint the bottom of metro-vault as plain shadow.
  2. Cut these to one line:
    • metro.py: entrance, platform, tunnel, depot and lighting
    • plan.py: Pickup
    • catalogue.py: tunnel_layer
    • painter.py: reference
    • sketches.py: catwalk, metro_steps and freight_lift
    • walk.e2e.ts: metroLeg

Checked and fine

  • Scope. The four files outside Owns are only the counts, the walk legs and onto. No schema change. Merges cleanly with S5: The player gets hungry #369 and S12: Aris and the incident #368.
  • Done-when. The walk covers the metro, and CI ran 110 of 110 legs. The ledge is proved out of reach by the path rule, positions.json and the walk. The lift and terminal lead nowhere, and machines get nothing on E.
  • The village.
    • Every cell and object on main's 36 maps is unchanged. Banyan Row gains only the door and the canopy, and the rest gain only the empty layers.
    • I re-ran the 24-hour day on both branches: 48,616 moves each, identical, none in the metro.
    • No activity, wander, spot or route reaches the metro.
  • Hooks.
    • S6: the salvage spots map one to one onto Pile. The two cash secrets don't, because Pile holds only items.
    • S8: three rows means a rise of about 3.3 tiles, which is plausible for the legs. But moves.possible and jump.json read one global JUMP, so S8 needs a jump per player.
    • S9: the link down would be a door between two streets, from the lift foot. test_metro's check that no map is called sewer will trip it.
  • Art and code.
    • Only new files in content/papercraft/, 9.5 of 12 MB. The pieces are clean.
    • No API use, no module-level imports, nothing personal.
    • Tests pass: 918 in tests/street, tests/world and tests/papercraft, and 510 in vitest src/side.

Taste, for you

  • The station: the tiles, teal band and ribs read well. The bays and smudges repeat at the same rhythm.
  • The grime is light, with room left for the sewers.
  • The canopy reads as a metro, but the signpost crosses its edge.
  • The tunnel is the same hall until S4.
  • The clinic reads well. Its roof shows a seam, and inside, the village's papercraft door and curtains sit on cartoon tiles.
  • The landing and the ticket hall reuse the platform's yellow safety line.
  • The follow-ups are right: the night tint, per-street pieces and pits.

jamescrosswell and others added 2 commits October 23, 2026 04:28
…ve the canopy

- near-metro is a solid tiled wall 4.6 m tall, keyed on its top row's colour, so it hides the foot
  of mid-metro, which no longer has rails.
- The clinic's front is painted in one go (Look.whole), with no seam in its roof.
- The canopy is narrower and left of the signpost, whose post no longer crosses it.
- Comments cut to one line, and test_metro no longer minds a map called sewer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jamescrosswell

Copy link
Copy Markdown
Contributor Author

Approved. Both items from the last review are fixed.

The two items

  • The gap is closed at every camera height.
    • near-metro now reaches 4.6 m and covers the foot of mid-metro.
    • The camera can't rise in the metro. viewCentre only lifts the view once the player's steady feet are 9.88 m up, which is (0.82 − 0.3) × 19 m. The highest standing point is 8.8 m, and the camera ignores jumps. So the layers never shift vertically, and the one height in the shots is the only height.
    • All the retaken shots show a solid wall from the platform to the arches. That includes stairwell-catwalk.jpg and alcove.jpg, the highest places.
  • The comments. Every docstring I listed is now one line.

The new cut option

The new cut option can't change any existing piece:

  • The above cut: build.py takes the above branch only when "above" in piece.cut, and near-metro is the only piece with it.
  • cutout.key: its new bg defaults to None, so every existing caller behaves as before.
  • Front.unit: it defaults to UNIT. _fields hashes only fields that differ from their defaults, so the new field leaves other fronts' hashes alone.
  • The manifest: this round only changed entries for metro and clinic pieces. catwalk, metro_steps and freight_lift changed only because their sketches' docstrings did.

Everything else

  • Only new files in content/papercraft/, now 9.48 MB of 12.
  • No map cell changed since 4fb33db: only the canopy got narrower.
  • Merges cleanly with S6 (S6: Salvage, and selling it #373), which already reads metro_salvage_*.
  • The cash secrets now fit Pile, which can hold money since S6a: Contract: salvage and selling #372.
  • Tests pass: 918 in tests/street, tests/world and tests/papercraft, 511 in vitest src/side. All 7 CI checks are green.
  • The one line outside Owns, in test_fronts.py, only loosens the check for a front painted as a single unit.

Nits, none blocking

  • Painting.cut's docstring in catalogue.py has grown to two lines. Trim it in passing.
  • There's a 1 px light seam where copies of the near wall meet. You can see it in platform.jpg by the ladder, and in train-roof.jpg right of the train. The village's near layers have clear edges, so their joins don't show, but a solid wall shows the join. Where copies are placed is client code, so this is a follow-up rather than S3's.

Taste, for you

  • The canopy: its left eave just touches the news kiosk, which is fine. You go down beside the canopy, at the signpost, rather than under it.
  • The clinic: it's whole now, with no seam. The faint light line down its left edge is barely visible, even at night. Its two neon crosses go dark at night because they aren't in the glow.
  • The station: with the rails gone, only the blurred foreground has track, so the train stands on the platform. The sack piles are bigger now, and they repeat about every 10 m.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jamescrosswell

Copy link
Copy Markdown
Contributor Author

Approved. The only change since 45ce675 is Painting.cut's docstring in catalogue.py, which is now one line (git diff 45ce675 f67789b: 1 file, +1 −2). All 7 checks are green, so my approval at 45ce675 stands.

@jamescrosswell
jamescrosswell marked this pull request as ready for review October 22, 2026 16:42
@jamescrosswell
jamescrosswell merged commit 3bd04b0 into main Oct 22, 2026
7 checks passed
@jamescrosswell
jamescrosswell deleted the task/350-metro branch October 22, 2026 16:42
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.

S3: The metro, by hand

1 participant