@aicopycoders/exodus 2026.9.2000-beta.2 → 2026.9.2000-beta.21
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.
- package/assets/docs/PIPELINES.md +2 -1
- package/assets/skills/exodus-meme/SKILL.md +4 -3
- package/assets/skills/exodus-template/SKILL.md +2 -1
- package/assets/skills/exodus-video/SKILL.md +201 -39
- package/assets/skills/exodus-video/scripts/first-cut.mjs +538 -38
- package/assets/skills/exodus-workflow/SKILL.md +1 -1
- package/dist/commands/ads.js +1 -1
- package/dist/commands/image.js +1 -1
- package/dist/commands/template.js +11 -4
- package/dist/commands/video.d.ts +137 -7
- package/dist/commands/video.js +778 -64
- package/dist/commands/workflow.d.ts +53 -4
- package/dist/commands/workflow.js +76 -10
- package/dist/lib/helperLedgerBase.d.ts +3 -0
- package/dist/lib/helperLedgerBase.js +3 -0
- package/dist/lib/meta-ads.d.ts +1 -0
- package/package.json +1 -1
package/assets/docs/PIPELINES.md
CHANGED
|
@@ -152,7 +152,8 @@ run options:
|
|
|
152
152
|
--mode auto|manual|hybrid Generation mode (default: auto)
|
|
153
153
|
--render-mode images|prompts prompts = skip render, return LLM prompts only (default: images)
|
|
154
154
|
--aspect 1:1|9:16 Image aspect ratio (default: 1:1)
|
|
155
|
-
--model gpt-image-2|
|
|
155
|
+
--model gpt-image-2.5|gpt-image-2.5-sunburst|gpt-image-2|nano-banana-pro
|
|
156
|
+
Kie.ai model (default: gpt-image-2.5)
|
|
156
157
|
--realism off|realistic Realism enforcement (default: off)
|
|
157
158
|
--quantities "slug:N,slug:N" manual-mode per-type counts (e.g. "testimonial:3,hero:2")
|
|
158
159
|
--pairings '<JSON>' hybrid-mode host/modifier pairs: '[{"host":"testimonial","modifier":"hero"}]'
|
|
@@ -244,6 +244,7 @@ internals into chat.
|
|
|
244
244
|
- The rig's child image runs are still `creativeSuiteRuns` with engine `meme`,
|
|
245
245
|
so finished memes appear in the creative-suite library alongside other engines
|
|
246
246
|
and `exodus browse --agent meme` still covers them.
|
|
247
|
-
- `run` accepts only the
|
|
248
|
-
`nano-banana-pro`,
|
|
249
|
-
|
|
247
|
+
- `run` accepts only the models the rig renders (`gpt-image-2.5`, the house
|
|
248
|
+
default, plus `gpt-image-2.5-sunburst`, `gpt-image-2` and `nano-banana-pro`,
|
|
249
|
+
or their Kie slugs); anything else is a 400 listing the accepted values. It
|
|
250
|
+
used to accept any value and silently ignore it.
|
|
@@ -17,7 +17,8 @@ run options:
|
|
|
17
17
|
--mode auto|manual|hybrid Generation mode (default: auto)
|
|
18
18
|
--render-mode images|prompts prompts = skip render, return LLM prompts only (default: images)
|
|
19
19
|
--aspect 1:1|9:16 Image aspect ratio (default: 1:1)
|
|
20
|
-
--model gpt-image-2|
|
|
20
|
+
--model gpt-image-2.5|gpt-image-2.5-sunburst|gpt-image-2|nano-banana-pro
|
|
21
|
+
Kie.ai model (default: gpt-image-2.5)
|
|
21
22
|
--realism off|realistic Realism enforcement (default: off)
|
|
22
23
|
--quantities "slug:N,slug:N" manual-mode per-type counts (e.g. "testimonial:3,hero:2")
|
|
23
24
|
--pairings '<JSON>' hybrid-mode host/modifier pairs: '[{"host":"testimonial","modifier":"hero"}]'
|
|
@@ -21,12 +21,28 @@ Your job in this skill is to drive that loop, hand over the pieces with the
|
|
|
21
21
|
facts about them, and make whatever cut the user asked for. **How to edit is the
|
|
22
22
|
user's call, not this skill's** — see "Cutting the ad".
|
|
23
23
|
|
|
24
|
+
This file ships on the member's machine. It holds commands, the manifest's
|
|
25
|
+
shape, and recipes for the cut. It does not hold prompt text, house primers,
|
|
26
|
+
judge wording, or model instructions.
|
|
27
|
+
|
|
24
28
|
## How a run starts
|
|
25
29
|
|
|
26
30
|
The ad is a saved workflow in the brand, started script-first with `exodus
|
|
27
31
|
workflow run`. From there the same nodes render, `video status` reads the run,
|
|
28
32
|
`video pull` writes the folder, and `video upload` and `approve` finish it.
|
|
29
33
|
|
|
34
|
+
A Show is no longer required. `exodus video start` starts from a script, a
|
|
35
|
+
conceit, and a style. The same parks follow, except that the app approves the
|
|
36
|
+
storyboard itself when its checks pass (see "What costs money"). The full line is under
|
|
37
|
+
"Starting a run". An optional `--direction` note is whole-ad rules, and that
|
|
38
|
+
note cannot contain a colon. "The script file" shows the right form and the
|
|
39
|
+
wrong one.
|
|
40
|
+
|
|
41
|
+
The Rig box on that workflow is where the run's Conceit and Style come from.
|
|
42
|
+
Conceit is the family plus Wrapper, Narrator Person, and Delivery. Style is the
|
|
43
|
+
look. Narrated Story is the voice-over family and Acted Story is the dialogue
|
|
44
|
+
family (`familyTree.ts`). Those family names stay the code's names.
|
|
45
|
+
|
|
30
46
|
## Before anything
|
|
31
47
|
|
|
32
48
|
- `npx @aicopycoders/exodus video --help` and `workflow --help` are the
|
|
@@ -69,6 +85,16 @@ exodus workflow run <workflowId|name> --input <field>=@script.txt --voices @voic
|
|
|
69
85
|
exodus workflow run <workflowId|name> --input <field>=@script.txt --voice-treatment @voice-treatment.json --wait
|
|
70
86
|
same, with the video model speaking voices you WROTE
|
|
71
87
|
exodus video status <runId> where it is, per scene
|
|
88
|
+
exodus video start --script <file> --conceit <podcast|ugc|stage|street|personification> --style <slug> [--direction "…"] [--voice-path <path>] [--video-model <id>] [--voice native] [--music] [--review-storyboard] [--wait]
|
|
89
|
+
start from a script, a conceit and a look.
|
|
90
|
+
No music bed unless you pass --music.
|
|
91
|
+
The app approves its own storyboard when its
|
|
92
|
+
checks pass and goes straight on to the clips,
|
|
93
|
+
which is the part that costs. It stops at the
|
|
94
|
+
gate only when a check finds a problem, and says
|
|
95
|
+
why. --review-storyboard always stops there.
|
|
96
|
+
Each conceit has its own video model and voice;
|
|
97
|
+
--video-model / --voice override them for one run
|
|
72
98
|
```
|
|
73
99
|
|
|
74
100
|
**From the storyboard on.**
|
|
@@ -81,7 +107,7 @@ exodus video approve <runId> keep going
|
|
|
81
107
|
exodus video retry-frame <runId> --node <nodeId> --scene <n> redo one still at the pixel gate
|
|
82
108
|
exodus video status <runId> where it is, per scene
|
|
83
109
|
exodus video pull <runId> --out ./ad-<runId> every piece + manifest.json
|
|
84
|
-
exodus video retry-clip <runId> --scene <n> [--node <nodeId>] [--note "…"]
|
|
110
|
+
exodus video retry-clip <runId> --scene <n> [--node <nodeId>] [--note "…"] [--voice-first]
|
|
85
111
|
redo one clip at the final watch
|
|
86
112
|
exodus video revoice <runId> --all | --scene <n> redo only the voice; no new video
|
|
87
113
|
… make the cut (your choice of tool)
|
|
@@ -98,7 +124,15 @@ already printed the same stop block, and `workflow inbox` lists a parked video
|
|
|
98
124
|
run, but neither shows the per-scene detail, and the checkpoint verbs cannot
|
|
99
125
|
resolve a video park — see "What the CLI can and cannot do".
|
|
100
126
|
|
|
101
|
-
**Where a run can stop.**
|
|
127
|
+
**Where a run can stop.** The two video parks come in order when the run has
|
|
128
|
+
both. The storyboard gate is first. You read the cards there and you set the
|
|
129
|
+
voices there. Approving that gate releases the voices and the clips. That is the
|
|
130
|
+
expensive part. The final watch is next, after the pieces exist, and only when
|
|
131
|
+
the video node sets `finalWatch: true`. That park is for the cut. You pull, you
|
|
132
|
+
cut, and you upload. Approving the upload makes it the ad. A node with
|
|
133
|
+
`finalWatch` off skips the second park and the run finishes.
|
|
134
|
+
|
|
135
|
+
Five stops, each with the exact next command printed
|
|
102
136
|
under it:
|
|
103
137
|
|
|
104
138
|
- storyboard gate: needs `approve`. When the stop block prints a `Redo one
|
|
@@ -110,11 +144,20 @@ under it:
|
|
|
110
144
|
lines under `guidance`). It is also
|
|
111
145
|
the one park where a finished clip can be redone, with `retry-clip`. A run
|
|
112
146
|
only reaches this park if its video node sets `finalWatch: true` — otherwise
|
|
113
|
-
it skips straight to finished.
|
|
147
|
+
it skips straight to finished. If a scene has no clip, the stop block names
|
|
148
|
+
it instead (`stop.missingScenes` in `--json`) and approval is refused until
|
|
149
|
+
it has one. A scene whose picture the video service refused needs
|
|
150
|
+
`retry-frame --note` before `retry-clip`; the clip redo alone resends the
|
|
151
|
+
refused picture.
|
|
114
152
|
- paused: a builder checkpoint neither video verb resolves —
|
|
115
153
|
`exodus workflow checkpoint <runId>` is the verb for that one.
|
|
116
154
|
- failed: `status` shows how far it got, and a `--wait` that was running exits
|
|
117
155
|
1 with the error. Tell the user; do not start another run on your own.
|
|
156
|
+
When the storyboard is the step that failed, `status` adds a "What happened
|
|
157
|
+
to the storyboard" block: which parts of the plan were accepted, which part
|
|
158
|
+
was turned down, and why (#1902). Relay it as written. On an admin key it may
|
|
159
|
+
also offer `status <runId> --rejected-draft`. That prints the draft the system
|
|
160
|
+
threw away. It is a record only: never build on it, edit it, or re-run it.
|
|
118
161
|
- finished: pull what it made.
|
|
119
162
|
|
|
120
163
|
**`--wait` stops at both video parks** (#1818). `workflow run --wait` ends at
|
|
@@ -132,18 +175,31 @@ minutes with "Still running after 60 minutes" and exit 0; that is not done, so
|
|
|
132
175
|
check `status` before treating it as finished. Do not poll `status` in a tight
|
|
133
176
|
loop; a full run is several minutes.
|
|
134
177
|
|
|
135
|
-
**What costs money.**
|
|
136
|
-
reference, cast and scene pictures
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
178
|
+
**What costs money.** Every run writes the storyboard first and then draws the
|
|
179
|
+
reference, cast and scene pictures. Each picture is a few cents and each scene
|
|
180
|
+
draws a few to choose from: about 25 cents on a small test, and it can approach
|
|
181
|
+
a dollar on a longer ad. The expensive part comes after the storyboard: the
|
|
182
|
+
voices and the clips. What happens at that point depends on how the run
|
|
183
|
+
started.
|
|
184
|
+
|
|
185
|
+
- A paste-a-script run (`exodus video start --conceit …`) checks its own
|
|
186
|
+
storyboard once the pictures are drawn. When every check passes, the app
|
|
187
|
+
approves the storyboard itself and goes straight on to the voices and the
|
|
188
|
+
clips, with no stop. It stops for the user only when a check finds a problem,
|
|
189
|
+
and the stop block says why in plain words. Started with
|
|
190
|
+
`--review-storyboard`, it always stops at the storyboard instead. `status`
|
|
191
|
+
prints "the app checks the storyboard and approves it itself if the checks
|
|
192
|
+
pass" on a run headed that way.
|
|
193
|
+
- A Show run (`video start --show`) and a saved workflow run (`workflow run`)
|
|
194
|
+
still pause at the storyboard for approval. Approving is what releases the
|
|
195
|
+
voices and the clips. `status` prints "This run will pause for your approval
|
|
196
|
+
once the frames are ready" on a run headed for that pause.
|
|
197
|
+
|
|
198
|
+
Either way, a run still drawing pictures is healthy and already spending a
|
|
199
|
+
little. Do not cancel it because nothing has happened yet. `workflow list`,
|
|
200
|
+
`workflow describe`, `video status`, `storyboard` and `pull` are free reads; run
|
|
201
|
+
them as often as you like. Never start a second run to "retry" without the user
|
|
202
|
+
asking; tell them what failed instead.
|
|
147
203
|
|
|
148
204
|
**`--auto-approve` does not cover either video gate.** It releases Checkpoint
|
|
149
205
|
boxes only (`convex/workflows.ts:7266` keys on `pauseReason === "checkpoint"`),
|
|
@@ -206,11 +262,42 @@ anything:
|
|
|
206
262
|
|
|
207
263
|
## The script file
|
|
208
264
|
|
|
209
|
-
Plain text.
|
|
210
|
-
`
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
265
|
+
Plain text. An optional `DIRECTION:` block may open the file, before `CAST:` or
|
|
266
|
+
the first spoken line. Then a `CAST:` block naming the speakers, one line per
|
|
267
|
+
turn, then a `CTA:` block.
|
|
268
|
+
|
|
269
|
+
`DIRECTION:` carries whole-ad rules and no spoken words. The header is its own
|
|
270
|
+
line. The lines under it are the rules. The block ends at a blank line, at
|
|
271
|
+
`CAST:`, at `CTA:`, or at the first line that names a speaker. A second
|
|
272
|
+
`DIRECTION:` block is refused. So is a `DIRECTION:` after the first spoken line.
|
|
273
|
+
An empty block is refused too. The error code is `malformed-direction`.
|
|
274
|
+
|
|
275
|
+
Do not put a colon inside direction prose. The reader splits a line at its first
|
|
276
|
+
colon to find a speaker, so a colon in that prose is read as a name.
|
|
277
|
+
|
|
278
|
+
Right.
|
|
279
|
+
|
|
280
|
+
```
|
|
281
|
+
DIRECTION:
|
|
282
|
+
Nobody looks at the camera. The product stays on the table until the last line.
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Wrong.
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
DIRECTION:
|
|
289
|
+
Rule: nobody looks at the camera.
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
The wrong line is not direction. `Rule` is read as the speaker, and the
|
|
293
|
+
block above it is empty, so the file is refused.
|
|
294
|
+
|
|
295
|
+
The planner sizes every line at 2.5 words per second (`WORD_LADDER_WPS`), so a
|
|
296
|
+
turn near 14 words plans a clip near 6 seconds. If a line does get truncated in
|
|
297
|
+
its clip, the manifest says so (`speech-cutoff`). That finding means the clip
|
|
298
|
+
cut the words off. Redo the clip. Do not speed the speech or cut it short to
|
|
299
|
+
hide the finding. The product rule is under "What the product actually
|
|
300
|
+
requires".
|
|
214
301
|
|
|
215
302
|
```
|
|
216
303
|
CAST:
|
|
@@ -224,6 +311,15 @@ CTA:
|
|
|
224
311
|
THE SOFTGEL: Tap below and give your eyes ClearBlink.
|
|
225
312
|
```
|
|
226
313
|
|
|
314
|
+
The dash in a `CAST:` line is the parser's own separator. The example above
|
|
315
|
+
already shows that dash. A cast line may separate the name from the description
|
|
316
|
+
with an em dash, an en dash, or a hyphen with a space on each side. Keep that
|
|
317
|
+
dash on cast lines. A reader who strips it makes the line fail.
|
|
318
|
+
|
|
319
|
+
Do not use a long dash in words a character says, or in words shown on screen.
|
|
320
|
+
Synthesised speech reads a long dash oddly, and so does burned-in text. A spoken
|
|
321
|
+
line stays `NAME: what they say`.
|
|
322
|
+
|
|
227
323
|
**How many speakers you may have depends on the rig.** Three by default. A rig
|
|
228
324
|
that carries saved format rules sets its own number: an ensemble rig seats more,
|
|
229
325
|
a talking-head rig seats one. Over the number, the launch refuses before
|
|
@@ -256,9 +352,13 @@ unattended.
|
|
|
256
352
|
By default a workflow run's characters have no voice of their own. A character
|
|
257
353
|
without one gets the run's default voice (the workflow's narrator voice) when the
|
|
258
354
|
run has one; with no default either, the clip keeps the voice the video model
|
|
259
|
-
invents. `exodus video voices` shows which of the three applies and is where
|
|
260
|
-
|
|
261
|
-
|
|
355
|
+
invents. `exodus video voices` shows which of the three applies, and it is where you
|
|
356
|
+
fix the mapping. Fix it before you approve the storyboard gate. Approving that
|
|
357
|
+
gate locks the mapping, and `exodus video voices` refuses afterwards. On a
|
|
358
|
+
finished clip whose voice was never applied, the later command is `exodus video
|
|
359
|
+
revoice`, and that pass bills again. A clip that already went through the voice
|
|
360
|
+
pass is refused there. Use `retry-clip` for that one. See "Redoing only the
|
|
361
|
+
voice on finished clips".
|
|
262
362
|
|
|
263
363
|
```
|
|
264
364
|
exodus video voices <runId>
|
|
@@ -332,7 +432,7 @@ nobody knows the speaker names yet. When the storyboard arrives, the voices are
|
|
|
332
432
|
already set and `exodus video voices <runId>` shows them.
|
|
333
433
|
|
|
334
434
|
**Choosing how the voices are made.** `--voice-treatment` on `workflow run` says
|
|
335
|
-
HOW a run makes its voices, and it is the only
|
|
435
|
+
HOW a run makes its voices, and it is the only way. Two
|
|
336
436
|
kinds of answer.
|
|
337
437
|
|
|
338
438
|
A name on its own picks a way of working that plays a voice you already have,
|
|
@@ -405,7 +505,8 @@ person made at a keyboard for one run, and nobody made it for the sub-workflow.
|
|
|
405
505
|
**Written voices cannot be changed at the review.** They are chosen when the run
|
|
406
506
|
starts. `exodus video voices <runId>` on a described run names the treatment and
|
|
407
507
|
prints each written voice, and says plainly that `--voice-treatment` at launch is
|
|
408
|
-
what changes them. Do not set a voice path in node config
|
|
508
|
+
what changes them. Do not set a voice path in node config. Node config does
|
|
509
|
+
not set the treatment.
|
|
409
510
|
|
|
410
511
|
**Where it shows up afterwards.** The launch receipt and `exodus workflow status`
|
|
411
512
|
both print one line naming the treatment and the speakers who got a written
|
|
@@ -483,6 +584,20 @@ manifest.json the index below
|
|
|
483
584
|
runId, pulledAt, dashboardUrl the run and the page that opens it:
|
|
484
585
|
/workflows/<workflowId>/runs/<runId>
|
|
485
586
|
storyboard, reference, music filenames, or null when not delivered
|
|
587
|
+
musicBed on | off | unknown — whether the RUN has a
|
|
588
|
+
music bed, which is not the same question
|
|
589
|
+
as the `music` filename above. "unknown" is
|
|
590
|
+
a run made before the run carried the
|
|
591
|
+
answer; it is not "off"
|
|
592
|
+
musicHeardScenes[] scene numbers whose clip came back with
|
|
593
|
+
music the video model baked in. A run with
|
|
594
|
+
the bed off can still list scenes here, and
|
|
595
|
+
those are the ones to listen to
|
|
596
|
+
pendingRedo[] scene numbers the app is redoing right
|
|
597
|
+
now. Their clip and words are left out,
|
|
598
|
+
because the file on the run is the take
|
|
599
|
+
being replaced: run `exodus video wait`,
|
|
600
|
+
then pull again
|
|
486
601
|
narration { file, timing }, or null on a per-scene run
|
|
487
602
|
cast[] one per identity still
|
|
488
603
|
characterId, name from the run's cast lock; null for an
|
|
@@ -515,6 +630,9 @@ scenes[] one per scene, in order
|
|
|
515
630
|
on record when the voice pass replaced the
|
|
516
631
|
clip with a new file; null when the clip IS
|
|
517
632
|
that file, or there is no clip
|
|
633
|
+
voiceMode "voice-first" when the clip was redone voice
|
|
634
|
+
first (its line recorded, then the clip made
|
|
635
|
+
to match it); null otherwise
|
|
518
636
|
provenance which saved rulebook this run followed:
|
|
519
637
|
{format: {via, nodeId, rigId, rigName,
|
|
520
638
|
rulesFrom, specVersion}}. Absent when the
|
|
@@ -537,15 +655,19 @@ depends on the scene; see "Which scenes carry their voice where" below.
|
|
|
537
655
|
terms. `script[]` is the ad's spoken words in order — `{lineId, speakerId, text}`,
|
|
538
656
|
with `speakerId: null` meaning narrator VO. Each scene carries `sceneIndex`,
|
|
539
657
|
`durationSec`, `dialogue[]`, `voText`, `notes`, and `lineIds` (the script lines
|
|
540
|
-
that scene renders). A scene with `kind: "cutaway"` carries `cueLineId`
|
|
541
|
-
|
|
542
|
-
keeps running, so
|
|
658
|
+
that scene renders). A scene with `kind: "cutaway"` carries `cueLineId` and a
|
|
659
|
+
`cutawayType` instead. Most cutaways are a picture-only takeover of the frame
|
|
660
|
+
while the spoken track underneath keeps running, so they add no audio and take
|
|
661
|
+
no place in the running order. A `cutawayType: "reaction"` cutaway is the room
|
|
662
|
+
reacting out loud to its cue line: it is its own short beat after that line,
|
|
663
|
+
heard with its own sound while the speaker is silent. The
|
|
543
664
|
envelope also carries `overlays[]` (each with a `cueLineId` and a `placement`)
|
|
544
665
|
and `audio` (`roomTone`, `music`, `sfxCues[]`) — the planner's notes on what
|
|
545
666
|
should sit on top. The image and motion prompts (`framePrompt`, `videoPrompt`,
|
|
546
667
|
`referencePrompt`) reach an admin key in full. A caller who cannot use video on
|
|
547
|
-
this brand gets them stripped before the file arrives
|
|
548
|
-
(`redactVideoIp` in `convex/workflows.ts`).
|
|
668
|
+
this brand gets them stripped before the file arrives. They are private Style
|
|
669
|
+
fragment IP (`redactVideoIp` in `convex/workflows.ts`). Style pack is the
|
|
670
|
+
retired name.
|
|
549
671
|
|
|
550
672
|
**The narration track** (`narration.mp3` + `narration.json`). Present when the
|
|
551
673
|
run recorded continuously: every narrated scene's `voText` joined into one
|
|
@@ -572,9 +694,9 @@ speech inside the clip — under the default voice treatment the video model's
|
|
|
572
694
|
invented voice is then replaced, in place, with the cast member's pinned
|
|
573
695
|
ElevenLabs voice (that is `revoiced: true`). Other treatments leave the render
|
|
574
696
|
owning its own audio, e.g. lip-sync retargeting a VO track onto the video. The
|
|
575
|
-
treatment is frozen on the run when it starts, and there is exactly one
|
|
697
|
+
treatment is frozen on the run when it starts, and there is exactly one flag
|
|
576
698
|
that sets it: `--voice-treatment` on `workflow run` (see **Choosing how the
|
|
577
|
-
voices are made**). Node config
|
|
699
|
+
voices are made**). Node config never sets it. Nothing on the canvas sets a
|
|
578
700
|
voice treatment, and a run that was given none renders the default. Read
|
|
579
701
|
`wordsFrom` and `revoiced` per scene rather than assuming.
|
|
580
702
|
|
|
@@ -636,6 +758,11 @@ blocking the run.
|
|
|
636
758
|
A `speech-cutoff` on the CTA scene is the one to worry about; the ad's last
|
|
637
759
|
words are missing. `status` shows the checker's own wording behind each
|
|
638
760
|
finding; the manifest carries only the verdict.
|
|
761
|
+
- A `pass` verdict is not a review. The checks are often optimistic. Watch the
|
|
762
|
+
frames and listen to the audio before you call the run good. Two checks fail
|
|
763
|
+
the wrong way. A cast-count check can reject a silent
|
|
764
|
+
listener who belongs in the shot. A clip check can flag a clip that is fine.
|
|
765
|
+
Read the finding, then watch the scene.
|
|
639
766
|
- `clipStatus: "failed"` or `"missing"` with a `keyframe`: `durationSec` is null
|
|
640
767
|
(it comes from the clip), but the scene can still hold its place as a still —
|
|
641
768
|
for the length of its voice track, or the storyboard's planned duration when
|
|
@@ -653,6 +780,7 @@ is no second run, no new storyboard and no re-render of anything else.
|
|
|
653
780
|
exodus video retry-clip <runId> --scene 3
|
|
654
781
|
exodus video retry-clip <runId> --scene 3 --note "keep both hands in frame on the handshake"
|
|
655
782
|
exodus video retry-clip <runId> --scene 3 --node video-2
|
|
783
|
+
exodus video retry-clip <runId> --scene 3 --voice-first
|
|
656
784
|
```
|
|
657
785
|
|
|
658
786
|
`--node` is only needed when a run has clips for that scene on two video steps;
|
|
@@ -675,7 +803,17 @@ revoiced and trimmed the same way, with fresh findings and fresh word timings.
|
|
|
675
803
|
scene's motion prompt only (`withRedoDirection`,
|
|
676
804
|
`scout/src/trigger/workflow-scene-retry.ts`); the spoken line still comes from
|
|
677
805
|
the approved storyboard. Asking for different words in a note will not change
|
|
678
|
-
them. If the words are wrong, that is a new run.
|
|
806
|
+
them. If the script's words are wrong, that is a new run.
|
|
807
|
+
|
|
808
|
+
**`--voice-first` fixes a clip that said its line wrong** (#2299). It is for a
|
|
809
|
+
clip whose findings include `speech-mismatch`, `speech-repeat`,
|
|
810
|
+
`speech-after-line`, `speech-extra-words` or `speech-long-pause`. The scene's line is recorded in each
|
|
811
|
+
speaker's pinned ElevenLabs voice, and MiniMax (`minimax-h3/reference-to-video`)
|
|
812
|
+
makes the clip to match the recording. Only that clip changes; the word check
|
|
813
|
+
and the other checks still run on it. It needs an ElevenLabs key and a voice for
|
|
814
|
+
every speaker in the scene, and it is refused for a scene with no spoken line.
|
|
815
|
+
The clip then reads `clip: redone voice first` in `status`, carries
|
|
816
|
+
`voiceMode: "voice-first"` in the manifest, and is listed in the `pull` summary.
|
|
679
817
|
|
|
680
818
|
**A redo whose take fails the checks keeps the original clip.** On a finished
|
|
681
819
|
clip the row stays `done` with the ORIGINAL take and only its findings are
|
|
@@ -762,7 +900,10 @@ they want; if they have not said and are not around, say which you used and why.
|
|
|
762
900
|
- **HyperFrames** — HTML/CSS compositions rendered to video. Suits an ad that
|
|
763
901
|
needs captions, title cards, overlays or motion graphics laid over the clips.
|
|
764
902
|
It is a separate skill pack; check that a `hyperframes` skill is installed
|
|
765
|
-
before offering it.
|
|
903
|
+
before offering it. The cut is made outside Exodus. `exodus video pull` is the
|
|
904
|
+
handover. The folder it writes is what the next tool reads. When a HyperFrames
|
|
905
|
+
skill pack is installed, that pack is the route for an HTML and CSS
|
|
906
|
+
composition. Do not look for a stitch inside Exodus.
|
|
766
907
|
- **An NLE over MCP** — DaVinci Resolve publishes an MCP server, so a timeline
|
|
767
908
|
can be built in a real editor and the user can carry on by hand afterwards.
|
|
768
909
|
Suits a user who wants to keep editing after you stop. Check what MCP servers
|
|
@@ -784,6 +925,13 @@ Read these out of `storyboard.json` before you build anything, in any tool:
|
|
|
784
925
|
running order. To find the moment, locate the A-roll scene whose `lineIds`
|
|
785
926
|
contain the cue line, then read the start time of the first word of that line
|
|
786
927
|
out of that scene's `words.json`.
|
|
928
|
+
- **Reactions.** A cutaway with `cutawayType: "reaction"` is the exception. Do
|
|
929
|
+
not lay it over the speech. Put it into the running order as its own beat
|
|
930
|
+
right after its cue line ends, play its own sound (the audience laughing),
|
|
931
|
+
keep it to about 1.5 s, then carry on with the speaker. Nobody talks during
|
|
932
|
+
it. When more lines follow the cue line in the same scene, cut that scene
|
|
933
|
+
where the cue line's last word ends in its `words.json` and put the reaction
|
|
934
|
+
between the two halves.
|
|
787
935
|
- **Overlays and SFX.** `overlays[]` and `audio.sfxCues[]` are cued the same
|
|
788
936
|
way, by `cueLineId`. Nothing renders them for you.
|
|
789
937
|
- **Captions.** Nothing is burned into any clip. Captions belong in post; the
|
|
@@ -800,12 +948,20 @@ the pieces:
|
|
|
800
948
|
holds its last frame for the difference. The narration is never sped up,
|
|
801
949
|
slowed down or cut short, so every scene plays at the speed it was recorded,
|
|
802
950
|
and the word times are handed on as they were measured.
|
|
951
|
+
- **It closes the dead air at the joins.** A clip that plays its own dialogue
|
|
952
|
+
keeps about 0.15 s after its last word and about 0.1 s before its first (0.25 s
|
|
953
|
+
when a different speaker answers), read from its `words.json`, so one clip
|
|
954
|
+
runs into the next like one conversation. It only ever shortens a clip's
|
|
955
|
+
silence and never cuts into a word. The ad's first lead-in and last tail, a
|
|
956
|
+
narrated scene, a still and a reaction beat are left as they are.
|
|
803
957
|
- **It ignores the continuous master.** It reads only `scene-NN.voice` files;
|
|
804
958
|
it never opens `narration.mp3` or `manifest.narration`. A tool that lays the
|
|
805
959
|
master down whole and cuts the pictures to it keeps the read intact.
|
|
806
|
-
- Otherwise: A-roll in manifest order as the spine, each
|
|
807
|
-
|
|
808
|
-
|
|
960
|
+
- Otherwise: A-roll in manifest order as the spine, each reaction put in as its
|
|
961
|
+
own beat of at most 1.5 s right after its cue line with its own sound, each
|
|
962
|
+
other cutaway laid over the spine at its cued word (falling back to a
|
|
963
|
+
proportional estimate when the scene has no word times, and saying which
|
|
964
|
+
method it used), a narrated scene's voice
|
|
809
965
|
replacing whatever the clip recorded, a dialogue scene keeping its performed
|
|
810
966
|
line, a clip-less scene becoming a still, everything normalized to 1080×1920
|
|
811
967
|
at 24 fps and −16 LUFS per segment, a generated room-tone bed under the whole
|
|
@@ -817,14 +973,15 @@ the pieces:
|
|
|
817
973
|
ad with its start and end) and `cut.srt` (the same words grouped into subtitle
|
|
818
974
|
lines), named from the `--out` basename. Those times are on the finished ad's
|
|
819
975
|
timeline, each scene's own word times offset by where that scene starts in the
|
|
820
|
-
cut and otherwise unaltered. Scenes with no word times leave
|
|
976
|
+
cut, less any lead-in trimmed at the join, and otherwise unaltered. Scenes with no word times leave
|
|
821
977
|
gaps and are named in the report; when no scene delivered any, neither file is
|
|
822
978
|
written. These sidecars are the script's own output — another tool will not
|
|
823
979
|
produce them.
|
|
824
980
|
|
|
825
981
|
Before uploading anything, from any tool, check what you made:
|
|
826
982
|
`ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 cut.mp4`
|
|
827
|
-
should be close to the sum of the scene durations you kept
|
|
983
|
+
should be close to the sum of the scene durations you kept (the bundled
|
|
984
|
+
script's cut runs somewhat shorter, by the silence it trimmed at the joins). A cut that is a few
|
|
828
985
|
seconds long when five clips went in means a filter dropped inputs; do not
|
|
829
986
|
upload it.
|
|
830
987
|
|
|
@@ -859,6 +1016,11 @@ lines, re-recording narration, or cutting words out of the CTA will ship,
|
|
|
859
1016
|
silently. Cut the pictures to the words, not the words to the pictures. If the
|
|
860
1017
|
words are wrong, that is a new run, not an edit.
|
|
861
1018
|
|
|
1019
|
+
Never stretch speech, speed it up, slow it down, or cut it short so it fits a
|
|
1020
|
+
clip. That is a product rule, and it holds for every tool that makes the cut,
|
|
1021
|
+
including the bundled script. If the audio does not fit, redo the clip with
|
|
1022
|
+
`exodus video retry-clip`. Do not repair the fit in the editor.
|
|
1023
|
+
|
|
862
1024
|
## Reporting to the user
|
|
863
1025
|
|
|
864
1026
|
Lead with where the run is and what it needs from them. Then, when you pulled
|