From ee13bc8a057eeff0ed8ba66c947d2ca13ed9f45d Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Sat, 6 Jun 2026 14:30:54 -0700 Subject: [PATCH] Dashboard worker orbs bloom from center instead of creeping in from top-left MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On page load every orb sat at the canvas origin: orbs are created at (0,0) and the random scatter skipped orbs that weren't visible yet — which on load is all of them, since the header hasn't been laid out when init() runs. The whole cluster then drifted in from the top-left corner. scatterOrbs() -> centerOrbs(): spawn the cluster dead-center of the canvas, positioning every orb regardless of visibility (a few px of jitter on purpose — the separation force ignores pairs closer than 0.1px, so a perfect stack would never split). enterOrbState() also re-centers right after resizeCanvas(), so activations get the true center even when init ran against a hidden 0x0 header — and returning to the dashboard replays the center-bloom intro. --- webui/static/worker-orbs.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/webui/static/worker-orbs.js b/webui/static/worker-orbs.js index 928dcc2c..43760dcb 100644 --- a/webui/static/worker-orbs.js +++ b/webui/static/worker-orbs.js @@ -117,7 +117,7 @@ }); computeHomes(); - scatterOrbs(); + centerOrbs(); dashboardHeader.addEventListener('mouseenter', onMouseEnter); dashboardHeader.addEventListener('mouseleave', onMouseLeave); @@ -137,15 +137,22 @@ }); } - function scatterOrbs() { + function centerOrbs() { + // Spawn the whole cluster dead-center and let the physics bloom it + // outward. Positions EVERY orb (visible or not): the old random + // scatter skipped not-yet-visible orbs, so on page load they all sat + // at the canvas origin and drifted in from the top-left corner. if (!canvas) return; const w = canvas.clientWidth || 600; const h = canvas.clientHeight || 80; orbs.forEach(orb => { - if (!orb.visible) return; - orb.x = ORB_RADIUS + Math.random() * (w - ORB_DIAMETER); - orb.y = ORB_RADIUS + Math.random() * (h - ORB_DIAMETER); + // A few px of jitter so the separation force can split the stack + // (it ignores pairs closer than 0.1px). + orb.x = w / 2 + (Math.random() - 0.5) * 6; + orb.y = h / 2 + (Math.random() - 0.5) * 6; + orb.vx = (Math.random() - 0.5) * 0.6; + orb.vy = (Math.random() - 0.5) * 0.6; }); } @@ -322,6 +329,10 @@ canvas.style.opacity = '1'; canvas.style.display = ''; resizeCanvas(); + // Dashboard (re)activation: the canvas just got its real size — init may + // have run while the header was hidden (0x0), leaving positions stale. + // Bloom the cluster from dead center instead of wherever that left them. + centerOrbs(); startLoop(); }