Shorts edit skill

Turn raw talking-head recordings (OBS, webcam, screen capture) into finished vertical shorts — cut the retakes and dead air, clean the audio, burn word-by-word captions, add cue-anchored motion graphics and retention pattern-interrupts, all in a single video encode, then prove it with a QA gate.

by timscheuerai·MIT license·★ 37 Stars on the repo·GitHub ↗

Use now

Inside this skill

SKILL.md · the author's own words
# shorts-edit

The orchestrator. Raw takes in, postable vertical shorts out.

Built and hardened on a real session: 14 OBS recordings, 57 minutes of raw → 21 minutes of
cut. **Every rule below exists because a defect got through review looking fine.**

## The prime directive

> **Nothing is done until `qa.py` passes. Not "looks good" — passes.**

Every single bug in this pipeline's history was invisible to eyeballs and obvious to a
measurement. A caption verifier that sampled long words reported perfect while short words
were silently wrong. A tier grade was revealed 5.7s before it was spoken and every frame
looked fine in isolation. Audio "sounded weird" and the cause was a filter silently
changing mode. **Do not trust your eyes on this material. Measure.**

Word-for-word excerpt, not a result. Read the full SKILL.md ↓

Files of Shorts edit

timscheuerai/main1 file shown
SKILL.md
Show the full text136 lines

shorts-edit

The orchestrator. Raw takes in, postable vertical shorts out.

Built and hardened on a real session: 14 OBS recordings, 57 minutes of raw → 21 minutes of cut. Every rule below exists because a defect got through review looking fine.

The prime directive

Nothing is done until qa.py passes. Not "looks good" — passes.

Every single bug in this pipeline's history was invisible to eyeballs and obvious to a measurement. A caption verifier that sampled long words reported perfect while short words were silently wrong. A tier grade was revealed 5.7s before it was spoken and every frame looked fine in isolation. Audio "sounded weird" and the cause was a filter silently changing mode. Do not trust your eyes on this material. Measure.

Subskills

Skill Owns
shorts-cut take selection, dead air, why ASR word-ends are fiction
shorts-audio the two silent audio traps, and why the answer was no denoiser
shorts-motion scout → plan → render, cue anchoring, the brand, the tier board
shorts-qa the gate. 7 checks. Run it before anything ships.

Read the one you need. Read shorts-qa always.

Project layout

<project>/
  raw/     source recordings (untouched)
  clips/   <name>_final.mp4   <- deliverables
  edit/    everything derived
    transcripts/       cached word-level ASR — NEVER re-transcribe
    edl_parts_tight/   the cut decisions — SOURCE OF TRUTH
    motion.json        the graphics plan (cue-anchored)
    word_fixes.json    ASR corrections + caption inserts
    caption_work/      per-frame PNG sequence + schedule.json

Scripts find the project via $SHORTS_PROJECT, --project <dir>, or by walking up from the cwd for raw/.

SETUP

brew install ffmpeg                 # every stage shells out to it
pip install pillow numpy            # the renderers

# transcription runs through the vendored video-use helpers
export ELEVENLABS_API_KEY=...

Then point two shell vars at this vault so the pipeline below copy-pastes:

V=~/.claude/skills/content-vault/skills    # wherever you cloned content-vault
S=$V/shorts-edit/scripts

Optional, all with sane fallbacks — see scripts/assets.py:

Env Default If unset
SHORTS_FONT macOS Helvetica Neue .ttc on Linux/Windows, set it — there is no fallback face
SHORTS_SFX_DIR shorts-edit/assets/sfx/ synthesised whoosh/impact/riser, measures clean
SHORTS_BRAND_MD shorts-edit/assets/BRAND.md ships conformant; edit it to your brand

The pipeline

export SHORTS_PROJECT="/path/to/project"

# 1. transcribe (word-level, CACHED)
python $V/video-use/helpers/transcribe_batch.py "$SHORTS_PROJECT/raw" \
       --edit-dir "$SHORTS_PROJECT/edit" --workers 4
python $V/video-use/helpers/pack_transcripts.py --edit-dir "$SHORTS_PROJECT/edit"
python $S/words_dump.py

# 2. pick takes   -> edit/edl_parts/*.json     (see shorts-cut)
# 3. tighten dead air inside kept takes
python $S/tighten_edl.py                        # -> edit/edl_parts_tight/

