From 57650160a6a5238e9fc07168a71b3e58f2674151 Mon Sep 17 00:00:00 2001 From: Oliver Rieger Date: Mon, 31 Aug 2026 15:56:08 +0200 Subject: [PATCH] The shields glint instead of burning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A chimney of rising embers on a trophy read as a fire. Three points ON the shield now, dark for most of a long cycle and flaring for a fraction of it, with delays and durations that share no common multiple — so a glint lands somewhere on the row every couple of seconds and never in the same rhythm. Co-Authored-By: Claude Fable 5 --- PROJECT.md | 7 +++++-- index.html | 21 ++++++++++----------- src/main.js | 24 ++++++++++++------------ 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/PROJECT.md b/PROJECT.md index 20eacfb..ae467fd 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -684,8 +684,11 @@ better" reads naturally. Playing more costs you the tie-break at worst, never th 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. + figure set once in a career belongs. An earned shield CATCHES THE LIGHT: three points on it, dark + for most of a long cycle and flaring for a fraction of it, on delays and durations that share no + common multiple. It was a chimney of rising embers first — Oliver: "nicht brennen sondern manchmal + random schimmern", and he was right, a trophy does not burn. Pure CSS either way: the menus park + the game loop and this has no business waking it. 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. diff --git a/index.html b/index.html index 79bf06e..f3b7a95 100644 --- a/index.html +++ b/index.html @@ -373,17 +373,16 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat 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. */ - /* they lift off the shield's TOP EDGE into the dark above it — at the old bottom:22px the whole - flight happened ACROSS the artwork, where a 3px gold speck is invisible (Oliver saw nothing) */ - #cdBadges .badge em { position: absolute; bottom: 52px; width: 3px; height: 3px; background: #fff2c9; - box-shadow: 0 0 6px 2px rgba(232,178,58,0.75); - opacity: 0; pointer-events: none; animation-name: ember; - animation-timing-function: linear; animation-iteration-count: infinite; } - @keyframes ember { - 0% { transform: translate(0, 6px) scale(0.6); opacity: 0; } - 20% { opacity: 1; } - 60% { transform: translate(3px, -10px) scale(1); opacity: 0.75; } - 100% { transform: translate(-2px, -32px) scale(0.35); opacity: 0; } } + /* ...and it CATCHES THE LIGHT: three points on the shield, dark for most of a long cycle and + flaring for a fraction of it (main.glints). Not a fire — a glint, the way metal behaves. */ + #cdBadges .badge em { position: absolute; width: 4px; height: 4px; border-radius: 50%; + background: #fff6dc; box-shadow: 0 0 7px 2px rgba(255,231,170,0.9); + opacity: 0; pointer-events: none; animation-name: glint; + animation-timing-function: ease-out; animation-iteration-count: infinite; } + @keyframes glint { + 0%, 88%, 100% { opacity: 0; transform: scale(0.3); } + 92% { opacity: 1; transform: scale(1); } + 96% { opacity: 0.35; transform: scale(0.6); } } @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; diff --git a/src/main.js b/src/main.js index 8579c8c..dc2e57f 100644 --- a/src/main.js +++ b/src/main.js @@ -598,16 +598,16 @@ const countUp = (write, target, dur = 700) => { if (p < 1) cardTimers.push(setTimeout(tick, 30)); })(); }; -// EMBERS off an earned shield (2026-08-31, Oliver: "particles die random nach oben wegfliegen, wie -// leichtes feuer"). CSS keyframes, not a loop: the menu deliberately parks the game loop, and six -// two-pixel sparks per badge have no business waking it. The randomness is baked into each spark's -// own delay, duration and lane at build time, so no two shields burn in step. -const embers = won => !won ? '' : Array.from({ length: 7 }, () => - ``).join(''); +// A SHIELD CATCHES THE LIGHT (2026-08-31, Oliver: not burning — "manchmal random schimmern"). +// The first cut was a chimney of embers, which read as a fire on a trophy. This is the opposite: +// three points ON the shield, each dark for most of a long cycle and flaring for a fraction of it, +// on delays and durations that share no common multiple — so a glint lands somewhere on the row +// every couple of seconds and never twice in the same rhythm. CSS keyframes, no game loop. +const glints = won => !won ? '' : Array.from({ length: 3 }, () => + ``).join(''); function buildCard() { for (const t of cardTimers) clearTimeout(t); @@ -652,13 +652,13 @@ function buildCard() { // figure set once and never again belongs. // an unearned slot says nothing: the shield's own art already says which league it is cell.innerHTML = `` - + `${won ? (at ? 'AT ' + at : 'WON') : '—'}` + embers(won); + + `${won ? (at ? 'AT ' + at : 'WON') : '—'}` + glints(won); row.appendChild(cell); } const champ = document.createElement('div'); champ.className = 'badge' + (profile.prof.ch ? '' : ' dark'); champ.innerHTML = `` - + `${profile.prof.ch ? 'CHAMPION' : '—'}` + embers(profile.prof.ch); + + `${profile.prof.ch ? 'CHAMPION' : '—'}` + glints(profile.prof.ch); row.appendChild(champ); const g = stats.read('all', undefined, stats.MODE_GORE), z = stats.read('all', undefined, stats.MODE_MATCH),