Skip to content

Repository files navigation

Showrunner

AI-powered video generation framework. Create animated social media videos from text topics with pluggable formats and providers.

showrunner-about-showrunner.mp4

Quick Start

pip install "showrunner @ git+https://github.com/scrollmark/showrunner.git"

Not on PyPI. Install from this repository. The name showrunner on PyPI belongs to an unrelated live-theatre package, so plain pip install showrunner silently installs the wrong project.

Prerequisites

  • Python 3.11+
  • Node.js 18+ (for Remotion video rendering)
  • An Anthropic API key (ANTHROPIC_API_KEY environment variable)

Before your first render: the default format renders with Remotion, which requires a paid license for companies of 4+ people and for hosted or automated rendering. See Licensing and docs/licensing.md.

Generate a video

showrunner create "Why do cats purr?"

Customize

showrunner create "The history of the internet" \
--style bold-neon \
--aspect-ratio 16:9 \
--captions \
--watermark "@mychannel"

Available commands

Generate:

showrunner create "topic"# Topic → storyboard → assets → rendered MP4.# Key flags: --style/--override, --aspect-ratio,# --captions, --watermark, --music auto|none|<id>,# --dry-run (plan only), --auto-approve, --parallel,# --analyze [--sync] (upload for cloud analysis), --json
showrunner render plan.json # Render a saved storyboard to video
showrunner refine <work_dir><scene_id>\ # Regenerate ONE scene and re-render (~2-3 min)
--instruction "..." --output out.mp4
showrunner resume <work_dir># Resume an interrupted create from its checkpoints

Export:

showrunner export<work_dir># Emit an editable timeline: OTIO (default),# or -f fcpxml|edl|aaf (needs showrunner[otio-all])

Cloud (see docs/cloud.md):

showrunner login # Log in (browser OAuth; --with-password for# email+password — today's production path)
showrunner logout# Revoke (best-effort) + clear credentials
showrunner whoami # Show identity and token status
showrunner analyze clip.mp4 # Upload for analysis; prints the post_id
showrunner analyze --id <id> [--sync] # Fetch results/artifacts (--report, --transcript,# --scenes, --caption, ...); --if-duplicate warn|reuse|fail
showrunner list # Your uploads (--local: offline ledger)

Discover:

showrunner formats # List video formats
showrunner styles # List style presets
showrunner voices # List TTS voices
showrunner providers # List discovered providers (installed vs configured)
showrunner music list|add|remove|inspect|where # Manage the local background-music catalog

Setup:

showrunner init # Create a .showrunner.yaml config file

Agent mode (--json)

Coding agents and other programs driving the CLI should pass --json (either globally, showrunner --json create ..., or per command, showrunner create ... --json) instead of scraping human prose:

  • stdout carries only JSON. For create, refine, and resume it is a newline-delimited JSON (NDJSON) event stream — one object per line, each with an "event" discriminator. For the listing commands (formats, styles, voices, providers), export, and the cloud commands (login, logout, whoami, list, analyze --id) it is a single JSON document. analyze with a PATH streams NDJSON upload events — full shapes in docs/cloud.md.
  • Human logging moves to stderr.
  • Failures end with an error event and a non-zero exit code.
  • In human mode (no --json), the WORKDIR: <path> line on stdout is retained for back-compat with existing integrations.

Stability contract

The schema below is additive-only: existing event names and fields never change meaning or disappear. New events and new fields may appear in any release, so consumers must ignore unknown events and fields.

Event stream (create, refine, resume)

EventFieldsMeaning
plan_readytitle, scenes (count), total_duration (s), plan (full storyboard object)Storyboard planned
work_dir_readywork_dirWork directory created (pass it to showrunner refine)
stage_startedstage (plan/assets/compose/render/refine/...), progress_pct (0-100 or null)Stage began
stage_completedstage, progress_pctStage finished
asset_progressscene_id, kind (tts|code|clip), status (started|completed), index/total or duration_secondsPer-scene asset progress
scene_failedscene_id, errorA scene exhausted its codegen retries
repair_attemptattempt, error_excerptReserved for the render repair loop (not yet emitted)
doneoutput_path, work_dir; optional usage, cost_usd, dry_run, previewTerminal success. output_path/work_dir are null for --dry-run
errorstage, messageTerminal failure; the process exits non-zero
cancelledwork_dir (resumable, may be null)Terminal cancellation

Example:

$ showrunner create "Why do cats purr?" --json 2>/dev/null
{"event": "stage_started", "stage": "plan", "progress_pct": 0.0}
{"event": "plan_ready", "title": "Why Do Cats Purr?", "scenes": 6, "total_duration": 42, "plan": {...}}
{"event": "stage_completed", "stage": "plan", "progress_pct": 10.0}
{"event": "work_dir_ready", "work_dir": "/tmp/showrunner-abc123"}
{"event": "asset_progress", "scene_id": "hook", "kind": "code", "status": "completed", "index": 1, "total": 6}
...
{"event": "done", "output_path": "output/why-do-cats-purr.mp4", "work_dir": "/tmp/showrunner-abc123"}

