Engine core: Timeline (fixed dt, audio-mastered in realtime), seeded Rng, Renderer, Layer/ShaderLayer/SceneLayer, Compositor with blend modes, feedback and post chain. Shader scenes are compiled against a fixed uniform contract and define only `vec4 scene(vec2 uv, vec2 p)`, so adding a scene costs a shader plus a params block. Deep Nebula ported from party-stage as the first one. Gate passes, 7/7 in checks.html: - 300 frames rendered twice are bit-identical - a fresh Engine reproduces the same frames - simulated dropped frames change nothing (proves dt is fixed) - seek matches sequential playback - 320x180 vs 1280x720 agree within 0.010 (limit 0.06) - seeded rng reproducible, forked streams independent - compositor reset clears feedback history Static gates: no wall-clock or unseeded randomness in deterministic directories; scene schemas and shader sources agree in both directions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
51 lines
1.5 KiB
JavaScript
51 lines
1.5 KiB
JavaScript
import { validateModule } from '../params/schema.js';
|
|
|
|
import { nebula } from './shader/nebula.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,
|
|
];
|
|
|
|
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;
|