diff --git a/PROJECT.md b/PROJECT.md index c8d28d5..20eacfb 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -643,6 +643,53 @@ through. Open for the phone: whether the fixture button should ever go to the setup screen (it does not now), and whether the promotion's WALK ON should enter the cup instead of the clubhouse. +## Session log: THE STATS STREAMLINE AND THE CUP BOARD (2026-08-31, STAGING ONLY) + +Oliver: "stats und board — es ist total verwirrend, ich habe keine ahnung was dort angezeigt wird... +ich habe die vermutung, dass hier noch viele kpis erfasst werden, die in alten spielmodi bedeutung +hatten". He was right, and the count was worse than the feeling: the screen had THREE mode tabs +times THREE period tabs, and the same three boxes meant something different in every one of the +nine states (KILLS/MULTI-KILLS/DEATHS · FELLED/DEEPEST/RUNS · PLAYED/WON/LOST). The card repeated +three of those numbers summed across modes, so the same word meant "this mode" in one place and +"all modes" in the other — and "BEST RUN" on the card counted GAMES while "BEST" on the board +counted KILLS. + +**What went, and why:** +- **MULTI-KILLS** — a vanity number on no board, from the gore era. +- **DEATHS** — every gore and climb run ends in one, so it was RUNS again in a second box. +- **The period tabs** — LAST RUN is the summary you just tapped away; 7 DAYS is a fitness metric in + a permadeath arcade game. `read()` keeps the parameter; the UI does not. +- **The mode tabs on BODY COUNT** — one career, four numbers that never change meaning: BODIES + FELLED, BEST GORE RUN, DEEPEST CLIMB, RUNS. Then the roster (the collection, which is what the + screen is actually good at) and the rack. +- **The CLASSIC board** — classic tennis is OUT OF COMPETITION by its own room's rule since the + text reduction, so ranking it contradicted the wall. Its records still bank locally; they just no + longer submit, and a classic best no longer opens the name prompt. + +**THE CUP BOARD** (Oliver: "cup board finde ich das wichtigste"), and the one real design argument +of the session. He wanted to rank THE LEVEL YOU TOOK THE LEAGUE AT. Challenged, and the challenge +held: xp comes only from playing, so a board that rewards a low level rewards NOT PLAYING — it +would pay you to avoid gore, the climb and training, the three rooms the season leans on. Three +smaller objections: it inverts the reading direction of every other number in the game, it can be +set exactly five times in a career and then freezes, and it makes the player who played MORE look +worse. + +Settled instead: **the league ranks, the level breaks the tie.** `LEAGUE 4 · AT 22` — the canonical +achievement sorts, and his number decides between everyone who got equally far, where "lower is +better" reads naturally. Playing more costs you the tie-break at worst, never the place. +- `BOARDS.u` (`MODE_CUP`) carries `subLow: true`; `server.rank_key()` is the other half — the ONE + board whose second column sorts ascending, and the "is this submission better" test uses the same + key, so a better row is a higher league or the same league at a lower level. +- `profile.at` (league -> level) is written ONCE, at the promotion, before `prof.lg` moves — the + level that WON the cup, not the one you walk on with. Mirrored server-side like `cups`. +- A promotion posts itself (`main.postCup`): no name prompt in the way, no personal-best gate. +- The same number is the INSCRIPTION under each earned shield on the card (`AT 14`) — where a + figure set once in a career belongs. Earned shields smoulder now: five CSS embers each, random + lane and delay, no game loop involved. + +The card also stopped repeating the ledger (it carries the CAREER: league, cups won, best cup) and +its crest moved beside the league line instead of pushing it down. + ## Session log: THE MENU TEXT REDUCTION — the design handoff, built (2026-08-31, STAGING ONLY) A handoff from a design session (its folder is on Oliver's disk, git-ignored: the prototype ships a diff --git a/index.html b/index.html index 98a9d45..5512d40 100644 --- a/index.html +++ b/index.html @@ -266,9 +266,15 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat /* four numbers read better two-up than four-across on a phone — at four the labels wrap and the row becomes a wall of two-line captions */ .figs.pair { display: grid; grid-template-columns: 1fr 1fr; } - .fig { flex: 1; min-width: 0; padding: 7px 6px; text-align: center; } + .figs.pair .fig:nth-child(2n) { border-left: 2px solid var(--line); } + .figs.pair .fig:nth-child(n+3) { border-top: 2px solid var(--line); } + .fig { flex: 1; min-width: 0; padding: 11px 8px 12px; text-align: center; } .fig + .fig { border-left: 2px solid var(--line); } - .fig b { display: block; font: 400 9px Silkscreen, monospace; color: var(--dim); letter-spacing: 1px; } + /* THE NUMBER NEVER MOVES (2026-08-31, Oliver: "manchmal sind die überschriften ein- manchmal + zweizeilig, das drückt die zahl runter"). The label gets two lines of room whether it needs + them or not, so every figure in a row sits on the same baseline. */ + .fig b { display: flex; align-items: flex-start; justify-content: center; min-height: 22px; + font: 400 9px/1.25 Silkscreen, monospace; color: var(--dim); letter-spacing: 1px; } .fig i { display: block; font: 700 18px Silkscreen, monospace; color: var(--acid); font-style: normal; letter-spacing: 1px; } .fig.bad i { color: var(--bad); } @@ -344,18 +350,48 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat #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; } + #cdMeta { flex: 1; min-width: 0; display: grid; gap: 8px 11px; align-items: center; + grid-template-columns: auto 1fr; + grid-template-areas: "crest league" "crest level" "bar bar" "xp xp" "career career"; } + /* THE CREST STANDS BESIDE THE LEAGUE (2026-08-31, Oliver: on its own row it pushed the text + down), so the two things that say WHERE YOU ARE share a line instead of stacking. */ + #cdBadge { grid-area: crest; width: 56px; image-rendering: pixelated; align-self: center; } + #cdLeague { grid-area: league; align-self: end; font: 700 10px/1.5 Silkscreen, monospace; + text-decoration: none; letter-spacing: 1.5px; } + #cdLeague i { display: block; font-style: normal; font-size: 9px; opacity: 0.85; } + #cdBar { grid-area: bar; } + #cdXp { grid-area: xp; } + #cdCareer { grid-area: career; } + #cdLevel { grid-area: level; align-self: start; 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; } + /* THE HONOURS ROW: a shield per league, and under an earned one the INSCRIPTION — the level it + was taken at (the cup board's tie-break, in the one place a once-in-a-career figure belongs). */ #cdBadges { display: flex; gap: 10px; align-items: flex-end; } + #cdBadges .badge { position: relative; flex: 1; min-width: 0; display: flex; flex-direction: column; + align-items: center; gap: 4px; } + /* ...and an earned shield SMOULDERS: two-pixel embers drifting off it, each on its own delay and + lane (main.embers). Pure CSS — the menu parks the game loop and this has no business waking it. */ + #cdBadges .badge em { position: absolute; bottom: 22px; width: 3px; height: 3px; background: #f2cf6a; + box-shadow: 0 0 4px 1px rgba(232,178,58,0.55); + opacity: 0; pointer-events: none; animation-name: ember; + animation-timing-function: linear; animation-iteration-count: infinite; } + @keyframes ember { + 0% { transform: translate(0, 0) scale(1); opacity: 0; } + 18% { opacity: 0.85; } + 60% { transform: translate(2px, -16px) scale(0.8); opacity: 0.5; } + 100% { transform: translate(-1px, -30px) scale(0.4); opacity: 0; } } + @media (prefers-reduced-motion: reduce) { #cdBadges .badge em { display: none; } } #cdBadges img { height: 46px; image-rendering: pixelated; } + #cdBadges .badge u { font: 700 7px Silkscreen, monospace; color: var(--acid); letter-spacing: 0.5px; + text-decoration: none; white-space: nowrap; } + #cdBadges .badge.dark img { filter: grayscale(1) brightness(0.3); } + #cdBadges .badge.dark u { color: #3f4d45; } #cdBadges img.dark { filter: grayscale(1) brightness(0.3); } /* earned badges BREATHE — a subtle gold halo, CSS-only (the menu parks the game loop, CSS animations do not care). The dark slots stay dead, which is the point of them. */ - #cdBadges img:not(.dark), #cdBadge { + #cdBadges .badge:not(.dark) img, #cdBadges img:not(.dark), #cdBadge { animation: badgeGlow 2.6s ease-in-out infinite; } @keyframes badgeGlow { 0%, 100% { filter: drop-shadow(0 0 2px rgba(232, 178, 58, 0.25)); } @@ -687,9 +723,10 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat .zrow.boss .pb s { background: var(--bad); } .zb i { grid-column: 1 / -1; margin-top: 4px; font: 400 9px Silkscreen, monospace; font-style: normal; color: var(--dim); letter-spacing: 1px; } - #stW { display: flex; flex-wrap: wrap; gap: 6px; } - .wtile { flex: 1 1 62px; max-width: 84px; padding: 8px 2px; border: 2px solid var(--line); - background: var(--panel); } + /* a GRID, not a wrapping flex row: `flex: 1 1 62px` gave the last row's tiles the whole width + to share, so a shelf of nine came out in three different sizes (Oliver) */ + #stW { display: grid; grid-template-columns: repeat(auto-fill, minmax(66px, 1fr)); gap: 6px; } + .wtile { padding: 8px 2px; border: 2px solid var(--line); background: var(--panel); } .wtile img { width: 34px; height: 34px; object-fit: contain; display: block; margin: 0 auto 2px; image-rendering: pixelated; } .wtile b { display: block; font: 400 11px Silkscreen, monospace; color: var(--acid); } @@ -996,7 +1033,8 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat