Fold the menu into the title screen, and stop the theme restarting
The menu stage was the same logo on the same backdrop with two buttons, so it read as the title screen failing to advance. The buttons move onto the title screen in place of the control list, which is the tutorial's job now. Death no longer reloads the page. The reload was an honest full reset, but it also tore down the AudioContext — so the theme restarted from silence every time you died, when it should carry straight on from the death summary into the title screen. restartRun() puts G, P, O, ball and score back from a structuredClone taken at module load (all plain data, so the clone is the whole job and a field added later is covered for free), and the two modules with timers of their own reset themselves: every zombies array plus spawnT/moanT/ mgTick, and input's held keys and half-finished drags, which would otherwise be inherited by the next run's first frame. The overlay is hidden rather than removed so it can come straight back, which needs its own [hidden] rule to beat the display:grid on #intro. The theme starts on the first tap and never restarts: loopBed's beds.has guard already makes every later menuMusic() a no-op. Verified: one background-music fetch across launch -> run -> death -> title -> second run, and a full second run through the transition after the in-place reset. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2d4fa79258
commit
d3aabc4bd6
7 files changed
+114
-74
No files matched your search
+27
-12
@@ -454,11 +454,29 @@ death summary is the end menu, and the zombie bed ducks out as it comes in. Two
|
||||
bed's gain at 0. Without it, a multi-megabyte file ducked mid-fetch comes up at full level several
|
||||
seconds later, over the match.
|
||||
|
||||
**The overlay is a four-stage machine**, not a screen per DOM node: `#intro[data-stage]` swaps
|
||||
`splash -> menu -> {courts, tutorial}` while the backdrop and card frame stay mounted, because a
|
||||
screen that unmounts the overlay flashes the live court through between menus. Court tiles SELECT
|
||||
only; `START GAME` and `BACK` are their own buttons. The tutorial is a data table (`TUT` in main.js)
|
||||
of Marvin poses, an optional picture already in `assets/`, and his lines — adding a page is a row.
|
||||
**The overlay is a three-stage machine**, not a screen per DOM node: `#intro[data-stage]` swaps
|
||||
`splash -> {courts, tutorial}` while the backdrop and card frame stay mounted, because a screen that
|
||||
unmounts the overlay flashes the live court through between menus. **The title screen IS the menu** —
|
||||
a separate menu stage behind it was the same logo on the same backdrop with two buttons, and read as
|
||||
the title screen failing to advance. Court tiles SELECT only; `START GAME` and `BACK` are their own
|
||||
buttons. The tutorial is a data table (`TUT` in main.js) of Marvin poses, an optional picture in
|
||||
`assets/`, and his lines — adding a page is a row.
|
||||
|
||||
**DEATH NO LONGER RELOADS THE PAGE.** `location.reload()` was an honest full reset and for a long
|
||||
time the right call — but it also tore down the AudioContext, so the menu theme restarted from
|
||||
silence every time you died, when it is supposed to carry straight on from the death summary into
|
||||
the title screen. `gameplay.restartRun()` replaces it:
|
||||
|
||||
- `state.resetState()` restores `G`, `P`, `O`, `ball` and `score` from a `structuredClone` taken at
|
||||
module load. Everything in those bags is plain data, so the clone is the whole job — nothing has
|
||||
to enumerate fields, and a field added later is covered for free.
|
||||
- The two modules with timers of their own put them back themselves: `zombies.resetZombies()` (every
|
||||
array plus `spawnT`/`moanT`/`mgTick`) and `input.resetInput()` — a key still held or a
|
||||
half-finished drag would otherwise be inherited by the next run's first frame.
|
||||
- The overlay is **hidden, not removed**, so it can come straight back. `#intro[hidden]` needs its
|
||||
own rule because the `display: grid` on `#intro` would otherwise beat the hidden attribute.
|
||||
|
||||
**If you add module-level mutable state anywhere, it belongs in one of those reset functions.**
|
||||
|
||||
**Menu and tutorial art is generated DIRECTLY, not through `_regen.py`.** That pipeline keys magenta
|
||||
and slices figures out of a sheet; these are whole illustrated panels with backgrounds, so they go
|
||||
@@ -478,13 +496,10 @@ Generated type is a lottery and would not match the rest of the HUD. `btn_start`
|
||||
a taller plate: by there the drips have run out to the ends and the centre is clear enough to print
|
||||
over, and the plate's own bottom border comes with it.
|
||||
|
||||
**The menu theme starts on the FIRST TAP, never at boot** (`go()` calls `menuMusic`). A title screen
|
||||
that plays at you before you touch it is rude, and on a phone the autoplay policy would have held it
|
||||
silent until that tap regardless.
|
||||
|
||||
**Death returns to the MENU, not the splash.** `maybeRestart` still reloads — that is the honest
|
||||
full reset and nothing has to unwind a run by hand — but it sets `sessionStorage.splatterStage` on
|
||||
the way out, and boot consumes it to open at the menu.
|
||||
**The menu theme starts on the FIRST TAP, never at boot.** A title screen that plays at you before
|
||||
you touch it is rude, and on a phone the autoplay policy would have held it silent until that tap
|
||||
regardless. `loopBed`'s `beds.has` guard makes every later `menuMusic()` a no-op, which is what lets
|
||||
the title screen pick up the track already playing instead of restarting it.
|
||||
|
||||
**The theme is AAC** (`background-music.m4a`, 768 KB — the WAV was 8.3 MB, and this one downloads on
|
||||
every page load before the player has decided to play). `loopBed` takes the FULL filename now,
|
||||
|
||||
Reference in new issue
Block a user