Multiplayer - Division Map - track design should not be horseshoe / square, but a single row (w/no running track) #18

Closed
opened 2026-08-26 04:03:01 +00:00 by Jesse.Markowitz · 3 comments
Owner

1 row for entire division.0

Westbound DP is in far left. Eastbound DP is far right.

Division map should not show any office area detail (no limits, no running track, etc.).

WDP - ML - A.Office - ML - J.Office - ML - R.Office - ML - B.office - EDP

1 row for entire division.0 Westbound DP is in far left. Eastbound DP is far right. Division map should not show any office area detail (no limits, no running track, etc.). WDP - ML - A.Office - ML - J.Office - ML - R.Office - ML - B.office - EDP
Author
Owner

Reviewed against the code. This is two separate changes, and the first one settles a large part of the Display backlog rather than adding to it.

What is there today

divisionSvg (src/sim/board-svg.ts) lays the route out around a table: one row for a single seat, two facing rows for two, a horseshoe for three, a square for four. That was deliberate — "players sit around a table, so the route is laid out the way they do" — and it is the direct cause of three separate reports.

Separately, an Office node does not draw as one cell. It expands into its whole Running Track, Limits to Limits (DivisionView.running, built in view.ts), so the Division map currently carries every straight, turnout, facility and Limits sign on the running row of every district.

Both halves of this issue are removals.

It closes four open Display items and contradicts a fifth

From TODO.md, queued from play:

# item with a single row
20 run the inter-row connector round the OUTSIDE, draw it as rail moot — no second row to connect
21 / 26 the buffer stop points the wrong way once the route wraps moot — both ends face outward, nothing wraps
22 fill the dead centre of the map with the common board moot — no centre
27 CONFIRMED IN PLAY: east is not always to the right fixed outright — one row means east is always right
25 the Division map does not draw track geometry moot here — the geometry lives on the Office map, which does draw it

Item 24 is the contradiction and needs your call. It asks to put the viewer's own district at the BOTTOM of the map and wrap the table around them, "so the screen sits you at the table". That cannot coexist with a single row. My read is that #18 supersedes it — the reason for wrapping was to seat you at the table, and the reason against is that it costs you "east is right", which is the more important of the two on a railroad. But 24 was your request, so I would rather have that confirmed than assume it.

A side benefit worth having

The map currently changes width as districts grow. An Office is drawn Limits-to-Limits, so every card added to a Running Track widens that cell group and shifts everything east of it sideways. Collapsing an Office to one cell makes the Division map a fixed size for a given player count — it stops moving under you mid-game.

Two things to settle before it is built

1. The sketch is one Mainline card short. buildDivision lays WDP · (ML · Office) × players · ML · EDP — so there is a Mainline card between the LAST Office and the East DP as well:

WDP - ML - A.Office - ML - J.Office - ML - R.Office - ML - B.Office - **ML** - EDP

That is five cards for four players, and a train leaving the easternmost district really does cross one more before it retires. I read your line as shorthand rather than a rule change, but the drawing should follow the engine.

2. Where does a train standing on the Running Track but NOT at the Office go? A crew can be part-way along its own running row, and today it is drawn on the card it is standing on. With the district collapsed to one cell there is nowhere to put it. Options: fold it into the Office cell alongside the A/D chips; or count it, the way trains switching below the Running Track are already counted ("2 switching below"). I would keep it visible somehow — a train that vanishes off the shared map is the complaint that produced the expansion in the first place.

I am assuming "no office area detail" means hide the track, not the trains: the Office cell keeps the owner's name, the A/D count, and the chips standing there. Say if you meant it more strictly than that.

Effort

Mostly deletion — the lane/table layout, the vertical rail renderer and the per-seat direction table all go, about eighty lines. The two constraints on the work: divisionSvg is embedded into the standalone replay by Function.toString(), so it must stay self-contained and may not gain an import; and web.test.ts asserts the current geometry ("seats 1 to 4 players without overlapping or spilling off the canvas") and will need rewriting against the row rather than being weakened.

No code changed yet — flagging the two questions above first.

