// Synthetic star histories → preview/sim-.png, to stress-test scaling and spike detection import { writeFileSync } from 'node:fs' import { execFileSync } from 'node:child_process' import { svg, markers } from '../stars.mjs' const DAY = 864e5, now = Date.parse('2026-10-28T12:00:00Z') let seed = 7; const rnd = () => (seed = seed * 16807 % 2147483647) / 2147483647 const pois = l => { if (l > 30) return Math.max(0, Math.round(l + Math.sqrt(l) * (rnd() + rnd() + rnd() - 1.5) * 2)); let k = 0, p = 1, L = Math.exp(-l); while ((p *= rnd()) > L) k++; return k } const sim = (born, rate) => { const b = Date.parse(born), out = []; for (let d = 0; b + d * DAY < now; d++) for (let k = pois(rate(d, Math.floor((now - b) / DAY))); k--;) out.push(Math.min(now - 1, b + (d + rnd()) * DAY)); return { born: b, stars: out.sort((x, y) => x - y) } } const bump = (d, at, h, w = 2) => d >= at ? h * Math.exp(-(d - at) / w) : 0 const S = { 'old-steady-hn': ['acme/old-steady', sim('2022-11-01T09:00:00Z', d => bump(d, 3, 120, 3) + 2 + d / 200 + bump(d, 500, 500, 2))], 'late-viral': ['acme/late-viral', sim('2024-09-10T09:00:00Z', (d, n) => .15 + bump(d, n - 5, 700, 1.5))], 'many-bumps': ['acme/many-bumps', sim('2025-04-01T09:00:00Z', d => 1.5 + [40, 95, 160, 210, 260, 330, 400, 470, 520].reduce((s, a, i) => s + bump(d, a, 20 + i * 8, 1), 0))], 'huge': ['acme/huge-framework', sim('2019-03-01T09:00:00Z', d => bump(d, 1, 3000, 4) + 40 + 30 * Math.sin(d / 180) + bump(d, 900, 4000, 3) + bump(d, 1700, 2500, 2))], 'step-change': ['acme/step-change', sim('2024-06-01T09:00:00Z', d => d < 400 ? 1 : 15)], 'one-star': ['acme/lonely', sim('2026-06-01T09:00:00Z', d => d == 30 ? 1 : 0)], 'zero': ['acme/nothing-yet', { born: Date.parse('2026-10-20T09:00:00Z'), stars: [] }], } for (const [k, [repo, d]] of Object.entries(S)) { const f = `${import.meta.dirname}/.sim-${k}.svg` writeFileSync(f, svg({ repo, ...d }, now)) execFileSync(`${import.meta.dirname}/render.sh`, [f, 'sim-' + k]) console.log(k.padEnd(14), String(d.stars.length).padStart(7), markers(d, now).map(m => `${m.title} (${m.sub})`).join(" | ")) }