Write talking-head scripts and produce Instagram reels and YouTube shorts
93
94%
Does it follow best practices?
Impact
88%
1.23xAverage score across 3 eval scenarios
Low
Low-risk findings worth noting
Three renderers accept the same plan/cut_plan.json and produce the same kind
of file, so they can be compared on identical input.
render_reel.py | render_moviepy.py | resolve_render.py | |
|---|---|---|---|
| Engine | ffmpeg — per-segment cuts, concat demuxer, one mux | MoviePy — in-memory clip graph, single write | DaVinci Resolve Studio — timeline, per-clip transform, native H.264 |
| Dependency | ffmpeg only | pip install moviepy | Resolve Studio running (free refuses scripting) |
| Speed | fast | slower — roughly 5x on a short 1080 preview | 15s for a 28s 1080x1920 reel, measured |
| Grading | ffmpeg filter chain | the same chain, applied as a second pass | bundled LUT looks on the clip node graph; cine/rapha have no LUT form |
| Reframe | plan's pan | plan's pan | plan's pan, or --smart-reframe (subject tracking) |
render_reel.py is the default. Only reach for MoviePy when the user asks
to compare, or when a plan needs per-clip compositing that the flat concat
model cannot express.
Hyperframes is an optional motion-graphics source, not a cut-plan renderer.
render_hyperframes.py turns an HTML project into an ordinary clip consumed
by any renderer above. See references/hyperframes.md for setup and placement.
Same plan, same grade, same resolution — change only the script:
python3 scripts/render_reel.py plan/cut_plan.json --preview --grade rapha --out preview/ab_ffmpeg.mp4
python3 scripts/render_moviepy.py plan/cut_plan.json --preview --grade rapha --out preview/ab_moviepy.mp4render_moviepy.py prints its wall-clock time so the two are directly
comparable. Grading is not reimplemented — MoviePy handles cut, concat, and
audio, then the identical GRADES chain from render_reel.py runs as a second
ffmpeg pass. That keeps the assembly engine as the only variable.
Which engine to use is a user-facing choice, not an implementation detail: it changes render time and, slightly, the audio mix. Offer the comparison rather than silently swapping engines mid-project.
compose recomputes the timeline.--resolution.python3 scripts/resolve_render.py plan/cut_plan.json --out work/master.mp4 --look gritty
python3 scripts/resolve_render.py plan/cut_plan.json --out work/master.mp4 --smart-reframe --keep-projectPicture comes from Resolve; the audio spine — music, --vo-overlay, or the
clips' own sound with --natural-audio — goes through the same mux as
render_reel.py, so the sound design does not fork with the engine. The
result is an ordinary master: check_cuts.py, then export_variants.py and
its compliance table, unchanged.
Reach for it when the reframe should track a subject (--smart-reframe), when
handheld footage wants stabilising (--stabilize — Resolve's analysis, no
ffmpeg equivalent shipped here), when the footage wants a LUT applied on
Resolve's node graph, or when the human will keep working the timeline
afterwards (--keep-project, then resolve_bridge.py pull). Measured with
both AI passes on 16 clips: about seven seconds of analysis per clip, then a
12s render.
What stays with ffmpeg on purpose:
NormalizeAudioLevel works per clip and our audio
is a mix built at render — measured, it drove near-silent drone clips to
+30 dB. export_variants.py normalises the mix.gen_captions.py.LUTs must live under Resolve's LUT directory — SetLUT refuses absolute
paths — so the bundled looks are copied to <LUT dir>/reel-builder/ on first
use. Pass --lut relative to that directory.
Whatever project the human has open is saved before the script switches to
its own, and the scratch project is deleted afterwards unless --keep-project.
.tessl-plugin
skills
reel-builder
assets
references
scripts
yap-writer