# 4. plan graphics (see shorts-motion)
python $S/motion_scout.py "<clip>"              # find the visualizable moments
#   -> hand-write edit/motion.json, CUE-ANCHORED

# 5. build — cut + captions + audio + graphics + polish, ONE encode
python $S/build.py "<clip>" --polish

# 6. THE GATE — nothing ships until this passes
python $S/qa.py "<clip>"

Hard rules (violating any of these produces a silent failure)

  1. ONE video encode. Trim → concat → zoom → overlay → encode, all in one filtergraph. Two encodes softened a 246 kbps source from SSIM 0.998 to 0.977. Never re-encode a finished clip to add something to it.
  2. ASR word END times are fiction. They pad into the following silence and can be phantom words over dead-silent audio. Word STARTs are reliable. All silence reasoning comes from the audio (silencedetect/RMS), never the transcript.
  3. Never let ffmpeg derive caption/graphic timing from durations. The concat demuxer re-times to CFR and rounds boundaries as it pleases. Use one PNG per output frame.
  4. Never use loudnorm for gain. See shorts-audio. It silently pumps.
  5. Graphics are cue-anchored, never hand-timed. See shorts-motion.
  6. Fades only at real cut edges. A mid-beat framing change is not a cut — the audio runs straight through it. A 30ms fade there dips the voice audibly.
  7. concat wants inputs interleaved v0,a0,v1,a1,… — not all video then all audio. The two are identical for one segment, so a single-segment test clip hides the bug.
  8. PIL's ImageDraw with a partial-alpha fill OVERWRITES pixels, it does not composite. Draw at full opacity on a layer, then fade the layer. Otherwise a fading element punches a transparent hole through whatever is beneath it.

What shipped

video libx264 CRF 6, preset slow, native res/fps, bt709/tv — SSIM 0.9996 vs source
audio highpass 60Hz + a constant gain to −1.5 dBTP. No denoiser.
captions Helvetica Neue Medium, lowercase, 18px, tracking −1, no stroke
graphics cue-anchored, on-brand, drawn per frame at 30fps
retention pattern interrupt every ≤4.8s; dead-air 0%

Fix the capture, not the edit

The source was 360×640, 246 kbps, −43 LUFS. No post-processing recovers detail that was never recorded. Raising the OBS canvas and input gain improves every future edit for free.

