
video-edit
Edits a complete talking-head video end to end with free tools (Remotion, whisper.cpp, ffmpeg) - a vertical short (1080x1920) or a full horizontal YouTube video (1920x1080). Use when the user says edit, cut, captions, subtitles, motion design, montage, "make it a short", "edit my YouTube video", render, or gives a recording from video-agent/takes/. Transcribes locally with word timings, cuts silences and retakes against the script, adds punch-in zooms, word-by-word captions in the creator's accent color, a hook card, callouts and a progress bar, levels the voice to -14 LUFS, and writes an .srt, a cut list for CapCut or Premiere, chapters for a long video, and the post copy.
- Installs
- 51
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/melvynx/video-agent-skills --skill video-edit- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads video-edit automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Video Edit
One raw take in, one finished video out: video-agent/edits/<slug>/final.mp4. Either a vertical short, or a full horizontal video for YouTube.
The tools are free and run on the creator's machine:
- Remotion (videos written in React) and its official TikTok template, which ships local speech-to-text with word timings (whisper.cpp).
- ffmpeg for the checks and the sound.
The look is fixed and simple: references/style.md. The code that draws it is in references/remotion-short.md.
How to run it
- Preflight:
node -v && ffmpeg -version && git --version. Anything missing: stop and send them to/video-setup tools. - Talk in the creator's language. Say what you do in one line before each long step (install, transcription, render) and how long it takes.
- Read
video-agent/voice.mdfor the language and the accent color. No voice file: ask both, or use English and#FFD400. - A named style (
style <name>in the request, made by/video-steal): readvideo-agent/styles/<name>.mdand apply it on top of style.md. Its values win, its sound effects, stickers and grade go into the edit as it says, and everything it does not name stays as in style.md. <slug>: lowercase, dashes, no dots or spaces (the transcriber cuts file names at the first dot).- Steps 1 and 2 run from the project root. From step 3 on, every command runs in
video-agent/studio/and its paths are relative to it.
1. The take and the format
Use the file they name, else the newest file in video-agent/takes/. Check it:
ffprobe -v error -show_entries format=duration:stream=codec_type,codec_name,width,height,r_frame_rate,avg_frame_rate,color_transfer -of compact "<take>"
- No audio stream: stop and say so.
color_transferissmpte2084orarib-std-b67: an HDR take (the iPhone default). Don't convert it: Remotion maps it to normal colors when it renders. Tell them to turn off HDR video in the camera settings for the next takes.- Otherwise, a
.webmor a variable frame rate (r_frame_rateandavg_frame_ratediffer): convert it, Remotion and the ffmpeg cut both drift on those. The new file is the take from now on:ffmpeg -y -i "<take>" -vf fps=30 -c:v libx264 -crf 18 -preset veryfast -pix_fmt yuv420p -c:a aac -b:a 192k -ar 48000 "video-agent/takes/<slug>-30fps.mp4"
Then the format. They said it (short, long, "for YouTube", "a reel"): take it. Otherwise pick from the take and say which in one line:
| Format | Composition | When | Defaults |
|---|---|---|---|
| Short | Short, 1080x1920 | a take under 90 s, or they want a short, a reel, a TikTok | captions on, hook card, a callout every 8 to 10 s |
| Long | Wide, 1920x1080 | a horizontal take over 90 s, a full YouTube video, a tutorial, a vlog | captions on (ask: YouTube viewers often prefer the .srt alone, showCaptions: false), no hook card unless they want one, a callout every 30 to 60 s at most, chapters |
- Horizontal take in Short: it is cropped to the center. Warn them if they are not in the middle of the frame.
- Vertical take in Long: it would be cropped to a thin band. Don't; offer Short.
- Long: say the time first. Transcription runs at about real time on a laptop with the
mediummodel (a 20-minute take, about 20 minutes;smallis 2 to 3 times faster), and the render takes 3 to 5 s per second of video (a 15-minute cut, about 1 hour). Both run in the background.
<comp> below is Short or Wide.
Find the script it comes from: the matching script in video-agent/scripts/ (same slug or same first line). No script is fine; the cuts then rely on the transcript only.
2. The studio (first time only)
Tell them first: about 1 GB of packages, then on the first transcription the speech engine and its model (0.5 to 1.5 GB) and a few minutes of setup.
git clone --depth 1 https://github.com/remotion-dev/template-tiktok video-agent/studio
cd video-agent/studio
npm i
- Delete
video-agent/studio/.gitso the studio is a plain folder of their project. - Language, in
whisper-config.mjs:- English: keep
WHISPER_MODEL = "medium.en"andWHISPER_LANG = "en". - Any other language:
WHISPER_MODEL = "medium"(or"small"on a slower machine, 466 MB) andWHISPER_LANG= its code ("fr","es","de","pt"...).
- English: keep
- Add the
ShortandWidecompositions and the font package: follow references/remotion-short.md sections 1 to 3, thennpx tsc --noEmit. A studio made beforeWideexisted: replacesrc/Short/index.tsxandsrc/Root.tsxwith the current sections 2 and 3. - Optional, better Remotion code from Claude:
npx skills add remotion-dev/skills.
3. Transcribe
cp "../takes/<take file>" public/<slug>.mp4
node sub.mjs public/<slug>.mp4
It writes public/<slug>.json: one entry per word, { "text": " word", "startMs", "endMs", "confidence" }. It skips a file that already has its JSON: delete the JSON to transcribe again.
Fix misheard words from the script (names, brands, numbers): change text only, never the times.
4. The cut list
Find the real silences, then list the gaps between words:
ffmpeg -nostats -i public/<slug>.mp4 -af silencedetect=noise=-35dB:d=0.3 -f null - 2>&1 | grep silence_
node -e 'const w=require("./public/<slug>.json"),G=350,B=100,A=150,s=(ms)=>(ms/1000).toFixed(2);let r=[{fromMs:Math.max(0,w[0].startMs-B)}];for(let i=1;i<w.length;i++){const g=w[i].startMs-w[i-1].endMs;if(g>G){console.error(`gap ${s(w[i-1].endMs)} -> ${s(w[i].startMs)} (${g} ms) after "${w[i-1].text.trim()}"`);r[r.length-1].toMs=w[i-1].endMs+A;r.push({fromMs:w[i].startMs-B})}}r[r.length-1].toMs=w[w.length-1].endMs+300;console.log(JSON.stringify(r))'
The second command prints every gap over 0.35 s with the word before it, then the kept ranges with the margins of style.md. Then fix the ranges:
- A gap that silencedetect does not report (a breath, a soft word, music): join its two ranges back.
- Retakes: walk the script line by line. When a line (or its first 3 words) appears more than once, keep the last complete attempt and drop the ranges from the first attempt's first word to the start of the kept one.
- Drop false starts (an "uh" or a half word before a restart), anything before the hook, and off-script talk.
Long video: same rules, with gaps over 0.5 s instead of 0.35 s (G=500): a full video needs some air, a thinking pause can stay. Keep asides that add something; cut the ones that go nowhere. With no script, a retake is a sentence said twice in a row: keep the last one.
Show the result before rendering, in a few lines:
Take 1:42 → short 0:47 (-55 s)
- 38 pauses cut (41 s)
- 3 retakes dropped: line 2 (x2), line 7
- dropped "ok let me do that again" at 0:58
5. Motion
From the script's visual notes (or your own picks when there are none):
- Hook card: the on-screen hook, 6 words or fewer, one
*accent*word, 2 to 3 s. - Callouts: a number, a result or a tool name the person says, about one every 8 to 10 s, never two within 4 s (Long: one every 30 to 60 s at most, only the key numbers).
atMs= that word'sstartMsin the JSON.
Write public/<slug>.edit.json (format in remotion-short.md section 4).
6. QC, then render
Render 3 or 4 stills: the hook (frame 30), a callout, a caption mid-video, the last second (Long: 6 to 8 stills spread over the video). Short only: lay the platforms' safe zone over each one:
npx remotion still <comp> out/<slug>-qc-30.png --frame=30 --props=public/<slug>.edit.json
ffmpeg -y -v error -i out/<slug>-qc-30.png -vf "drawbox=x=0:y=0:w=iw:h=230:color=red@0.35:t=fill,drawbox=x=0:y=1440:w=iw:h=480:color=red@0.35:t=fill,drawbox=x=850:y=900:w=230:h=540:color=red@0.35:t=fill" out/<slug>-qc-30-safe.png
Read each -safe PNG (Long: each still): no text in a red zone (the app's buttons, name and description cover it), captions below the face, hook card readable, callout not covering the eyes, accent color right. Fix the edit file, then:
npx remotion render <comp> out/<slug>.mp4 --props=public/<slug>.edit.json
About 3 to 5 s of render per second of video on a laptop. Run it in the background and say how long.
7. Sound
Music (only if they ask, royalty-free, e.g. the YouTube Audio Library) goes in first, 22 dB under the voice:
ffmpeg -y -i out/<slug>.mp4 -stream_loop -1 -i "<music file>" -filter_complex "[1:a]volume=-22dB[m];[0:a][m]amix=inputs=2:duration=first:normalize=0[a]" -map 0:v -map "[a]" -c:v copy -c:a aac -b:a 192k out/<slug>-music.mp4
Then level the render (out/<slug>-music.mp4 when there is music). Remotion does not level the voice, and a plain loudnorm pass lands 2 to 3 LU too quiet on clips this short. Measure:
ffmpeg -nostats -i out/<slug>.mp4 -af ebur128=peak=true -f null - 2>&1 | grep -E "^\s+(I|Peak):"
Gain = -14 minus the I: value (e.g. I = -17.0 → 3.0dB), with a limiter:
mkdir -p ../edits/<slug>
ffmpeg -y -i out/<slug>.mp4 -c:v copy -af "volume=<gain>dB,alimiter=limit=0.8:level=false" -c:a aac -b:a 192k -ar 48000 ../edits/<slug>/final.mp4
Measure final.mp4 the same way: I between -15 and -13 and Peak under -1 dBFS is right.
8. Deliver
In video-agent/edits/<slug>/:
final.mp4, ready to post.captions.srt: the words moved to the cut timeline, up to 7 words per cue, a new cue after each sentence. Platforms read it as closed captions.node -e 'const e=require("./public/<slug>.edit.json"),w=require("./public/"+e.captions),F=30,fr=(ms)=>Math.round(ms/1000*F);let at=0;const p=e.ranges.map(r=>{const f=fr(r.fromMs),n=Math.max(1,fr(r.toMs)-f),q={...r,s:(at-f)/F*1000};at+=n;return q});const o=w.flatMap(x=>{const q=p.find(q=>x.startMs>=q.fromMs&&x.startMs<q.toMs);return q?[{t:x.text.trim(),a:x.startMs+q.s,b:Math.min(x.endMs,q.toMs)+q.s}]:[]});const ts=(ms)=>new Date(Math.max(0,Math.round(ms))).toISOString().slice(11,23).replace(".",",");let c=[],n=0,out="";const flush=()=>{if(c.length)out+=`${++n}\n${ts(c[0].a)} --> ${ts(c[c.length-1].b)}\n${c.map(x=>x.t).join(" ")}\n\n`;c=[]};for(const x of o){c.push(x);if(c.length===7||/[.?!]$/.test(x.t))flush()}flush();process.stdout.write(out)' > ../edits/<slug>/captions.srtedit.json: a copy ofpublic/<slug>.edit.json, to redo the video later.post.md: the text to paste when posting (below).- Long only, in
post.md: chapters for the YouTube description, one every 1 to 3 minutes where the topic changes, times on the cut timeline (fromcaptions.srt), the first at0:00, at least 3, each 10 s or longer.
Then say: length, what was cut, where the files are, and offer one change ("shorter hook card? fewer callouts? another accent?"). A change = edit the JSON, render again (steps 6 and 7). Next: /video-publish <slug>.
Post copy
post.md, written from the script and voice.md, in the language of the video:
- Title (YouTube Shorts): under 60 characters, the topic in the first 3 words. Long: under 70 characters, the promise of the video, true to it.
- Caption: the first 125 characters work on their own (apps cut there behind "more"). Then 1 or 2 short lines and one ask, the one from voice.md.
- Search words: the 2 or 3 words their viewer would type to find this video, written plainly in the title or the first line.
- Hashtags: 3 to 5 at the end, about the topic. No #fyp or #viral.
- Nothing the video doesn't say: no new number, claim or promise.
Run the humanize pass of video-script (its references/humanize.md) on it when that skill is installed.
Title: Your hook is too long
Caption: Nobody hears word 12 of your hook. Cut it to 12 words and put the result first.
Try it on your next three videos.
Follow for one script fix a day.
#shortformvideo #videohooks #contentcreator
CapCut, Premiere or no Remotion
Some creators prefer their editor, and Remotion needs a paid license for companies of more than 3 people. Do steps 1 to 4, write public/<slug>.edit.json with the ranges ("hook": null, "callouts": []), skip steps 5 to 7, and give them captions.srt (step 8) plus:
cuts.md, the kept ranges to cut by hand:mkdir -p ../edits/<slug> node -e 'const e=require("./public/<slug>.edit.json"),t=(ms)=>new Date(ms).toISOString().slice(14,23);for(const r of e.ranges)console.log(t(r.fromMs)+" → "+t(r.toMs))' > ../edits/<slug>/cuts.md- or a plain cut with ffmpeg alone:
SEL=$(node -e 'const e=require("./public/<slug>.edit.json");console.log(e.ranges.map(r=>`between(t,${r.fromMs/1000},${r.toMs/1000})`).join("+"))') ffmpeg -y -i public/<slug>.mp4 -vf "select='$SEL',setpts=N/FRAME_RATE/TB" -af "aselect='$SEL',asetpts=N/SR/TB" -c:v libx264 -crf 18 -c:a aac ../edits/<slug>/cut.mp4
Honest limits
- whisper.cpp mishears names and jargon: the script fixes them, check numbers by eye.
- The cuts are good, not perfect: a cut can clip a breath or a soft last syllable. Watch the result once before posting.
- Claude cannot hear the take: it trusts the timings and silencedetect. Bad audio (music, echo, two voices) makes both worse.
- The safe zone is a middle ground between TikTok, Reels and Shorts; each app moves its buttons a little.
- Remotion license: free for individuals, companies of up to 3 people and non-profits; bigger companies need a company license (remotion.pro/license).
FAQ
What does the video-edit skill do?
Edits a complete talking-head video end to end with free tools (Remotion, whisper.cpp, ffmpeg) - a vertical short (1080x1920) or a full horizontal YouTube video (1920x1080). Use when the user says edit, cut, captions, subtitles, motion design, montage, "make it a short", "edit my YouTube video", render, or gives a recording from video-agent/takes/. Transcribes locally with word timings, cuts silences and retakes against the script, adds punch-in zooms, word-by-word captions in the creator's accent color, a hook card, callouts and a progress bar, levels the voice to -14 LUFS, and writes an .srt, a cut list for CapCut or Premiere, chapters for a long video, and the post copy.
How do I install video-edit?
Run npx skills add https://github.com/melvynx/video-agent-skills --skill video-edit in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/video-edit/ (personal) or .claude/skills/video-edit/ (project).
Which AI agents can use video-edit?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is video-edit safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains video-edit?
It is published by melvynx in melvynx/video-agent-skills. It has 51 recorded installs.
More from melvynx/video-agent-skills
codex-images
melvynx/video-agent-skills
Open the skill to read its SKILL.md instructions.
short-editing
melvynx/video-agent-skills
Open the skill to read its SKILL.md instructions.
studio-script
melvynx/video-agent-skills
Open the skill to read its SKILL.md instructions.
studio-setup
melvynx/video-agent-skills
Open the skill to read its SKILL.md instructions.
steal
melvynx/video-agent-skills
Open the skill to read its SKILL.md instructions.
clips
melvynx/video-agent-skills
Turns one long video (YouTube link, podcast, webinar, livestream, or a local file) into finished vertical shorts. Use when the user says long to short, repurpose, long video to shorts, clips from my video, podcast clips, cut my YouTube video into shorts, or gives a long video link. Finds clips that stand alone (one idea, 20 to 60 seconds), scores them, cuts them and edits each one with short-editing (split-screen paper look, captions, cuts, hook, boards, 1080x1920), and writes new scripts in the studio-script format from the ideas too spread out to clip. Reads YouTube captions and chapters with yt-dlp, or transcribes a local file with the short-editing engine (whisper.cpp, free, offline).
Popular media & creative skills
hyperframes
heygen-com/hyperframes
Read first to make, edit, animate or render any video with HyperFrames (HTML rendered to video), including launch films, explainers, music videos, charts, maps, vertical clips, title cards, captions and overlays. Holds the render contract, the work loop and what each kind of video needs.
media-use
heygen-com/hyperframes
Get or make any media for a HyperFrames video - music, sound effects, images, icons, logos, voiceover, avatar and generated video, transcripts, cutouts, colour grades and looks - with HeyGen or free local tools, and mix placed audio. Also for footage that looks dark, flat or dull, or should be stylized or hidden.
hyperframes-registry
heygen-com/hyperframes
About 450 ready-made HyperFrames blocks and components installed as editable source - transitions, overlays, titles, kinetic type, captions, charts, map overlays, 3D, camera moves. Use it before hand-building any named visual (CRT scanlines, glitch, film grain, a chart); also for hyperframes add and catalog.
hyperframes-creative
heygen-com/hyperframes
Non-animation creative direction for HyperFrames videos. Use for design spec (frame.md / design.md) handling, palettes, typography, narration, beat planning, audio-reactive visuals, composition patterns, and brand / style decisions. For atomic motion patterns and scene blueprints, use hyperframes-animation.
ai-video-generation
101-skills/superpowers
Generate AI videos with Google Veo, Seedance 2.0, HappyHorse, Wan, Grok and 40+ models via inference.sh CLI. Models: Veo 3.1, Veo 3, Seedance 2.0, HappyHorse 1.0, Wan 2.5, Grok Imagine Video, OmniHuman, Fabric, HunyuanVideo. Capabilities: text-to-video, image-to-video, reference-to-video, video editing, lipsync, avatar animation, video upscaling, foley sound. Use for: social media videos, marketing content, explainer videos, product demos, AI avatars. Triggers: video generation, ai video, text to video, image to video, veo, animate image, video from image, ai animation, video generator, generate video, t2v, i2v, ai video maker, create video with ai, runway alternative, pika alternative, sora alternative, kling alternative, seedance, happyhorse
ai-image-generation
101-skills/superpowers
Generate AI images with GPT-Image-2, FLUX, Gemini, Grok, Seedream, Reve and 50+ models via inference.sh CLI. Models: GPT-Image-2, FLUX Dev LoRA, FLUX.2 Klein LoRA, Gemini 3 Pro Image, Grok Imagine, Seedream 4.5, Reve, ImagineArt. Capabilities: text-to-image, image-to-image, inpainting, LoRA, image editing, upscaling, text rendering. Use for: AI art, product mockups, concept art, social media graphics, marketing visuals, illustrations. Triggers: flux, image generation, ai image, text to image, stable diffusion, generate image, ai art, midjourney alternative, dall-e alternative, text2img, t2i, image generator, ai picture, create image with ai, generative ai, ai illustration, grok image, gemini image, gpt image, openai image, chatgpt image