The setup grows a league face: badge, felled tally, the band's roster — and a bigger ribbon

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-29 16:10:31 +02:00
1 parent 5c34632513
commit d4780de76d
3 files changed
+86 -3

No files matched your search

+14
View File
@@ -491,6 +491,20 @@ zombie (now an occasional opponent, `TUNE.racketEvery`, not the every-game fixtu
`RETURNED`, `DOUBLE KILL`) is a footnote to something you already watched happen. Sharing the loud
FACE with the milestone cards is right; sharing their SIZE made every footnote read as a milestone.
## Session log: THE LEAGUES — the setup grows a league face (2026-08-29, same day, STAGING ONLY)
Two more from Oliver's screenshots:
- **THE LEAGUE PANEL.** The generic MATCH SETUP screen showed the player block (tour/kit/skin) on
the league modes too — redundant since the identity moved to the card. On zombie/cup the block
now steps aside (syncSetup toggles, "01 · YOUR LEAGUE") for the league writ large: the breathing
badge, "LEAGUE N — NAME" in the league colour, a felled tally line ("2 OF 4 FELLED · THE CUP IS
THE WAY UP" / "ALL 4 FELLED — TAKE THE CUP"), and the band's roster as head tiles — felled
bodies in colour with their ALL-TIME count (stats' per-foe tallies, key 'L'+index), the rest
grey; the band's top rung wears the red border, it is the final. Every other mode keeps the
player block (main.buildLeaguePanel).
- **The ribbon grew** (13px type, taller band), per his call.
## Session log: THE LEAGUES — the polish round: the ribbon, the glow, the count-up (2026-08-29, same day, STAGING ONLY)
Oliver's retest ("schon viel besser") with five polish items, all built:
+37 -3
View File
@@ -330,6 +330,28 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
#cdCareer { display: flex; align-items: center; gap: 8px; }
#cdCareer u { font: 700 8px Silkscreen, monospace; color: var(--dim); text-decoration: none;
letter-spacing: 1px; }
/* THE LEAGUE PANEL: the setup's league-mode face. The badge breathes like the card's, the
name is the announcement face in the league's own colour, and the band's roster stands in a
row — felled bodies in colour with their all-time count, the rest grey and waiting. */
#lgPanel { display: none; }
#lgHead { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
#lgBadge { height: 56px; image-rendering: pixelated; animation: badgeGlow 2.6s ease-in-out infinite; }
#lgHead b { display: block; font: 400 24px Bangers, cursive; letter-spacing: 1.5px; }
#lgHead i { display: block; margin-top: 3px; font: 400 9px Silkscreen, monospace;
color: var(--dim); font-style: normal; letter-spacing: 1px; }
#lgFoes { display: flex; gap: 7px; }
.lgFoe { flex: 1; min-width: 0; padding: 7px 2px 6px; background: var(--panel);
border: 2px solid var(--line); text-align: center; }
.lgFoe img { height: 42px; image-rendering: pixelated; }
.lgFoe b { display: block; margin-top: 4px; font: 700 8px Silkscreen, monospace;
color: var(--cream); letter-spacing: 0.5px; white-space: nowrap; overflow: hidden; }
.lgFoe i { display: block; margin-top: 2px; font: 400 8px Silkscreen, monospace;
color: var(--acid); font-style: normal; }
.lgFoe.un { opacity: 0.55; }
.lgFoe.un img { filter: grayscale(1) brightness(0.6); }
.lgFoe.un i { color: var(--dim); }
/* the band's top rung is the final — it wears the door's own red */
.lgFoe.fin { border-color: var(--red); }
/* the WAY-UP RIBBON, horizontal (Oliver's call after two diagonal cuts — a rotated pixel font
was the one anti-aliased thing in the menu): a red band running in from OVER the left border,
dissolving rightward through a real PIXEL FADE — an inline-SVG mask of 6px cells thresholded
@@ -339,7 +361,7 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
shadow survives the mask and follows the dither blocks (a box-shadow on the masked element
itself was eaten with it). */
.way { position: absolute; top: 12px; left: -8px; z-index: 2; white-space: nowrap;
padding: 5px 56px 5px 14px; font: 700 10px Silkscreen, monospace; font-style: normal;
padding: 8px 64px 8px 16px; font: 700 13px Silkscreen, monospace; font-style: normal;
color: #fff;
text-shadow: 1px 1px 0 rgba(0,0,0,0.55);
filter: drop-shadow(0 2px 3px rgba(0,0,0,0.5));
@@ -676,7 +698,7 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
the court off the bottom of the phone. The tiles are gone: the live player IS the picture,
so who-you-are shrinks to two words, and every control that changes him stands beside him
where you can watch it land. Kit and skin rows are built in main.js from the tables. -->
<h3>01 · PLAYER</h3>
<h3 id="s01">01 · PLAYER</h3>
<div id="who">
<canvas id="look" width="96" height="224"></canvas>
<div id="whoCtl">
@@ -687,6 +709,18 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
<div id="skinRow" class="swrow"></div>
</div>
</div>
<!-- THE LEAGUE PANEL (the leagues): on the league modes this stands where the player block
does elsewhere — the identity already lives on the card, so the setup shows the thing
that matters HERE instead: your league, writ large, and who of its band you have
already felled (all-time, from the stats' own per-foe tallies). Built by
main.buildLeaguePanel, toggled by syncSetup. -->
<div id="lgPanel">
<div id="lgHead">
<img id="lgBadge" alt="">
<div><b id="lgName"></b><i id="lgSub"></i></div>
</div>
<div id="lgFoes"></div>
</div>
<h3>02 · COURT</h3>
<div id="courtList"></div>
<div class="foot">
@@ -884,6 +918,6 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
</div>
</div>
</div>
<script type="module" src="src/main.js?v=322"></script>
<script type="module" src="src/main.js?v=323"></script>
</body>
</html>
+35
View File
@@ -303,9 +303,44 @@ swatches('kitRow', 'kitName', KITS, 'kit', () => pickedKit, id => pickedKit = id
swatches('skinRow', 'skinName', SKINS, 'skin', () => pickedSkin, id => pickedSkin = id);
refreshLook();
// THE LEAGUE PANEL (the leagues): the setup's league-mode face — your league writ large and the
// band's roster with your all-time felled counts (stats' per-foe tallies, key 'L'+index). The
// identity block this replaces still shows for every non-league mode; the card owns it anyway.
function buildLeaguePanel() {
const lg = leagueOf(profile.prof.lg);
const badge = document.getElementById('lgBadge');
badge.src = `assets/badge_l${lg.id}.png?v=${SPRV}`;
const name = document.getElementById('lgName');
name.textContent = `LEAGUE ${lg.id} — ${lg.name}`;
name.style.color = lg.color;
const z = stats.read('all', undefined, stats.MODE_MATCH).z;
const foes = document.getElementById('lgFoes');
foes.innerHTML = '';
let felled = 0;
for (let n = lg.band[0]; n <= lg.band[1]; n++) {
const f = matchFoe(n), k = z[f.key] || 0;
if (k) felled++;
const d = document.createElement('div');
d.className = 'lgFoe' + (k ? '' : ' un') + (n === lg.band[1] ? ' fin' : '');
d.innerHTML = `<img src="${foeArt(f)}" alt=""><b>${f.short}</b><i>${k ? '×' + k : '—'}</i>`;
foes.appendChild(d);
}
const size = lg.band[1] - lg.band[0] + 1;
document.getElementById('lgSub').textContent = felled >= size
? 'ALL ' + size + ' FELLED — TAKE THE CUP'
: felled + ' OF ' + size + ' FELLED · THE CUP IS THE WAY UP';
}
// The setup screen's rows, brought up to date with picks made elsewhere (the identity screen).
// Selection state lives in picked*; the rows are just its picture and must be repainted on entry.
// On the LEAGUE MODES the player block steps aside for the league panel (Oliver: the identity is
// on the card now — the setup should show the league and who of it you have already beaten).
function syncSetup() {
const leagueMode = pickedMode === 'zombie' || pickedMode === 'cup';
document.getElementById('who').style.display = leagueMode ? 'none' : 'flex';
document.getElementById('lgPanel').style.display = leagueMode ? 'block' : 'none';
document.getElementById('s01').textContent = leagueMode ? '01 · YOUR LEAGUE' : '01 · PLAYER';
if (leagueMode) buildLeaguePanel();
if (!courtUnlocked(picked)) picked = leagueOf(profile.prof.lg).court;
for (const el of courtList.children) {
const c = COURTS.find(x => x.id === el.dataset.id), l = courtLeague(el.dataset.id);