Skip to content

Edit coaster track from a selected piece - #194

Merged
jiro-by-nori[bot] merged 4 commits into
mainfrom
feat/edit-from-selected-track-piece
Nov 2, 2026
Merged

jiro-by-nori[bot] merged 4 commits into
mainfrom
feat/edit-from-selected-track-piece

Conversation

@jiro-by-nori

@jiro-by-nori jiro-by-nori Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

🤖 Generated with Nori

Players can now pick any piece of a coaster and edit from there. Before, the only option was to demolish from the last piece.

  • Select a piece.
    • From the park: click or tap a coaster's rails to open the ride window, then press Edit from this piece.
    • From the Ride construction window: with Track mode on, click or tap rails. Rails of another coaster switch the window to that coaster.
    • Effect: the piece pulses with a yellow outline and the window shows Selected piece N of M · <shape>. Selecting changes nothing on the track.
    • Trains, supports and riders: clicking one of these gives a hint instead of guessing a piece.
  • Navigate.
    • Previous piece / Next piece walk along the track and wrap round a circuit.
    • Track end goes back to the old build-at-the-end mode, which is still the default when nothing is selected.
    • Build before this piece extends the track backwards from a section's first piece.
  • Edit.
    • Demolish selected piece removes only that piece. It splits the track into sections, or opens a closed circuit there, and every later piece stays put.
    • After a demolish, the selection moves to the piece before the gap, so Build piece fills the gap.
    • Reconnecting closes the circuit again. The ride then needs a new test before it can open.
  • Safety, following the existing busy rule. Track edits are refused while the ride is open, testing, has a train out, or has riders aboard. The message is "Close the ride and wait for its train to return empty before changing the track." Previously an edit silently force-closed an open ride and removed its trains.
  • Station access stays consistent. Removing the station tile next to an entrance or exit detaches that entrance or exit. The ride then asks for a new one before it can open.
  • Feedback text. Demolishing now says "Track piece removed." instead of "Track piece placed."

How it works

  • Sim (src/sim/track/construction.ts):
    • A ride's track is one ring, or one or more open sections.
    • Any piece can be removed.
    • A placement can attach to any open end, which merges sections. closed is set only when everything forms a single ring.
    • head/tail track the section being built, so removeTrack -1 and the cursor behave as before.
    • No save format change: prev/next were already saved, and a save/load round trip with split sections is tested.
  • Snapshot: new trackLinks (id, prev, next per track row).
  • Coaster scene and picking: each sprite carries its pieceId and coasterPart. pickTrackPiece hit-tests coaster sprites only, by alpha and topmost first. Both Canvas2D and WebGL2 use the same pick targets, so rotation, stacked track and multi-tile pieces resolve to the visible piece.
  • Selection: editor-only UI state (piece id plus a geometry signature, which catches reused ids). It is never saved.

Behaviour references (described in docs/mechanics/track.md §2.8; original code, clean-room)

Test Plan

  • pnpm lint, pnpm format:check, pnpm typecheck, pnpm test (all pass locally).
  • New sim tests (track-editing.test.ts, track-edit-safety.test.ts):
    • Middle removal keeps the later pieces.
    • Gap rebuild, then test, then open, with a train carrying riders.
    • Several gaps filled in any order.
    • Backward build.
    • First and last piece.
    • Stale piece id.
    • Refusal while open, testing, or with a loaded train out. Allowed once the train is home.
    • Station removal detaches the entrance and exit.
    • Save/load of split track.
  • New UI and picking unit tests: build-before placement checked against the sim, prev/next stepping and ring wrap, open ends, stationless ring numbering, picking that never maps a train or support click to a piece, and refusal versus warning classification.
  • New e2e/track-edit-selection.spec.ts, WebGL2 and Canvas2D × desktop and Pixel 8 touch, 8/8 passing. Two flows:
    • Closed circuit: click a middle rail, check that exact piece is highlighted and nothing changed, demolish it, check the other 13 piece ids survive, rebuild, test, open, then a refused edit while open.
    • Unfinished and stacked track: pick the overpass, then the piece under it, demolish and reconnect, rotate the view and select again, then Previous to the first piece, build before it, Track end, and demolish last.
    • Editing in the closed-circuit flow runs while the game is paused.
  • pnpm e2e:quick: 12 passed. 2 context-menu tests failed with Chromium "Target crashed"; the same crash happens on main's code in this environment.
  • Coaster-related specs rerun. 10 failures in starter-ride-access, ride-access-repro and universal-clearance happen identically on main's code here (tile-coordinate calibration and timeouts). They are not caused by this PR, and CI does not run them.
  • Full pnpm e2e (329 tests, one worker, this machine): 173 passed, 116 failed, 40 skipped. I reran all 116 failures with main's code (--last-failed) and 115 failed the same way, so they come from this environment (Chromium crashes, coordinate calibration, guest spawning, art), not from this PR. The one difference was stall-storefront "explains a stall whose window faces no footpath". It failed once and then passed on this branch, so it is flaky. None of the 8 new track-edit tests failed.

