---
name: video-editing-montage
description: AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish. Includes real-world lessons from actual montage projects on old Mac hardware. Use when user wants to edit video, cut footage, create vlogs, montages, or build video content.
origin: ECC (affaan-m), hardened through real projects
---

# Video Editing & Montage

AI-assisted editing for real footage. Not generation from prompts. Editing existing video fast.

## When to Activate

- User wants to edit, cut, or structure video footage
- Turning long recordings into short-form content
- Building vlogs, tutorials, or demo videos from raw capture
- Adding overlays, subtitles, music, or voiceover to existing video
- Reframing video for different platforms (YouTube, TikTok, Instagram)
- User says "edit video", "cut this footage", "make a montage", or "video workflow"

## Core Thesis

AI video editing is useful when you stop asking it to create the whole video and start using it to compress, structure, and augment real footage. The value is not generation. The value is compression.

## ⚠️ CRITICAL: Plan-First Workflow (Step 0)

Do NOT jump into ffmpeg immediately. The user expects to see the plan first.

### Step 0: Edit Decision List (MANDATORY)
1. Scan all footage — group by scene/location/date
2. Dedup by MD5 (Telegram re-downloads create ` (1)` suffix dupes)
3. Pick best clips (be brutal: ~12 clips for 1 min, ~18 for 2 min)
4. Structure narrative arc (3-4 acts with emotional progression)
5. Assign per-clip durations to hit target length
6. **Present formatted plan to user** with acts, clips, durations, vibe
7. Wait for "давай" / approval before executing

Narrative arc template for travel montage:
```
Act 1: Departure/Start  (freedom, anticipation)
Act 2: Arrival/Discovery (wonder, exploration)
Act 3: Immersion         (culture, details, people)
Act 4: Return/Sunset     (reflection, closure)
```

### Step 1: Analyze footage
- Group by Telegram message ID prefix (first 6 digits) — same ID = same scene batch
- Get durations: `ffmpeg -i file.mp4 2>&1 | grep -E "Duration|Stream"`
- Get resolution: parse `Stream #0:1... h264, (\d+)x(\d+)` from stderr
- Check a few frames with `vision_analyze` to categorize scenes
- Categorize: sailing / streets / market / harbor / sunset etc.

### Step 2: Normalize clips (one ffmpeg pass per clip)
Each clip gets trim + scale+pad + fade in/out + title — ALL in ONE command:

```python
vf = ",".join([
    f"scale={w}:{h}:force_original_aspect_ratio=decrease",
    f"pad={w}:{h}:(ow-iw)/2:(oh-ih)/2:color=black",
    f"fade=t=in:st=0:d=0.5",
    f"fade=t=out:st={dur-0.5}:d=0.5",
])
if title:
    safe = title.replace("'", "'\\\\''")
    vf += f",drawtext=text='{safe}':fontsize=30:fontcolor=white:x=(w-text_w)/2:y=h-th-50:box=1:boxcolor=black@0.35"

cmd = ['ffmpeg', '-y', '-i', str(src), '-t', str(dur),
       '-vf', vf,
       '-c:v', 'libx264', '-preset', 'ultrafast', '-crf', '24',
       '-c:a', 'aac', '-b:a', '96k', '-movflags', '+faststart',
       str(out)]
```

### Step 3: Concatenate
```python
inputs = []  # flat list: -i seg1.mp4 -i seg2.mp4 ...
parts = [f"[{i}:v][{i}:a]" for i in range(n)]
concat_str = f"{''.join(parts)}concat=n={n}:v=1:a=1[outv][outa]"
cmd = ['ffmpeg', '-y'] + inputs + ['-filter_complex', concat_str,
       '-map', '[outv]', '-map', '[outa]',
       '-c:v', 'libx264', '-preset', 'ultrafast', '-crf', '20',
       '-c:a', 'aac', '-b:a', '128k', '-movflags', '+faststart', output]
```

### Step 4: Global fades
```python
dur = get_duration(input_path)
vf = f"fade=t=in:st=0:d=0.5,fade=t=out:st={dur-1}:d=1"
af = f"afade=t=in:st=0:d=0.5,afade=t=out:st={dur-1}:d=1"
```

### Step 5: Music
- Try VPS Suno: `POST /api/v1/generate` with `model: V3_5/V4/V5`
- **WARNING**: Status endpoint `GET /api/v1/suno/get-music-details?taskId=X` returns 404 on our VPS — polling wastes credits
- Fallback: generate ambient drone with ffmpeg
```bash
ffmpeg -f lavfi -i "aevalsrc=sin(110*2*PI*t)*exp(-t/30)+sin(165*2*PI*t)*0.3+sin(55*2*PI*t)*0.2:d=120" \
  -af "volume=0.08,lowpass=f=400" -ac 2 -ar 44100 music.wav
```
- Mix: `[1:a]volume=0.25[music];[0:a][music]amix=inputs=2:duration=first:weights=1 0.3[audio]`

### Step 6: Deliver + handle feedback
- Always expect 1-2 revision rounds
- If user corrects you on bot tokens, API usage, or creative direction — fix immediately + save to memory

## Performance Notes (MacBook Air 2015, High Sierra, Intel x86_64)

- Each clip re-encode: 30-60s with `-preset ultrafast`
- Total for 12 clips + concat + fades + music: 8-15 min
- Use `background=true` + `notify_on_complete=true` for long runs
- Set timeout 600-900s
- No Homebrew — use static ffmpeg from evermeet.cx (7.1, x86_64)
- ffprobe NOT available — parse `ffmpeg -i` stderr instead
- Python output buffers in background processes — check `ls segments_v4/` for progress

## Suno VPS API Reference (157.173.122.51:18999)

- Valid models: `V3_5`, `V4`, `V4_5`, `V4_5PLUS`, `V4_5ALL`, `V5`, `V5_5`
- Endpoint: `POST /api/v1/generate`
- Body: `{"model":"V3_5","customMode":false,"prompt":"style description","instrumental":true,"callBackUrl":"http://..."}`
- callBackUrl REQUIRED — no status polling endpoint exists
- Credits cost: ~$0.06/track
- 402 response = credits insufficient

## Pitfalls (learned the hard way — read before starting)

- ❌ **macOS grep** has NO `-P` flag — use `-E` or Python `re`
- ❌ **`boxborder_w`** not supported in ffmpeg 7.1 (High Sierra static build) — just omit
- ❌ **Emoji in drawtext** can crash ffmpeg — use ASCII or skip
- ❌ **Stream copy concat** fails on mixed resolutions — re-encode all to same res first
- ❌ **Double re-encode** kills performance — combine trim + scale + fade + title in ONE pass
- ❌ **Never reuse bot tokens** without explicit permission — see bots.md
- ❌ **Suno status endpoint** returns 404 — don't attempt polling, you'll waste credits
- ❌ **Crossfade via concat filter is NOT overlap** — it's sequential. True overlap crossfade needs complex overlay filter. Use per-clip fades as 80% solution.
- ✅ **Never auto-submit to paid APIs** — confirm credits first, or skip
- ✅ **`-movflags +faststart`** mandatory for web playback
- ✅ **`-preset ultrafast`** for iteration, `slow` for final
- ✅ **Always save user's bot preferences to memory** immediately when corrected

## Format Reference

| Platform | Aspect | Resolution |
|----------|--------|------------|
| YouTube | 16:9 | 1920×1080 |
| TikTok/Reels | 9:16 | 1080×1920 (preview: 720×1280) |
| Instagram Feed | 1:1 | 1080×1080 |
