---
name: video-editing
description: Edit Kenerate clips into one finished video. Trims, joins with crossfades or other transitions, normalizes to 9:16 / 16:9 / 1:1 / 4:5 at 1080p, lays a music bed that ducks under speech, burns captions from an SRT or a script, and exports an H.264 MP4. Use when the user wants several generated clips (generate_video, talking_avatar, motion_control...) cut together, a music track under a video, captions burned in, or a reel / ad / short assembled. Works locally with Python + ffmpeg after the clips are made with the Kenerate MCP.
compatibility: Needs the Kenerate MCP server (mcp.kenerateai.com) for generation and Python 3.9+ with Pillow and ffmpeg (system or imageio-ffmpeg) for the edit.
metadata:
  author: kenerate
  version: "1.0"
  kenerate-tools: "generate_image generate_video generate_music generate_speech wait_for_generation estimate_cost"
---

# Video editing (assemble Kenerate clips)

The Kenerate MCP makes clips but has no tool that joins them or mixes in a separate track. This skill does that part
locally with `scripts/edit.py`. Read [references/KENERATE.md](references/KENERATE.md) first; it covers the money rules,
job polling and downloads.

## When to use
- "Cut these clips together", "make one 30 s ad from the shots", "add music under it", "burn the captions in".
- After `storyboard-to-film`, `hook-multiplier` or any multi-clip plan, when the user wants one file.

## Ask the user
1. Which clips, in what order. Use Kenerate urls from earlier results, or `list_generations("video")`. Ask for trims
   too, if they want them.
2. Format: 9:16 (Reels / TikTok / Shorts, default), 16:9 (YouTube), 1:1 or 4:5 (feed).
3. Sound - never add it on your own. Ask: "Voice-over? Music? Keep the clips' native audio? Or silent?"
   (many video models make native audio; see [references/MODELS.md](references/MODELS.md), "Audio policy").
4. Captions: an SRT file, or the script text (auto-timed), or none. For animated word-by-word captions use the
   `captions-pro` skill on the finished edit.
5. Font, if they care: `--font-family "Montserrat"` downloads a free OFL font (see KENERATE.md, "Fonts").

## 1. Make what's missing (Kenerate MCP)
- Clips: `estimate_cost("generate_video", {...})` for each one, add them up, confirm, then `generate_video` with the
  same `model`, `aspect_ratio` and `resolution` for every shot. Pick with `pick_model` or MODELS.md: drafts and
  silent b-roll `kenerate/wan-3.0` (`audio=false`), image-to-video product shots `kenerate/seedance-2.0`, cinematic
  `kenerate/seedance-2.5`; 720p, 5 s. Use image-to-video from a `generate_image` frame when products or faces must
  stay consistent.
- Music bed (only if the user said yes): `generate_music(prompt="<genre, mood, BPM>, instrumental background bed", engine="elevenlabs-music-v2.5", instrumental=true, seconds=<edit length>)`.
  Wait with kind `"music"`.
- Voice-over (only if the user said yes): `generate_speech(text=<script>, engine="elevenlabs-eleven-v3", voice=<name>)`
  with a voice from `pick_voice(use_case=...)` or MODELS.md's voice table (always pass one; there is no default).
  Kind `"voice"`. Pass it with `--voiceover`: the script mixes it over the clips and ducks the music under it.
- `wait_for_generation(kind, id)` for every job; keep `urls[0]`.

## 2. Edit (local)
```
python <skill-dir>/scripts/edit.py \
  --clip "<url1>@0-4.5" --clip "<url2>" --clip "<url3>@1-" \
  --aspect 9:16 --transition fade --xfade 0.4 \
  --music "<music url>" --music-db -14 --voiceover "<speech url>" \
  --captions "<the script text>" --caption-style bold \
  --out kenerate-out/video-editing/<project>_9x16.mp4
```
- `--clip SRC@IN-OUT` trims in seconds (`@2-` = from 2 s to the end, `@-3` = the first 3 s). Images work too: they become
  shots with a slow push-in (`--still-seconds`).
- `--fit cover` (default) fills and crops, `blur` keeps the whole frame over a blurred fill, `contain` letterboxes.
- `--transition cut|fade|dissolve|wipeleft|slideup|circleopen|smoothleft|fadeblack|zoomin|…` and `--xfade` seconds.
- Music loops or trims to the edit, fades out, and ducks under the clips' speech and the voice-over (`--no-duck` turns
  that off, `--mute-clips` drops the clips' own sound). `--voiceover` (+ `--vo-start`, `--clip-db` to lower the clips
  under the voice, default -12 dB). No `--music` / `--voiceover` = the clips' own sound only.
- Check before the final export: `--preview` writes a contact sheet of the edit (`*_preview.jpg`); show it.
- Captions: `--srt file.srt` (timed to the final edit) or `--captions "text"` (spread over the edit);
  `--caption-style bold|box|minimal|karaoke`, `--caption-pos bottom|center|top`. An `.srt` is written next to the output.
- Many clips: put them in a JSON file and pass `--clips-json edit.json`:
  `{"clips":[{"src":"...","in":0,"out":4}], "music":"...", "captions":"..."}`.

## Progress and output
Relay the `[n/7]` lines: fetching → normalizing each clip → joining → voice-over → music → captions → export. Parse the final
`RESULT_JSON` for `output.path`, `seconds` and `srt`, and give the user the path.

## If something fails
- A Kenerate job failed: it's refunded automatically. Ask before retrying, maybe with a cheaper model (`kenerate/wan-3.0`).
- Download 403/404: the link expired. `get_generation(kind, id)` gives a fresh url.
- `ffmpeg failed`: re-run with `--keep-temp` and check the clip plays. A clip shorter than 2x `--xfade` gets a shorter
  transition automatically.
- Optional: to get Kenerate's animated captions instead of local ones, the final file must be online. If the user can
  share a public link, `upload_media(url=...)` it and run `add_subtitles` (speech only, up to 4 min).

## Limits
Output is H.264 / AAC MP4 at 30 fps (`--fps`). Edits longer than about 10 minutes work, but encode slowly.
