The shields glint instead of burning

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 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-31 15:56:08 +02:00
1 parent 87833db095
commit 57650160a6
3 files changed
+27 -25

No files matched your search

+12 -12
View File
@@ -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 }, () =>
`<em style="left:${(16 + Math.random() * 58).toFixed(0)}%;` +
// a SHORT delay window: spread over 2.6s the shield was empty half the time, which is why the
// first cut read as nothing happening at all
`animation-delay:${(Math.random() * 1.7).toFixed(2)}s;` +
`animation-duration:${(1.7 + Math.random() * 1.1).toFixed(2)}s"></em>`).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 }, () =>
`<em style="left:${(18 + Math.random() * 60).toFixed(0)}%;` +
`top:${(12 + Math.random() * 52).toFixed(0)}%;` +
`animation-delay:${(Math.random() * 9).toFixed(2)}s;` +
`animation-duration:${(6 + Math.random() * 5).toFixed(2)}s"></em>`).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 = `<img src="assets/badge_l${l.id}.png?v=${SPRV}" alt="" title="${l.name}">`
+ `<u>${won ? (at ? 'AT ' + at : 'WON') : '—'}</u>` + embers(won);
+ `<u>${won ? (at ? 'AT ' + at : 'WON') : '—'}</u>` + glints(won);
row.appendChild(cell);
}
const champ = document.createElement('div');
champ.className = 'badge' + (profile.prof.ch ? '' : ' dark');
champ.innerHTML = `<img src="assets/badge_champ.png?v=${SPRV}" alt="" title="CHAMPION OF THE DEAD CLUB">`
+ `<u>${profile.prof.ch ? 'CHAMPION' : '—'}</u>` + embers(profile.prof.ch);
+ `<u>${profile.prof.ch ? 'CHAMPION' : '—'}</u>` + glints(profile.prof.ch);
row.appendChild(champ);
const g = stats.read('all', undefined, stats.MODE_GORE),
z = stats.read('all', undefined, stats.MODE_MATCH),