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
|
|
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
|
|
141
|
-
npx miriad-viz@latest scaffold-
|
|
140
|
+
# 1. Scaffold curation file (once)
|
|
141
|
+
npx miriad-viz@latest scaffold-curation
|
|
142
142
|
|
|
143
|
-
# 2. Edit
|
|
144
|
-
npx miriad-viz@latest preview --from-
|
|
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 (`
|
|
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
|
|
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 **
|
|
8
|
-
1.
|
|
9
|
-
2.
|
|
10
|
-
|
|
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/
|
|
19
|
-
| `data/timing.json` | Generated | Engine-facing timing (generated by
|
|
20
|
-
| `output/viz-data.json` | Generated | Final viz data (generated by
|
|
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
|
|
25
|
+
### 1. Scaffold the Curation File
|
|
25
26
|
|
|
26
27
|
```bash
|
|
27
|
-
npx miriad-viz@latest scaffold-
|
|
28
|
+
npx miriad-viz@latest scaffold-curation
|
|
28
29
|
```
|
|
29
30
|
|
|
30
|
-
This reads `script.json` + measures audio clip durations → generates `
|
|
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
|
|
33
|
+
### 2. Understand the Curation File
|
|
33
34
|
|
|
34
35
|
```json
|
|
35
36
|
{
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
{ "
|
|
51
|
-
"
|
|
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
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
|
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
|
-
|
|
79
|
+
## How vizSpeed Works
|
|
74
80
|
|
|
75
|
-
|
|
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
|
-
|
|
87
|
-
|
|
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
|
|
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 `
|
|
104
|
+
After every edit to `viz-curation.json`, run ONE command:
|
|
105
105
|
|
|
106
106
|
```bash
|
|
107
|
-
npx miriad-viz@latest preview --from-
|
|
107
|
+
npx miriad-viz@latest preview --from-curation
|
|
108
108
|
```
|
|
109
109
|
|
|
110
110
|
This auto-chains three operations:
|
|
111
|
-
1.
|
|
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
|
|
117
|
+
### The Curation Table
|
|
118
118
|
|
|
119
|
-
`
|
|
119
|
+
`next` prints a table showing computed vizSpeed and density per line:
|
|
120
120
|
|
|
121
121
|
```
|
|
122
|
-
|
|
123
|
-
narrator-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
-
|
|
130
|
-
-
|
|
131
|
-
-
|
|
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
|
-
##
|
|
134
|
+
## Pacing Reasoning — Creative Choice, Not Formula
|
|
134
135
|
|
|
135
|
-
The `next` output shows **event density** per
|
|
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
|
|
139
|
-
- **
|
|
140
|
-
- **Dramatic reveal** →
|
|
141
|
-
- **Emotional moment** → low
|
|
142
|
-
- **Montage** → high
|
|
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
|
|
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"* →
|
|
157
|
-
- *"
|
|
158
|
-
- *"
|
|
159
|
-
- *"The whole thing is too long"* →
|
|
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
|
|
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
|
|
177
|
-
| **What data appears** — can't add/remove agents, PRs, or events from the viz | Data comes from extraction, not
|
|
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** (
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|