import { validateModule } from '../params/schema.js'; import { nebula } from './shader/nebula.js'; import { classicWave } from './shader/classic-wave.js'; import { floatingGeometry } from './shader/floating-geometry.js'; import { synthwaveRun } from './shader/synthwave-run.js'; import { psychedelicDrift } from './shader/psychedelic-drift.js'; import { particleField } from './layers3d/particles.js'; import { horizonLines } from './shader/horizon-lines.js'; import { spectrumSculpture } from './shader/spectrum-sculpture.js'; import { slowOrb } from './shader/slow-orb.js'; import { curlFlow } from './shader/curl-flow.js'; import { plasmaBloom } from './shader/plasma-bloom.js'; import { metaballs } from './shader/metaballs.js'; import { kaleidoTunnel } from './shader/kaleido-tunnel.js'; import { moireGrid } from './shader/moire-grid.js'; import { ridgeTerrain } from './shader/ridge-terrain.js'; import { scanTear } from './shader/scan-tear.js'; import { blockMosh } from './shader/block-mosh.js'; import { neonCity } from './shader/neon-city.js'; import { flora } from './shader/flora.js'; import { fireflyDrift } from './shader/firefly-drift.js'; import { silkRibbon } from './shader/silk-ribbon.js'; import { pylonGrid } from './shader/pylon-grid.js'; import { prismBloom } from './shader/prism-bloom.js'; import { pitchShatter } from './shader/pitch-shatter.js'; import { auroraVeil } from './shader/aurora-veil.js'; import { tideRings } from './shader/tide-rings.js'; import { dustChamber } from './shader/dust-chamber.js'; import { cargoBelt } from './shader/cargo-belt.js'; import { circuitBloom } from './shader/circuit-bloom.js'; import { truchetFold } from './shader/truchet-fold.js'; import { signalDecay } from './shader/signal-decay.js'; import { inkBleed } from './shader/ink-bleed.js'; import { saltFlat } from './shader/salt-flat.js'; import { stormRift } from './shader/storm-rift.js'; import { vortexDrift } from './shader/vortex-drift.js'; import { gateCorridor } from './shader/gate-corridor.js'; /** * The scene library. Families exist so the arc driver can choose by section * character rather than at random — a breakdown never lands on a strobing glitch * scene, and an intro never opens at full density. */ export const FAMILIES = { flow: { label: 'Flow', energy: [0.0, 0.7] }, organic: { label: 'Organic', energy: [0.0, 0.8] }, minimal: { label: 'Minimal', energy: [0.0, 0.45] }, structural: { label: 'Structural', energy: [0.3, 0.9] }, geometric: { label: 'Geometric', energy: [0.4, 1.0] }, glitch: { label: 'Glitch', energy: [0.6, 1.0] }, }; const MODULES = [ nebula, classicWave, floatingGeometry, synthwaveRun, psychedelicDrift, particleField, // Phase 7 additions. 'minimal' came first: with the family empty, intros and // breakdowns fell through to flow/organic and every track opened at density. horizonLines, spectrumSculpture, slowOrb, curlFlow, plasmaBloom, metaballs, kaleidoTunnel, moireGrid, ridgeTerrain, scanTear, blockMosh, neonCity, flora, fireflyDrift, silkRibbon, pylonGrid, prismBloom, pitchShatter, // Ten added to widen the library past the point where a track's rosters // start repeating: the casting rule shrinks the pool per track, so depth in // every family is what keeps two videos from drawing the same four scenes. // Weighted toward the 'space' and 'shape' traits, which were the thinnest // and therefore the signatures most likely to run out of cast. auroraVeil, tideRings, dustChamber, cargoBelt, circuitBloom, truchetFold, signalDecay, inkBleed, saltFlat, stormRift, vortexDrift, gateCorridor, ]; const errors = []; for (const m of MODULES) { const e = validateModule(m); if (e.length) errors.push(...e); if (m.family && !FAMILIES[m.family]) errors.push(`${m.name}: unknown family '${m.family}'`); } if (errors.length) { // Fail loudly at import: a malformed scene must never reach the compositor, // where the symptom would be a black frame with no explanation. console.error('[registry] invalid scene modules:\n' + errors.join('\n')); } export const scenes = MODULES; export const sceneErrors = errors; export function sceneByName(name) { return MODULES.find((m) => m.name === name) || null; } export function scenesInFamily(family) { return MODULES.filter((m) => m.family === family); } export function familyNames() { return Object.keys(FAMILIES); } export default scenes;