feat: relay station masts come online through the toolkit chapter

This commit is contained in:
2026-10-11 08:32:33 +03:00
parent 568b0802b4
commit 33585f7e34
22 changed files with 935 additions and 2 deletions

View File

@@ -0,0 +1,35 @@
/**
* RELAY STATION: the Toolkit chapter is a pre-dawn relay station. One mast
* per toolkit group comes online in turn as the chapter scrolls, its lamp
* rungs igniting bottom-up, one per technology. Shared by the DOM
* (html[data-relay-online]) and the lazy scene chunk, so it stays tiny and
* pure. Scroll-driven, so scrolling back takes the masts offline again.
*/
/** Chapter-local progress at which each mast comes online. */
export const RELAY_STOPS = [0.04, 0.22, 0.4, 0.58] as const;
/** A mast's rungs light bottom-up over this much chapter progress after its stop. */
export const RELAY_RAMP = 0.12;
/** Beacon blink rate (photosensitivity: well under 3 Hz). */
export const BEACON_HZ = 0.5;
/** How many masts are online at chapter progress p (0 outside the chapter). */
export const relayOnline = (p: number | null): number =>
p === null ? 0 : RELAY_STOPS.filter((stop) => p >= stop).length;
/** 0..1: rung `rung` of `count` on mast `mast` at progress p. Each rung takes its own slice of the ramp. */
export function rungLit(p: number | null, mast: number, rung: number, count: number): number {
const stop = RELAY_STOPS[mast];
if (p === null || stop === undefined || count <= 0) return 0;
const t = Math.min(1, Math.max(0, (p - stop - (RELAY_RAMP * rung) / count) / (RELAY_RAMP / count)));
return t * t * (3 - 2 * t);
}
/** The DOM publishes rung counts (technologies per group) here; the scene reads them each frame. */
let counts: readonly number[] = [];
export function publishRelay(next: readonly number[]): void {
counts = next.slice(0, RELAY_STOPS.length);
}
export const readRelay = (): { counts: readonly number[] } => ({ counts });