Rate monitor: call embers rise off the bars in proportion to real traffic

1-3 tiny accent sparks per socket update drift up from each bar's fill tip,
scaled by the real (unclamped) rate — motion strictly means API calls are
happening right now. Self-removing DOM nodes with a per-bar live cap of 6,
suppressed during cooldown and under reduced-effects mode. The taste-risk one
of the set: revert this commit alone if it reads as noise.
This commit is contained in:
BoulderBadgeDad 2026-06-06 15:44:54 -07:00
parent 7efb5da893
commit 1ad3dac222
2 changed files with 45 additions and 0 deletions

View file

@ -383,6 +383,14 @@ function _renderEqualizerBars(grid, data) {
}
bar.classList.toggle('cooldown', cooling);
// Call embers: tiny accent sparks rise off the fill tip, spawned per
// socket update in proportion to REAL traffic — motion strictly means
// API calls are happening right now. Suppressed during cooldown and
// under reduced-effects.
if (!window._reduceEffectsActive && !cooling && realPct > 0.03) {
_spawnEmbers(bar, pct, realPct > 0.6 ? 3 : realPct > 0.25 ? 2 : 1);
}
// Daily-budget ring (Spotify is the only service with a real daily
// cap): a conic rim inside the avatar disc fills as the budget is
// spent — green → amber → red, purple once the worker has bridged
@ -409,6 +417,23 @@ function _renderEqualizerBars(grid, data) {
}
}
// Spawn ember particles at a bar's fill tip. Self-removing DOM sparks with
// a per-bar live cap so a busy hour can't accumulate nodes.
function _spawnEmbers(bar, pct, count) {
const track = bar.querySelector('.rate-eq-track');
if (!track || track.querySelectorAll('.rate-eq-ember').length > 6) return;
for (let i = 0; i < count; i++) {
const e = document.createElement('span');
e.className = 'rate-eq-ember';
e.style.left = `${20 + Math.random() * 60}%`;
e.style.bottom = `${Math.min(96, pct * 100)}%`;
e.style.setProperty('--ember-drift', `${(Math.random() - 0.5) * 14}px`);
e.style.animationDuration = `${1.1 + Math.random() * 0.7}s`;
e.addEventListener('animationend', () => e.remove());
track.appendChild(e);
}
}
// Animate a single integer counter from `from` to `to` with an
// easeOutCubic curve. Used by the equalizer bars so the live count
// digit-rolls instead of snapping when sockets push a new value.

View file

@ -63340,6 +63340,26 @@ body.reduce-effects .dash-card::after {
text-shadow: 0 0 8px rgba(239, 68, 68, 0.8);
}
/* Call embers tiny accent sparks rising off the fill tip, spawned per
* socket update in proportion to real traffic. Motion == actual API calls. */
.rate-eq-ember {
position: absolute;
width: 3px;
height: 3px;
border-radius: 50%;
background: color-mix(in srgb, var(--eq-accent) 60%, white 40%);
box-shadow: 0 0 6px var(--eq-accent);
pointer-events: none;
animation: rate-eq-ember-rise 1.4s ease-out forwards;
z-index: 1;
}
@keyframes rate-eq-ember-rise {
0% { opacity: 0; transform: translate(0, 0) scale(1); }
15% { opacity: 0.9; }
100% { opacity: 0; transform: translate(var(--ember-drift, 0px), -26px) scale(0.4); }
}
/* Recovery flash — the moment a ban expires the track blinks back alive */
.rate-eq.recovered .rate-eq-track {
animation: rate-eq-recovered 1.2s ease-out;