---
name: ai-video-editor
description: This skill provides AI-powered video editing — transcription with Whisper, intelligent clip selection, highlight reel creation, xfade transitions, audio mixing with music overlay, and multi-platform export for YouTube, LinkedIn, TikTok, Instagram, and Twitter/X. This skill should be used when editing video, creating highlight reels, transcribing audio, cutting clips, adding transitions, mixing audio tracks, or exporting video for social media platforms.
---

# AI Video Editor

AI-powered video editing combining Whisper transcription, intelligent content analysis, and FFmpeg precision editing. Turn long-form footage into polished highlight reels with crossfade transitions, background music, and multi-platform export.

## Essential Principles

### 1. Analyze Before Cutting

Always run `ffprobe` metadata extraction and review transcription before making any cuts. Understand the content, resolution, codec, and framerate first.

```bash
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4
```

### 2. Keyframe-Aligned Cuts

Use re-encoding for frame-accurate cuts. Stream copy (`-c copy`) cuts at the nearest keyframe, producing imprecise edits.

```bash
# Correct: re-encode for precision
ffmpeg -ss 26 -i input.mp4 -t 22 -c:v libx264 -preset medium -crf 18 -c:a aac -b:a 192k -pix_fmt yuv420p clip.mp4

# Wrong: stream copy, imprecise
ffmpeg -ss 26 -i input.mp4 -t 22 -c copy clip.mp4
```

### 3. Non-Destructive Workflow

Never modify source files. All operations produce new output files. Keep intermediates until final export is verified.

### 4. AI Judges Content, FFmpeg Executes

Claude's role is understanding what makes a good clip — energy, key quotes, statistics, audience engagement, narrative arc. FFmpeg handles the mechanical cutting, joining, and encoding.

---

## Quick Start

Fastest path from source video to highlight reel:

1. **Analyze**: `ffprobe -v quiet -print_format json -show_format -show_streams input.mp4`
2. **Extract audio**: `ffmpeg -i input.mp4 -vn -ac 1 -ar 16000 -acodec pcm_s16le audio.wav`
3. **Transcribe**: Run [transcribe.py](./scripts/transcribe.py) or use mlx-whisper directly
4. **Read transcript** — Identify 5-7 strongest moments (key stats, quotable lines, emotional peaks)
5. **Cut clips**: Run [extract_clips.py](./scripts/extract_clips.py) with a clips JSON config
6. **Build reel**: Run [build_reel.py](./scripts/build_reel.py) to concatenate with xfade transitions
7. **Export**: Run [export_platforms.py](./scripts/export_platforms.py) for target platform

---

## Workflow Router

Determine the video editing task and follow the appropriate workflow:

| Task | Keywords | Action |
|------|----------|--------|
| Analyze video | "analyze", "metadata", "ffprobe", "info" | Read [ffmpeg-filters.md](./references/ffmpeg-filters.md), run [analyze_video.py](./scripts/analyze_video.py) |
| Transcribe | "transcribe", "whisper", "transcript", "captions" | Read [transcription-guide.md](./references/transcription-guide.md), run [transcribe.py](./scripts/transcribe.py) |
| Highlight reel | "highlight", "reel", "summary", "best moments" | Full pipeline: transcribe → analyze → extract → build → export |
| Cut clips | "cut", "clip", "extract", "trim", "segment" | Run [extract_clips.py](./scripts/extract_clips.py) |
| Add transitions | "transition", "xfade", "crossfade", "concatenate" | Read [ffmpeg-filters.md](./references/ffmpeg-filters.md), run [build_reel.py](./scripts/build_reel.py) |
| Mix audio | "audio", "music", "mix", "ducking", "background" | Read [audio-mixing.md](./references/audio-mixing.md), run [mix_audio.py](./scripts/mix_audio.py) |
| Export for platform | "export", "youtube", "linkedin", "tiktok", "instagram" | Read [platform-export-specs.md](./references/platform-export-specs.md), run [export_platforms.py](./scripts/export_platforms.py) |

---

## Anti-Patterns

### 1. Stream Copy for Precision Cuts

**Problem**: Using `-c copy` for clip extraction produces cuts at the nearest keyframe, not the requested timestamp.

**Wrong**:
```bash
ffmpeg -ss 133 -i input.mp4 -t 22 -c copy clip.mp4
# Actual cut point may be 1-5 seconds off
```

**Correct**:
```bash
ffmpeg -ss 133 -i input.mp4 -t 22 -c:v libx264 -preset medium -crf 18 -c:a aac -b:a 192k -pix_fmt yuv420p clip.mp4
```

### 2. Seeking After Input

**Problem**: Placing `-ss` after `-i` forces ffmpeg to decode everything up to the seek point.

**Wrong** (slow — decodes 600 seconds of video):
```bash
ffmpeg -i input.mp4 -ss 600 -t 30 -c:v libx264 output.mp4
```

**Correct** (fast — seeks directly):
```bash
ffmpeg -ss 600 -i input.mp4 -t 30 -c:v libx264 output.mp4
```

### 3. Hardcoded Pixel Dimensions

**Problem**: Using `scale=1920:1080` distorts non-16:9 source material.

**Wrong**:
```bash
ffmpeg -i input.mp4 -vf "scale=1920:1080" output.mp4
# Stretches 4:3 or ultrawide content
```

**Correct** (preserves aspect ratio with letterboxing):
```bash
ffmpeg -i input.mp4 -vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2" output.mp4
```

### 4. Missing Pixel Format

**Problem**: Omitting `-pix_fmt yuv420p` can produce videos that fail on mobile players, browsers, or social media platforms.

