video-render-local
Render an ace-web connect-videos program or a DDD connect-ddd-walkthrough to MP4 locally on a Mac, much faster than ace-web's server-side Re-render; works from a local spec and master clip with no Dri
Files1
View on GitHubSKILL.mdskills/video-render-local/SKILL.md
GitHubVideo Render — Local (Mac-metal)
Render an ace-web connect-videos program to output.mp4 on the host's
Node / Chromium / esbuild (1–3 min) instead of the slower Docker/server
/build queue. Wraps ace-web's scripts/render_locally.py. ElevenLabs
voiceover + music bed are muxed in; the renderer holds the last frame of
a clip range when its narration overruns, so a too-long script shows up
as frozen footage (see the timing report below).
When to use
- Iterating on a video locally and you want the fast render, not the server queue.
- Rendering a DDD narrative as a
connect-ddd-walkthroughfrom aspec.yaml+ master clip that exist only locally (e.g. canopy's emitter output) — no Drive, no container. - NOT for publishing to Drive/labs — that's the server
/build, or Mode B with--publish.
Prerequisites
- An ace-web checkout (default
~/emdash-projects/ace-web; override$ACE_WEB_ROOT). It vendors the renderer atvideo-production/connect-videosandscripts/render_locally.py. - connect-videos deps installed once:
cd "$ACE_WEB/video-production/connect-videos" && npm ci(~minutes). The script errors clearly if absent. ELEVENLABS_API_KEYin the environment or the ace.env(a value in ACE's Canopy vault on canopy-web). The renderer refuses to silently drop voice.ffmpegon PATH.
Resolve the checkout
ACE_WEB="${ACE_WEB_ROOT:-$HOME/emdash-projects/ace-web}"
[ -f "$ACE_WEB/scripts/render_locally.py" ] || { echo "no ace-web checkout at $ACE_WEB — set ACE_WEB_ROOT"; exit 1; }
Mode A — local spec + master clip (DDD / general, no Drive)
A style: recorded spec does NOT render here. canopy's recorded-walkthrough
mode (several standalone cuts, no music, no cards, footage near real time) lives
in canopy's own engine; ace-web's vendored copy predates it — its spec.ts has no
style field and scripts/render.ts muxes defaults.music_bed unconditionally,
so a recorded cut rendered here gets the music bed back (ace#2788). If the
narrative's recipe sets style: recorded (each cut is an
explainer_spec.<cut>.yaml), render with canopy's video-engine/render_locally.py
per /canopy:ddd-recorded-walkthrough instead, and stop reading this mode. Its
uploads (snippets upload-video, render_locally.py publish) run through
bin/ace-canopy-web --workspace "$WS" -- <command> and are read back with
verify walkthrough <id> (playbook/integrations/canopy-web.md, ace#2805).
The caller already has a connect-videos spec.yaml (e.g. canopy's emitted
explainer_spec.yaml) and a master clip. Stage + render directly:
cd "$ACE_WEB"
python scripts/render_locally.py \
--local-spec /path/to/spec.yaml \
--master /path/to/walkthrough.mp4 \
--final # omit for a faster --draft preview
Slug + run come from the spec (slug: / --run, default run-001); the
master is copied to the spec's manifest.master: file:… path. Output:
video-production/connect-videos/programs/<slug>/runs/<run>/output.mp4.
Mode B — existing Drive program (Docker app container up)
cd "$ACE_WEB"
python scripts/render_locally.py <program-slug> # or: <slug> <run-id>
python scripts/render_locally.py --publish <program-slug> # also push artifacts to Drive
Read the output — the timing report
After rendering the script prints:
clip footage (spec beats): 64.0s
rendered duration: 77.5s
held-frame overrun: +13.5s ⚠ VO overruns clips — trim narration
A large overrun means the narration is longer than the footage and the
renderer froze the last frame waiting for the VO. Trim the narration to
play continuously — budget ≈2.2 words/sec for the ElevenLabs
eleven_turbo_v2 voice (not 2.5; that overshoots).
Pointing at a specific renderer
$CONNECT_VIDEOS_ROOT (or --connect-videos-root) overrides just the
connect-videos project — render against a canonical install regardless of
which checkout the script lives in. Honored by both render_locally.py
and its QA probe.
Common mistakes
- Stale checkout — default is
~/emdash-projects/ace-web; set$ACE_WEB_ROOT(or$CONNECT_VIDEOS_ROOT) to target another. Don't render from a feature worktree by accident. - Missing
node_modules—npm ciin connect-videos once; the host arch must match (run on the Mac, not in the Linux container — that's the whole point). --publishin local-spec mode — rejected; there's no Drive program. Use Mode B to publish.manifest.masternot afile:ref — local mode copies--masterto thefile:path the spec names; emit the spec with afile:master (canopy's DDD emitter does).
Intended caller
canopy's on-demand ddd-ace-render emits the connect-ddd-walkthrough
spec + records the master clip, then invokes this skill (Mode A) to produce
the narrated MP4.