Single-document commands

formats, styles, voices, and providers print one JSON object: {"formats": [{"name", "description"}, ...]}, {"styles": [...]}, {"voices": [...]}, {"providers": {"llm": "anthropic", ...}}. export prints {"output_path", "format"}. The cloud commands' JSON shapes are documented in docs/cloud.md.

Agent Skill (Claude Code / Cursor / etc.)

Showrunner ships a first-party Agent Skill so coding agents can drive video generation correctly on the first try — the prerequisites check, the create → inspect → refine loop, style/format selection, quality self-review, and troubleshooting are all encoded in the skill rather than left to trial and error.

Install it with the skills CLI:

npx skills add scrollmark/showrunner

Or copy it manually into your agent's skills directory:

# Claude Code (project-level)
mkdir -p .claude/skills/showrunner
cp skills/showrunner/SKILL.md .claude/skills/showrunner/
# Claude Code (user-level, all projects)
mkdir -p ~/.claude/skills/showrunner
cp skills/showrunner/SKILL.md ~/.claude/skills/showrunner/

Then ask your agent for a video ("make me a 9:16 explainer about black holes") — it will pick up the skill automatically.

Configuration

Create .showrunner.yaml in your project:

default_format: faceless-explainerdefault_style: 3b1b-darkproviders:
llm: anthropictts: kokororender: remotionanthropic:
model: claude-sonnet-4-5-20250929kokoro:
voice: af_heartspeed: 1.0output:
aspect_ratio: "9:16"captions: false# Max render→repair retries: on a failed render the error output is fed# back to the LLM (Format.revise) and the render retried. 0 disables.repair_attempts: 2# Cloud server for `showrunner login` / cloud analysis (docs/cloud.md).cloud:
server_url: https://api.gpt.social# oauth (default) or firebase — see "Connecting to SocialGPT" below. The# `showrunner login --with-password` flag overrides this.auth_method: oauth

CLI arguments override config file values.

Connecting to SocialGPT

Showrunner can upload any local video — or the render inside a work_dir — to SocialGPT's cloud analyzer and fetch back a deep analysis (hook, scene breakdown, transcript, themes, technical read). docs/cloud.md is the full reference — login methods and credential storage, every analyze flag with sample output, exit codes, the --json shapes, idempotent uploads and the local ledger, create --analyze [--sync], and troubleshooting. The 30-second version:

pip install "showrunner[cloud] @ git+https://github.com/scrollmark/showrunner.git"# 1. Log in — today's production path is email + password:
showrunner login --with-password # plain `showrunner login` is browser# OAuth, pending the server deploy (#55)# 2. Upload — async by default; the bare post_id is the only stdout line:
id=$(showrunner analyze output/cats.mp4)# 3. Get results whenever they're ready:
showrunner analyze --id "$id"# one check: report, or exit 2
showrunner analyze --id "$id" --sync # poll until ready (10 min cap)
showrunner analyze --id "$id" --transcript --caption # artifacts combine
showrunner list # your uploads (--local: offline)

Or in one shot (showrunner analyze clip.mp4 --sync) — and straight from generation:

showrunner create "topic" --auto-approve --analyze # render, upload, print id
showrunner create "topic" --auto-approve --analyze --sync # …and wait for the report

Essentials (full contracts in docs/cloud.md):

  • Exit codes: 0 success/ready · 1 real error or a terminally failed analysis (failure_reason on stderr) · 2not ready yet — retry later, not a failure (also a --sync timeout) · 3 duplicate refused under --if-duplicate fail.
  • Clean stdout, safe to redirect: stdout carries only the payload — the bare post_id for uploads, the artifact content for reads (--transcript > script.txt yields a clean file). Progress lives behind --verbose, on stderr. --json streams NDJSON events for uploads and prints one JSON object for --id reads.
  • Idempotent uploads: the post_id is minted client-side (UUIDv4) before any bytes move; transient failures retry with the same id and interrupted uploads resume it — re-running showrunner analyze is always safe. Every upload is recorded in the local ledger (~/.showrunner/analyses.jsonl; browse with showrunner list --local).
  • Accounts created with Google sign-in have no password — set one via the web app's password reset before login --with-password. In CI, set SHOWRUNNER_TOKEN to a pre-issued token instead of logging in.

Video Formats

FormatRendererBest for
faceless-explainer (default)Remotion (React/TSX)Educational / explainer motion graphics
ai-videoFFmpeg (AI clip concat)Cinematic, storytelling
manim-explainerManim CE + FFmpegMath animations (equations, graphs, geometry)

manim-explainer prerequisites

The manim-explainer format renders each scene with Manim Community Edition and stitches clips with FFmpeg:

pip install "showrunner[manim] @ git+https://github.com/scrollmark/showrunner.git"# Manim CE >= 0.20

You also need:

  • A LaTeX toolchain on PATH for MathTex/Tex equations (e.g. TinyTeX, MacTeX, or TeX Live — see the Manim installation docs)
  • FFmpeg on PATH (used by both Manim and the final concat/narration mix)
