diff --git a/PROJECT.md b/PROJECT.md index d222e4a..5d9cdae 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -491,6 +491,34 @@ 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, PHASE 3 — the character card, badges, the skill trail (2026-08-29, STAGING ONLY) + +Phase 3. STAGING ONLY, like 1 and 2. + +- **THE CHARACTER CARD** (`#card`, main.buildCard): the splash's LEVEL STRIP is the door (tap it — + it wears `cursor: pointer` and nothing else changed on the splash). Name as the screen title, + the live sprite (drawLook, third canvas on refreshLook), the current league's crest + name in + the league colour, LEVEL in Bangers over the gradient bar with "N XP · M TO LEVEL X", an + HONOURS row, and THE LEDGER (two .figs rows off stats.read per mode: kills / multi-kills / + deaths, best run / most felled / runs). EDIT PLAYER borrows the identity screen and returns to + the card (`playerReturn`). Deviation from the plan: no death-screen entry — the death screen + already carries the XP moment inline, and its tap is the restart. +- **The honours row is a COLLECTION**: all five league shields plus the champion's laurel always + visible, earned bright, unearned dark (`filter: grayscale brightness`) — the empty slots are + the incentive. A shield is earned by FINISHING its league (being past it); league five's lights + with the champion crown, since there is no league six to be past it. +- **Badges rolled via OpenRouter** (one sheet on #FF00FF, cut by connected components + chroma + key, 4x NEAREST downscale): `badge_l1..l5.png` (terracotta / slate / grass / navy-ice / + marble-gold shields, each with the crossed-rackets motif and a chip of decay) + `badge_champ.png` + (gold laurel + cup). DOM `` only — not in SPR, nothing draws them on canvas yet. +- **THE SKILL TRAIL**: `LEAGUES` rows carry `color` (each riding its court's palette), and the + player's OWN sprint dust wears it — `dustPuff` grew an optional colour, the mover's emit passes + `skillDust()`. League 1 keeps the shipped court dust: the tint itself is a progression reward. + Read off the profile (not `G.league`), so the gore mode shows your colour too. The aura stays + made of MOTION, never paint — the full-body glow idea was dropped against the painted-layer veto. +- Pane-verified: card at league 5 (four bright shields, dark L5 + laurel, ledger numbers, edit + round trip). Suite unchanged at 121 — the card is DOM, the dust is a colour. + ## Session log: THE LEAGUES, PHASE 2 — bands, pace tiers, courts, the promotion (2026-08-29, STAGING ONLY) Phase 2 of the plan. STAGING ONLY, like phase 1. diff --git a/assets/badge_champ.png b/assets/badge_champ.png new file mode 100644 index 0000000..c76e0c8 Binary files /dev/null and b/assets/badge_champ.png differ diff --git a/assets/badge_l1.png b/assets/badge_l1.png new file mode 100644 index 0000000..d550140 Binary files /dev/null and b/assets/badge_l1.png differ diff --git a/assets/badge_l2.png b/assets/badge_l2.png new file mode 100644 index 0000000..a12cce7 Binary files /dev/null and b/assets/badge_l2.png differ diff --git a/assets/badge_l3.png b/assets/badge_l3.png new file mode 100644 index 0000000..90b73f0 Binary files /dev/null and b/assets/badge_l3.png differ diff --git a/assets/badge_l4.png b/assets/badge_l4.png new file mode 100644 index 0000000..e849bdd Binary files /dev/null and b/assets/badge_l4.png differ diff --git a/assets/badge_l5.png b/assets/badge_l5.png new file mode 100644 index 0000000..dbe7e10 Binary files /dev/null and b/assets/badge_l5.png differ diff --git a/index.html b/index.html index a53ffc5..d2c1070 100644 --- a/index.html +++ b/index.html @@ -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, #player, #promo { display: none; } + #splash, #setup, #stats, #ranks, #newbest, #secret, #bosses, #stmode, #stsub, #bracket, #vs, #train, #player, #promo, #card { 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 */ @@ -190,6 +190,7 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat #intro[data-stage="vs"] #vs, #intro[data-stage="player"] #player, #intro[data-stage="promo"] #promo, + #intro[data-stage="card"] #card, #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 @@ -274,14 +275,31 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat image-rendering: pixelated; animation: drop 0.5s ease-out 0.5s backwards; } #prCourtName { margin: 0; font: 400 10px Silkscreen, monospace; color: var(--acid); letter-spacing: 1.5px; animation: drop 0.5s ease-out 0.62s backwards; } + /* THE CHARACTER CARD (the leagues, phase 3): the player writ large — sprite, crest, level, + honours, ledger. The honours row is a collection with visible empty slots: the unearned + badges sit dark, which is the whole incentive. */ + #cdTop { display: flex; gap: 14px; align-items: flex-start; margin-top: 14px; } + #cdLook { position: static; display: block; flex: none; margin: 0; width: auto; height: 200px; + touch-action: auto; image-rendering: pixelated; } + #cdMeta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; } + #cdBadge { width: 56px; image-rendering: pixelated; } + #cdLeague { font: 700 10px Silkscreen, monospace; text-decoration: none; letter-spacing: 1.5px; } + #cdLevel { font: 400 30px Bangers, cursive; color: var(--cream); letter-spacing: 1.5px; } + #cdXp { display: block; margin-top: 5px; font: 400 9px Silkscreen, monospace; color: var(--dim); + text-decoration: none; letter-spacing: 1px; } + #cdBadges { display: flex; gap: 10px; align-items: flex-end; } + #cdBadges img { height: 46px; image-rendering: pixelated; } + #cdBadges img.dark { filter: grayscale(1) brightness(0.3); } /* 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); + #xpRow { cursor: pointer; } /* the strip IS the door to the character card */ + #xpRow s, #cdBar 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%; + #cdBar s { height: 8px; } + #xpRow s i, #cdBar s i { display: block; height: 100%; width: 0%; background: linear-gradient(90deg, #3f9560, var(--acid) 55%, #e8b23a); transition: width 0.4s ease; } /* KIT and SKIN: a row of colour squares, under a label that names whatever is selected. That is @@ -629,6 +647,30 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat + +
+

YOUR PLAYER

+
+ +
+ + + LEVEL 1 +
+
+
+

HONOURSWIN THE CUP TO CLIMB

+
+

THE LEDGERALL TIME

+
+
+
+
+ +
+