Proof (before/after screenshots): see the PR comment.

Requested in Nori: https://demo.norisessions.com/chat/01a16c13-c814-7295-9955-b11ff875ed14

Share Nori with your team: https://www.npmjs.com/package/nori-skillsets

jiro-by-nori Bot and others added 4 commits November 2, 2026 07:08
Select any placed piece (click its rails in the track tool, or Edit from
this piece in the ride window), step with Previous/Next piece, then
demolish that piece or build from its open end. Removing a middle piece
splits the track into sections instead of refusing; placements join any
open end and close the circuit once one ring remains. Track edits are
refused while the ride is open, testing, has a train out or riders
aboard. Removing a station detaches a stranded entrance or exit.

Co-authored-by: Nori <contact@tilework.tech>
🤖 Generated with [Nori](https://noriagentic.com)

Co-Authored-By: Nori <contact@tilework.tech>
🤖 Generated with [Nori](https://noriagentic.com)

Co-Authored-By: Nori <contact@tilework.tech>
…; first piece of a new coaster may go beside other track

🤖 Generated with [Nori](https://noriagentic.com)

Co-Authored-By: Nori <contact@tilework.tech>
jiro-by-nori Bot added a commit that referenced this pull request Nov 2, 2026
… renderers, desktop and Pixel 8)

Co-authored-by: Nori <contact@tilework.tech>
@jiro-by-nori

jiro-by-nori Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

Proof: before and after (I checked every image myself)

All files are in the proofs branch at commit 1f97550e: https://github.com/tilework-tech/opencoaster/blob/1f97550ed509975a65c09c12afa41d6cb3133dea/pr-194
The README there explains each image.

Before (main)

In the track tool, a click on a middle rail only says the circuit is complete. Demolish last piece removes the end piece and reports "Track piece placed."
before: click middle
before: demolish last

After, WebGL2 desktop, closed circuit

The clicked middle piece (7 of 14) is outlined, and nothing on the track changed:
selected
Demolish selected piece removes only that piece. The other 13 piece ids survive, and the selection moves to the piece before the gap, with a preview of the next piece:
gap
Build piece reconnects the circuit. The e2e then tests and opens the ride, and confirms that an edit on the open ride is refused.
rebuilt

After, stacked track, rotation and the other renderer and devices

stacked

@jiro-by-nori
jiro-by-nori Bot merged commit 8eca345 into main Nov 2, 2026
1 check passed
jiro-by-nori Bot added a commit that referenced this pull request Nov 2, 2026
Co-authored-by: Nori <contact@tilework.tech>
@jiro-by-nori

jiro-by-nori Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

Live verification on https://opencoaster.noriagentic.com/ after #194 and the follow-up fix #195 (Previous piece now works on a closed circuit when nothing is selected). Pages deploy runs: https://github.com/tilework-tech/opencoaster/actions/runs/41431840467 and https://github.com/tilework-tech/opencoaster/actions/runs/41436435967 (both succeeded). Captures: https://github.com/tilework-tech/opencoaster/tree/8721b28da2d09e0df204d4416b850d1a159ca0d9/pr-194/live

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.

0 participants