Talking-Head Short — master editor
Write terse replies. Don't echo transcripts or long logs. Fix things by editing spec.json with the Edit tool, never by rewriting it. Every script prints a compact report; read it, act, move on.
S=<this skill dir>/scripts, WD=<work dir next to the raw file>/ths_<name>.
0. Setup (once per machine/sandbox)
bash $S/setup.sh → use the printed PY=. It installs everything from PyPI, including a static ffmpeg if none exists.
Every download has an automatic fallback. Sandboxes (claude.ai code execution, free or paid) usually block HuggingFace, Mixkit and the Google Fonts API, but allow GitHub:
- transcription model: HuggingFace → GitHub mirror (whisper-base, then whisper-tiny)
- music/SFX: Mixkit → GitHub mirror CC0 pack (ids look like
pack:lofi_chill) - fonts: Google Fonts repo → jsDelivr → GitHub mirror OFL pack (32 families) → system font
- B-roll: Mixkit → none (use cards, or ask the user to upload clips)
If setup prints "no network" / pip fails: the sandbox has network egress OFF. Tell the user exactly (one message):
"claude.ai → Settings → Capabilities → Code execution → Network access: All domains (or add: pypi.org, files.pythonhosted.org, github.com, objects.githubusercontent.com, release-assets.githubusercontent.com, api.github.com, raw.githubusercontent.com, cdn.jsdelivr.net, huggingface.co, mixkit.co, assets.mixkit.co), then start a new chat and run /talking-head-short again." Don't attempt the edit without numpy/ffmpeg.
Only if every source fails: ask for a pasted transcript →
$PY $S/align_text.py $WD transcript.txt. Assets cache in~/.ths_assets.
1. Analyze
$PY $S/analyze.py RAW $WD
It prints the resolution, eye point, the clean length, auto-removed fillers/stutters/restarts, CHECK (soft fillers, low-confidence words, long pauses), and TEXT with timestamps every 8 words.
- Judge bad takes yourself. Remove false starts, unfinished sentences, "you know like yeah", "kind of". Keep rhetorical repetition. Re-run with
--remove '[[s,e],...]'(source seconds). Transcription is cached. - Look at
$WD/frames.jpgonly if the eye point or framing is in doubt.
2. Brief (in your head, then 4 lines to the user)
Write: topic · core message · emotion arc (hook → … → payoff) · niche row (from NICHES) · tone (calm/balanced/energetic) · raw framing (wide or tight).
Then run $PY $S/style.py RAW "<niche>" --out $WD/style.json. It gives the adapted palette with reasons, fonts, MG/B-roll/music/SFX direction and hard notes.
Read references/craft.md once (the rules) and references/spec.md (the spec format).
3. Ask before building (never render first)
Use AskUserQuestion if available; otherwise one compact numbered message. Recommend option 1 each time.
- Style: detected niche + tone (e.g. "Self-help · calm-reflective") vs 1–2 alternatives.
- Fonts: the row's pair vs 2 alternatives with a clear style contrast (sans lead + serif/italic key, or bold sans key + italic serif accent).
- Palette: footage-adapted row palette vs footage-derived vs a brand color the user gives.
- Visual density: Minimal (captions + 2–3 cards) · Balanced (captions + 4–6 cards / B-roll) · Rich (more MG + B-roll).
- Music: 3 licensed candidates from
$PY $S/assets.py music "<mood>"(id · title · tags), or none. - B-roll: yes (licensed stock matching literal lines) / no. Skip any question the user already answered. Wait for the answers.
4. Gather assets
- Fonts:
$PY $S/assets.py font "Family" ... - Music, SFX, video: run
assets.py music|sfx|video "<query>"to list, thenassets.py get <kind> <id> $WD.- SFX by tone: calm → "air woosh", "chime"; balanced → "whoosh", "pop"; energetic → "swoosh", "impact" (used once).
- Blocked sources fall back automatically (pack ids).
assets.py packlists the whole offline CC0 pack.
5. Write spec.json, plan, styleframes
- Write
$WD/spec.json(see references/spec.md): captions in spoken order, cards on the right clauses, audio. $PY $S/engine.py $WD --plan→ fix every ISSUE by editing the spec (shorten or merge beats, move or drop captions under cards), then re-plan until it reports none or only acceptable ones.$PY $S/engine.py $WD --frames t1,...with 10–15 times: every card mid-point and end−0.3 s, and every caption at its end−0.1 s. Look at$WD/styleframes.jpgand fix anything cut off, crowded, mis-aligned or off-palette.- Show the user the styleframes with one line ("ok to render?"). Iterate only on what they flag.
6. Render, mix, QA
bash $S/render.sh $PY $WDrenders parts in parallel and concatenates them (≈5 min per minute of video on a laptop). In a sandbox with a time limit per command, run$PY $S/engine.py $WD --render --part i/Nonce per part, then--concat N.$PY $S/mix.py $WD→final.mp4(voice clean-up, ducked music with payoff alignment, SFX, -14 LUFS).$PY $S/qa.py $WD→ look atqa_endframes.jpg. Every beat and card end must show finished text and animation. Flash frames must be none.- Deliver the file path, plus 3 lines on what you chose and why. Mention any assets you couldn't download.
Non-negotiables (why: each one was called out as amateur)
- Captions never cut off. Lead is ≤ key width and sits close. Two contrasting font styles at a golden ratio. Never caption lone filler words.
- Motion graphics show the meaning, finish before the scene changes, and stay in one visual system. No stick figures or clip art.
- Smooth: an eased, eye-locked zoom across cuts; no flash frames; varied transitions.
- Color correction only. Licensed assets only (Mixkit / Google Fonts OFL), with LICENSES.txt kept in $WD.