**Reviewed against the code. This is two separate changes, and the first one settles a large part of the Display backlog rather than adding to it.** ### What is there today `divisionSvg` (`src/sim/board-svg.ts`) lays the route out **around a table**: one row for a single seat, two facing rows for two, a horseshoe for three, a square for four. That was deliberate — "players sit around a table, so the route is laid out the way they do" — and it is the direct cause of three separate reports. Separately, an Office node does not draw as one cell. It **expands into its whole Running Track, Limits to Limits** (`DivisionView.running`, built in `view.ts`), so the Division map currently carries every straight, turnout, facility and Limits sign on the running row of every district. Both halves of this issue are removals. ### It closes four open Display items and contradicts a fifth From `TODO.md`, queued from play: | # | item | with a single row | | --- | --- | --- | | 20 | run the inter-row connector round the OUTSIDE, draw it as rail | **moot** — no second row to connect | | 21 / 26 | the buffer stop points the wrong way once the route wraps | **moot** — both ends face outward, nothing wraps | | 22 | fill the dead centre of the map with the common board | **moot** — no centre | | 27 | CONFIRMED IN PLAY: east is not always to the right | **fixed outright** — one row means east is always right | | 25 | the Division map does not draw track geometry | **moot here** — the geometry lives on the Office map, which does draw it | **Item 24 is the contradiction and needs your call.** It asks to put the viewer's own district at the BOTTOM of the map and wrap the table around them, "so the screen sits you at the table". That cannot coexist with a single row. My read is that #18 supersedes it — the reason for wrapping was to seat you at the table, and the reason against is that it costs you "east is right", which is the more important of the two on a railroad. But 24 was your request, so I would rather have that confirmed than assume it. ### A side benefit worth having The map currently **changes width as districts grow**. An Office is drawn Limits-to-Limits, so every card added to a Running Track widens that cell group and shifts everything east of it sideways. Collapsing an Office to one cell makes the Division map a fixed size for a given player count — it stops moving under you mid-game. ### Two things to settle before it is built **1. The sketch is one Mainline card short.** `buildDivision` lays `WDP · (ML · Office) × players · ML · EDP` — so there is a Mainline card between the LAST Office and the East DP as well: `WDP - ML - A.Office - ML - J.Office - ML - R.Office - ML - B.Office - **ML** - EDP` That is five cards for four players, and a train leaving the easternmost district really does cross one more before it retires. I read your line as shorthand rather than a rule change, but the drawing should follow the engine. **2. Where does a train standing on the Running Track but NOT at the Office go?** A crew can be part-way along its own running row, and today it is drawn on the card it is standing on. With the district collapsed to one cell there is nowhere to put it. Options: fold it into the Office cell alongside the A/D chips; or count it, the way trains switching below the Running Track are already counted ("2 switching below"). I would keep it visible somehow — a train that vanishes off the shared map is the complaint that produced the expansion in the first place. I am assuming "no office area detail" means hide the **track**, not the **trains**: the Office cell keeps the owner's name, the A/D count, and the chips standing there. Say if you meant it more strictly than that. ### Effort Mostly deletion — the lane/table layout, the vertical rail renderer and the per-seat direction table all go, about eighty lines. The two constraints on the work: `divisionSvg` is embedded into the standalone replay by `Function.toString()`, so it must stay self-contained and may not gain an import; and `web.test.ts` asserts the current geometry ("seats 1 to 4 players without overlapping or spilling off the canvas") and will need rewriting against the row rather than being weakened. No code changed yet — flagging the two questions above first.
Author
Owner

Settled with Jesse, 2026-08-26. This is the design; recording it here so it is not left in a chat log.

The layout

One row, west to east, no wrapping:

WDP - ML - A.Office - ML - J.Office - ML - R.Office - ML - B.Office - ML - EDP

The sketch in the issue was one Mainline card short and Jesse has confirmed that — buildDivision lays WDP · (ML · Office) × players · ML · EDP, so there is a Mainline card between the last Office and the East Division Point as well. A train leaving the easternmost district really does cross one more before it retires.

No office-area detail: an Office draws as ONE cell, not as its Running Track expanded Limits-to-Limits the way it is today.

What this closes

It definitively supersedes TODO.md item 24 — "put the viewer's own district at the BOTTOM of the Division map and wrap the table around them". A single row and a table wrapped around the viewer cannot both hold, and the row wins: being able to rely on east meaning right is worth more than being seated at the table.

And it makes four more irrelevant rather than fixing them: the inter-row connector (20), the buffer stops pointing the wrong way once the route wraps (21, and 26 which confirmed it in play), filling the dead centre of the map with the common board (22), and drawing track geometry on this map (25 — the geometry belongs on the Office map, which already draws it). Item 27, "east is not always to the right", is fixed outright.

What an Office cell carries

  • the owner's name as the headline, and the A/D count (n of m);
  • a chip for every train in the district, not only those holding an A/D track.

A train at an A/D track must be visually distinct from a crew switching in the district. They are different things: A/D occupancy is a hard capacity that causes collisions, switching below the Running Track is not. Proposed as structure rather than decoration — the cell holds two registers, A/D above and switching below — so the distinction is where the chip sits rather than a colour to learn.

