Skip to content

Phones: frame the selected track piece and compact the construction window - #196

Merged
jiro-by-nori[bot] merged 1 commit into
mainfrom
phone-selected-piece-framing
Nov 2, 2026
Merged

jiro-by-nori[bot] merged 1 commit into
mainfrom
phone-selected-piece-framing

Conversation

@jiro-by-nori

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

Copy link
Copy Markdown
Contributor

Summary

🤖 Generated with Nori

Follow-up to #194/#195. On phones, picking a piece with Edit from this piece left it hidden under the ride and construction sheets, and the camera never framed it. Now you can see the selected piece and its controls together.

  • Camera framing (all screen sizes, only when needed).
    • When the selection changes (Edit from this piece, a rail tap, Previous/Next, or the follow-up after a build or demolish), the camera pans once.
    • It pans only if part of the piece's drawn rails is under a window, sheet or bar, or off screen. The piece is centred in the largest part of the map that nothing covers.
    • A piece that is already visible never moves the camera. Desktop clicks behave exactly as before, and the desktop captures match Edit coaster track from a selected piece #194 pixel for pixel apart from the outline pulse.
    • The camera never re-centres on ticks. If the player pans while a reveal is waiting, the player's camera wins.
  • Compact construction window on phones.
    • Applies to narrow screens (under 700 px) and short touch screens (landscape phones, 500 px tall or less).
    • The selection line, Previous/Next/Track end, the cost line and Build piece / Demolish come first, above the piece palettes.
    • On portrait phones the sheet is capped at 44 dvh and scrolls inside.
    • On short touch screens the construction buttons are at least 40 px tall.
  • Ride window. On those compact screens, Edit from this piece closes the ride window instead of stacking the construction window on top of it. Tapping the rails reopens it. Desktop keeps both windows.

Unchanged: track and economy rules, save format, desktop layout.

How it works

  • src/app/tools/selection-reveal.ts:
    • Pure largestFreeRect, and revealShift, which uses rail alpha masks so transparent sprite margins don't count.
    • SelectionReveal, driven each frame before the world draw. It waits until window rectangles are stable (window placement happens a few frames late), pans at most twice (first to the projected tile if the piece is off screen, then to its drawn rails), and then stops.
    • It drops the request if the piece is no longer selected or the camera moved.
    • It uses the same pick targets as both renderers, so WebGL2, Canvas2D and rotation all agree.
  • CoasterPanel.focusPiece is the one place where the selection changes. It calls the new optional reveal action.
  • COMPACT_QUERY lives in window-layout.ts. The CSS reorders controls with order behind the same media query.

Test Plan

  • pnpm lint, pnpm format:check, pnpm typecheck, and pnpm test (255 files, 2770 tests) pass.
  • New unit tests (selection-reveal.test.ts, 13 tests):
    • free area on portrait and landscape phones
    • a piece left alone when it is visible (including when that isn't the largest free area, and when only its transparent margin is under a bar)
    • hidden, partly covered and off-screen pieces centred in the free area
    • pieces larger than the free area
  • e2e/track-edit-selection.spec.ts: 10/10 pass across WebGL2 and Canvas2D × desktop, Pixel 8 portrait and a new Pixel 8 landscape (915×412, touch) run of the circuit flow. Additions:
    • expectPieceUncovered: at least 99% of the selected piece's rail pixels hit the canvas (no sheet or bar over them) and the outline matches the piece. Checked after Edit from this piece, Next and Previous, a demolish and a rebuild.
    • On phones, Previous, Next, Demolish and Build are fully in the viewport without scrolling.
    • On desktop, the camera does not move on Edit from this piece.
    • A manual pan survives 1.5 s of the game running. The next Next piece then brings the piece back.
    • Existing coverage is kept: touch taps in the track tool select without building (piece counts unchanged), rotation, stacked rails, demolish/rebuild of a middle section with all later pieces kept, retest/reopen, and the busy-ride refusal.
    • ridePieces now reads the snapshot in one evaluation. This fixes an intermittent detached-buffer read I hit once.
  • pnpm e2e:quick: 13 passed, 1 skipped, 1 failed. The failure is context-menu "with the patrol tool…", a Chromium Target crashed. It fails identically on clean main (7c5857f) in this environment, as Edit coaster track from a selected piece #194 also noted.
  • Related phone and construction specs:
    • mobile.spec "is playable on a phone" passes.
    • train-layout passes, both Canvas2D and the block-brakes test. They failed once while a second Playwright run was competing for CPU and passed when rerun alone, as they do on main.
    • mobile.spec "guest and footpath controls" and 7 starter-ride-access tests fail identically on clean main in this environment (tile calibration and timeouts, as Edit coaster track from a selected piece #194 noted). CI does not run them.
  • Visually checked before/after screenshots, both on main and on this branch, in portrait and landscape. Proof: https://github.com/tilework-tech/opencoaster/tree/dcaf856ce546924d2b5993833a622da2340fcd2c/pr-196 (images in 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

… window

Co-authored-by: Nori <contact@tilework.tech>
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

Proof

All files are at proofs commit dcaf856ce546924d2b5993833a622da2340fcd2c (immutable): https://github.com/tilework-tech/opencoaster/tree/dcaf856ce546924d2b5993833a622da2340fcd2c/pr-196. The README there explains each capture.

Pixel 8 portrait, Edit from this piece (piece 7 of 14)

main (before) this PR (after)

Short landscape phone (915×412), Edit from this piece

main (before) this PR (after)

After: Next piece, gap after demolish, and rebuilt circuit (Canvas2D, Pixel 8)

Next (8 of 14) gap after demolish landscape rebuilt

Desktop is unchanged: compare https://raw.githubusercontent.com/tilework-tech/opencoaster/dcaf856ce546924d2b5993833a622da2340fcd2c/pr-196/after/webgl2-desktop-circuit/circuit-selected-full.png with #194's capture of the same view. Mean RGB difference is 0.13, which is the outline pulse.

@jiro-by-nori
jiro-by-nori Bot merged commit 152523b 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

Merged as 152523b. Pages deploy https://github.com/tilework-tech/opencoaster/actions/runs/41459867533 succeeded. The deployed CSS contains the compact-construction rules.

Checked on https://opencoaster.noriagentic.com with an emulated Pixel 8, tapping a circuit rail and then Edit from this piece. The ride window closes, piece 7 of 14 is highlighted clear of the construction window, and Previous/Next/Build are fully on screen. Proof commit (immutable): https://github.com/tilework-tech/opencoaster/tree/34ee47a329afd161d8ce203e4112a1443df850f5/pr-196/live

portrait landscape

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