| name | vj-timeline |
| description | Compose and execute timed music video shows inside WibWob-DOS TUI.
Declarative timeline files sync visual cues (window layout, theme changes,
primer art, figlet typography) to audio playback. Use when: creating a
music video, VJ show, timed visual performance, or any task that needs
coordinated window choreography synced to audio. Triggers on: "music video",
"VJ show", "visual performance", "timeline", "timed show", "sync to music".
|
VJ Timeline
Compose timed music video shows inside WibWob-DOS.
What This Is
A declarative timeline format that an agent writes as a file. The timeline
service parses it and plays it back: audio starts, visual cues fire at
exact timestamps. No sleep() drift. No manual command sequencing.
The Format
Timeline files are JSON (YAML support planned). The agent writes these.
{
"version": 1,
"title": "PC Music Recap Video",
"track": "/path/to/track.mp3",
"duration": 60,
"palette": [
{ "name": "sequencer", "file": "/path/to/chromatic-sequencer.txt", "note": "grid aesthetic" },
{ "name": "tracker", "file": "/path/to/msdos-music-tracker.txt", "note": "DROP anchor" }
],
"scenes": {
"intro": {
"name": "intro",
"theme": "wibwob-dark",
"windows": [
{ "role": "backdrop", "open": { "type": "primer", "file": "/path/to/sequencer.txt" }, "layout": "hero-left" },
{ "role": "headline", "open": { "type": "figlet", "text": "HYPERPOP", "font": "slant" }, "layout": "top-banner" }
]
},
"drop": {
"name": "drop",
"theme": "wibwob-dark",
"windows": [
{ "role": "backdrop", "open": { "type": "primer", "file": "/path/to/tracker.txt" }, "layout": "backdrop" },
{ "role": "headline", "open": { "type": "figlet", "text": "DROP", "font": "banner" }, "layout": "top-right-corner" }
]
}
},
"cues": [
{ "at": { "t": 0 }, "scene": "intro" },
{ "at": { "t": 4 }, "patch": { "theme": "wibwob-dark-pastel", "set": [
{ "role": "face", "open": { "type": "primer", "file": "/path/to/synth-face.txt" }, "layout": "sidebar-right" }
]}},
{ "at": { "t": 19 }, "scene": "drop" },
{ "at": { "t": 25 }, "command": { "id": "theme.set", "args": { "name": "wibwob-dark-pastel" } } }
]
}
Core Concepts
Scenes
A scene is a complete desired desktop state. When a scene cue fires, the
planner diffs the current desktop against the scene and emits close/open/
move/resize operations. Windows matched by role are reused; unmatched
existing windows are closed; unmatched scene windows are opened.
Patches
A patch is a partial update. It can add windows (set), remove windows by
role (close), and change the theme. Use patches for incremental changes
between major scene transitions.
Commands
A command cue fires a single registry command by ID. Useful for theme.set,
or any discrete action that does not involve window layout.
Roles
Every window in a scene has a stable ROLE (e.g. "backdrop", "headline",
"lyric", "face"). Roles persist across cues. If the "backdrop" role
appears in two consecutive scenes, the planner reuses the window rather
than closing and reopening it.
Layout Tokens
Layout tokens are named positions resolved against the live desktop size:
| Token | Description |
|---|
| backdrop | full usable desktop |
| fullscreen | same as backdrop |
| hero-left | 65% width, full height, left-aligned |
| hero-right | 65% width, full height, right-aligned |
| hero-center | 70% width, 80% height, centered |
| top-banner | full width, top 15% |
| bottom-banner | full width, bottom 15% |
| lyric-bar | full width, bottom 12 rows |
| top-right-corner | 30% width, 20% height, top-right |
| top-left-corner | 30% width, 20% height, top-left |
| sidebar-right | 30% width, full height, right |
| sidebar-left | 30% width, full height, left |
| center-card | 40% width, 50% height, centered |
| strip-bottom | full width, bottom 30% |
You can also use explicit coordinates: { "x": 0, "y": 0, "w": 90, "h": 40 }
Or proportional: { "xPct": 0, "yPct": 0, "wPct": 0.5, "hPct": 1.0 }
Timing
Cues can be timed three ways:
- Absolute:
{ "t": 4.0 } — seconds from track start
- Beat:
{ "beat": 16 } — requires a beat map
- Section:
{ "section": "drop" } — fires at section start
Cues must be in monotonic time order.
Beat Maps
Optional audio analysis output. Inline in the timeline or as a separate file:
{
"bpm": 150,
"key": "F minor",
"duration": 60,
"beats": [
{ "beat": 1, "t": 0.0 },
{ "beat": 2, "t": 0.4 }
],
"sections": [
{ "name": "intro", "startBeat": 1, "endBeat": 10, "startT": 0, "endT": 4 },
{ "name": "drop", "startBeat": 48, "endBeat": 85, "startT": 19, "endT": 34 }
]
}
Primer Palette
Curate visual assets before composing. The palette lists primers with
short names and creative notes explaining why each was chosen.
IMPORTANT: Use just the FILENAME for primer file references, not full
paths. The runner resolves filenames to real paths automatically via
the primer.list API. This means timeline files are portable and you
do not need to know where primers live on disk.
"palette": [
{ "name": "sequencer", "file": "chromatic-sequencer.txt", "note": "grid aesthetic, instruments" },
{ "name": "jellyfish", "file": "disco-jellyfish.txt", "note": "hyperpop energy" },
{ "name": "tracker", "file": "msdos-music-tracker.txt", "note": "DROP anchor, recursive" }
]
The palette tells a story arc. Curating it IS part of the creative work.
Composition Workflow
- Listen to the track. Read the trackview data if available.
- Map musical sections to visual moods and energy levels.
- Curate a primer palette (6-10 assets that fit the track).
- Define scenes for major sections (intro, verse, drop, outro, finale).
- Write cues: scene transitions at section boundaries, patches for
incremental changes within sections.
- Typography is emotion: figlet text should land at lyrical moments.
- Theme slams as punctuation at energy shifts.
Available themes: wibwob-dark, wibwob-dark-nord, wibwob-dark-pastel, wibwob-light
- Leave breathing room. Not every beat needs a visual change.
- Plan a finale — slower, more composed, separate register from the show.
Creative Heuristics
- The DROP is a clear-and-rebuild gesture. Wipe the stage, land one big thing.
- Layer figlet text OVER primers, not beside them. Text on art creates depth.
- Theme changes are free and instant. Use them as percussion.
- One hero window per scene. Everything else supports it.
- The finale breathes. The show rushes. Contrast is everything.
- Vary primer sizes. A tiny window next to a huge one creates hierarchy.
- Animated primers (three-hyphen frame separators) add motion without effort.
Script Toolkit
Six scripts cover the full workflow:
bun run scripts/timeline-new.ts path/to/track.mp3 --name my-show
bun run scripts/timeline-validate.ts path/to/timeline.json
bun run scripts/timeline-dry-run.ts path/to/timeline.json [width] [height]
bun run scripts/timeline-run.ts path/to/timeline.json [--no-audio]
bun run scripts/timeline-capture.ts path/to/timeline.json [--no-audio]
bun run scripts/timeline-review.ts scratch/timeline-captures/<timestamp>/
Typical agent workflow:
new → edit → validate → dry-run → capture → review → fix → repeat
Alignment with Chiptune Studio
The chiptune-studio skill has a trackview format for audio composition.
The VJ timeline describes the VISUAL layer over the same time axis.
They share a common transport envelope: beats, bars, sections, duration.
But they are different domains:
- Trackview = what the AUDIO does at each beat
- Timeline = what the VISUALS do at each beat
A unified workflow: compose the track with chiptune-studio, export a
beat map, then compose the visual timeline referencing that beat map.
The agent can do both in one session.
Files
| File | Purpose |
|---|
src/services/timeline-types.ts | Schema: TimelineFile, Cue, Scene, etc |
src/services/timeline-service.ts | Parse, validate, schedule, execute |
src/services/scene-planner.ts | Diff desired vs live desktop state |
src/services/scene-layout.ts | Resolve layout tokens to coordinates |
scripts/timeline-new.ts | Scaffold a timeline from a track file |
scripts/timeline-validate.ts | CLI validator |
scripts/timeline-dry-run.ts | Print resolved cue schedule |
scripts/timeline-run.ts | Execute against running app |
scripts/timeline-capture.ts | Run + screenshot every cue to disk |
scripts/timeline-review.ts | Compare expected vs actual from captures |
scratch/timelines/ | Where timeline files live |
scratch/timeline-captures/ | Where capture runs are saved |