Per chip, at a glance: the train number and its direction, eastbound or westbound. On the tooltip: what it is hauling. All three already exist in the data — a chip carries its label, its facing, and its full consist with the engine drawn at the position it actually occupies, so this is a layout job and not a plumbing one.

Sizing, measured rather than guessed

Over 60 games and 20,140 samples, one office area holds at most 4 distinct trains (mean 0.33). Up to 3 of those can be crews switching below the Running Track and up to 2 standing on it.

That matters because the Office cell is currently sized by A/D capacity — one slot at a Whistle Post — and crews switching below do not occupy A/D tracks. So a one-slot cell can need to show four trains. Sizing by occupancy instead is exactly what "The Roster Pass" fixed: the cell then resizes whenever a train arrives and shoves the rest of the map sideways. So every Office cell is sized for four chips regardless of tier, stacked two-by-two.

Resulting canvas, against 842 x 608 today at four players:

layout width
all Whistle Posts, chips in a line ~1,410
four Terminals, chips in a line ~2,010
2 x 2 stacking, fixed all game ~1,580

Horizontal scrolling and zooming are accepted — Jesse: "as per earlier multiplayer design, zooming and scrolling worked fine." The row is only ~132px tall, so vertical space is free and horizontal space is the scarce thing; the 2 x 2 stacking spends the free dimension and holds the map still as offices upgrade.

One question that answered itself

I had asked whether a district's own local crew should get a chip. It should not, because it does not exist: a Crew Tray may carry trainNumber: null and four files render it as "the local crew — no timetable, no card, no special rules", but nothing in the engine ever creates one. Measured at zero across 26,458 decision points in 80 games, and no rule in the docs describes it. Every train in an office area has a number.

Whether a player's own switcher SHOULD exist is a rules question for RAR, and a separate one from this issue.

Not changing

Mainline cards keep their region bars — a card is 1 to 3 regions after Gitea#3 and a train's position within it stays drawn. Trains standing in the Interchange's yard stay drawn on the card and counted against nothing, as now.

Implementation note

divisionSvg is embedded into the standalone replay by Function.toString(), so it must stay self-contained and may not gain an import. The work is mostly deletion — the lane layout, the vertical rail renderer and the per-seat direction table, around eighty lines. web.test.ts asserts the current geometry across 1 to 4 players and will be rewritten against the row rather than weakened.

**Settled with Jesse, 2026-08-26. This is the design; recording it here so it is not left in a chat log.** ### The layout One row, west to east, no wrapping: `WDP - ML - A.Office - ML - J.Office - ML - R.Office - ML - B.Office - ML - EDP` **The sketch in the issue was one Mainline card short and Jesse has confirmed that** — `buildDivision` lays `WDP · (ML · Office) × players · ML · EDP`, so there is a Mainline card between the last Office and the East Division Point as well. A train leaving the easternmost district really does cross one more before it retires. No office-area detail: an Office draws as ONE cell, not as its Running Track expanded Limits-to-Limits the way it is today. ### What this closes **It definitively supersedes `TODO.md` item 24** — "put the viewer's own district at the BOTTOM of the Division map and wrap the table around them". A single row and a table wrapped around the viewer cannot both hold, and the row wins: being able to rely on east meaning right is worth more than being seated at the table. And it makes four more irrelevant rather than fixing them: the inter-row connector (20), the buffer stops pointing the wrong way once the route wraps (21, and 26 which confirmed it in play), filling the dead centre of the map with the common board (22), and drawing track geometry on this map (25 — the geometry belongs on the Office map, which already draws it). **Item 27, "east is not always to the right", is fixed outright.** ### What an Office cell carries - the owner's **name** as the headline, and the **A/D count** (`n of m`); - a **chip for every train in the district**, not only those holding an A/D track. **A train at an A/D track must be visually distinct from a crew switching in the district.** They are different things: A/D occupancy is a hard capacity that causes collisions, switching below the Running Track is not. Proposed as structure rather than decoration — the cell holds two registers, A/D above and switching below — so the distinction is where the chip sits rather than a colour to learn. Per chip, at a glance: the **train number** and its **direction**, eastbound or westbound. On the tooltip: **what it is hauling**. All three already exist in the data — a chip carries its label, its facing, and its full consist with the engine drawn at the position it actually occupies, so this is a layout job and not a plumbing one. ### Sizing, measured rather than guessed Over 60 games and 20,140 samples, **one office area holds at most 4 distinct trains** (mean 0.33). Up to 3 of those can be crews switching below the Running Track and up to 2 standing on it. That matters because the Office cell is currently sized by A/D capacity — **one slot at a Whistle Post** — and crews switching below do not occupy A/D tracks. So a one-slot cell can need to show four trains. Sizing by occupancy instead is exactly what "The Roster Pass" fixed: the cell then resizes whenever a train arrives and shoves the rest of the map sideways. So every Office cell is sized for **four chips regardless of tier**, stacked two-by-two. Resulting canvas, against 842 x 608 today at four players: | layout | width | | --- | --- | | all Whistle Posts, chips in a line | ~1,410 | | four Terminals, chips in a line | ~2,010 | | **2 x 2 stacking, fixed all game** | **~1,580** | **Horizontal scrolling and zooming are accepted** — Jesse: "as per earlier multiplayer design, zooming and scrolling worked fine." The row is only ~132px tall, so vertical space is free and horizontal space is the scarce thing; the 2 x 2 stacking spends the free dimension and holds the map still as offices upgrade. ### One question that answered itself I had asked whether a district's own **local crew** should get a chip. It should not, because it does not exist: a Crew Tray may carry `trainNumber: null` and four files render it as "the local crew — no timetable, no card, no special rules", but **nothing in the engine ever creates one**. Measured at zero across 26,458 decision points in 80 games, and no rule in the docs describes it. Every train in an office area has a number. Whether a player's own switcher SHOULD exist is a rules question for RAR, and a separate one from this issue. ### Not changing Mainline cards keep their region bars — a card is 1 to 3 regions after Gitea#3 and a train's position within it stays drawn. Trains standing in the Interchange's yard stay drawn on the card and counted against nothing, as now. ### Implementation note `divisionSvg` is embedded into the standalone replay by `Function.toString()`, so it must stay self-contained and may not gain an import. The work is mostly deletion — the lane layout, the vertical rail renderer and the per-seat direction table, around eighty lines. `web.test.ts` asserts the current geometry across 1 to 4 players and will be rewritten against the row rather than weakened.
Author
Owner

