A fast, deterministic Python CLI that generates complete YouTube Shorts, TikToks, and landscape videos end-to-end using entirely free AI services.
ffmpeg-ai
a python cli that generates youtube shorts and landscape videos end-to-end using mostly free ai services. give it a topic, get back a video with voiceover, burned captions, paced visuals, thumbnails, and either cinematic ken burns motion or faster storyboard cuts.
screenshot โ pipeline running

screenshot โ example output

what it does
- generates a script from your topic via openrouter (free llm, auto-fallback through 6 models)
- synthesizes voiceover with edge-tts โ hook, each segment, and cta in parallel
- expands the visual timeline so no segment holds one image forever
- fetches ai images synced to script segments (7 providers, cascading fallback)
- renders either cinematic ken burns clips or faster storyboard cuts
- transcribes audio locally with faster-whisper to produce burned-in captions
- optionally mixes background music with sidechain compression
- final encode to spec (shorts 9:16 or landscape 16:9)
install
requires python 3.11+, ffmpeg on your $PATH, and uv.
git clone https://github.com/numbpill3d/ffmpeg-ai.git
cd ffmpeg-ai
uv pip install -e ".[dev]"
copy .env.example to .env and add your openrouter key:
cp .env.example .env
edit .env โ get a free key at https://openrouter.ai
usage
# basic short
ffmpeg-ai generate "the history of the moon"
landscape video (up to 10 min, storyboard render by default)
ffmpeg-ai generate "history of the roman empire" --mode landscape -d 300
force cinematic ken burns + xfade, or a fast storyboard proof
ffmpeg-ai generate "lost unix workstations" --mode landscape --render-mode kenburns
ffmpeg-ai generate "lost unix workstations" --mode landscape --render-mode fast-preview
style preset
ffmpeg-ai generate "deep sea creatures" --style dramatic
caption style
ffmpeg-ai generate "stoic philosophy" --caption-style plain
edit the script before rendering
ffmpeg-ai generate "mars colonization" --edit-script
add background music (auto-ducked under narration)
ffmpeg-ai generate "ancient egypt" --music ~/music/ambient.mp3
use your own images instead of ai generation
ffmpeg-ai generate "topic" --images-dir ~/my-images/
batch generate from a topics file (one topic per line, # = comment)
ffmpeg-ai batch topics.txt -o ~/Videos/batch/
resume a job (uses cached script + images)
ffmpeg-ai generate "the history of the moon"
force fresh run, ignore all cache
ffmpeg-ai generate "the history of the moon" --fresh
dry run โ script only, no video rendered
ffmpeg-ai generate "any topic" --dry-run
skip the hook text overlay (useful on Windows where fontconfig is missing)
ffmpeg-ai generate "topic" --no-hook
force a specific font for overlays/captions (.ttf path)
ffmpeg-ai generate "topic" --font /path/to/MyFont-Bold.ttf
launch the desktop control panel
ffmpeg-ai gui
windows / hook overlay
on windows, ffmpeg has no fontconfig, so the hook text overlay can fail with Fontconfig error: Cannot load default config file and previously aborted the whole pipeline. that is now handled:
- the pipeline auto-detects common windows fonts (
C:\Windows\Fonts\*.ttf). - if drawtext still fails, the overlay is skipped with a warning and the
--no-hookskips the overlay entirely;--font <path>forces a specific
.ttf. both flags also work on batch.
output modes
| mode | resolution | aspect | max length | default render | |-----------|---------------|--------|------------|----------------| | shorts | 1080 ร 1920 | 9:16 | 58 seconds | kenburns | | landscape | 1920 ร 1080 | 16:9 | 10 minutes | storyboard |
both modes use h.264 + aac, burned-in captions, and paced visual prompts.
render modes (--render-mode)
| render mode | best for | behavior | |--------------|----------|----------| | kenburns | shorts, cinematic promos | per-image motion clips plus xfade transitions | | storyboard | longform, essay, slide-card videos | quick still-card cuts without expensive xfade chains | | fast-preview | proof renders | storyboard-style preview path for checking script, timing, and visuals before a slower final render |
if omitted, shorts use kenburns; landscape uses storyboard so 5โ10 minute videos don't crawl through a giant xfade furnace by default.
style presets (--style)
| preset | tone | |--------------|---------------------------------------------------| | educational | authoritative, measured, surprising fact โ implication | | dramatic | cinematic, intense, short punchy sentences | | listicle | countdown format, numbered points, fast cuts | | documentary | journalistic, reflective, context โ story โ insight | | morris | empirical, intimate, pharmacological precision โ Hamilton Morris register | | mythology | epic oral-tradition storytelling around gods, heroes, and places | | finance | practical money explanations with concrete numbers and actions | | horror | slow-burn dread with restrained escalation | | curiosity | wonder-driven explanations of impossible-sounding facts |
caption styles (--caption-style)
| style | description | |-------------|--------------------------------------------------| | karaoke | word-level highlight, 3 words per line (default) | | plain | clean subtitles, 6 words per line | | bold-center | large centered text, 3 words per line |
image providers
tried in this order, falling back on failure. all paid keys are optional.
| provider | env var | notes | |----------------|----------------------|------------------------------------| | bfl | BFLAPIKEY | flux 1.1 pro (paid) | | fal | FAL_KEY | flux dev via fal.ai (paid) | | prodia | PRODIA_TOKEN | flux schnell, ultra-fast (paid) | | pollinations | โ | flux-realism / flux, free, no key | | huggingface | HF_TOKEN | flux schnell + sdxl fallback | | stablehorde | STABLEHORDEAPIKEY | community cluster, guest key built-in | | together | TOGETHERAPIKEY | flux schnell free tier |
override the order with --providers bfl,fal,pollinations.
job cache
each job is cached at ~/.cache/ffmpeg-ai/jobs/<slug>/:
script.jsonโ reused on re-run unless--freshimages/frame_*.jpgโ reused if count matchestts/โ cached by script+voice+rate hash; re-synthesized on any changerun_report.jsonโ machine-readable summary of the run: cache hits, render mode, visual pacing, provider attempts, caption/thumbnail outcome, placeholders, and artifact paths
project structure
src/ffmpeg_ai/
โโโ cli.py # typer entrypoint + all commands
โโโ pipeline.py # orchestrates the full generation pipeline
โโโ ai/
โ โโโ openrouter.py # llm client, model fallback logic
โ โโโ images.py # multi-provider image generation
โ โโโ tts.py # edge-tts voiceover
โโโ video/
โ โโโ composer.py # all ffmpeg subprocess calls
โ โโโ captions.py # faster-whisper + ass/srt generation
โ โโโ shorts.py # video spec constants (resolution, fps, codec args)
โโโ ui/
โโโ display.py # animated ascii banner
โโโ widgets.py # rich live pipeline tracker
โโโ gui.py # retro Tk desktop operator panel
env vars
| var | required | purpose | |-----------------------|----------|----------------------------------| | OPENROUTERAPIKEY | yes | llm script generation (free tier)| | BFLAPIKEY | no | black forest labs flux 1.1 | | FAL_KEY | no | fal.ai flux dev | | PRODIA_TOKEN | no | prodia flux schnell | | HF_TOKEN | no | huggingface inference | | STABLEHORDEAPI_KEY| no | registered horde key (priority) | | TOGETHERAPIKEY | no | together ai flux schnell free | | EDITOR | no | editor for --edit-script |
dev
uv pip install -e ".[dev]"
ruff check src/
pytest
license
mit