broll_veo_generate
AI agent that fills remaining broll gaps by generating 8-second clips with Google Veo 3, then aggressively trimming each clip to its most impactful moment.
Tip: The
mediaprocessor'sveopreset generates the same clips from a spec, and withsource: gapsfills empty spans. This processor remains the transcript-driven agent that writes its own prompts. Seemediaand Filling gaps and generating per segment.
When to use
Run after broll_place to cover gaps that existing clips couldn't fill. See the Broll guide.
In the editor
Add it from the Library (B-Roll group), or with + add step and a search for broll_veo_generate, below your broll_place step so that footage you already have gets first pick of the gaps.
Under Inputs, add transcript as a step input and backbone as a step input pointing at your cut. The step's Prompt describes the kind of shot you want, and it is worth being concrete and physical: animals, food, streets, objects. max_generate is a hard budget for the run and the single most useful setting here, because each clip costs money. min_gap_sec decides which gaps are worth filling, target_clip_sec how long the trimmed result should be, and eval_prompt is the standard each generated clip must meet before it is used.
This step needs your own Google key. Add it in the workspace's Variables & Service API Keys, from the editor's Settings. A run that needs a key you have not set is refused before it starts, so nothing is generated or charged.
Tick Review gate and look at what came back before continuing.
Generated clips appear on the b-roll level in the run timeline. Every prompt is checked before anything is generated, and prompts featuring people, faces, screens or objects passing through each other are rejected: those are what generated video gets visibly wrong. Clips already generated in a run group are reused rather than paid for twice.
YAML Example
- id: broll_ai
processor: broll_veo_generate
input:
- id: transcript
step: transcribe_main
- id: backbone
step: ai_cut
params:
min_gap_sec: 8
max_gap_sec: 20
backbone_step: ai_cut
max_generate: 5
min_clip_sec: 2.0
target_clip_sec: 4.0
trim_style: aggressive
eval_prompt: >
Accept: clear, focused shot without glitches or uncanny elements.
Reject: blurry, morphing objects, impossible physics.
output:
timeline: broll
prompt: |
Check get_timeline_state() first to see what's already placed.
Only generate clips for unfilled gaps longer than max_gap_sec.
Feature animals, nature, food, architecture, objects. NO people or faces.
Simple, literal, physical scene. 1–3 sentences max.
review: true
cache: true
Required secrets
GOOGLE_API_KEY: set in workspace or template secrets. A run whose pipeline includes this processor is refused before it starts if the key is missing; the web UI prompts for it.
Inputs
| ID | Source | Description |
|---|---|---|
transcript |
step | Word-level timestamps |
backbone |
step (optional) | Cache dep: re-run when cut changes |
segment_plan |
step (optional) | A SegmentPlan (e.g. from video_director) constraining which gaps to fill. |
Params
| Param | Type | Default | Description |
|---|---|---|---|
eval_prompt |
text | none | Accept/reject criteria for generated clip analysis |
context |
text | none | Background context injected into the system prompt. Supports text:, file:, dir:, files:. |
min_gap_sec |
duration (s) | 5 |
Minimum gap size to fill |
max_gap_sec |
duration (s) | 0 |
Gaps longer than this need coverage (0 = AI decides) |
max_duration_sec |
duration (s) | 8 |
Max seconds to use from any single generated clip |
min_clip_sec |
duration (s) | 2 |
Minimum clip duration after trimming |
min_use_sec |
duration (s) | 0 |
Minimum clip use duration in seconds |
target_clip_sec |
duration (s) | 4 |
Target clip duration to aim for |
trim_style |
select: conservative, balanced, aggressive |
"aggressive" |
"aggressive" (trim to best moment) or "conservative" (preserve more) |
full_coverage |
bool | false |
Require every second of the backbone to be covered: no gaps allowed |
max_generate |
number | 0 |
Veo 3 budget per run. 0 = unlimited. Existing cached clips don't count. |
no_clip_reuse |
bool | false |
Reject placements that reuse overlapping in/out ranges |
required_clips |
list | none | Previously generated clip filenames that must be placed. The AI force-places these before filling remaining gaps. |
backbone_step |
string | none | Step ID to read backbone timeline from (optional) |
Output
EditDecisions on the broll level.
Notes
- Uses Puffin Ship's built-in AI for the prompt judge; requires a
GOOGLE_API_KEY(set in your workspace's Service API Keys) for Veo 3 generation. - Veo 3 always generates 8-second clips. The trim step finds the most impactful moment.
- A prompt judge (Claude) validates every prompt before generation. It rejects: people/faces/humanoids, screens/keyboards, objects passing through each other, intricate mechanical parts, abstract concepts, prompts over 3 sentences.
- Generated clips are kept separately from the material you uploaded, and each one records what it was generated for, so re-running the step reuses clips it already has.
- What works: animals, nature, food, architecture, city streets (no people), animation style.