1---
2name: shorts-edit
3description: Turn raw talking-head recordings (OBS, webcam, screen capture) into finished vertical shorts — cut the retakes and dead air, clean the audio, burn word-by-word captions, add cue-anchored motion graphics and retention pattern-interrupts, all in a single video encode, then prove it with a QA gate. Use when asked to edit/cut/clip raw talking-head footage, remove retakes or dead air, denoise recording audio, add captions or motion graphics to a talking-head video, or improve a video's retention.
4---
5 
6# shorts-edit
7 
8The orchestrator. Raw takes in, postable vertical shorts out.
9 
10Built and hardened on a real session: 14 OBS recordings, 57 minutes of raw → 21 minutes of
11cut. **Every rule below exists because a defect got through review looking fine.**
12 
13## The prime directive
14 
15> **Nothing is done until `qa.py` passes. Not "looks good" — passes.**
16 
17Every single bug in this pipeline's history was invisible to eyeballs and obvious to a
18measurement. A caption verifier that sampled long words reported perfect while short words
19were silently wrong. A tier grade was revealed 5.7s before it was spoken and every frame
20looked fine in isolation. Audio "sounded weird" and the cause was a filter silently
21changing mode. **Do not trust your eyes on this material. Measure.**
22 
23## Subskills
24 
25| Skill | Owns |
26|---|---|
27| **shorts-cut** | take selection, dead air, why ASR word-ends are fiction |
28| **shorts-audio** | the two silent audio traps, and why the answer was no denoiser |
29| **shorts-motion** | scout → plan → render, cue anchoring, the brand, the tier board |
30| **shorts-qa** | the gate. 7 checks. Run it before anything ships. |
31 
32Read the one you need. Read **shorts-qa** always.
33 
34## Project layout
35 
36```
37<project>/
38 raw/ source recordings (untouched)
39 clips/ <name>_final.mp4 <- deliverables
40 edit/ everything derived
41 transcripts/ cached word-level ASR — NEVER re-transcribe
42 edl_parts_tight/ the cut decisions — SOURCE OF TRUTH
43 motion.json the graphics plan (cue-anchored)
44 word_fixes.json ASR corrections + caption inserts
45 caption_work/ per-frame PNG sequence + schedule.json
46```
47 
48Scripts find the project via `$SHORTS_PROJECT`, `--project <dir>`, or by walking up from
49the cwd for `raw/`.
50 
51## SETUP
52 
53```bash
54brew install ffmpeg # every stage shells out to it
55pip install pillow numpy # the renderers
56 
57# transcription runs through the vendored video-use helpers
58export ELEVENLABS_API_KEY=...
59```
60 
61Then point two shell vars at this vault so the pipeline below copy-pastes:
62 
63```bash
64V=~/.claude/skills/content-vault/skills # wherever you cloned content-vault
65S=$V/shorts-edit/scripts
66```
67 
68Optional, all with sane fallbacks — see `scripts/assets.py`:
69 
70| Env | Default | If unset |
71|---|---|---|
72| `SHORTS_FONT` | macOS Helvetica Neue `.ttc` | on Linux/Windows, set it — there is no fallback face |
73| `SHORTS_SFX_DIR` | `shorts-edit/assets/sfx/` | synthesised whoosh/impact/riser, measures clean |
74| `SHORTS_BRAND_MD` | `shorts-edit/assets/BRAND.md` | ships conformant; edit it to your brand |
75 
76## The pipeline
77 
78```bash
79export SHORTS_PROJECT="/path/to/project"
80 
81# 1. transcribe (word-level, CACHED)
82python $V/video-use/helpers/transcribe_batch.py "$SHORTS_PROJECT/raw" \
83 --edit-dir "$SHORTS_PROJECT/edit" --workers 4
84python $V/video-use/helpers/pack_transcripts.py --edit-dir "$SHORTS_PROJECT/edit"
85python $S/words_dump.py
86 
87# 2. pick takes -> edit/edl_parts/*.json (see shorts-cut)
88# 3. tighten dead air inside kept takes
89python $S/tighten_edl.py # -> edit/edl_parts_tight/
90 
91# 4. plan graphics (see shorts-motion)
92python $S/motion_scout.py "<clip>" # find the visualizable moments
93# -> hand-write edit/motion.json, CUE-ANCHORED
94 
95# 5. build — cut + captions + audio + graphics + polish, ONE encode
96python $S/build.py "<clip>" --polish
97 
98# 6. THE GATE — nothing ships until this passes
99python $S/qa.py "<clip>"
100```
101 
102## Hard rules (violating any of these produces a silent failure)
103 
1041. **ONE video encode.** Trim → concat → zoom → overlay → encode, all in one filtergraph.
105 Two encodes softened a 246 kbps source from SSIM 0.998 to 0.977. Never re-encode a
106 finished clip to add something to it.
1072. **ASR word END times are fiction.** They pad into the following silence and can be
108 phantom words over dead-silent audio. Word STARTs are reliable. **All silence reasoning
109 comes from the audio (`silencedetect`/RMS), never the transcript.**
1103. **Never let ffmpeg derive caption/graphic timing from durations.** The concat demuxer
111 re-times to CFR and rounds boundaries as it pleases. Use one PNG per output frame.
1124. **Never use `loudnorm` for gain.** See shorts-audio. It silently pumps.
1135. **Graphics are cue-anchored, never hand-timed.** See shorts-motion.
1146. **Fades only at real cut edges.** A mid-beat framing change is not a cut — the audio
115 runs straight through it. A 30ms fade there dips the voice audibly.
1167. **`concat` wants inputs interleaved** `v0,a0,v1,a1,…` — not all video then all audio.
117 The two are identical for one segment, so a single-segment test clip hides the bug.
1188. **PIL's ImageDraw with a partial-alpha fill OVERWRITES pixels, it does not composite.**
119 Draw at full opacity on a layer, then fade the layer. Otherwise a fading element punches
120 a transparent hole through whatever is beneath it.
121 
122## What shipped
123 
124| | |
125|---|---|
126| video | libx264 CRF 6, preset slow, native res/fps, bt709/tv — SSIM 0.9996 vs source |
127| audio | highpass 60Hz + a constant gain to −1.5 dBTP. **No denoiser.** |
128| captions | Helvetica Neue Medium, lowercase, 18px, tracking −1, no stroke |
129| graphics | cue-anchored, on-brand, drawn per frame at 30fps |
130| retention | pattern interrupt every ≤4.8s; dead-air 0% |
131 
132## Fix the capture, not the edit
133 
134The source was **360×640, 246 kbps, −43 LUFS**. No post-processing recovers detail that was
135never recorded. Raising the OBS canvas and input gain improves every future edit for free.
136 

