'Render a scripted video project into mp4 clips with the Google Veo 3.1 API. Reads a project''s shot package (shots/*.md), one clip per camera cut, reusing each shot''s prompt and sketch — world anchor only with `--with-reference`, seed unless `--no-seed`. Use on "render the Veo video for <project>", "generate the videos from the shot scripts", "make the clips with Veo".'
Recursos
1Instal·la
npx skillscat add blackbelttechnology/pi-agent-dashboard/veo-generator Instal·la des del registre de SkillsCat.
Veo Generator
Turns an already-scripted shot package into actual video. The prompting is done
by the veo-showreel-production-kit skill (STYLE BIBLE → per-shot shots/*.md);
this skill is the render step that calls the Veo 3.1 API and downloads mp4s.
It expects the layout the production kit emits:
<Project>/
.env <- (optional) per-project API key lives here
video_production/
shots/shot_*.md <- source of truth: prompt, negative, seed, aspect, refs
storyboard/*.png <- first-frame sketches + 00_world_anchor.png
renders/ <- mp4 output (created here)Each shots/shot_NN.md already contains everything the renderer needs: the
▶ Full Veo prompt block, the ⛔ Negative prompt block, and a
Reproduction & consistency line with the seed, aspect ratio, resolution,
reference image(s) and first-frame image. The renderer parses those — it never
re-invents the prompt.
Prerequisites
- The
pi-veoCLI (this package). Runs as TypeScript via pi's jiti loader — no build step. - ffmpeg — only needed for
--chain(seamless A→B last-frame handoff).
Declared inpi.toolsand resolved via the tool registry; absent →
non-chain videos still generate. - An API key (see below). Get one at https://aistudio.google.com/apikey.
Declared as anenvprobe (GEMINI_API_KEY) inpi.tools. The registry
recognizesGEMINI_API_KEYonly — the CLI'sVEO_API_KEY/GOOGLE_API_KEYaliases still work at run time but are NOT tracked in
Settings → Tools.
API key — per project or global
Resolution order, first non-empty wins:
| # | Source | Use |
|---|---|---|
| 1 | --api-key <KEY> flag |
one-off |
| 2 | VEO_API_KEY / GEMINI_API_KEY / GOOGLE_API_KEY env var |
machine-wide |
| 3 | <Project>/.env or …/video_production/.env |
per-project key |
| 4 | this package's .env |
global fallback |
Copy `.env.example` and set VEO_API_KEY=…. Never commit real keys.
Procedure
Dry-run / validate the package (no key spent):
pi-veo parse <Project>Confirms every shot has a parseable prompt, shows seed/aspect/resolution, the
first-frame sketch, the reference image and seamless→next chaining. Add--jsonfor machine output,--shots 01 03Afor a subset.Plan the render (resolves key + model + outputs, still no API call):
pi-veo plan <Project>Render (calls Veo, polls, downloads to
video_production/renders/):pi-veo render <Project>- Test a single shot first:
--shots 01 - Cheaper/faster preview pass:
--model fast --resolution 720p - Seamless A→B handoff (sequential, uses ffmpeg last frame):
--chain - Render several independent shots at once:
--parallel 4 - Also attach the world-anchor as a reference image:
--with-reference - Re-render existing clips:
--force
Already-renderedshot_NN.mp4files are skipped unless--force, so the
command is safe to re-run / resume.
- Test a single shot first:
(Optional) regenerate storyboard sketches (the first-frame images) via
nano-banana, if they're missing or you changedsketch_prompts.json:pi-veo storyboard <Project>Assemble in post — cut the
renders/*.mp4in timecode order, lay the
official voiceover + music, bake captions, drop the logo into the reserved
space of the final shot. (Veo only makes ambient SFX — speech is forbidden in
the AUDIO LOCK on purpose.) With sidecars (film.json+timeline.json)
automate it:pi-veo export timeline <Project> --clips video_production/renders
→ callvideo_composeon the printed spec →pi-veo mux <Project> --picture <final_video.mp4>→video_production/master/master.mp4.
Optional: other providers via pi-video-gen
Needs sidecars (film.json, shots/shot_NN.json) — see the production kit.@amaster.ai/pi-video-gen is a user-level pi extension, never a dependency of
this package: pi install npm:@amaster.ai/pi-video-gen (verified 0.1.18;
0.1.x formats may change). Coupling is file-format only.
- Run every
pi-veo exportfrom the pi session cwd, withoutcd— pi-video-gen
resolves frames and itsoutputDir(default.video-gen) against that cwd.
IfoutputDiris configured differently, pass--out <that dir>. - Call
video_capabilities, copy the model's duration range and aspect ratios
into--durations <min>-<max>/--aspect 16:9,9:16(not parsed automatically). pi-veo export render <Project> [--durations 4-15] [--aspect 16:9]→ callvideo_renderwith the printedrender-input.json. SEAMLESS shots becomelastFramePath= next shot's sketch;--no-last-framefor models without
first+last frame (e.g. kling-3.0-turbo).- Resume = call
video_renderagain on the SAME spec. Never re-export — a new
job re-bills every shot. Export refuses while a previous spec exists
(.pi-veo/exports.json);--new-jobonly for a genuinely revised film. - Picture edit:
pi-veo export timeline <Project> --clips .video-gen/<job>/shots
(orvideo_production/renders) →video_compose→pi-veo mux.
Trade-offs: no seed, no local reference images, resolution = the model default
(OpenRouter Veo is 720p / 16:9) — keep pi-veo render (Veo direct) for 4K/seed
quality passes; use pi-video-gen for Seedance / Kling / MiniMax. Run/video-gen doctor and one cheap clip first. pi-veo mux needs ffmpeg +ffprobe; --burn needs ffmpeg's subtitles filter (libass), soft captions
are the default.
Notes & pitfalls
- Veo clips are ≤8s. The shot package is already split into ≤8s units; don't
merge them. Long beats are A/B pairs. - Model IDs:
standard→veo-3.1-generate-preview,fast→veo-3.1-fast-generate-preview. Pass a full id to--modelto use another. - Resolution
4kis Veo 3.1 preview only and is slower + pricier; use--resolution 1080p(or720pfor cheap previews) to override the shot files. - Parallel rendering: by default shots render one-at-a-time.
--parallel N
keeps up to N Veo operations in flight; the real ceiling is your Veo API
quota.--chainforces sequential (B needs A's rendered last frame). - first-frame vs reference: by default the shot's own storyboard sketch is the
image-to-video first frame.--with-referenceadditionally sends the
world-anchor as anassetreference; if the model rejects that combo the
renderer automatically retries without it. - Cost: every render call spends credits. Always
parse→plan→ render one
shot → then the batch. - Gemini Developer API quirks (AI Studio key): the Developer API rejects
seed
andenhance_prompt. Use--no-seed(and leave enhance_prompt off — it's
opt-in via--enhance-prompt, Vertex only). Reproducibility then relies on the
first-frame sketches + STYLE LOCK, not the seed. - Vertex env trap: if
GOOGLE_GENAI_USE_VERTEXAI=true/GOOGLE_CLOUD_PROJECT
are exported, the client routes to Vertex and fails. Unset them to force the
Developer API. - Logs: each run appends to
renders/render_log.jsonl(status, seed, model,
resolution, output path, seconds) for auditing.