Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"style": {
"type": "string",
"title": "Scene",
"description": "fire: a ░▒▓█ fire with sparks and smoke; warp: stars that speed up to hyperspace; avalon: a colony ship whose shield burns up the asteroids that hit it; balloon: a hot-air balloon that climbs from the grass to space; engine: a steampunk engine that runs up to full speed; falcon: a Falcon 9 carrying Dragon: its booster lands on its legs, Dragon comes home under parachutes to a splashdown; starship: a bigger rocket that hot-stages: its booster is caught by the tower's arms, the Ship splashes down; surf: a surfer and the swell; ski: a skier down the mountain; bubbles: bubbles fizzing up; train: a train through the countryside, faster with the work; earthrise: the Earth over the moon, rising and turning faster with the work; doom: a space marine fighting through a 1993 techbase, faster and harder with the work; doom3d: the same fight through his own eyes, in a taller band",
"description": "fire: a ░▒▓█ fire with sparks and smoke; warp: stars that speed up to hyperspace; avalon: a colony ship whose shield burns up the asteroids that hit it; balloon: a hot-air balloon that climbs from the grass to space; engine: a steampunk engine that runs up to full speed; falcon: a Falcon 9 carrying Dragon: its booster lands on its legs, Dragon comes home under parachutes to a splashdown; starship: a bigger rocket that hot-stages: its booster is caught by the tower's arms, the Ship splashes down; surf: a surfer and the swell; ski: a skier down the mountain; bubbles: bubbles fizzing up; train: a train through the countryside, faster with the work; earthrise: the Earth over the moon, rising and turning faster with the work; doom: a space marine fighting through a 1993 techbase, faster and harder with the work; doom3d: the same fight through his own eyes, in a taller band; roadster: Tesla's new Roadster, from a city lot to the freeway with the work, flipping over the traffic at 10",
"default": "fire",
"options": [
"fire",
Expand All @@ -52,7 +52,8 @@
"train",
"earthrise",
"doom",
"doom3d"
"doom3d",
"roadster"
]
},
"idle": {
Expand Down Expand Up @@ -84,7 +85,7 @@
"time": {
"type": "string",
"title": "Day or night",
"description": "For balloon, falcon, starship, surf, ski, bubbles and train: clock follows your local time (night from 19:00 to 7:00); day or night pins it",
"description": "For balloon, falcon, starship, surf, ski, bubbles, train and roadster: clock follows your local time (night from 19:00 to 7:00); day or night pins it",
"default": "clock",
"options": [
"clock",
Expand Down
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ hooks/
fire.ts the fire scene's automaton (its heat grid), glyphs and 256-color ramps
fire-palette.ts the fire scene's truecolor ramps
<scene>.ts one file per scene: starfield (warp), colony, balloon + sky + clouds/,
engine, rocket (falcon, starship), surf, ski, bubbles, train, doom (doom3d)
engine, rocket (falcon, starship), surf, ski, bubbles, train, doom (doom3d), roadster (its spine's sky has clouds/' cumulus)
opencode/
tui.ts opencode adapter (a terminal UI plugin: the band above the prompt, the spine in the sidebar, /flow,
settings in its storage, the soundscape)
Expand Down Expand Up @@ -70,7 +70,7 @@ A scene implements `Scene` (`hooks/styles.ts`). Its file exports a `SceneDef` (`
- **Dials**, set every frame by `SceneDriver.dial()`:
- `strength` 0–10: 0 draws nothing, every cell blank; 1 is calm idle; 10 is the busiest. Ease changes; never jump.
- `coverageBoost`: above 0 while subagents run (15 each; in manual mode too). Add company (more streams, thicker steam).
- `agents`: each running subagent on its own (`AgentDial`: a stable `id`, `state` `'working' | 'idle' | 'waiting' | 'done'`, `ok` once done, its `task` and `type`, `ms` run), in the order they started (in manual mode too: holding a level holds how busy it looks, not who's about); `[]` in pi. In opencode a subagent is a child session (`session.created` with a `parentID`): `opencode/mapping.ts` lists them to the same `Roster`, done when their run ends. The adapter derives it (`Roster`, `agents.ts`) from `agent.list()` polls (teammates left out) and each agent's own events by `agentId`: a model step or streamed output or a tool call is working, a tool running keeps it working, nothing for `QUIET_MS` (20 s) or a held/between-turns status is idle, a dialog put to the person is waiting (a permission once `classic.PermissionRequest` shows its dialog, since auto mode's classifier settles most asks alone, matched to that loop's running call of the tool (by its input when the loop runs several), each noted as `tool.call` starts it, so another call ending never ends it; `AskUserQuestion`/`ExitPlanMode` from the start; it ends with the call, a refusal too since the permission prompt runs beneath `tool.call`, or its `ToolProgress` pill; one tracker, `Waits` in `waits.ts`, keeps every loop's waits for the roster and the `waiting` dial alike), its `turn.complete` (or its status ending, or its leaving the list) is done, kept `DONE_MS` (6 s) so its companion can leave. What's heard from a loop before a poll names it (tools running, waits) is kept and counts once it is. A scene that gives each agent a companion keeps a `Crew` (`crew.ts`): set `crew.room` to how many companions this layout can actually show (the spine fits fewer), `update(this.agents, this.coverageBoost)` once a frame, then draw `crew.mates`, every one of them on screen: each keeps its `slot` (its colors, its place; only slots below `room` are given, and a layout with less room sends the rest back to wait) while on screen, `here` eases 0 → 1 as it arrives and back to 0 as it leaves (then its slot frees for an agent waiting past `capacity`), `busy` eases 1 working / 0 resting, `waiting` and `leaving`/`ok` say the rest (`resting`, `beckon` for a waiting one's blink, `finished`, `failed`, `easeTo` and `crew.inSlot` say them alike in every scene). Arrive from an edge, work visibly, rest visibly (and show waiting on you), leave out of sight (failed, another way); never pop. An adapter with no list (only a count) still gets anonymous working companions from `coverageBoost`. Note each companion's cells with `crew.mark` while drawing and return `crew.marks` from `agentMarks()`: desktop puts the agent's hover card there. Fire, surf, ski, balloon, falcon, starship (a mini rocket each: a hosted `LaunchSite` flying the same code, a few frames late, in the host's world and pixel layer), engine, train, avalon (probes launched from the ship) and doom and doom3d (marines of a co-op squad) have companions (the fire's are small fires of their own beside the main one, which narrows to make room: one automaton, its burners shaped column by column); warp and bubbles keep plain coverage (a first-person stream, anonymous bubbles: nothing stays put to be someone).
- `agents`: each running subagent on its own (`AgentDial`: a stable `id`, `state` `'working' | 'idle' | 'waiting' | 'done'`, `ok` once done, its `task` and `type`, `ms` run), in the order they started (in manual mode too: holding a level holds how busy it looks, not who's about); `[]` in pi. In opencode a subagent is a child session (`session.created` with a `parentID`): `opencode/mapping.ts` lists them to the same `Roster`, done when their run ends. The adapter derives it (`Roster`, `agents.ts`) from `agent.list()` polls (teammates left out) and each agent's own events by `agentId`: a model step or streamed output or a tool call is working, a tool running keeps it working, nothing for `QUIET_MS` (20 s) or a held/between-turns status is idle, a dialog put to the person is waiting (a permission once `classic.PermissionRequest` shows its dialog, since auto mode's classifier settles most asks alone, matched to that loop's running call of the tool (by its input when the loop runs several), each noted as `tool.call` starts it, so another call ending never ends it; `AskUserQuestion`/`ExitPlanMode` from the start; it ends with the call, a refusal too since the permission prompt runs beneath `tool.call`, or its `ToolProgress` pill; one tracker, `Waits` in `waits.ts`, keeps every loop's waits for the roster and the `waiting` dial alike), its `turn.complete` (or its status ending, or its leaving the list) is done, kept `DONE_MS` (6 s) so its companion can leave. What's heard from a loop before a poll names it (tools running, waits) is kept and counts once it is. A scene that gives each agent a companion keeps a `Crew` (`crew.ts`): set `crew.room` to how many companions this layout can actually show (the spine fits fewer), `update(this.agents, this.coverageBoost)` once a frame, then draw `crew.mates`, every one of them on screen: each keeps its `slot` (its colors, its place; only slots below `room` are given, and a layout with less room sends the rest back to wait) while on screen, `here` eases 0 → 1 as it arrives and back to 0 as it leaves (then its slot frees for an agent waiting past `capacity`), `busy` eases 1 working / 0 resting, `waiting` and `leaving`/`ok` say the rest (`resting`, `beckon` for a waiting one's blink, `finished`, `failed`, `easeTo` and `crew.inSlot` say them alike in every scene). Arrive from an edge, work visibly, rest visibly (and show waiting on you), leave out of sight (failed, another way); never pop. An adapter with no list (only a count) still gets anonymous working companions from `coverageBoost`. Note each companion's cells with `crew.mark` while drawing and return `crew.marks` from `agentMarks()`: desktop puts the agent's hover card there. Fire, surf, ski, balloon, falcon, starship (a mini rocket each: a hosted `LaunchSite` flying the same code, a few frames late, in the host's world and pixel layer), engine, train, avalon (probes launched from the ship), doom and doom3d (marines of a co-op squad) and roadster (smaller Roadsters in the far lane, flipping as the big one does) have companions (the fire's are small fires of their own beside the main one, which narrows to make room: one automaton, its burners shaped column by column); warp and bubbles keep plain coverage (a first-person stream, anonymous bubbles: nothing stays put to be someone).
- `tint`: `'smoke'` (a failed command or compaction) or `'blue'` (context nearly full). Must be clearly visible in every scene, at every level, in both layouts, and to colour-blind eyes: move lightness or blue-yellow, not only red-green (white to cyan, say, is a change of red alone, and red-green colour blindness can't see it). `npm run cvd` measures it.
- `night`: for scenes with a night version. Ease a `kNight` toward it with `easeNight` rather than switching in one frame. Use `night.ts` so every night matches, and falls at the same pace.
- `waiting`: Claude waits on the person (a dialog is up for them: a permission, its question, a plan to approve; auto mode only, never in pi). Any loop's dialog counts (a background subagent's too); the main turn's 30 s clock stops for the main loop's own waits and for a dialog up, not for a subagent's ask the mode is still deciding, and the main turn ending forgets only its own. A wait is its session's: the adapter forgets them when the session ends, so a /clear or a resume never carries one over. The level drops to a calm 2 by itself (`WAIT_LEVEL`). Every scene eases a `kWait` toward it (`easeWait`) and ends `grid()` with `waitTone(out, kWait, t)`: the frame turns sepia and breathes, the same in every scene, so it reads at a glance and never like smoke or blue (`PixelScene` does both; `d.wait` says how far). Then settle and hold your own way, never as if working: a place the level stands for holds (the balloon hovers, a rocket keeps its stage and doesn't launch), what moves comes to rest where that's natural (the skier stops, the engine runs down, the stars stop, the train draws up at a signal or a platform). A light can shine through the sepia, only breathing (`waitTone`'s `lamps`; in a `PixelScene`, paint it with `px.lamp`), as the train's signals do. A warm scene can skip the sepia (`waitTone(..., 0)`) but must breathe, as the fire's coals do.
Expand All @@ -97,7 +97,7 @@ A scene implements `Scene` (`hooks/styles.ts`). Its file exports a `SceneDef` (`
- **Someone there**: nothing is heard till someone's been seen at the session: a key in the prompt (`prompt.edit`), a turn or a `/flow`, kept in `state` (`present`) so a reload keeps it. Claude Code warms spare sessions in the background, each with a terminal no one sees, that load Flow and show its scene.
- **The chime**: when a wait on the person begins (the driver's `waiting()`), one clip for every scene (`CHIME`) at a fixed gain, not the scene's master: about as loud as a scene at 6, a cue over the waiting bed's calm 2, never an alarm. `chimeStep` plays it once a wait, `CHIME_DELAY_MS` in, and not for a wait beginning within `CHIME_QUIET_MS` of the last one's end (back-to-back asks find the person there). It's an event clip (the player rules above), part of the soundscape, so it follows the session's own sound setting: no setting of its own.
- **Building**: `npm run sounds [folders]` (needs `sox` and `ffmpeg`) runs every recipe in `scripts/make-sounds.ts` into `.sound-cache/` (WAV), mixes and encodes `sounds/` (AAC: beds 32 kbps, events 64) and writes `hooks/sound-files.ts` (the clips and `BED_GAINS`); `npm run sounds fire` rebuilds one folder or scene, `npm run sounds events/chime` just those clips. sox dithers at random, so every rebuild differs: rebuild only what you changed. A partial rebuild takes the beds' gains from `.sound-cache/bed-gains.json`: without it (a fresh checkout) the manifest comes out with none, so copy `.sound-cache/` over first. Commit `sounds/` and the manifest.
- **Tuning** a scene (how these were made): get a real recording of the thing (public-domain or CC0 is easiest; it's only measured, never shipped), measure it and the scene's mix the same way (octave bands, spectral centre, crackle kurtosis and bursts a second, onsets, flutter depth and rate, rhythm), and adjust the recipe until they match within a few dB. The references: rockets, NASA's STS-131 and SDO/Atlas V launch recordings; fire, a campfire; surf, a calm tropical beach and rough sea waves; engine, two steam engines; bubbles, water bubbling, boiling and big bubbles; balloon, strong wind and a pressurized gas flame; ski, crunchy snow; booms, a sonic boom; train, wheels knocking over jointed track heard from a carriage, a freight train passing (and its horn), a diesel locomotive idling and a diesel railcar pulling away (all on Wikimedia Commons). The colony ship, the warp drive and earthrise have no real counterpart: theirs are designed, after spacecraft cabin noise (earthrise's only steady low tones: no air on the moon, so no noise or wind). Doom's are designed too, after a plant room, gunshots in a hard corridor and generic sci-fi, never the game's own sounds; doom3d sounds as doom (`soundsAs`: its beds and master are doom's). A doom marine with a target come into sight takes aim for the player's start-up time first, so his shot's sound, sent then, lands with its flash. A gun firing faster than the player can take clips (doom's chaingun and plasma rifle) is heard a volley at a time, one clip of about 1.4 s of shots at its rate, the next sent as the last runs out; when the gun stops early a `cease` event stops that clip (a stop takes no start-up, so it lands on time). What's dense and secondary (squad shots, falls, doors, footsteps in a fight) is thinned or left out so the four places go to what matters.
- **Tuning** a scene (how these were made): get a real recording of the thing (public-domain or CC0 is easiest; it's only measured, never shipped), measure it and the scene's mix the same way (octave bands, spectral centre, crackle kurtosis and bursts a second, onsets, flutter depth and rate, rhythm), and adjust the recipe until they match within a few dB. The references: rockets, NASA's STS-131 and SDO/Atlas V launch recordings; fire, a campfire; surf, a calm tropical beach and rough sea waves; engine, two steam engines; bubbles, water bubbling, boiling and big bubbles; balloon, strong wind and a pressurized gas flame; ski, crunchy snow; booms, a sonic boom; train, wheels knocking over jointed track heard from a carriage, a freight train passing (and its horn), a diesel locomotive idling and a diesel railcar pulling away (all on Wikimedia Commons). The colony ship, the warp drive and earthrise have no real counterpart: theirs are designed, after spacecraft cabin noise (earthrise's only steady low tones: no air on the moon, so no noise or wind). The Roadster's is designed too (no recording matched yet), after an electric car heard from inside: tyre roar near 1 kHz, a motor whine rising with speed, wind on the freeway, a city's distant traffic while it's parked; its loudness set against the train's at levels 1, 5 and 10. Its jets alone are matched to a recording: Tesla's film of the car's jump (its deep roar under the hiss, octave bands within a few dB from 125 Hz up). Doom's are designed too, after a plant room, gunshots in a hard corridor and generic sci-fi, never the game's own sounds; doom3d sounds as doom (`soundsAs`: its beds and master are doom's). A doom marine with a target come into sight takes aim for the player's start-up time first, so his shot's sound, sent then, lands with its flash. A gun firing faster than the player can take clips (doom's chaingun and plasma rifle) is heard a volley at a time, one clip of about 1.4 s of shots at its rate, the next sent as the last runs out; when the gun stops early a `cease` event stops that clip (a stop takes no start-up, so it lands on time). What's dense and secondary (squad shots, falls, doors, footsteps in a fight) is thinned or left out so the four places go to what matters.

## Mod API rules

Expand Down
Loading
Loading