8.1 KiB
AGENTS.md — SciFi-XZBT
Guidance for AI coding agents working in this repository.
What this project is
A browser-only, zero-dependency sci-fi ambient audio + visual display. It synthesizes starship room tone (hull drone, worp core, life support, telemetry, alerts) with the Web Audio API and renders LCARD-styled UI, an audio visualizer, and a procedural "observation" viewscreen on HTML canvas.
It runs by opening index.html in a browser. There is no build step, no
package manager, no server, and no test suite.
Architecture
index.html loads one stylesheet and eight scripts in a fixed order:
css/style.css
js/audio.js -> js/config.js -> js/core-animations.js -> js/visualizer.js
js/observation-bezels.js -> js/observation-engine.js
js/midi.js -> js/generative-experience.js -> js/app.js
Order matters: every file defines plain classes/objects and publishes them on
window; js/app.js runs last and consumes all of them. Do not reorder the
tags without checking the dependencies.
| File | Owns | ~Lines |
|---|---|---|
index.html |
DOM skeleton, script/link tags | 460 |
css/style.css |
LCARD themes, CRT effects, palettes | 2,430 |
js/audio.js |
AudioManager, FuturisticNoiceCancellation + all synth classes (hull, warp, life support, telemetry, alert, Whataverse, expanded sci-fi) |
6,890 |
js/config.js |
StarshipPresets, UniverseRegistry — data only, no behavior |
1,170 |
js/core-animations.js |
CoreAnimations — settings-panel core animations |
220 |
js/visualizer.js |
StarshipVisualizer — spectrum + worp core canvas |
670 |
js/observation-bezels.js |
ObservationBezels — procedural SVG viewport frames per era |
270 |
js/observation-engine.js |
ObservationEngine — celestial simulation, canvas rendering, per-universe waveform |
3,590 |
js/midi.js |
XZBTControlBus (semantic control registry) + XZBTMidiController (Web MIDI / MIDI learn) |
170 |
js/generative-experience.js |
XZBTGenerativeExperience — optional local LLM narration and neural speech |
1,370 |
js/app.js |
DOM bindings, hotkeys, UI controllers, main loop | 4,440 |
tools/package.ps1 |
Builds the standalone single-file HTML | — |
dist/SciFiAmbientDisplay_V<commit>.html |
Generated output — never edit by hand | — |
Hard constraints
- No dependencies. No npm, no CDN links, no external fonts, images, or audio files. The packaged build must work when double-clicked while offline.
- No ES modules. No
import/export, notype="module". Scripts are classic globals.
The one documented exception
js/generative-experience.js is the only file permitted to reach the
network, and it is the only file permitted to use import. It lazily pulls
WebLLM and Kokoro via dynamic import() from CDN:
this.webllm = this.webllm || await import('https://esm.run/@mlc-ai/web-llm');
this.kokoroModule = this.kokoroModule || await import('https://esm.sh/[email protected]?bundle');
The exception is bounded, and every bound is load-bearing:
- The imports live inside
prepareExperience()/prepareTTS(). Nothing is fetched at parse time, so the packaged single-file build still opens and runs fully offline — the Generative Experience panel simply stays on STANDBY. - Both are guarded:
navigator.gpuis checked before the WebLLM import, and a failed Kokoro load falls back rather than throwing. - No other subsystem may depend on this one. The deterministic engine stays authoritative; the LLM only verbalizes world state that audio.js and app.js already decided.
Do not widen this exception. New network use anywhere else, a static
<script type="module">, or a top-level import in any file is still a bug.
Web MIDI (js/midi.js) is a browser API, not a dependency, and is unaffected.
- Publish globals explicitly. End each file with
window.Thing = Thing;, matching the existing pattern. - All audio is synthesized, not sampled. New sounds are built from
oscillators / noise / filters in
js/audio.js.
Where to make a change
- New room or ship preset, universe, palette →
js/config.js - Sound generation, oscillators, envelopes, filters →
js/audio.js - FNC comfort-filter behavior, source attenuation curves →
FuturisticNoiceCancellationinjs/audio.js - MIDI mapping, learn flow, new controllable targets →
js/midi.js(register targets on the bus injs/app.js) - Speech profiles, prompts, LLM/TTS handling →
js/generative-experience.js - Spectrum bars, warp-core animation →
js/visualizer.js - Viewscreen frame / bezel shapes per era →
js/observation-bezels.js - Planets, stars, drift, observation-mode canvas →
js/observation-engine.js - Buttons, sliders, hotkeys, state wiring, animation loop →
js/app.js - Colors, layout, theme classes, CRT overlay →
css/style.css
Presets in config.js follow a fixed shape — copy an existing one rather than
inventing fields:
'era-room': {
id, name, era, theme, alertType, description,
hull: { volume, baseFreq, filterCutoff, resonance, noiseMix, harmonicSpread },
warp: { volume, bpm, carrierFreq, filterCutoff, pulseShape, resonance, swirlMix },
lifeSupport: { volume, noiseType, highpassFreq, lowpassFreq, airflowModSpeed, airflowModDepth },
telemetry: { volume, density, era }
}
Adding a new JS file
-
Create
js/your-file.jsand end it withwindow.YourThing = YourThing;. -
Add the tag to
index.htmlin this exact form, positioned before any file that depends on it (and always beforejs/app.js):<script src="js/your-file.js"></script>tools/package.ps1inlines assets by matching<script\s+src="([^"]+)"></script>and<link\s+rel="stylesheet"\s+href="([^"]+)"\s*/?>. Extra attributes, a different quote style, or a self-closing script tag will be silently left as an external reference and the standalone build will break.
Build
powershell -ExecutionPolicy Bypass -File .\tools\package.ps1
Writes dist/SciFiAmbientDisplay_v4.html (CSS and JS inlined). Re-run it after
any change to CSS, JS, or index.html. tools/extract.ps1 is the original
extraction script, kept for reference only.
Verifying work
There are no automated tests. Verification is manual:
- Open
index.htmlin a browser; check the console is clean. - Exercise the affected area — play a preset, switch era/universe, enter the Watch Experience, toggle FNC.
- Re-run
package.ps1and open the generateddist/SciFiAmbientDisplay_V<commit>.htmlwith the network disabled to confirm it is genuinely self-contained. The Generative Experience panel must report an error and everything else must still work — that is the test for the exception above, not a failure.
Browser autoplay policy blocks audio until a user gesture; audio starting only after a click is expected behavior, not a bug.
The Generative Experience needs a WebGPU-capable browser (Chrome/Edge) and network access on first preparation. Absence of either is expected to degrade quietly, never to break the console.
Conventions and cautions
- 2-space indentation; single quotes in JS; existing brace and spacing style.
js/app.js,js/audio.jsandjs/observation-engine.jsare large. Make surgical, scoped edits — do not rewrite, reorder, or reformat whole files.- Do not reformat or lint files wholesale; diffs should stay minimal and reviewable.
- Never edit anything in
dist/— regenerate it instead. - Preserve the offline, single-file-deliverable property in every change.
Terminology
Theme_Terminology_IP_Changes.md is the authoritative rename table and applies
to identifiers as well as display strings. The universe id is whataverse,
the theme class is theme-whataverse-tardix, preset ids are tardix-*, and the
telemetry era is 'whataverse'. Do not reintroduce the original franchise
spellings anywhere, including in comments.
TelemetrySynth still accepts 'who' and 'what' as era values purely for
backward compatibility with older presets; do not write new presets against them.