---
name: long-video-editor
description: Edit a long talking-head or stickman-style YouTube video from a raw voice/screen recording plus a timestamped notes file. Builds an edit decision list, cuts dead air, speeds speech after the hook, times character expression swaps to audio, inserts real outputs uncut, adds sight gags, cleans and masters audio, runs automated QA, and loops through fix rounds until a rubric passes.
---

# Long-form video editor

## 0. Ground rules
- The raw notes file is authoritative. Work from the raw file, never from a summary of it. Every note line must be handled and checked off.
- Never fake output. Any clip claimed to be a tool's or model's output must be the real recording or render, played uncut, with its own audio.
- Keep a running log in `PROGRESS.md` and update it after every step. If you are interrupted, read it first when you resume.
- Never overwrite source media. Large inputs may be hardlinks shared with other projects, so write new files instead of editing in place.
- Do not call the video done until the QA and rubric sections both pass.

## 1. Inputs and folder layout
```
project/
  CLAUDE.md            # this brief / rules
  TASK_BRIEF.md        # what to make, the asks for this round
  notes/NOTES.txt      # raw transcript with NOTE lines + timestamps (+ START CUT / END CUT markers)
  src/voice.wav        # raw voice recording
  src/screen_*.mp4     # screen recordings, real outputs
  src/hook.mp4         # locked hook (use as-is if provided)
  assets/poses/        # character expression PNGs (transparent)
  assets/gags/         # sight-gag overlays
  build/               # all your code (commit this)
  qa/                  # metrics, transcripts, contact sheets
  final/               # outputs + NOTES_CHECK.md + CHANGELOG.md
```

## 2. Turn the notes into an edit decision list (EDL)
1. Transcribe the voice with word timestamps:
   `whisper src/voice.wav --model medium --word_timestamps True --output_format json --output_dir qa/`
2. Parse `NOTES.txt` into records: `{line, src_time, note_text, action}`. The action is one of `cut | keep | insert_clip | gag | pose | fix_text`. A NOTE applies to the transcript lines next to it, so read the context around it.
3. Honour `START CUT` / `END CUT` markers at word level. A cut that falls partway through a word removes only the marked words. Snap cut points to whisper word boundaries plus about 40 ms of padding.
4. Write `build/edl.json` as an ordered list of `{src_in, src_out, speed, layer_ops[]}`.
5. Write `final/NOTES_CHECK.md` with one row per note: the note, what you did, the output timestamp and the evidence. Use "on hold" only when the brief says so.

## 3. Cut dead air and dead sections
- Find silences: `ffmpeg -i src/voice.wav -af silencedetect=noise=-35dB:d=0.6 -f null - 2> qa/silence.log`
- Trim gaps longer than 0.6 s down to 0.25 s, but keep one deliberate beat before a reveal line.
- Remove whole sections the brief asks to kill, from their first word to their last.
- If a line was recorded twice, keep the take the brief prefers and make sure the edit actually includes it. A missing-line bug usually means a cut fell between the two takes.

## 4. Speed up speech 1.2x after the hook
- Apply speed-up only after the hook. Real output clips that play uncut stay at 1.0x.
  `ffmpeg -i seg.wav -af atempo=1.2 seg_fast.wav`
  For video+audio: `ffmpeg -i seg.mp4 -filter_complex "[0:v]setpts=PTS/1.2[v];[0:a]atempo=1.2[a]" -map "[v]" -map "[a]" seg_fast.mp4`
- Verify by measurement, not by trust. For matched speech spans, compute `src_duration / out_duration` and expect 1.18–1.22. Use `ffprobe -v error -show_entries format=duration -of csv=p=0 file`, or compare the timestamps of the same words in the source and output transcripts.

## 5. Character expressions (face cam / stickman)
- Map transcript words and emotion to poses, for example laughing, facepalm, shrugging, clapping, leaning in or a thumbs-up. Key each swap to the word that triggers it.
- Swap every 3–4 s, aiming for 8–12 visual changes per minute. Never hold one pose longer than about 3.2 s, and never show two near-identical poses back to back.
- Put the character on a high-contrast background. Don't put full-body animations over dense screen footage; use a face-cam card instead.
- Never put text over the character's face.

## 6. Insert real outputs uncut
- Play outputs full screen at 1.0x with their own audio and native fades. Check the source file's duration against the duration in the timeline.
- Keep loading, login and settings screens out of the edit. Freeze the previous frame over any flash of one.