Discussion

Alternatives

Subscription Lifecycle: Trial, Churn, Win-backWhen the user wants to optimize their subscription business end-to-end — from trial start through renewal, cancellation, and win-back. Use when the user mentions "subscription lifecycle", "trial conversion", "churn", "cancellation", "win-back", "lapsed subscribers", "dunning", "billing retry", "grace period", "renewal rate", "subscriber LTV", or "resubscribe". For paywall design and pricing strategy, see monetization-strategy. For subscription analytics dashboards, see app-analytics.Business & ops · MITWin back customers before they cancelTell us about your subscription business and why people quit. Get back a ready-to-use plan to keep more customers and recover failed payments.Business & ops · MITCustomer success managerUse this agent when you need to assess customer health, develop retention strategies, identify upsell opportunities, or maximize customer lifetime value. Invoke this agent for account health analysis, churn prevention, product adoption optimization, and customer success planning. Specifically:\\n\\n<example>\\nContext: Customer success team notices a large enterprise customer has reduced usage frequency by 40% over the past month and hasn't engaged in quarterly business reviews.\\nuser: "We're concerned about TechCorp's engagement. Usage is down significantly. Can you assess what's happening and help us develop a retention strategy?"\\nassistant: "I'll analyze TechCorp's health metrics including usage patterns, feature adoption, support interactions, and engagement history. I'll identify specific churn risks, assess whether there are product fit issues or implementation gaps, and develop a targeted intervention plan with clear milestones and success metrics."\\n<commentary>\\nUse customer-success-manager when you need to evaluate at-risk accounts and create proactive retention strategies. This agent analyzes health signals holistically and prescribes specific interventions.\\n</commentary>\\n</example>\\n\\n<example>\\nContext: Product team is rolling out new features and customer success team wants to maximize adoption across the customer base while identifying expansion revenue opportunities.\\nuser: "We're launching three new features next month. How do we ensure our customers actually adopt them? And which customers might be willing to upgrade to higher tiers?"\\nassistant: "I'll segment your customer base by maturity level and current product usage patterns. I'll develop feature-specific adoption strategies for each segment, identify high-value customers ready for expansion conversations, and create a phased rollout plan with success metrics and training resources."\\n<commentary>\\nInvoke this agent when you need to drive adoption of new features or identify expansion opportunities. The agent analyzes customer readiness and creates tailored engagement strategies for different segments.\\n</commentary>\\n</example>\\n\\n<example>\\nContext: Quarterly renewal period is approaching and customer success team wants to prepare for renewal conversations with key accounts and identify which customers are at risk of non-renewal.\\nuser: "We have 40 accounts up for renewal in the next 90 days. Can you help us prepare renewal strategies and flag which ones might be at risk?"\\nassistant: "I'll assess each account's health indicators including NPS, usage trends, executive engagement, feature adoption, and any unresolved issues. I'll prioritize high-risk accounts for intervention, develop renewal talking points based on demonstrated value, and create a pre-renewal engagement plan for each tier of customer."\\n<commentary>\\nUse this agent when renewal periods are approaching or you need to forecast renewal risk. The agent quantifies customer health and develops specific pre-renewal strategies to maximize renewal rates.\\n</commentary>\\n</example>\\n\\nDoes not handle individual support tickets or FAQ/help-center content — hand those to customer-support. Does not own pre-sale technical POC/RFP work — hand that to sales-engineer. Does not finalize pricing or discount decisions — route to the account/deal team. Does not review or negotiate contract/legal terms — route to legal-advisor.Business & ops · MIT/cs:cco-review — CCO Forcing Questions/cs:cco-review <plan> — Retention-obsessed Chief Customer Officer interrogation of any plan that touches customer retention, segmentation, CS team sizing, or CS team hiring. Use when gross retention is slipping, before approving CSM headcount, or when deciding which customer segments to keep or fire. · MIT