PORTAL / LIBRARY / video-edit

[ CREATIVE ]

/video-edit

Edit an existing source video (from Drive or local) into a finished ad.

Download the skill file (.md)

Placeholders like ACME Agency, <id> and you@example.com mark values that are per-agency — your install fills them with YOUR clients and accounts. If a section references a helper script you don't have yet, it ships with that workflow's install.

Skill: /video-edit

Overview

Takes existing footage (typically a raw 1–5 minute shoot from the client) and produces a finished ad — cut down, voiced over, reframed, delivered.

This is the only skill in the workspace that edits real-world video. All other video skills (/<id>, /heygen-ad-generator, /motion-ad-generator, /video-ad-generator, /static-ad-generator) generate new footage via Krea / Kling / Veo / Creatomate / HeyGen. If the user already has footage, this is the skill.

Built after one-off editing requests started piling up (see ACME Agency/clients/ACME Agency/video-ads/ for the prototype that motivated this skill).

What it produces:

What it does NOT do:


The Golden Rules

  1. Vision-based shot selection is YOUR job. The prepare phase extracts pACME Agencyw frames to disk — you read them with the Read tool and pick which timestamps make the cut. The Node script does not guess shot boundaries.
  1. Pacing is enforced. No shot longer than shotMaxDuration (default 3.0s). The script warns and reports any shot that exceeds it.
  1. ElevenLabs only — no silent fallback. If ElevenLabs fails, the script errors loudly. If you must fall back, pre-generate an MP3 with another TTS, drop it in vo/voiceover.mp3, and rerun with --no-voice. The Slack report must mention any fallback explicitly.
  1. Plan.json is the contract. Every decision — shot timestamps, VO script, target ratios, audio mode — goes into plan.json. The script never asks the user a question; it reads the plan and executes.
  1. One source of truth for the final duration. plan.target.duration is the contract. The script warns if the sum of shot durations deviates more than 20% from target.

