The leagues, phase 1: the profile clock ticks — xp, levels, the identity screen, the server mirror

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-29 12:22:33 +02:00
1 parent bc10216d0b
commit 9133c0d351
12 files changed
+507 -19

No files matched your search

+53 -8
View File
@@ -174,7 +174,7 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
/* 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, #setup, #stats, #ranks, #newbest, #secret, #bosses, #stmode, #stsub, #bracket, #vs, #train { display: none; }
#splash, #setup, #stats, #ranks, #newbest, #secret, #bosses, #stmode, #stsub, #bracket, #vs, #train, #player { display: none; }
#intro[data-stage="splash"] #splash { display: flex; flex-direction: column; flex: 1; }
/* flex COLUMN, not block: it is what lets the footer's margin-top:auto reach the bottom of a
screen whose content does not fill it */
@@ -188,6 +188,7 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
#intro[data-stage="bracket"] #bracket,
#intro[data-stage="train"] #train,
#intro[data-stage="vs"] #vs,
#intro[data-stage="player"] #player,
#intro[data-stage="newbest"] #newbest { display: flex; flex-direction: column; flex: 1;
animation: drop 0.3s ease-out; }
/* the overlay is HIDDEN during play, not removed: a restart puts it straight back, and the
@@ -236,22 +237,35 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
font-style: normal; color: var(--dim); letter-spacing: 0.5px; }
/* THE PLAYER BLOCK: the live man on the left, everything that changes him on the right, so a tap
and its result are never more than a thumb apart and the whole of "who am I" is one screenful. */
#who { display: flex; gap: 12px; align-items: flex-start; }
#whoCtl { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 7px; }
#who, #who2 { display: flex; gap: 12px; align-items: flex-start; }
#whoCtl, #pCtl { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 7px; }
/* The live player. `position: static` is not decoration: the bare `canvas` rule above is the COURT
— fixed, full-bleed, 100dvh — and it catches any canvas in the document, so this one flew to the
top-left corner of the screen until it was told otherwise. Every geometry property that rule
sets has to be undone here. The buffer is the sprite's own 96x224, so width follows height. */
#look { position: static; display: block; flex: none; margin: 0;
#look, #pLook { position: static; display: block; flex: none; margin: 0;
width: auto; height: 176px; touch-action: auto; image-rendering: pixelated; }
/* the tour is now TWO WORDS, not two portraits — the live player next to them is the picture, and
a second drawing of the same man (front-facing, and deaf to every colour on this screen) was
both a duplicate and the reason the court list started below the fold */
#tours { display: flex; gap: 7px; }
#tours button { flex: 1; padding: 10px 2px; background: var(--panel); border: 2px solid var(--line);
#tours, #pTours { display: flex; gap: 7px; }
#tours button, #pTours button { flex: 1; padding: 10px 2px; background: var(--panel); border: 2px solid var(--line);
color: var(--dim); font: 400 10px Silkscreen, monospace; letter-spacing: 1px;
cursor: pointer; -webkit-tap-highlight-color: transparent; }
#tours button.on { border-color: var(--acid); background: rgba(188,212,85,0.09); color: var(--cream); }
#tours button.on, #pTours button.on { border-color: var(--acid); background: rgba(188,212,85,0.09); color: var(--cream); }
/* THE IDENTITY SCREEN (the leagues, phase 1): name row = the input plus the die. */
#nameRow { display: flex; gap: 8px; }
#nameRow .tin { flex: 1; margin: 0; }
#pDice { width: 52px; flex: none; margin: 0; padding: 0; font-size: 20px; line-height: 1; }
/* THE LEVEL STRIP: the one meta number over a thin bar, riding the splash foot. The fill colour
is the acid accent for now; the leagues will hand it the skill colour in phase 3. */
#xpRow { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; }
#xpRow u { font: 700 9px Silkscreen, monospace; color: var(--cream); text-decoration: none;
letter-spacing: 1px; white-space: nowrap; }
#xpRow s { flex: 1; height: 6px; background: rgba(255,255,255,0.10); border: 1px solid var(--line);
text-decoration: none; display: block; }
#xpRow s i { display: block; height: 100%; width: 0%; background: var(--acid);
transition: width 0.4s ease; }
/* KIT and SKIN: a row of colour squares, under a label that names whatever is selected. That is
the whole UI — the pick has no meters and no art to show, and a labelled tile per colour would
be five times the screen for a choice you make by looking at the colour. */
@@ -503,6 +517,9 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
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>
<!-- THE LEVEL STRIP (the leagues): the clock the whole meta-game runs on, visible on every
visit to the title. Filled by refreshSplash. -->
<div id="xpRow"><u id="xpLv">LEVEL 1</u><s><i id="xpFill"></i></s></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>
@@ -552,6 +569,34 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
<button class="btn big" id="cStart">SERVE UP</button>
</div>
</div>
<!-- THE IDENTITY (the leagues, phase 1): the first boot asks who walks on — a name (prefilled
with a zombie name, the die rolls another), the tour and the colours. Everything here
writes the SAME stores the setup screen reads (stats' name key, the picker localStorage
keys), so the two screens cannot disagree about who you are. Rebuilt on every visit by
main.buildPlayer, so the .on states track the setup screen's. -->
<div id="player">
<div class="hdr"><button class="chev" id="pBack">&lsaquo;</button><h2>YOUR PLAYER</h2></div>
<h3>NAME<span>YOURS ON EVERY BOARD</span></h3>
<div id="nameRow">
<input id="pName" class="tin" maxlength="12" autocomplete="off" spellcheck="false">
<button class="btn" id="pDice" aria-label="roll a zombie name">&#127922;</button>
</div>
<h3>THE BODY</h3>
<div id="who2">
<canvas id="pLook" width="96" height="224"></canvas>
<div id="pCtl">
<div id="pTours"></div>
<u class="swlab">KIT<i id="pKitName"></i></u>
<div id="pKitRow" class="swrow"></div>
<u class="swlab">SKIN<i id="pSkinName"></i></u>
<div id="pSkinRow" class="swrow"></div>
</div>
</div>
<div class="foot">
<p class="cent">THE CLUB WILL LEARN YOUR NAME.</p>
<button class="btn big" id="pGo">ENTER THE CLUB</button>
</div>
</div>
<!-- THE DRAW (cup mode only). SERVE UP lands here instead of on a court: the four rounds roll
through their own band of the ladder and stop, and what you watched land is what walks on
(main.js hands the settled rungs to startMatch). The rows are built in main.js from
@@ -675,6 +720,6 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
</div>
</div>
</div>
<script type="module" src="src/main.js?v=311"></script>
<script type="module" src="src/main.js?v=312"></script>
</body>
</html>