help quicky produce instagram reels and youtube shorts
94
96%
Does it follow best practices?
Impact
87%
2.12xAverage score across 3 eval scenarios
Passed
No findings from the security scan
#!/usr/bin/env python3
"""Render headline / logo cards for talking-head b-roll, via Remotion.
Talking-head b-roll is usually cards and screen recordings rather than footage,
and a static card held for three seconds reads as dead air. These render as
real motion clips at mezzanine spec, so the cut plan treats them like any other
segment.
Requires Node 18+. The first run installs Remotion into the project (a few
hundred MB including a headless Chrome), so it is slow once and fast after.
The template is copied out of the plugin into <outdir>/_project first —
node_modules never lands inside the installed skill.
Input JSON (a list, or {"cards": [...]}):
[
{"name": "acquisition", "title": "Garmin bought TrainingPeaks",
"kicker": "July 2026", "subtitle": "The neutral ground changed hands",
"duration": 3.0, "bg": "#0F1D2B", "accent": "#F26B21", "logo": "garmin.png"}
]
Only "title" is required. "logo" is a filename inside <outdir>/_project/public.
Usage:
make_cards.py cards.json --outdir work/cards
make_cards.py cards.json --outdir work/cards --resolution 4k
"""
import argparse, json, shutil, subprocess, sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from render_reel import RESOLUTIONS
TEMPLATE = Path(__file__).resolve().parent.parent / "assets/remotion-cards"
FPS = 30
DEFAULTS = {"kicker": "", "subtitle": "", "duration": 3.0,
"bg": "#0F1D2B", "accent": "#F26B21", "fg": "#FFFFFF", "logo": ""}
def require_node():
if not shutil.which("node"):
sys.exit("Node not found — install Node 18+ (brew install node) or "
"build cards as stills and let normalize_clips.py apply Ken "
"Burns motion instead.")
def ensure_project(outdir):
"""Copy the template out of the plugin and install deps once."""
proj = outdir / "_project"
if not proj.exists():
shutil.copytree(TEMPLATE, proj)
(proj / "public").mkdir(exist_ok=True)
if not (proj / "node_modules").exists():
print("Installing Remotion (first run only, several minutes)...",
flush=True)
r = subprocess.run(["npm", "install", "--no-audit", "--no-fund"],
cwd=proj, capture_output=True, text=True)
if r.returncode != 0:
sys.exit(f"npm install failed:\n{r.stderr[-1200:]}")
return proj
def render_card(proj, card, dims, outdir):
name = card.get("name") or card["title"][:40].strip().replace(" ", "_")
dst = outdir / f"{name}.mp4"
props = {**DEFAULTS, **{k: v for k, v in card.items() if k != "name"}}
duration = float(props.pop("duration"))
frames = max(1, round(duration * FPS))
w, h = dims
cmd = ["npx", "remotion", "render", "Card", str(dst.resolve()),
"--props", json.dumps(props),
"--width", str(w), "--height", str(h),
"--frames", f"0-{frames - 1}",
"--log", "error"]
r = subprocess.run(cmd, cwd=proj, capture_output=True, text=True)
if r.returncode != 0:
print(f" FAILED {name}: {r.stderr.strip()[-500:]}", file=sys.stderr)
return None
return dst
def main():
ap = argparse.ArgumentParser()
ap.add_argument("cards_json")
ap.add_argument("--outdir", default="work/cards")
ap.add_argument("--resolution", choices=sorted(RESOLUTIONS), default="1080",
help="Match the mezzanine the project was normalized at.")
args = ap.parse_args()
require_node()
spec = json.loads(Path(args.cards_json).read_text())
cards = spec["cards"] if isinstance(spec, dict) else spec
if not cards:
sys.exit("No cards in the spec — nothing to render.")
for c in cards:
if not c.get("title"):
sys.exit(f"Every card needs a 'title': {json.dumps(c)[:120]}")
outdir = Path(args.outdir)
outdir.mkdir(parents=True, exist_ok=True)
proj = ensure_project(outdir)
dims = RESOLUTIONS[args.resolution]
done, failed = [], []
for c in cards:
print(f"Rendering card: {c['title'][:60]}...", flush=True)
out = render_card(proj, c, dims, outdir)
(done if out else failed).append(c.get("name") or c["title"])
print(json.dumps({"rendered": len(done), "failed": failed,
"outdir": str(outdir),
"resolution": f"{dims[0]}x{dims[1]}"}, indent=2))
if failed:
sys.exit(1)
print(f"\nAdd these to raw/ (or reference directly) and probe them — they "
f"are ordinary {dims[0]}x{dims[1]} clips from here on.",
file=sys.stderr)
if __name__ == "__main__":
main().tessl-plugin
evals
skills
reel-builder
assets
remotion-cards
references
scripts