**Correct**: Always include `-pix_fmt yuv420p` for maximum compatibility.

### 5. No Faststart Flag for Web Delivery

**Problem**: Without `-movflags +faststart`, the moov atom is at the end of the file. The entire video must download before playback begins.

**Correct**: Always add `-movflags +faststart` for any video delivered via web or social media.

### 6. Transcribing Full-Quality Audio

**Problem**: Feeding 48kHz stereo WAV to Whisper wastes memory and processing time. Whisper internally downsamples to 16kHz mono.

**Wrong**:
```bash
ffmpeg -i input.mp4 -vn audio.wav  # 48kHz stereo, 4x larger than needed
```

**Correct**:
```bash
ffmpeg -i input.mp4 -vn -ac 1 -ar 16000 -acodec pcm_s16le audio.wav
```

### 7. Cumulative xfade Offset Miscalculation

**Problem**: Using clip start times or simple addition as xfade offsets produces broken transitions. Each crossfade shortens total output duration.

**Wrong**: `offset = clip_start_time` or `offset = sum(all_durations)`

**Correct formula**:
```
offset[0] = duration[0] - crossfade
cumulative = duration[0]
for i in 1..n-1:
    offset[i] = cumulative - crossfade
    cumulative = cumulative + duration[i] - crossfade
```

**Worked example** (7 clips, 0.5s crossfade):
```
Durations: [6, 22, 22, 36, 29, 33, 20]
Offset 1: 6 - 0.5 = 5.5      | cumulative: 27.5
Offset 2: 27.5 - 0.5 = 27.0   | cumulative: 49.0
Offset 3: 49.0 - 0.5 = 48.5   | cumulative: 84.5
Offset 4: 84.5 - 0.5 = 84.0   | cumulative: 113.0
Offset 5: 113.0 - 0.5 = 112.5 | cumulative: 145.5
Offset 6: 145.5 - 0.5 = 145.0 | final duration: 165.0s
```

---

## Platform Export Presets

| Platform | Resolution | Aspect | Max Duration | Codec | Bitrate | Key Flags |
|----------|-----------|--------|-------------|-------|---------|-----------|
| YouTube 4K | 3840x2160 | 16:9 | 12h | H.264 | 35-45 Mbps | CRF 18, +faststart |
| YouTube 1080p | 1920x1080 | 16:9 | 12h | H.264 | 8-12 Mbps | CRF 20, +faststart |
| LinkedIn | 1920x1080 | 16:9 / 1:1 | 10 min | H.264 | 5 Mbps | Max 5GB, captions recommended |
| TikTok | 1080x1920 | 9:16 | 10 min | H.264 | 5-8 Mbps | Vertical, safe zones top/bottom |
| Instagram Reels | 1080x1920 | 9:16 | 90 sec | H.264 | 3.5 Mbps | Cover frame at 0:01 |
| Instagram Feed | 1080x1080 | 1:1 | 60 sec | H.264 | 3.5 Mbps | Square, autoplay muted |
| Twitter/X | 1920x1080 | 16:9 | 2:20 | H.264 | 5 Mbps | Max 512MB |

See [platform-export-specs.md](./references/platform-export-specs.md) for complete ffmpeg commands per platform.

---

## Production Checklist

Before exporting final video:

- [ ] Source video analyzed with ffprobe (resolution, codec, framerate, duration confirmed)
- [ ] Audio extracted at 16kHz mono for transcription
- [ ] Transcript reviewed for accuracy (names, technical terms, timestamps)
- [ ] Clip boundaries verified (no mid-word cuts, natural sentence breaks)
- [ ] All clips re-encoded with matching framerate and pixel format (yuv420p)
- [ ] Transitions verified (xfade offsets calculated cumulatively)
- [ ] Audio levels consistent (target -14 LUFS for web, -16 LUFS for broadcast)
- [ ] Background music volume ducked during speech (12-15% of full volume)
- [ ] Output includes `-movflags +faststart`
- [ ] Output verified with ffprobe (correct duration, resolution, codec)

---

## Requirements

```
Prerequisites:
- ffmpeg 5+ with libx264 support (brew install ffmpeg / apt install ffmpeg)
- ffprobe (included with ffmpeg)
- Python 3.10+
- mlx-whisper (Apple Silicon, recommended): pip install mlx-whisper
  OR openai-whisper (NVIDIA GPU): pip install openai-whisper
```

---

## References

- [ffmpeg-filters.md](./references/ffmpeg-filters.md) — xfade transitions, audio filters, filter chain syntax, CRF/preset guide
- [transcription-guide.md](./references/transcription-guide.md) — Whisper model selection, audio extraction, JSON schema, AI analysis prompts
- [audio-mixing.md](./references/audio-mixing.md) — Volume envelopes, loudness standards, music integration, crossfade curves
- [platform-export-specs.md](./references/platform-export-specs.md) — Per-platform export commands for YouTube, LinkedIn, TikTok, Instagram, Twitter/X

## Scripts

- [analyze_video.py](./scripts/analyze_video.py) — Extract and display video metadata via ffprobe
- [transcribe.py](./scripts/transcribe.py) — Extract audio and transcribe with Whisper (word-level timestamps)
- [extract_clips.py](./scripts/extract_clips.py) — Cut clips from JSON config with frame-accurate re-encoding
- [build_reel.py](./scripts/build_reel.py) — Concatenate clips with xfade/acrossfade transitions
- [mix_audio.py](./scripts/mix_audio.py) — Overlay background music with volume envelope
- [export_platforms.py](./scripts/export_platforms.py) — Export video optimized for specific platforms