Implemented in v0.7.2 (2ab25e3).

Not ported to the 0.4.9 playtest line, deliberately. It is a multiplayer redesign, and pushing
one of those into the build people are mid-playtest on invalidates the feedback. At one player the
old code already drew a single row, so the 0.4.9 testers lose nothing but the office-area detail —
and that can follow whenever the line is next rebased.

Built as agreed above: one row west to east, WDP - ML - Office - ... - ML - EDP including the
Mainline card before the East Division Point that the sketch omitted; one cell per district with no
office-area detail; trains kept in two registers, those holding an A/D track ON the rail and crews
switching in the district UNDER it. Each chip carries its number, a direction arrow and a car count,
with the consist and the train's printed card on the tooltip. Every district cell is four chips
two-by-two regardless of tier.

1,580px wide at four players against 842 before, drawn at 1:1 so it scrolls rather than shrinking
— .bs is width:100%, which would have rendered every label at half size in a panel narrower than
the map.

The layout test was rewritten rather than weakened: it asserted "a row, two facing rows, a horseshoe
and a square", and now asserts one row (a single distinct y, x strictly increasing west to east), the
right cell count including the trailing Mainline, and a Division Point at each end. That is what
makes "east is right" true, and it is what would silently regress if anyone reintroduced lanes.

TODO.md item 24 is struck through as superseded, 19-22 and 25-26 as irrelevant, and 27 as fixed.

Implemented in **v0.7.2** (`2ab25e3`). **Not ported to the 0.4.9 playtest line, deliberately.** It is a multiplayer redesign, and pushing one of those into the build people are mid-playtest on invalidates the feedback. At one player the old code already drew a single row, so the 0.4.9 testers lose nothing but the office-area detail — and that can follow whenever the line is next rebased. Built as agreed above: one row west to east, `WDP - ML - Office - ... - ML - EDP` including the Mainline card before the East Division Point that the sketch omitted; one cell per district with no office-area detail; trains kept in two registers, those holding an A/D track ON the rail and crews switching in the district UNDER it. Each chip carries its number, a direction arrow and a car count, with the consist and the train's printed card on the tooltip. Every district cell is four chips two-by-two regardless of tier. **1,580px wide at four players against 842 before**, drawn at 1:1 so it scrolls rather than shrinking — `.bs` is `width:100%`, which would have rendered every label at half size in a panel narrower than the map. The layout test was rewritten rather than weakened: it asserted "a row, two facing rows, a horseshoe and a square", and now asserts one row (a single distinct y, x strictly increasing west to east), the right cell count including the trailing Mainline, and a Division Point at each end. That is what makes "east is right" true, and it is what would silently regress if anyone reintroduced lanes. `TODO.md` item 24 is struck through as superseded, 19-22 and 25-26 as irrelevant, and 27 as fixed.
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Jesse.Markowitz/station-master#18