Preflight (before touching Node)

  1. Client exists in clients.json (3-step cascade — clients.json → registry sheet → API discovery). Resolve the canonical key.
  2. Source video provided. Either a Drive URL (https://drive.google.com/file/d/<ID>/view) or a local path. If the user pasted only a filename without a folder, ask which Drive folder it's in.
  3. Required env vars: ELEVENLABS_API_KEY, <id>. Abort if missing.
  4. Disk space ≥ 2 GB free (source videos can be 500 MB – 1 GB for a 3-min shoot).
  5. client.drive_folder_id is set. If not, auto-discover via Drive search (don't just skip).

Step-by-step workflow

Step 0 — Identify client + parse source

Extract from the user's message:

If any of those are missing, ask before running anything. Examples of ambiguous briefs that need clarification:

Step 1 — Run prepare phase

node ACME Agency/scripts/video_edit.mjs prepare "<ClientKey>" "<drive-url-or-path>" --slug "YYYY-MM-DD-<short-descriptor>"

Example:

node ACME Agency/scripts/video_edit.mjs prepare "ACME Agency" \
  "https://drive.google.com/file/d/<id>/view" \
  --slug "<id>"

What this does:

Step 2 — Read the frames (vision-based shot selection)

This is the judgment-heavy step. Use the Read tool to read the frames from <campaignDir>/frames/ in order. You're looking for:

Map frames to timestamps from the filename (frame_012_t22.0.jpg → t=22s) and build a candidate list in your head.

Pacing math. Given target.duration and shotMaxDuration, you need at minimum ceil(target / shotMaxDuration) shots. For a 25s ad at 3s max, that's ≥9 shots. Aim higher — 11–13 shots for a 25s ad gives you room for varied pacing (a 1.5s punch cut followed by a 2.5s beauty hold).

Step 3 — Write the voiceover script

Apply direct-response principles from .claude/skills/copywrite/PRINCIPLES.md if you haven't already loaded them. Beat structure for a 25s editing ad:

HOOK (3-5s)    — benefit-led promise OR intrigue question
BODY (10-15s)  — what the product is, why it's different, one concrete proof
CLOSE (5-7s)   — the transformation + CTA

Word budget:

25s German → ~60 words. 15s → ~36 words.

Anti-AI sweep (required — do NOT skip):

If the user gave you 2-3 script options to choose from (like a teammate did), present them first, wait for pick, then proceed.

Step 4 — Fill plan.json

Edit the plan file the script wrote. Example for ACME Agency's Lamellenpergola ad:

{
  "version": 1,
  "client": "ACME Agency",
  "clientKey": "ACME Agency",
  "slug": "<id>",
  "source": {
    "path": "...",
    "duration": 183.5,
    "ratio": "16:9",
    "width": 1920,
    "height": 1080,
    "fps": 30
  },
  "target": {
    "duration": 25,
    "ratios": ["16:9", "9:16"],
    "language": "de",
    "shotMaxDuration": 3.0
  },
  "shots": [
    { "id": "h1", "start": 12.5, "duration": 2.5, "tag": "hook",    "note": "wide beauty shot, finished pergola w/ furniture" },
    { "id": "h2", "start": 48.0, "duration": 1.8, "tag": "hook",    "note": "close angle lamel — sun through slats" },
    { "id": "m1", "start": 64.0, "duration": 2.2, "tag": "montage", "note": "aluminum profile pickup" },
    { "id": "m2", "start": 72.0, "duration": 2.0, "tag": "montage", "note": "drill into mounting bracket" },
    { "id": "m3", "start": 88.0, "duration": 2.5, "tag": "montage", "note": "lifting crossbeam into place" },
    { "id": "m4", "start": 104.0,"duration": 1.8, "tag": "montage", "note": "snap-fit assembly wide" },
    { "id": "m5", "start": 118.0,"duration": 2.0, "tag": "montage", "note": "scaffold overhead shot" },
    { "id": "c1", "start": 152.0,"duration": 2.2, "tag": "closing", "note": "lamels rotating — slow motion" },
    { "id": "c2", "start": 165.0,"duration": 2.5, "tag": "closing", "note": "view through olive trees to finished pergola" },
    { "id": "c3", "start": 172.0,"duration": 2.5, "tag": "closing", "note": "aerial top-down of closed lamels" },
    { "id": "cta","start": 178.0,"duration": 3.0, "tag": "cta",     "note": "final beauty hold — VO delivers CTA over this" }
  ],
  "voiceover": {
    "enabled": true,
    "language": "de",
    "voiceId": "j46AY0iVY3oHcnZbgEJg",
    "script": "Von der leeren Fläche zu Ihrem persönlichen Rückzugsort. In nur zwei Tagen baut unser Team Ihre Lamellenpergola auf. Präzise, wetterfest, maßgefertigt. Kein Bausatz, ein Premiumprodukt. Das Ergebnis: Ihr neuer Lieblingsplatz, bei jedem Wetter. Jetzt Angebot anfordern und zehn Prozent Rabatt sichern.",
    "stability": 0.5,
    "similarityBoost": 0.75
  },
  "audio": { "mode": "replace", "videoVolume": 0.3, "audioVolume": 1.0 },
  "logo": null,
  "logoPosition": "br"
}

Key fields to fill:

Audio mode choice:

Step 5 — Script approval gate (REQUIRED)

Before calling execute, post a summary to the user:

═══════════════════════════════════════════════════════════════
VIDEO EDIT PLAN — ACME Agency | Lamellenpergola | 25s | 11 shots | DE
═══════════════════════════════════════════════════════════════

Shots:                      Duration: 24.5s  (target 25s, within tolerance)
  h1  12.5s  +2.5s  hook
  h2  48.0s  +1.8s  hook
  m1  64.0s  +2.2s  montage
  ... (condensed)
  cta 178.0s +3.0s  cta

Voiceover (DE, Chris Norddeutscher):
  "Von der leeren Fläche zu Ihrem persönlichen Rückzugsort. In nur zwei Tagen..."

Variants: 16:9 (primary), 9:16 (vertical crop)
Audio mode: replace (source audio dropped)
═══════════════════════════════════════════════════════════════

Ask: "Approve and execute?" Wait for explicit go-ahead before spending ElevenLabs credits.

Step 6 — Run execute phase

node ACME Agency/scripts/video_edit.mjs execute "<ClientKey>" --plan "<path-to-plan.json>"

The script:

  1. Cuts each shot from source (re-encode, for uniform params)
  2. Concats into master_silent.mp4
  3. Generates ElevenLabs VO → vo/voiceover.mp3
  4. Muxes VO onto silent master → master_vo.mp4
  5. Applies logo overlay if plan.logo is set → master_branded.mp4
  6. Exports one final MP4 per requested ratio → final/<ClientKey>_<slug>_<ratio>.mp4
  7. Uploads finals + plan.json to Drive Klijenti/<Client>/Video Ads/<YYYY>/<MM>/<slug>/
  8. Posts Slack report to the client's channel
  9. Appends to video_edit_manifest.json in the client's video-ads folder
  10. Writes a knowledge inbox entry (future — not wired yet)

Step 7 — Verification

After execute completes, confirm:

If any step failed, re-run just the failed piece — the plan is the single source of truth and intermediate files stay on disk.


Iteration patterns

The plan-based design makes iterations cheap. Common ones:

ChangeWhat to editRerun
Swap a shotEdit shots[i].start or duration in plan.jsonexecute
Rewrite VOEdit voiceover.scriptexecute
Different voiceChange voiceover.voiceIdexecute
Add 9:16 variantAdd "9:16" to target.ratiosexecute
Different durationChange target.duration, re-pick shotsexecute
New source videoRun prepare again with new slug

For small script tweaks, you can also skip prepare entirely and just rerun execute — the cut clips get regenerated each time, but the source is already downloaded.


Hard constraints

RuleWhy
Vision-based shot selection happens in Claude, never in the scriptThe script doesn't know what "good footage" looks like — it's deterministic, not judgmental
ElevenLabs failures must be loud, never silentThe OpenAI TTS fallback on a teammate's first run produced robotic audio that shipped before the user caught it. Never again.
shotMaxDuration default is 3.0sMeta ads with >3s cuts have visibly lower retention. Override only for explicit creative direction.
target.duration ± 20% is a warning, not a hard stopSometimes you want 23s or 28s — but if it's ±50%, the shot list is broken and the skill should refuse to execute
Plan version must match PLAN_VERSION in the scriptSchema breaks will silently destroy edits otherwise
Script approval gate before executeElevenLabs credits cost money, and Drive uploads clutter client folders

When to use this skill vs generators

User saysSkill
"Edit this video" + Drive link/video-edit
"Cut this raw footage"/video-edit
"Make a 15s ad from this 3 min shoot"/video-edit
"Make us a video ad for X" (no source)/<id>
"Make a video like this reference" (reference but no editable footage)/<id> with reference
"Explainer-style video of someone talking"/heygen-ad-generator
"Branded motion graphic"/motion-ad-generator

The creative director agent routes on presence of editable source footage — if the user handed you an MP4 they already own, it's /video-edit.


Critical files

Reference example

ACME Agency/clients/ACME Agency/video-ads/ — the ad-hoc prototype that motivated this skill:

Rebuilding this with the skill: create a plan.json pointing at pergola-montaz-source.mp4, fill in the shots with the same timestamps, run execute. Result should match the prototype.