showrunner create "why does e^ipi = -1" --format manim-explainer

Style Presets

PresetDescription
3b1b-darkNavy/blue/gold, math education
bold-neonBlack/cyan/pink, gaming/tech
clean-corporateWhite/blue, professional
dramatic-storyBlack/gold/red, cinematic
forest-breathSage green/off-white, grounded and calm
minty-freshMint green/cream, cheerful product marketing
paper-pressCream/black/red, newspaper editorial
pastel-gradientLavender/purple, wellness
sunny-editorialWarm yellow/cream/charcoal, long-form editorial
tech-startupDark/indigo/pink, SaaS
warm-minimalCream/brown, lifestyle

Custom style overrides:

showrunner create "topic" --style 3b1b-dark --override "use green accents, faster pacing"

As a Library

fromshowrunnerimportPipelinepipeline=Pipeline(format_name="faceless-explainer")
video_path=pipeline.run(
"Why do cats purr?",
style="3b1b-dark",
captions=True,
)

Dry run (plan only, no render)

plan=pipeline.run("topic", dry_run=True)
print(plan.to_json())

Captions (work_dir contract)

--captions produces word-level, TikTok-style captions in both built-in formats. After TTS, each scene's word timings are written into the work_dir (printed as WORKDIR: <path> during create) as:

captions/{scene_id}.json

Each file is a Caption[] array matching the @remotion/captions shape, so exporters and NLE handoff tools can consume it directly:

[
{ "text": "Cats", "startMs": 0, "endMs": 280, "timestampMs": 140 },
{ "text": "purr", "startMs": 280, "endMs": 590, "timestampMs": 435 }
]

Word timing sources, in preference order:

  1. TTS timing metadata — Kokoro token timestamps are used directly (exact alignment, no extra cost).
  2. Whisper transcription — install the optional dependency with pip install "showrunner[captions] @ git+https://github.com/scrollmark/showrunner.git" (uses faster-whisper locally).
  3. Estimation — words are distributed proportionally across the audio duration as a last resort.

Rendering:

  • faceless-explainer — captions are grouped into short pages and rendered by a Remotion overlay (src/captions/captions.generated.ts), styled from the active style preset (caption font family, colors.text for unspoken words, colors.accent highlight for the spoken word).
  • ai-video — the same JSON is converted to captions.ass with karaoke word-highlight tags and burned in by FFmpeg's ass filter.

Creating Format Plugins

Formats are Python packages that register via entry points:

fromshowrunnerimportFormat, Plan, FeedbackfrompathlibimportPathclassMyFormat(Format):
name="my-format"description="My custom video format"required_providers= ["llm", "tts", "render"]
defplan(self, topic, style, config, llm):
...
defgenerate_assets(self, plan, providers, work_dir):
...
defcompose(self, plan, assets, work_dir, **kwargs):
...
defrevise(self, plan, feedback, llm):
...

Register in your package's pyproject.toml:

[project.entry-points."showrunner.formats"]
my-format = "my_package:MyFormat"

Then it's automatically available:

showrunner create "topic" --format my-format

Providers

LLM

  • anthropic (default) — Claude via Anthropic API
  • openai — GPT via OpenAI API

TTS

  • kokoro (default) — Free local TTS (82M params, Apache 2.0)
  • elevenlabs — Cloud TTS (paid API)

Render

  • remotion (default) — React-based programmatic video
  • ffmpeg — Clip concatenation for AI video formats

Video

  • gemini — Google Veo via Gemini API
  • minimax — MiniMax video generation

Adding a provider

Providers are discovered via entry points, just like formats — no core edits needed. Implement the matching ABC (showrunner/providers/<kind>/base.py) and register it in your package's pyproject.toml under showrunner.providers.{llm,tts,video,render}:

[project.entry-points."showrunner.providers.tts"]
my-tts = "my_package:MyTTSProvider"

Then select it in .showrunner.yaml (providers.tts: my-tts). Constructor kwargs come from the provider's config section (e.g. a top-level my-tts: mapping). Run showrunner providers to see what's installed vs configured.

Licensing

Showrunner itself is MIT-licensed — free for any use, including commercial. However, Showrunner's license does not grant you any rights to Remotion or other third-party providers. Showrunner shells out to the Remotion install in your environment, so the license obligation falls on whoever runs the render.

Key points (verified against remotion.dev and remotion.pro as of July 2026):

  • Remotion (used by the default faceless-explainer format) is free for individuals, nonprofits, and for-profit companies of up to 3 people. Larger companies need a paid plan: Creators ($25/seat/mo) for low-volume manual creation, or Automators ($0.01/render, $100/mo minimum) for automated/hosted rendering — the tier that applies to prompt-to-video services.
  • The FFmpeg-based ai-video format does not use Remotion — no Remotion license implications on that path.
  • Cloud TTS/video providers (ElevenLabs, Veo, MiniMax) have their own commercial-use terms.

Full details: docs/licensing.md.

About

Open-source AI video generation framework. Pluggable formats, swappable providers, one CLI.

Resources

Contributing

Stars

12 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages