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
+12
-27
@@ -57,7 +57,7 @@
|
||||
/* desktop key hint — up in the empty top-right corner now that the rack owns the bottom edge */
|
||||
#hint { position: fixed; top: 6px; right: 10px; text-align: right;
|
||||
font: 400 10px Silkscreen, monospace; color: #6b7688; }
|
||||
@media (pointer: coarse) { #hint, #intro .kb { display: none; } }
|
||||
@media (pointer: coarse) { #hint { display: none; } }
|
||||
#intro { position: fixed; inset: 0; z-index: 10; touch-action: none; display: grid; place-items: center;
|
||||
background: radial-gradient(circle at 50% 34%, rgba(34,16,20,0.92), rgba(8,10,16,0.96)); }
|
||||
#intro .card { font: 400 11px Silkscreen, monospace; color: #dfe6f2; text-align: center; line-height: 1.9;
|
||||
@@ -66,24 +66,21 @@
|
||||
/* the logo is generated pixel art now (assets/logo.png), not stacked CSS text */
|
||||
#intro .logo { display: block; width: min(320px, 78vw); height: auto; margin: 0 auto 8px;
|
||||
image-rendering: pixelated; filter: drop-shadow(0 3px 0 rgba(0,0,0,0.45)); }
|
||||
#intro .slogan { margin: 8px 0 16px; font-size: 12px; color: #b6a0a4; letter-spacing: 0.5px; }
|
||||
/* the slogan carries most of the gap between the logo's blood and the first button */
|
||||
#intro .slogan { margin: 10px 0 26px; font-size: 12px; color: #b6a0a4; letter-spacing: 0.5px; }
|
||||
#intro .slogan b { color: #c9564a; }
|
||||
#intro .how { display: inline-block; text-align: left; color: #cbd4e2; line-height: 2; }
|
||||
#intro .how p { margin: 0; }
|
||||
#intro .how span { display: inline-block; width: 30px; }
|
||||
#intro em { color: #8a96ab; font-style: normal; font-size: 12px; }
|
||||
/* which build is served — filled in by main.js, empty (and invisible) if the header is missing */
|
||||
#build { margin: 10px 0 0; font-size: 9px; color: #5a6270; letter-spacing: 0.5px; }
|
||||
#intro .start { margin-top: 18px; color: #e0cc72; font-weight: bold; letter-spacing: 1px; animation: blink 1.1s step-end infinite; }
|
||||
@keyframes blink { 50% { opacity: 0.25; } }
|
||||
/* ONE overlay, four panels, swapped by #intro[data-stage]. Keeping the backdrop and the card frame
|
||||
alive across every screen is the point — a screen that unmounts the whole overlay flashes the
|
||||
court through between menus. */
|
||||
#splash, #menu, #courts, #tutorial { display: none; }
|
||||
#splash, #courts, #tutorial { display: none; }
|
||||
#intro[data-stage="splash"] #splash { display: block; }
|
||||
#intro[data-stage="menu"] #menu { display: block; animation: drop 0.3s ease-out; }
|
||||
#intro[data-stage="courts"] #courts { display: block; animation: drop 0.3s ease-out; }
|
||||
#intro[data-stage="tutorial"] #tutorial { display: block; animation: drop 0.3s ease-out; }
|
||||
/* the overlay is HIDDEN during play, not removed: a restart puts it straight back, and the
|
||||
display:grid above would otherwise win over the hidden attribute */
|
||||
#intro[hidden] { display: none; }
|
||||
/* headline: taller than the body text, so a screen reads as a screen and not as a list */
|
||||
#intro h2 { margin: 0 0 20px; font: 400 15px Silkscreen, monospace; color: #e0cc72;
|
||||
letter-spacing: 3px; line-height: 1.5; }
|
||||
@@ -102,9 +99,6 @@
|
||||
image-rendering: pixelated; text-shadow: 0 2px 0 rgba(0,0,0,0.9); }
|
||||
.btn.plate { background-image: url('assets/btn_start.png?v=94'); color: #f7ecb8; }
|
||||
.btn.plate2 { background-image: url('assets/btn_tut.png?v=94'); color: #d6dfec; }
|
||||
/* the logo sits exactly as it does on the title screen — same width, and enough room under it that
|
||||
the blood running off its bottom edge never touches the first button */
|
||||
#menu .logo { margin-bottom: 30px; }
|
||||
.btn.back { font-size: 10px; padding: 9px 10px; color: #8a96ab; }
|
||||
/* a row, not a stacked tile: three 3:2 tiles stacked fill a phone twice over, and the art still
|
||||
reads at this size. -webkit-tap-highlight-color kills iOS's blue flash over the pixel art. */
|
||||
@@ -139,24 +133,15 @@
|
||||
<div id="hint">move: WASD/arrows · serve/swing: SPACE · aim: hold a direction while swinging · T: tuning panel</div>
|
||||
<div id="intro" data-stage="splash">
|
||||
<div class="card">
|
||||
<!-- The title screen IS the menu. A separate menu stage behind it was the same logo over the
|
||||
same backdrop with two buttons, so it read as the title screen failing to advance. The
|
||||
control list that used to sit here is the tutorial's job now. -->
|
||||
<div id="splash">
|
||||
<img class="logo" src="assets/logo.png" alt="Splatter Tennis">
|
||||
|
||||
<p class="slogan">Fifteen. Thirty. Forty. <b>Dead.</b></p>
|
||||
<div class="how">
|
||||
<p><span>👆</span> tap — serve + swing</p>
|
||||
<p><span>👉</span> flick — aimed shot</p>
|
||||
<p><span>✋</span> drag — run <em>(auto-run is on)</em></p>
|
||||
<p class="kb"><span>⌨️</span> WASD / arrows + SPACE</p>
|
||||
</div>
|
||||
<p class="start">TAP TO START</p>
|
||||
<p id="build"></p>
|
||||
</div>
|
||||
<div id="menu">
|
||||
<!-- the logo IS the menu's headline; the title screen's own art, not a word set in Silkscreen -->
|
||||
<img class="logo" src="assets/logo.png" alt="Splatter Tennis">
|
||||
<button class="btn go plate" id="mStart">START GAME</button>
|
||||
<button class="btn plate2" id="mTut">TUTORIAL</button>
|
||||
<p id="build"></p>
|
||||
</div>
|
||||
<!-- court rows are built from config.COURTS in main.js: adding a court is a table row, never markup -->
|
||||
<div id="courts">
|
||||
@@ -183,6 +168,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="main.js?v=94"></script>
|
||||
<script type="module" src="main.js?v=95"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user