Load the game once, not on every launch
The cold-start complaints — late fonts, zombies missing from the stats screen — were one header. server.py sent no-cache, must-revalidate for everything, so a fresh launch revalidated ~230 sprites and three fonts before the game had a full set of frames. Assets under /assets now cache for a year when the URL carries ?v= (changing the file changes the URL, which is what SPRV is for) and a day when it does not; the fonts get a ?v= too. HTML and JS stay no-cache, so a deploy is still visible. Two client-side halves of the same report: a dropped sprite request used to be permanent for the session — the sheet stayed undefined and the zombie drew as some other design — so each one gets one retry. And the splash now holds its buttons back behind a loading bar until the last sheet has landed and both faces are ready, instead of letting you open the stats screen while half of it is still in flight. The bar is driven by setInterval, not rAF: rAF does not fire in a hidden tab, and an app that loads while backgrounded would come back to a frozen bar and a menu with no buttons on it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a1a8a61422
commit
c5a9746bc1
4 files changed
+80
-13
No files matched your search
+23
-5
@@ -15,16 +15,19 @@
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta name="theme-color" content="#2b2735">
|
||||
<style>
|
||||
/* pixel HUD font — bundled so it renders offline; used by the canvas scoreboard + rack */
|
||||
/* pixel HUD font — bundled so it renders offline; used by the canvas scoreboard + rack.
|
||||
?v= like the sprites: server.py caches a VERSIONED asset for a year and an unversioned one for
|
||||
a day, so these three files are fetched once per release instead of revalidated on every cold
|
||||
start. Bump alongside SPRV in render.js if a font file is ever replaced. */
|
||||
@font-face { font-family: 'Silkscreen'; font-weight: 400; font-display: block;
|
||||
src: url('assets/fonts/Silkscreen-Regular.ttf') format('truetype'); }
|
||||
src: url('assets/fonts/Silkscreen-Regular.ttf?v=86') format('truetype'); }
|
||||
@font-face { font-family: 'Silkscreen'; font-weight: 700; font-display: block;
|
||||
src: url('assets/fonts/Silkscreen-Bold.ttf') format('truetype'); }
|
||||
src: url('assets/fonts/Silkscreen-Bold.ttf?v=86') format('truetype'); }
|
||||
/* the ANNOUNCEMENT face. Silkscreen is the HUD and the instructions — small, even, quiet. The
|
||||
things that shout (SET, CHAPTER, EPIC!, PERFECT) are a second register on purpose, so a message
|
||||
tells you which kind it is before you have read a word of it. Bundled, like the other one. */
|
||||
@font-face { font-family: 'Bangers'; font-weight: 400; font-display: block;
|
||||
src: url('assets/fonts/Bangers-Regular.ttf') format('truetype'); }
|
||||
src: url('assets/fonts/Bangers-Regular.ttf?v=86') format('truetype'); }
|
||||
/* html needs a real HEIGHT: the root element's background paints the viewport, but a GRADIENT is
|
||||
laid out in the root's own box — and with the canvas position:fixed the root has no content and
|
||||
collapses, so the gradient render.js sets had nowhere to go. */
|
||||
@@ -207,6 +210,16 @@
|
||||
/* the splash's bottom band: no bar, no rule — the court art has to keep running under it */
|
||||
.foot.bare { border: 0; background: none; }
|
||||
.foot.bare .btn.big { margin-bottom: 10px; }
|
||||
/* the boot bar wears the stats screen's kill bar, doing duty as a loading bar. While #splash is
|
||||
.busy it stands in the buttons' place — same band, same height, so nothing jumps when it goes. */
|
||||
#boot { display: none; margin-bottom: 10px; }
|
||||
#boot s { display: block; height: 6px; background: rgba(0,0,0,0.45); text-decoration: none; }
|
||||
#boot s > i { display: block; width: 0; height: 100%; background: var(--acid);
|
||||
transition: width 0.15s linear; }
|
||||
#boot u { display: block; margin-top: 7px; text-align: center; text-decoration: none;
|
||||
font: 400 9px Silkscreen, monospace; color: var(--dim); letter-spacing: 2px; }
|
||||
#splash.busy #boot { display: block; }
|
||||
#splash.busy .btn, #splash.busy .two, #splash.busy #build { display: none; }
|
||||
#sSum { display: flex; justify-content: space-between; gap: 8px; margin: 0 0 8px;
|
||||
font: 400 9px Silkscreen, monospace; color: var(--dim); letter-spacing: 1px; }
|
||||
.tabs { display: flex; gap: 6px; margin: 12px 0 14px; }
|
||||
@@ -284,6 +297,11 @@
|
||||
<p class="slogan">Fifteen. Thirty. Forty. <b>Dead.</b></p>
|
||||
</div>
|
||||
<div class="foot bare">
|
||||
<!-- THE BOOT BAR. Every sprite is requested the moment render.js is imported; this only
|
||||
shows how far that got, and stands where the buttons will be until it is done — a menu
|
||||
you can press before the sheets have landed is how you reach the stats screen with half
|
||||
the zombies missing. Swapped by #splash.busy, see main.js. -->
|
||||
<div id="boot"><s><i></i></s><u>LOADING</u></div>
|
||||
<button class="btn big" id="mStart">PLAY MATCH</button>
|
||||
<div class="two">
|
||||
<button class="btn sec" id="mStats">STATS<i id="mKills">0 KILLS</i></button>
|
||||
@@ -341,6 +359,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="main.js?v=125"></script>
|
||||
<script type="module" src="main.js?v=127"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user