174 lines
8.1 KiB
Markdown
174 lines
8.1 KiB
Markdown
# 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`, no `type="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:
|
|
|
|
```js
|
|
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.gpu` is 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 → `FuturisticNoiceCancellation` in `js/audio.js`
|
|
- MIDI mapping, learn flow, new controllable targets → `js/midi.js` (register targets on the bus in `js/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:
|
|
|
|
```js
|
|
'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
|
|
|
|
1. Create `js/your-file.js` and end it with `window.YourThing = YourThing;`.
|
|
2. Add the tag to `index.html` **in this exact form**, positioned before any
|
|
file that depends on it (and always before `js/app.js`):
|
|
|
|
```html
|
|
<script src="js/your-file.js"></script>
|
|
```
|
|
|
|
`tools/package.ps1` inlines 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
|
|
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:
|
|
|
|
1. Open `index.html` in a browser; check the console is clean.
|
|
2. Exercise the affected area — play a preset, switch era/universe, enter the
|
|
Watch Experience, toggle FNC.
|
|
3. Re-run `package.ps1` and open the generated `dist/SciFiAmbientDisplay_V<commit>.html`
|
|
**with 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.js` and `js/observation-engine.js` are 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.
|