Put a menu in front of the game, with Marvin to explain it

The overlay is a four-stage machine now — splash -> menu -> {courts, tutorial}
— swapped by data-stage while the backdrop and card frame stay mounted, so the
live court never flashes through between screens.

Court tiles SELECT only. Tapping one used to start the match on the spot, which
gave you no way to compare the three and no way back out; START GAME and BACK
are their own buttons now. Headlines are 15px against the 11px body, so a screen
reads as a screen rather than as a list.

The tutorial is a data table: a Marvin pose, an optional picture already in
assets/, and his lines. Seven pages covering tennis, the turn, the slingshot,
the rack and the duel. Marvin is four new frames off x_boymop1 — waving,
pointing, shrugging, and clutching his mop in terror.

The theme no longer starts at boot. A title screen that plays at you before you
have touched it is rude, and the autoplay policy would have held it silent until
that first tap anyway.

Death returns to the menu instead of the title. The reload stays — it is the
honest full reset — and a sessionStorage flag is what picks the stage on the way
back in.

Machine-gun rounds are tennis balls, so they are drawn as balls and take the
perspective. A fixed 4x4 fillRect was exactly as big at the far baseline as at
your feet, which read as square confetti pinned to the screen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-08-01 13:31:00 +02:00
1 parent 60f7ce2cf1
commit 9a65a50cc4
10 files changed
+199 -44

No files matched your search

+4 -4
View File
@@ -111,10 +111,10 @@ export const ambient = () => loopBed('tennis-ambient-loop.wav', 500, 0.035); //
// 982597 frames at 48 kHz, which is the un-round 20.47077 s below — an AAC loop needs the SOURCE
// length as loopEnd, not the decoder's padded one. See the note on menuMusic.
export const zombieMusic = () => loopBed('zombie-mode.m4a', 800, 0.2, 20.47077);
// Menu theme: the splash, the court picker, the death summary. Barely highpassed — this one is
// MUSIC, not an atmosphere bed, so the low end is the point. Started at boot so it is already
// running by the time the title is on screen; on a phone the autoplay policy holds the context
// suspended until the first tap, and it becomes audible then (see loopBed).
// Menu theme: every menu screen and the death summary. Barely highpassed — this one is MUSIC, not
// an atmosphere bed, so the low end is the point. Started by the FIRST TAP (main.js `go`), never at
// boot: a title screen that starts playing at you before you have touched it is rude, and on a phone
// the autoplay policy would have held it silent until that tap anyway.
// AAC, not WAV: 48 s of stereo music is 8.3 MB as a WAV and this one downloads on every page load,
// before the player has decided to play anything. 768 KB encoded, and the master is exactly 48.000 s
// — which is the loopEnd, because the decoded buffer is NOT (measured 48.0174 s in Chrome; see the