web: dots trickle in randomly per round, the share counts live

Per Justin: a round's dots no longer start fading together. Every node
gets a deterministic random appearance moment inside the first 70% of
the round interval (the rest is its fade), and a new roundProgress
value, driven by the playback frame loop, feeds the same jitter into
the panel stats: the big percentage and reached count now tick up
exactly as dots start appearing, in the cards, the mobile strip, and
the focus modal. Pausing, stepping, and seeking hold the full round;
reduced motion keeps discrete swaps.
This commit is contained in:
Justin Visser 2026-06-10 18:14:35 +02:00
parent 609ba6f0dd
commit 3cd48ca7ea
9 changed files with 342 additions and 16 deletions

View file

@ -1,5 +1,37 @@
import { mulberry32 } from './mulberry32'
// Cumulative reach at a playback round, shared by the panel stats and the
// reach chart so both always agree with the network picture.
export function reachedCountAtRound(reachedAtRound: number[], round: number): number {
return reachedAtRound.filter((reachedAt) => reachedAt >= 0 && reachedAt <= round).length
}
// During playback, dots of the current round do not appear at once: each
// node gets a deterministic random moment inside the first APPEAR_WINDOW
// of the round interval (the rest of the interval is its fade). The same
// jitter drives the dot's animation-delay and the live counter, so the
// percentage ticks up exactly as dots start appearing.
export const APPEAR_WINDOW = 0.7
export function appearanceJitter(nodeIndex: number): number {
return mulberry32(nodeIndex * 7919 + 17)()
}
// Reach as displayed mid-transition: every earlier round fully, plus the
// current round's nodes whose appearance moment has passed. With
// roundProgress = 1 this equals reachedCountAtRound.
export function reachedCountDisplayed(
reachedAtRound: number[],
round: number,
roundProgress: number,
): number {
let displayed = 0
reachedAtRound.forEach((reachedAt, nodeIndex) => {
if (reachedAt < 0 || reachedAt > round) return
if (reachedAt < round || roundProgress >= appearanceJitter(nodeIndex) * APPEAR_WINDOW) {
displayed += 1
}
})
return displayed
}