From c0b308e1fedd3c681adc0953276b6632f0ee3c03 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Tue, 30 Jun 2026 01:48:04 -0500 Subject: [PATCH] fix(desktop): center memory-graph timeline stars, surface quiet buckets Revert the helix coil to the constellation scatter, biased toward the midline (triangular vertical), and stop a packed core ring from crushing every quieter bucket into one invisible speck: sqrt-scale the per-bucket star count, floor star size to 2px, and lift the dim baseline. --- apps/desktop/src/app/starmap/timeline.tsx | 42 +++++++++++------------ 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/apps/desktop/src/app/starmap/timeline.tsx b/apps/desktop/src/app/starmap/timeline.tsx index 81da1f62c9c..405eb79c94a 100644 --- a/apps/desktop/src/app/starmap/timeline.tsx +++ b/apps/desktop/src/app/starmap/timeline.tsx @@ -35,10 +35,6 @@ const ACTIVE_MARKER_CLASS = 'opacity-100' const INACTIVE_MARKER_CLASS = 'opacity-30' // Busiest bucket gets this many stars; quieter ones scale down proportionally. const MAX_STARS_PER_BUCKET = 7 -// Full coils the constellation winds across the timeline's width. -const COIL_TURNS = 6 -// Vertical swing (in % of track height) the coil arcs above/below the midline. -const COIL_AMPLITUDE = 36 // Deterministic PRNG (mulberry32) so a bucket's stars stay put across renders. function rng(seed: number): () => number { @@ -54,11 +50,11 @@ function rng(seed: number): () => number { } } -// Wind each time bucket's activity into stars along a helix: count ∝ events, -// split between skill- and memory-coloured stars, ordered left→right and arced -// above/below the midline by a sine wave so the field reads as a coiling spiral -// rather than random scatter. Front-of-coil stars (cos→1) read brighter and -// larger for a sense of depth. A starmap timeline for a starmap. +// Scatter each time bucket's activity into stars: count ∝ events, split between +// skill- and memory-coloured stars, jittered within the bucket's horizontal slot +// and across the track height. Vertical placement is biased toward the midline +// (a triangular distribution) so stars cluster near the centre more often than +// the edges. A starmap timeline for a starmap. function buildStars(axis: TimeAxis): Star[] { const n = Math.max(1, axis.buckets.length) const stars: Star[] = [] @@ -69,28 +65,30 @@ function buildStars(axis: TimeAxis): Star[] { } const intensity = axis.maxTotal > 0 ? b.total / axis.maxTotal : 0 - const count = Math.max(1, Math.round(intensity * MAX_STARS_PER_BUCKET)) + // sqrt curve so a single co-timed burst (a packed core ring) doesn't crush + // every quieter bucket down to the 1-star floor and read as blank. + const count = Math.max(1, Math.round(Math.sqrt(intensity) * MAX_STARS_PER_BUCKET)) const skillCount = Math.round((b.skill / b.total) * count) const r = rng(i * 9973 + 7) const slot = 1 / n + const center = (i + 0.5) / n for (let s = 0; s < count; s++) { - // Ordered position within the bucket's slot keeps the coil smooth. - const frac = (i + (s + 0.5) / count) / n - const angle = frac * COIL_TURNS * Math.PI * 2 - // Depth: front of the coil (cos→1) is brighter/larger than the back. - const depth = (Math.cos(angle) + 1) / 2 - const wobble = (r() - 0.5) * slot * 0.25 - const top = 50 + Math.sin(angle) * COIL_AMPLITUDE + (r() - 0.5) * 5 + const jitter = (r() - 0.5) * slot * 0.9 + // Average of two uniforms → triangular peak at 0.5, pulling stars toward + // the midline more often while still reaching the edges occasionally. + const vertical = (r() + r()) / 2 stars.push({ delay: r() * 3, duration: 2.4 + r() * 2.6, kind: s < skillCount ? 'skill' : 'memory', - leftPct: Math.max(0, Math.min(1, frac + wobble)) * 100, - opacity: 0.45 + depth * 0.5, - size: 1 + Math.round(depth * 2.4), - topPct: Math.max(6, Math.min(94, top)) + leftPct: Math.max(0, Math.min(1, center + jitter)) * 100, + // Brighter, slightly larger stars are rarer. + opacity: 0.5 + r() * 0.5, + // Floor at 2px so a lone star in a quiet bucket still reads on black. + size: 2 + Math.round(r() * r() * 2.2), + topPct: 12 + vertical * 76 }) } }) @@ -225,7 +223,7 @@ export const Timeline = memo(function Timeline({ backgroundColor: colorFor(star.kind), height: star.size, left: `${star.leftPct}%`, - opacity: 0.16, + opacity: 0.22, top: `${star.topPct}%`, width: star.size }}