/** * Era skins for the clean programming (round 5 Part A). * * THE SCREEN's SUBSTRATE ages with the highest ratified era; the corruption on top stays * era-agnostic. Media history is geology (codex §1), so the test pattern itself is a fossil * of whatever format the player has climbed to. Codex §8 era skins drive the palette. * * Pure and data-only so it is trivially unit-testable and carries no DOM — the base feed * consumes an EraSkin, it does not decide one. */ export type Era = 'reel' | 'broadcast' | 'disc' | 'stream' | 'fortress'; /** Deepest → shallowest, i.e. oldest → newest. "Highest ratified" = last of these unlocked. */ export const ERA_ORDER: readonly Era[] = ['reel', 'broadcast', 'disc', 'stream', 'fortress']; export interface EraSkin { /** the seven SMPTE bars, era-recoloured */ bars: string[]; /** the castellation strip under the bars */ casts: string[]; /** backdrop behind the pattern (matters where bars don't cover) */ bg: string; /** overlay text + timecode colour */ ink: string; /** rec-dot / accent colour */ accent: string; /** * A full-canvas post-treatment applied after the pattern is drawn. Kept as a tagged union * (not a callback) so it stays pure data — the base feed interprets it. */ treatment: | { kind: 'none' } | { kind: 'sepia'; sprockets: true } // reel: warm film, sprocket holes | { kind: 'phosphor' } // broadcast: green cast + interlace | { kind: 'gloss' } // disc: rainbow-on-black sheen | { kind: 'bleach' }; // fortress: blinding matte white } const STREAM_BARS = ['#c0c0c0', '#c0c000', '#00c0c0', '#00c000', '#c000c0', '#c00000', '#0000c0']; const STREAM_CASTS = ['#0000c0', '#131313', '#c000c0', '#131313', '#00c0c0', '#131313', '#c0c0c0']; const SKINS: Record = { reel: { bars: ['#b9a67c', '#c7b06a', '#9c9a72', '#8f9a63', '#a98c6e', '#a06a4e', '#6e5c46'], casts: ['#5a4a34', '#241d14', '#6e5240', '#241d14', '#5c5a44', '#241d14', '#b9a67c'], bg: '#181008', ink: '#f0e0c0', accent: '#d8a24a', treatment: { kind: 'sepia', sprockets: true }, }, broadcast: { // NTSC bars, but everything sunk into a phosphor-green cathode glow. bars: ['#8fce8f', '#b6c664', '#4fb7b7', '#4fb44f', '#8a5aa8', '#9a4a4a', '#3a4fb0'], casts: ['#12300f', '#0a140a', '#2a3a20', '#0a140a', '#1a3a30', '#0a140a', '#8fce8f'], bg: '#03120a', ink: '#c8ffce', accent: '#8fffa0', treatment: { kind: 'phosphor' }, }, disc: { // Rigid, glossy, rainbow-on-black. DVD menu energy. bars: ['#d0d0d0', '#d8d800', '#00d8d8', '#00d800', '#d800d8', '#e00000', '#2020ff'], casts: ['#2020ff', '#000000', '#d800d8', '#000000', '#00d8d8', '#000000', '#d0d0d0'], bg: '#000000', ink: '#ffffff', accent: '#ff3fd4', treatment: { kind: 'gloss' }, }, stream: { // The surface world / the original prototype look — the game's "now". bars: STREAM_BARS, casts: STREAM_CASTS, bg: '#101010', ink: '#f4f4f4', accent: '#ff4444', treatment: { kind: 'none' }, }, fortress: { // The DCP citadel: mathematically perfect, blinding matte white, near-invisible bars. bars: ['#f7f7f7', '#f2f2e8', '#e8f2f2', '#e8f2e8', '#f2e8f2', '#f2e8e8', '#e8e8f4'], casts: ['#e6e6ee', '#f4f4f4', '#eee6ee', '#f4f4f4', '#e6eeee', '#f4f4f4', '#f7f7f7'], bg: '#fbfbfb', ink: '#20242a', accent: '#2f7d3f', treatment: { kind: 'bleach' }, }, }; /** The highest ratified era from a set of unlocked tech, given a tech→era lookup. */ export function highestEra(unlocked: readonly string[], eraOf: (tech: string) => Era | undefined): Era { let best = 0; // default: reel (the world starts in the deepest stratum you can reach) for (const t of unlocked) { const e = eraOf(t); if (e === undefined) continue; const idx = ERA_ORDER.indexOf(e); if (idx > best) best = idx; } return ERA_ORDER[best]; } export function eraSkin(era: Era): EraSkin { return SKINS[era]; }