## 7. Sight gags every 20–30 s
- Base each gag on the spoken line, for example a "$$$" gag on "take my money". Keep gags short (0.5–1.5 s) and keep text minimal.
- Compare against earlier cuts and restore any gags that were dropped, unless they conflict with a note.

## 8. Audio cleanup and mastering
- Denoise with DeepFilterNet: `deepFilter src/voice.wav -o build/clean/`
- Separate the voice from music or bleed with demucs: `demucs --two-stems=vocals clip.wav`
- Normalize to −14 LUFS with two-pass loudnorm:
```
ffmpeg -i mix.wav -af loudnorm=I=-14:TP=-1.5:LRA=11:print_format=json -f null - 2> qa/ln1.txt
# read measured_I, measured_TP, measured_LRA, measured_thresh, target_offset
ffmpeg -i mix.wav -af loudnorm=I=-14:TP=-1.5:LRA=11:measured_I=X:measured_TP=X:measured_LRA=X:measured_thresh=X:offset=X:linear=true -ar 48000 mix_norm.wav
```
- Check the result with `ffmpeg -i final.mp4 -af ebur128=peak=true -f null -`. Integrated loudness should be −14 ±0.5 LUFS and true peak at or below −1 dBTP.

## 9. Render
- Compose the layers in Python with PIL (or Remotion, optionally): background, then footage, then character card, then gags, then captions. Write frames or segments, then concatenate:
```
ffmpeg -f concat -safe 0 -i build/segments.txt -c copy build/video_noaudio.mp4
ffmpeg -i build/video_noaudio.mp4 -i build/mix_norm.wav -c:v libx264 -preset slow -crf 18 -pix_fmt yuv420p -c:a aac -b:a 192k -movflags +faststart final/FULL_1080.mp4
ffmpeg -i final/FULL_1080.mp4 -vf scale=-2:720 -c:v libx264 -crf 23 -c:a copy final/FULL_720.mp4   # review copy, keep it < 200 MB
```
- If you rebuild only part of the video, frames before the change should be bit-identical. Spot-check them with `-f framemd5`.

## 10. QA (run every time)
- Black frames: `ffmpeg -i final.mp4 -vf blackdetect=d=0.1:pix_th=0.10 -an -f null - 2> qa/black.log`. Every hit must fall inside a real output's own fade.
- Silences: run `silencedetect` on the final. No gap may exceed 0.8 s unless it is a planned beat.
- Transcript diff: re-transcribe the final with whisper and diff it against the intended script/EDL. Look for missing lines, stray half-words, doubled takes and wrong cuts.
- Stills: extract one frame every 2 s, then build contact sheets numbered left to right and top to bottom, with each label directly above its own tile:
  `ffmpeg -i final.mp4 -vf "fps=0.5,scale=480:-1,tile=6x5" qa/sheet_%03d.png`
  Inspect zoomed crops for clipped text, missing glyphs ("?" or tofu), cut-off logos, grids or placeholders, and text over the face.
- Speed: rerun the 1.2x measurement. Loudness: rerun ebur128.

## 11. Fix-round loop
1. The reviewer's feedback goes into `FIX_BRIEF_Rn.md` as numbered items, quoted verbatim, each with a timestamp.
2. For each item, find the root cause, then fix it in the build code, not by patching the output.
3. Rebuild and rerun all of the QA, not just the fixed spot.
4. Append to `final/CHANGELOG.md`: each item, its cause, the fix, the new timestamp, the evidence, any side effects and the duration change.
5. Set the last line of `PROGRESS.md` to `STATUS: FIXED-Rn`.

## 12. Rubric (score it before calling the video done; every item must pass)
1. Every note in NOTES_CHECK.md is handled, with evidence.
2. The hook is unchanged, and the first frame sells the premise.
3. Speech after the hook measures 1.18–1.22x.
4. No pose is held longer than 3.2 s, with 8–12 visual changes per minute.
5. A sight gag lands every 20–30 s.
6. Real outputs play uncut and nothing is faked.
7. No dead air over 0.8 s, and no stray half-words.
8. Loudness is −14 LUFS and true peak is at or below −1 dBTP.
9. blackdetect hits occur only inside the outputs' own fades.
10. Contact sheets are clean: no broken glyphs, no text over the face, no leftover grids or login flashes.
11. The 1080p and 720p outputs exist, and their durations match the EDL.
Report the score as N/11, label it self-checked, and list anything left open.
