miriad-viz 0.13.1 → 0.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -133,19 +133,19 @@ See [Voice Generation Guide](./miriad-viz-voice-generation.md) for the full guid
133
133
 
134
134
  See [Viz Timing Guide](./miriad-viz-viz-timing.md) for the full guide.
135
135
 
136
- **This is where the video's rhythm is crafted.** You scaffold a pacing file, annotate speed and pauses, and iterate with the human watching the preview.
136
+ **This is where the video's rhythm is crafted.** You scaffold a curation file, adjust narration placement and pills, and iterate with the human watching the preview.
137
137
 
138
138
  **The iterate loop:**
139
139
  ```bash
140
- # 1. Scaffold pacing file (once)
141
- npx miriad-viz@latest scaffold-pacing
140
+ # 1. Scaffold curation file (once)
141
+ npx miriad-viz@latest scaffold-curation
142
142
 
143
- # 2. Edit pacing.json, then run ONE command:
144
- npx miriad-viz@latest preview --from-pacing
143
+ # 2. Edit viz-curation.json, then run ONE command:
144
+ npx miriad-viz@latest preview --from-curation
145
145
  # This auto-chains: generate-timing → transform → preview
146
146
  ```
147
147
 
148
- You edit ONE file (`pacing.json`), run ONE command, see the result. Repeat until the human approves.
148
+ You edit ONE file (`viz-curation.json`), run ONE command, see the result. Repeat until the human approves.
149
149
 
150
150
  **Timeline padding:**
151
151
  ```bash
@@ -185,7 +185,7 @@ See [Video Export](./miriad-viz-video.md) for the full guide. Mechanical step
185
185
  | Extract (git) | `npx miriad-viz@latest extract &> extract.log &` |
186
186
  | Extract (chat) | `./extract-channel.sh ./raw-data &> chat-extract.log &` |
187
187
  | Transform | `npx miriad-viz@latest transform &> transform.log &` |
188
- | Preview (from pacing) | `npx miriad-viz@latest preview --from-pacing &> preview.log &` |
188
+ | Preview (from curation) | `npx miriad-viz@latest preview --from-curation &> preview.log &` |
189
189
  | Render (video) | `pnpm render &> render.log &` |
190
190
 
191
191
  Pattern: start in background → set alarm (1-min for extract/transform, 3-min for render) → poll + report → repeat until done.
@@ -4,10 +4,11 @@
4
4
 
5
5
  Place narration on the timeline and decide how fast the viz moves. This is where the video's **pacing** is crafted — the rhythm of fast and slow, tension and release.
6
6
 
7
- Voice clip durations are fixed facts (from Step 3). You control **three things:**
8
- 1. How long to pause between lines (`pauseAfter`)
9
- 2. How fast the viz moves during a line (`vizSpeed`)
10
- 3. How fast the viz moves during pauses (`gapVizSpeed`)
7
+ Voice clip durations are fixed facts (from Step 3). You control **two things:**
8
+ 1. Where each narration line sits on the 0-100 progress scale (`progress`)
9
+ 2. Which chat pills appear and where (`pills` array)
10
+
11
+ vizSpeed is **computed mechanically**: `gap / clipDuration`. You control it indirectly by moving progress points closer (slower) or further apart (faster).
11
12
 
12
13
  ## Files
13
14
 
@@ -15,131 +16,131 @@ Voice clip durations are fixed facts (from Step 3). You control **three things:*
15
16
  |------|-----------|-------------|
16
17
  | `data/script.json` | Read | The narrative script |
17
18
  | `audio/*.mp3` | Read | Voice clips (durations measured automatically) |
18
- | `data/pacing.json` | **Write** | Your pacing annotations |
19
- | `data/timing.json` | Generated | Engine-facing timing (generated by `generate-timing`) |
20
- | `output/viz-data.json` | Generated | Final viz data (generated by `transform`) |
19
+ | `data/viz-curation.json` | **Write** | Your narration placement + chat pills |
20
+ | `data/timing.json` | Generated | Engine-facing timing (generated by transform) |
21
+ | `output/viz-data.json` | Generated | Final viz data (generated by transform) |
21
22
 
22
23
  ## Getting Started
23
24
 
24
- ### 1. Scaffold the Pacing File
25
+ ### 1. Scaffold the Curation File
25
26
 
26
27
  ```bash
27
- npx miriad-viz@latest scaffold-pacing
28
+ npx miriad-viz@latest scaffold-curation
28
29
  ```
29
30
 
30
- This reads `script.json` + measures audio clip durations → generates `pacing.json` with all defaults filled in. The output is ready to preview immediately — you only edit where you want to deviate from defaults.
31
+ This reads `script.json` + measures audio clip durations → generates `viz-curation.json` with density-proportional defaults. The output is ready to preview immediately — you only edit where you want to deviate from defaults.
31
32
 
32
- ### 2. Understand the Pacing File
33
+ ### 2. Understand the Curation File
33
34
 
34
35
  ```json
35
36
  {
36
- "version": 1,
37
- "leadInSec": 1.0,
38
- "tailOutSec": 2.0,
39
- "defaultPauseSec": 0.5,
40
- "defaultVizSpeed": 1.0,
41
- "lines": [
42
- { "id": "narrator-01", "text": "February 9th. Midnight.", "clipDuration": 3.2 },
43
- { "id": "narrator-02", "text": "The team had been shipping for 12 hours.",
44
- "clipDuration": 4.8, "vizSpeed": 1.5, "pauseAfter": 2.0, "gapVizSpeed": 0.5,
45
- "note": "montage of commits, then let it breathe" },
46
- { "id": "lead-03", "text": "Adding agents is free.", "clipDuration": 2.1 },
47
- { "id": "snorre-04", "text": "Full throttle.", "clipDuration": 1.4,
48
- "vizSpeed": 2.0, "pauseAfter": 3.0, "gapVizSpeed": 0.3,
49
- "note": "dramatic silence before crisis reveal" },
50
- { "id": "narrator-05", "text": "Then everything broke.", "clipDuration": 3.6,
51
- "vizSpeed": 0.5, "note": "slow down for impact" }
37
+ "meta": { "totalClipDuration": 226.5, "totalProgress": 100,
38
+ "phases": [{ "id": "bootstrap", "label": "Bootstrap", "progress": [0, 22] }] },
39
+ "narration": [
40
+ { "id": "narrator-01", "type": "narrator", "speaker": "narrator",
41
+ "text": "February 9th. Midnight.", "clipDuration": 3.2, "progress": 3.5 },
42
+ { "id": "narrator-02", "type": "narrator", "speaker": "narrator",
43
+ "text": "The team had been shipping for 12 hours.",
44
+ "clipDuration": 4.8, "progress": 8.3 },
45
+ { "id": "snorre-04", "type": "quote", "speaker": "snorre",
46
+ "text": "Full throttle.", "clipDuration": 1.4, "progress": 45.0 }
47
+ ],
48
+ "pills": [
49
+ { "speaker": "snorre", "text": "Full throttle.", "progress": 45.0,
50
+ "duration": 2.0, "anchor": true },
51
+ { "speaker": "bob", "text": "rendering now", "progress": 46.5,
52
+ "duration": 1.5 }
52
53
  ]
53
54
  }
54
55
  ```
55
56
 
56
- ### What You Can Edit (4 fields per line)
57
+ ### What You Can Edit
58
+
59
+ **Narration array** — adjust `progress` (0-100) to control where each line plays:
60
+ - Move points **closer together** → smaller gap → lower vizSpeed → slower playback
61
+ - Move points **further apart** → larger gap → higher vizSpeed → faster playback
57
62
 
58
- | Field | Default | Description |
59
- |-------|---------|-------------|
60
- | `pauseAfter` | `defaultPauseSec` | Seconds of silence after this line |
61
- | `vizSpeed` | `defaultVizSpeed` | Viz speed multiplier DURING this clip |
62
- | `gapVizSpeed` | `defaultVizSpeed` | Viz speed multiplier DURING the pause after this clip |
63
- | `note` | | Your reasoning (not rendered, just for you and the human) |
63
+ **Pills array** add/edit/remove chat pills:
64
+ - `speaker` — who says it
65
+ - `text` what appears on screen (can be fabricated)
66
+ - `progress` where it appears (0-100)
67
+ - `duration` how long it stays visible (in progress-space units)
68
+ - Pills with `anchor: true` are auto-generated from quote lines add your own WITHOUT anchor
64
69
 
65
70
  ### What You Must NOT Edit (read-only)
66
71
 
67
72
  | Field | Why |
68
73
  |-------|-----|
69
74
  | `id` | Matches script.json and audio filenames |
70
- | `text` | From script.json — shown so you can reason about content → pacing |
75
+ | `text` (narration) | From script.json — shown so you can reason about content |
71
76
  | `clipDuration` | Measured from audio clips — this is a fact, not a choice |
77
+ | `meta` | Computed by the lib — phases, totalClipDuration |
72
78
 
73
- ### Global Settings
79
+ ## How vizSpeed Works
74
80
 
75
- | Field | Description |
76
- |-------|-------------|
77
- | `leadInSec` | Silence before the first line (intro breathing room) |
78
- | `tailOutSec` | Silence after the last line (outro) |
79
- | `defaultPauseSec` | Default pause between lines (when `pauseAfter` is absent) |
80
- | `defaultVizSpeed` | Default viz speed (when `vizSpeed`/`gapVizSpeed` are absent) |
81
-
82
- ## How Speed Works
81
+ vizSpeed is **computed**, not set directly:
83
82
 
84
83
  ```
85
- ┌─────────────────┐ ┌─────┐ ┌─────────────────┐ ┌─────┐
86
- │ narrator-01 clip│ │ gap │ │ narrator-02 clip│ │ gap │
87
- │ vizSpeed: 1.0 │ 2.0 │ vizSpeed: 0.5 │ 1.0 │
88
- └─────────────────┘ └─────┘ └─────────────────┘ └─────┘
89
- ↑ speed DURING clip ↑ gapVizSpeed ↑ speed DURING clip ↑ gapVizSpeed
90
- (audio playing) (silence/pause) (audio playing) (silence/pause)
84
+ vizSpeed = gap / clipDuration
85
+
86
+ gap = distance to next narration point in progress-space
91
87
  ```
92
88
 
89
+ **Example:**
90
+ - narrator-01 at progress 3.5, clipDuration 5.0s
91
+ - narrator-02 at progress 8.3
92
+ - gap = 8.3 - 3.5 = 4.8
93
+ - vizSpeed = 4.8 / 5.0 = 0.96x
94
+
93
95
  **vizSpeed is a multiplier on project-time-per-second:**
94
96
  - `1.0` = default rate
95
97
  - `2.0` = viz covers project time 2× faster → **less screen time** (fast-forward)
96
98
  - `0.5` = viz covers project time 2× slower → **more screen time** (slow motion)
97
99
 
98
- **Key insight:** higher vizSpeed = faster = less screen time. Lower = slower = more screen time. The timing preview table (printed by `generate-timing`) shows concrete screen-time-per-line numbers so you don't have to do the math.
99
-
100
- **`gapVizSpeed` defaults to `defaultVizSpeed`, NOT to the line's `vizSpeed`.** This is intentional — a slow dramatic line (`vizSpeed: 0.5`) shouldn't automatically make its pause slow too. The pause speed is a separate creative choice.
100
+ **Key insight:** wider gaps = higher vizSpeed = faster. Narrower gaps = lower vizSpeed = slower. The curation table (shown by `next`) displays concrete vizSpeed per line so you don't have to do the math.
101
101
 
102
102
  ## The Iterate Loop
103
103
 
104
- After every edit to `pacing.json`, run ONE command:
104
+ After every edit to `viz-curation.json`, run ONE command:
105
105
 
106
106
  ```bash
107
- npx miriad-viz@latest preview --from-pacing
107
+ npx miriad-viz@latest preview --from-curation
108
108
  ```
109
109
 
110
110
  This auto-chains three operations:
111
- 1. `generate-timing` — computes `timing.json` from pacing + project time range
111
+ 1. Derives `timing.json` from viz-curation.json + project time range
112
112
  2. `transform` — produces `viz-data.json` with timing-aware narration
113
113
  3. Opens the preview viewer
114
114
 
115
- **You edit ONE file, run ONE command, see the result.** The three-step chain is an implementation detail.
115
+ **You edit ONE file (viz-curation.json), run ONE command, see the result.** The three-step chain is an implementation detail.
116
116
 
117
- ### The Timing Preview Table
117
+ ### The Curation Table
118
118
 
119
- `generate-timing` prints a table showing concrete screen time per line:
119
+ `next` prints a table showing computed vizSpeed and density per line:
120
120
 
121
121
  ```
122
- narrator-01 (3.2s clip + 0.5s pause) covers 2h at 1.0x = 10.4s screen
123
- narrator-02 (4.8s clip + 2.0s pause) → covers 4h at 0.5x = 52.8s screen ⚠️ LONG
124
- lead-03 (2.1s clip + 0.5s pause) → covers 1h at 1.0x = 5.2s screen
125
- Total: 4:32 video
122
+ LINE | CLIP | PROGRESS | GAP | vizSpeed | MSGS | COMMITS
123
+ narrator-01 | 5.2s | @ 3.5 | 3.6 | 0.69x | 182 | 12
124
+ snorre-01 | 3.2s | @ 7.1 | 4.9 | 1.53x | 47 | 3
125
+ narrator-02 | 4.1s | @ 12.0 | 16.0 | 3.90x | 0 | 0 ← dead zone
126
126
  ```
127
127
 
128
128
  Use this to catch problems **before watching the preview:**
129
- - `⚠️ LONG` — this segment takes a lot of screen time. Is that intentional?
130
- - Very short segmentswill the audience have time to read the narration?
131
- - Total durationdoes the video length feel right for the content?
129
+ - `← dead zone` — zero activity in this region. Space out narration (larger gaps) to skip through it.
130
+ - High vizSpeed (> 3x) — the viz is moving very fast here. Is that intentional?
131
+ - Low vizSpeed (< 0.5x) — the viz is very slow. Enough content to fill the screen time?
132
+ - Anchors — quote-type lines auto-generate pills. Place related pills nearby.
132
133
 
133
- ## Speed Reasoning — Creative Choice, Not Formula
134
+ ## Pacing Reasoning — Creative Choice, Not Formula
134
135
 
135
- The `next` output shows **event density** per script line — how many PRs, commits, and messages happened during each line's time range. Use this as input, not as a rule:
136
+ The `next` output shows **event density** per narration line — how many messages and commits happened in each line's progress window. Use this as input, not as a rule:
136
137
 
137
138
  **Guidelines (not rules):**
138
- - **Dead time** (few events, nothing happening) → high `gapVizSpeed` (skip through it)
139
- - **Intense action** (many PRs, message bursts) → normal or low `vizSpeed` (let the viewer see the frenzy)
140
- - **Dramatic reveal** → big `pauseAfter` (tension before the next line)
141
- - **Emotional moment** → low `vizSpeed` (slow down for impact)
142
- - **Montage** → high `vizSpeed` during clip (time-lapse of activity)
139
+ - **Dead zones** (zero events) → space out narration points (larger gaps, higher vizSpeed)
140
+ - **Dense areas** (many events) → cluster narration points (smaller gaps, lower vizSpeed)
141
+ - **Dramatic reveal** → place narration points close together before the reveal (slow buildup)
142
+ - **Emotional moment** → narrow gap (low vizSpeed, slow down for impact)
143
+ - **Montage** → wide gap (high vizSpeed, time-lapse of activity)
143
144
 
144
145
  **Trust your creative judgment.** The data tells you what happened. You and the human decide how it should feel. A quiet period might deserve slow pacing if it's the calm before the storm. A busy period might deserve fast pacing if it's routine work.
145
146
 
@@ -148,23 +149,15 @@ The `next` output shows **event density** per script line — how many PRs, comm
148
149
  Share the preview link and watch together. The human evaluates:
149
150
 
150
151
  - **Does the pacing feel right?** Too fast? Too slow? Uneven?
151
- - **Do the pauses land?** Is there enough silence before dramatic moments?
152
+ - **Do the pills land?** Are they readable? Too many? Too few?
152
153
  - **Does the narration sync with the visuals?** When the narrator says "then everything broke," is the viz showing the crisis?
153
154
  - **Is the total duration right?** Too long for the content? Too short to absorb?
154
155
 
155
156
  Common feedback and how to respond:
156
- - *"Slow down the middle section"* → lower `vizSpeed` on those lines
157
- - *"The pause before the crisis isn't dramatic enough"* → increase `pauseAfter`
158
- - *"Skip through the overnight period faster"* → increase `gapVizSpeed` on lines covering that range
159
- - *"The whole thing is too long"* → increase `defaultVizSpeed` globally, or increase specific `gapVizSpeed` values
160
-
161
- ## Validation
162
-
163
- `generate-timing` validates the pacing file and warns about:
164
- - Total wall-clock time < 30s or > 30min (unusual for typical scripts)
165
- - Viz coverage < 50% (narration only covers half the timeline — intentional?)
166
- - Negative values (invalid)
167
- - Missing line IDs (script.json has lines not in pacing.json)
157
+ - *"Slow down the middle section"* → move narration points closer together in that region
158
+ - *"Skip through the overnight period faster"* → space out narration points in that region
159
+ - *"Add a pill when Bob says that"* → add a pill to the pills array at the right progress point
160
+ - *"The whole thing is too long"* → space out narration points globally (wider gaps)
168
161
 
169
162
  ## What You Cannot Control (v1)
170
163
 
@@ -172,12 +165,12 @@ Be honest with the human about these boundaries:
172
165
 
173
166
  | Cannot control | Why | Future |
174
167
  |---|---|---|
175
- | **Visual emphasis** — can't zoom into an agent, hide a band, or highlight a node at a specific moment | Viz is a pure function of progress. No per-moment visual overrides. | Camera directives in pacing file |
176
- | **Cross-fades between lines** — every line cuts to the next, no overlap or blend | Audio clips are discrete files, no mixing in v1 | Crossfade field on PacingLine |
177
- | **What data appears** — can't add/remove agents, PRs, or events from the viz | Data comes from extraction, not pacing | Selective data filtering |
168
+ | **Visual emphasis** — can't zoom into an agent, hide a band, or highlight a node at a specific moment | Viz is a pure function of progress. No per-moment visual overrides. | Camera directives |
169
+ | **Cross-fades between lines** — every line cuts to the next, no overlap or blend | Audio clips are discrete files, no mixing in v1 | Crossfade support |
170
+ | **What data appears** — can't add/remove agents, PRs, or events from the viz | Data comes from extraction, not curation | Selective data filtering |
178
171
  | **Layout or visual style** — can't change colors, positions, or rendering | Renderer is fixed, driven by viz-data | Style overrides per phase |
179
172
 
180
- You control **pacing** (how fast time moves) and **audio** (what you hear). The visual content is determined by the extracted data and the renderer. This is by design — it keeps the pacing file simple and the iterate loop fast.
173
+ You control **pacing** (via narration placement) and **pills** (what text appears on screen). The visual content is determined by the extracted data and the renderer. This is by design — it keeps the curation file simple and the iterate loop fast.
181
174
 
182
175
  ## When to Stop for Human Review
183
176
 
@@ -187,4 +180,4 @@ You control **pacing** (how fast time moves) and **audio** (what you hear). The
187
180
  npx miriad-viz@latest next --timing-approved
188
181
  ```
189
182
 
190
- **Timing is now locked.** Step 5 (Sound Design) adds SFX and music on top of the locked timing. Changes to pacing after this point require going back to this step.
183
+ **Timing is now locked.** Step 5 (Sound Design) adds SFX and music on top of the locked timing. Changes to curation after this point require going back to this step.
@@ -21,7 +21,7 @@ echo $ELEVENLABS_API_KEY
21
21
 
22
22
  **If missing:** Tell the human: "ElevenLabs API key not configured. To add narration, set `ELEVENLABS_API_KEY` in your environment. Without it, I can skip voices — the viz will use estimated durations based on text length, and the video will be silent."
23
23
 
24
- **No API key is not a blocker.** The pipeline continues without audio — `scaffold-pacing` estimates clip durations from text length, and the viz renders with text-only narration. Audio can be added later.
24
+ **No API key is not a blocker.** The pipeline continues without audio — `scaffold-curation` estimates clip durations from text length, and the viz renders with text-only narration. Audio can be added later.
25
25
 
26
26
  ## The Filename Convention
27
27
 
@@ -35,7 +35,7 @@ script.json line: { "id": "lead-03", ... }
35
35
  audio file: audio/lead-03.mp3
36
36
  ```
37
37
 
38
- `scaffold-pacing` (Step 4) looks up clips by this convention. Wrong filenames = missing audio = broken pacing.
38
+ `scaffold-curation` (Step 4) looks up clips by this convention. Wrong filenames = missing audio = broken timing.
39
39
 
40
40
  ## Workflow
41
41
 
@@ -103,7 +103,7 @@ After generating all clips, measure their durations:
103
103
  ffprobe -v quiet -show_entries format=duration -of csv=p=0 audio/narrator-01.mp3
104
104
  ```
105
105
 
106
- You don't need to record these manually — `scaffold-pacing` (Step 4) reads them automatically from the audio files.
106
+ You don't need to record these manually — `scaffold-curation` (Step 4) reads them automatically from the audio files.
107
107
 
108
108
  ### 5. Human Review
109
109
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miriad-viz",
3
- "version": "0.13.1",
3
+ "version": "0.13.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/snorrees/miriad-viz.git"