video-editor
Skill4 starsChanged 7 months agoMITView on GitHub
Edits existing videos using ffmpeg and Python. Use ALWAYS when the user wants to edit a video, cut a video, join videos, add subtitles, add music, remove audio, resize a video, convert format, compress a video, extract audio, extract frames, add a watermark, make a timelapse, slow motion, speed up, reverse, add a transition, crop, rotate, adjust brightness/contrast, color grading, generate a GIF, generate a thumbnail, or any manipulation of an existing video file. Also activates when the user mentions: ffmpeg, moviepy, cutting a clip, joining clips, captioning a video, or processing a video.
- Installs packages
19 other projects use a version of this.
Adopted by
Most recently taken up by
- orage-developers/skills-editortheir own version, first seen Nov 8, 2026
- Jrkesari/skillstheir own version, first seen Nov 8, 2026
- weibo-job/guagua-animation-skillstheir own version, first seen Nov 8, 2026
- fralapo/awesome-agent-skillstheir own version, first seen Nov 7, 2026
- humzabuilds/claude-skillstheir own version, first seen Oct 20, 2026
- nelsonelagunar/obs-ai-workflowtheir own version, first seen Oct 15, 2026
Other versions19 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 19
- jtydhr88/ComfyTV★ 1.2ksame name
- ckorhonen/claude-skills★ 17same name
- coopersimson96/ai-content-system★ 17same name
- EverythingAI-Pro/ai-video-editor★ 16same name
- Isaac-Flath/agent-starter-skills★ 8same name
- darker2016/WorkbuddySkillGroups4DSH★ 6same name
- kevinaimonster/skill-hub★ 4same name
- tyler-berggren/tb-claude-kit★ 2same name
- weibo-job/guagua-animation-skills★ 2same name
- fralapo/awesome-agent-skills★ 1same name
9 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository21 other files it gives its agents.
- analyticsSkill
- brainstormSkill
- brandingSkill
- code-reviewSkill
- devops-deploySkill
- dev-workflowSkill
- founderSkill
- grill-meSkill
- idea-validationSkill
- improve-codebase-architectureSkill
- landing-pageSkill
- legal-complianceSkill
- marketingSkill
- prd-to-issuesSkill
- senior-backendSkill
- senior-frontendSkill
- senior-qaSkill
- seoSkill
- software-architectSkill
- video-creatorSkill
- write-a-prdSkill
The file
We split this skill into the rules it gives an agent
5 rules. 0 are common, 2 are distinctive, and 3 are very specific to this project.
0
Common
Most of the 12 edited versions we read keep these.
2
Distinctive
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 22
Always start by analyzing the input video:
- Very specific: line 252
Use -c copy whenever possible (no re-encoding = instant)
- Very specific: line 253
Use -preset ultrafast for quick tests, -preset slow for final output
- Very specific: line 262
Use filter_complex to composite multiple video layers onto a base, with per-overlay time-gating and position control.
- Distinctive: line 425
Use whisper output to make edit decisions based on speech content rather than manual timecodes.
“Common” is measured: kept by at least 6 in 10 of the 12 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Video Editor — Video Editing via Code
You are an expert in video editing and manipulation using ffmpeg and Python. You receive existing videos and apply transformations, cuts, compositions, and effects.
Principles
- Understand before editing — Analyze the input video (resolution, codec, duration, fps, audio) before any operation
- Preserve quality — Use
-c copywhenever possible (no re-encoding). Re-encode only when necessary (filters, resize, compositing) - Non-destructive — Never overwrite the original. Always generate a new file
- Batch-friendly — Scripts should work for 1 or 100 videos
First Step: Analyze the Video
Always start by analyzing the input video:
# Full video info
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4
# Quick summary
ffprobe -v quiet -show_entries format=duration,size,bit_rate:stream=codec_name,width,height,r_frame_rate,channels -of compact input.mp4Essential information:
- Resolution: width x height
- Codec: h264, h265, vp9, av1
- FPS: frames per second
- Duration: in seconds
- Bitrate: quality
- Audio: codec, sample rate, channels
Common Operations
Trim
# Without re-encoding (fast, keyframe-accurate)
ffmpeg -ss 00:01:00 -to 00:02:30 -i input.mp4 -c copy output.mp4
# With re-encoding (frame-accurate)
ffmpeg -i input.mp4 -ss 00:01:00 -to 00:02:30 -c:v libx264 -c:a aac output.mp4Concatenate (Join Videos)
# Create list
echo "file 'v1.mp4'" > list.txt
echo "file 'v2.mp4'" >> list.txt
echo "file 'v3.mp4'" >> list.txt
# Concatenate (same resolution/codec)
ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4
# Concatenate (different resolutions)
ffmpeg -i v1.mp4 -i v2.mp4 \
-filter_complex "[0:v]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080[v0];[1:v]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080[v1];[v0][v1]concat=n=2:v=1:a=0" \
output.mp4Resize
# Specific resolution
ffmpeg -i input.mp4 -vf "scale=1280:720" -c:a copy output.mp4
# Maintain aspect ratio (width 1080, proportional height)
ffmpeg -i input.mp4 -vf "scale=1080:-2" -c:a copy output.mp4
# Fit in box without distorting
ffmpeg -i input.mp4 -vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black" output.mp4Crop (Crop Area)
# Crop center 1080x1080 from 1920x1080 video
ffmpeg -i input.mp4 -vf "crop=1080:1080:(iw-1080)/2:(ih-1080)/2" output.mp4
# Crop with automatic black border detection
ffmpeg -i input.mp4 -vf "cropdetect" -f null - 2>&1 | tail -5Rotate
# 90 degrees clockwise
ffmpeg -i input.mp4 -vf "transpose=1" output.mp4
# 90 degrees counter-clockwise
ffmpeg -i input.mp4 -vf "transpose=2" output.mp4
# 180 degrees
ffmpeg -i input.mp4 -vf "transpose=1,transpose=1" output.mp4Format Conversion
# MP4 to WebM (VP9)
ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 30 -c:a libopus output.webm
# MOV to MP4
ffmpeg -i input.mov -c:v libx264 -c:a aac -preset fast output.mp4
# MP4 to GIF
ffmpeg -i input.mp4 -vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" output.gifCompression
# Good quality, smaller file (CRF 23 = default, 28 = more compressed)
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k output.mp4
# For WhatsApp (max 16MB)
# Formula: target_bitrate = (16 * 8192 / duration_seconds) - 128
ffmpeg -i input.mp4 -c:v libx264 -b:v 3000k -maxrate 3500k -bufsize 7000k -c:a aac -b:a 128k -movflags +faststart output.mp4
# 2-pass (best quality/size)
ffmpeg -i input.mp4 -c:v libx264 -b:v 2000k -pass 1 -f null /dev/null
ffmpeg -i input.mp4 -c:v libx264 -b:v 2000k -pass 2 -c:a aac output.mp4Audio Editing
Add background music
ffmpeg -i video.mp4 -i music.mp3 \
-filter_complex "[1:a]volume=0.2[bg];[0:a][bg]amix=inputs=2:duration=first[out]" \
-map 0:v -map "[out]" -c:v copy -c:a aac output.mp4Replace entire audio
ffmpeg -i video.mp4 -i new_audio.mp3 -c:v copy -map 0:v -map 1:a -shortest output.mp4Remove audio
ffmpeg -i video.mp4 -an -c:v copy silent.mp4Extract audio
ffmpeg -i video.mp4 -vn -c:a libmp3lame -q:a 2 audio.mp3Normalize volume
ffmpeg -i video.mp4 -af "loudnorm=I=-14:LRA=11:TP=-1.5" -c:v copy output.mp4Subtitles and Text
Add embedded SRT subtitles
# Soft subtitles (player shows/hides)
ffmpeg -i video.mp4 -i subs.srt -c copy -c:s mov_text output.mp4
# Hard subtitles (burned-in, always visible)
ffmpeg -i video.mp4 -vf "subtitles=subs.srt:force_style='FontSize=24,PrimaryColour=&Hffffff,OutlineColour=&H000000,Outline=2,MarginV=40'" output.mp4Generate SRT with Whisper
pip install openai-whisper
whisper video.mp4 --model base --output_format srt --language ptOverlaid text
ffmpeg -i video.mp4 \
-vf "drawtext=text='Title':fontcolor=white:fontsize=64:x=(w-text_w)/2:y=50:shadowcolor=black:shadowx=3:shadowy=3" \
output.mp4Effects and Adjustments
Speed
# 2x faster
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" fast.mp4
# 0.5x slower
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]" -map "[v]" -map "[a]" slow.mp4Color Grading
# Brightness, contrast, saturation
ffmpeg -i input.mp4 -vf "eq=brightness=0.05:contrast=1.2:saturation=1.3" output.mp4
# Cinematic (crush blacks, roll highlights)
ffmpeg -i input.mp4 -vf "curves=m='0/0.05 0.5/0.5 1/0.95'" output.mp4
# Black and white
ffmpeg -i input.mp4 -vf "hue=s=0" output.mp4Stabilization
# Step 1: Analyze
ffmpeg -i shaky.mp4 -vf vidstabdetect -f null -
# Step 2: Apply
ffmpeg -i shaky.mp4 -vf vidstabtransform=smoothing=10:input=transforms.trf output.mp4Watermark/Logo
ffmpeg -i video.mp4 -i logo.png \
-filter_complex "[1:v]scale=80:-1,format=rgba,colorchannelmixer=aa=0.5[logo];[0:v][logo]overlay=W-w-20:20" \
output.mp4Batch Processing
Convert all MOV to MP4
for f in *.mov; do
ffmpeg -i "$f" -c:v libx264 -c:a aac -preset fast "${f%.mov}.mp4"
doneGenerate thumbnails for all videos
for f in *.mp4; do
ffmpeg -i "$f" -ss 00:00:05 -vframes 1 "thumb_${f%.mp4}.jpg"
doneResize all to 1080p
for f in *.mp4; do
ffmpeg -i "$f" -vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2" -c:a copy "1080p_$f"
doneEditing Workflow
- Analyze —
ffprobeon the input video - Plan — List the required operations in order
- Chain filters — Combine operations in a single command when possible (avoids multiple re-encodings)
- Execute — Run the command
- Verify —
ffprobeon the output, confirm quality - Optimize — Adjust CRF, bitrate, resolution if needed
Performance Tips
- Use
-c copywhenever possible (no re-encoding = instant) - Use
-preset ultrafastfor quick tests,-preset slowfor final output -movflags +faststartfor web videos (loads faster)- For batch processing, use GNU
parallelto process multiple videos simultaneously - Hardware acceleration:
-hwaccel auto(uses GPU if available)
Overlay Compositing
Use filter_complex to composite multiple video layers onto a base, with per-overlay time-gating and position control.
Multiple overlays with time-gating
Each overlay layer is activated only within its time window using enable='between(t,start,end)':
ffmpeg -y \
-i base-footage.mp4 \
-i overlay-01.mov \
-i overlay-02.mov \
-i overlay-03.mov \
-filter_complex "
[0:v]copy[base];
[1:v]setpts=PTS-STARTPTS[o0];
[base][o0]overlay=0:800:enable='between(t,5.0,12.5)'[v0];
[2:v]setpts=PTS-STARTPTS[o1];
[v0][o1]overlay=540:0:enable='between(t,14.0,22.0)'[v1];
[3:v]setpts=PTS-STARTPTS[o2];
[v1][o2]overlay=0:0:enable='between(t,25.5,35.0)'[vout]
" \
-map "[vout]" -map 0:a \
-c:v libx264 -crf 18 -c:a aac -b:a 320k \
output.mp4Key techniques
setpts=PTS-STARTPTS— Resets each overlay's PTS to 0 so it plays from the start of its own file, not from the position in the base timelineenable='between(t,start,end)'— Time-gates the overlay filter; the overlay is composited only within this second range- Chained labels — Each overlay step produces an intermediate label (
[v0],[v1], ...) feeding into the next; the final step produces[vout] -map "[vout]" -map 0:a— Uses the composited video but keeps the original base audio stream unchanged
Lower-third overlay at fixed position
ffmpeg -i video.mp4 -i lower-third.mov \
-filter_complex "
[1:v]setpts=PTS-STARTPTS[lt];
[0:v][lt]overlay=0:810:enable='between(t,3,8)'[vout]
" \
-map "[vout]" -map 0:a \
-c:v libx264 -crf 20 -c:a aac output.mp4Picture-in-picture with time window
ffmpeg -i main.mp4 -i pip.mp4 \
-filter_complex "
[1:v]scale=320:180,setpts=PTS-STARTPTS[pip];
[0:v][pip]overlay=W-w-20:H-h-20:enable='between(t,10,30)'[vout]
" \
-map "[vout]" -map 0:a \
-c:v libx264 -crf 20 output.mp4Dynamic overlay opacity
# Fade overlay in over 1 second (alpha blend requires yuva pixel format or separate approach)
ffmpeg -i video.mp4 -i overlay.mov \
-filter_complex "
[1:v]setpts=PTS-STARTPTS,format=yuva420p,
colorchannelmixer=aa=0.8[ov];
[0:v][ov]overlay=0:0:enable='between(t,5,15)'[vout]
" \
-map "[vout]" -map 0:a -c:v libx264 output.mp4Batch Processing at Scale
Basic for loop
# Process all .mp4 files in a directory
for f in *.mp4; do
ffmpeg -i "$f" -c:v libx264 -crf 23 -c:a aac "processed_${f}"
doneGNU parallel (parallel execution)
# Install: brew install parallel / apt install parallel
# Convert all MOV to MP4 using all CPU cores
ls *.mov | parallel 'ffmpeg -i {} -c:v libx264 -c:a aac -preset fast {.}.mp4'
# Resize all videos with 4 parallel jobs
ls *.mp4 | parallel -j4 'ffmpeg -i {} -vf "scale=1920:1080" -c:a copy resized_{}'
# Generate thumbnails in parallel
ls *.mp4 | parallel 'ffmpeg -i {} -ss 00:00:05 -vframes 1 thumb_{.}.jpg'Queue management with a job file
# jobs.txt — one ffmpeg command per line
# Run with controlled concurrency
cat jobs.txt | parallel -j2 bash -c '{}'Batch with logging and error handling
#!/usr/bin/env bash
INPUT_DIR="./input"
OUTPUT_DIR="./output"
LOG_FILE="batch.log"
mkdir -p "$OUTPUT_DIR"
for f in "$INPUT_DIR"/*.mp4; do
name=$(basename "$f" .mp4)
out="$OUTPUT_DIR/${name}_processed.mp4"
echo "[$(date '+%H:%M:%S')] Processing: $name" | tee -a "$LOG_FILE"
if ffmpeg -y -i "$f" -c:v libx264 -crf 23 -c:a aac "$out" 2>>"$LOG_FILE"; then
echo "[OK] $name" | tee -a "$LOG_FILE"
else
echo "[FAIL] $name" | tee -a "$LOG_FILE"
fi
done
echo "Done. See $LOG_FILE for details."Python queue with subprocess
import subprocess
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed
def process_video(input_path: Path, output_dir: Path) -> tuple[Path, bool]:
out = output_dir / f"processed_{input_path.name}"
result = subprocess.run(
["ffmpeg", "-y", "-i", str(input_path),
"-c:v", "libx264", "-crf", "23", "-c:a", "aac", str(out)],
capture_output=True,
)
return input_path, result.returncode == 0
input_files = list(Path("./input").glob("*.mp4"))
output_dir = Path("./output")
output_dir.mkdir(exist_ok=True)
with ThreadPoolExecutor(max_workers=4) as executor:
futures = {executor.submit(process_video, f, output_dir): f for f in input_files}
for future in as_completed(futures):
path, success = future.result()
print(f"{'OK' if success else 'FAIL'}: {path.name}")Transcript-Based Editing
Use whisper output to make edit decisions based on speech content rather than manual timecodes.
Generate word-level transcript
pip install faster-whisper
python3 - video.mp4 > transcript.json <<'EOF'
import json, sys, subprocess
from faster_whisper import WhisperModel
# Extract audio first
audio = sys.argv[1].replace(".mp4", "_audio.wav")
subprocess.run(["ffmpeg", "-y", "-i", sys.argv[1], "-ar", "16000", "-ac", "1", "-vn", audio], check=True)
model = WhisperModel("medium", device="cpu", compute_type="int8")
segments, info = model.transcribe(audio, beam_size=5, word_timestamps=True, vad_filter=True)
result = {"language": info.language, "segments": []}
for seg in segments:
result["segments"].append({
"id": seg.id, "start": round(seg.start, 3), "end": round(seg.end, 3),
"text": seg.text.strip(),
"words": [{"word": w.word.strip(), "start": round(w.start, 3), "end": round(w.end, 3)} for w in seg.words],
})
print(json.dumps(result, indent=2))
EOFCut at specific phrase
import json, subprocess
with open("transcript.json") as f:
data = json.load(f)
# Find timestamp of a phrase
target = "let's get started"
for seg in data["segments"]:
if target.lower() in seg["text"].lower():
cut_time = seg["start"]
print(f"Found '{target}' at {cut_time:.3f}s")
# Trim video to start at this phrase
subprocess.run([
"ffmpeg", "-y", "-i", "video.mp4",
"-ss", str(cut_time), "-c", "copy", "trimmed.mp4"
], check=True)
breakRemove filler words (cut segments around "um", "uh")
import json, subprocess
with open("transcript.json") as f:
data = json.load(f)
FILLERS = {"um", "uh", "hmm", "like", "you know"}
keep_segments = []
cursor = 0.0
all_words = [w for seg in data["segments"] for w in seg["words"]]
for i, word in enumerate(all_words):
if word["word"].lower().strip(".,!?") in FILLERS:
# End previous segment just before this word
if word["start"] > cursor + 0.1:
keep_segments.append((cursor, word["start"]))
cursor = word["end"]
# Add final segment
total = data["segments"][-1]["end"]
if cursor < total:
keep_segments.append((cursor, total))
# Extract and reassemble
concat_lines = []
for i, (start, end) in enumerate(keep_segments):
tmp = f"_seg_{i:04d}.ts"
subprocess.run([
"ffmpeg", "-y", "-i", "video.mp4",
"-ss", f"{start:.3f}", "-to", f"{end:.3f}",
"-c", "copy", "-avoid_negative_ts", "make_zero", tmp
], check=True)
concat_lines.append(f"file '{tmp}'")
with open("_concat.txt", "w") as f:
f.write("\n".join(concat_lines))
subprocess.run(["ffmpeg", "-y", "-f", "concat", "-safe", "0", "-i", "_concat.txt", "-c", "copy", "no_fillers.mp4"], check=True)Auto-generate chapter markers from transcript
import json
with open("transcript.json") as f:
data = json.load(f)
# Find sentences that could be chapter starts (heuristic: start of segment after pause)
chapters = []
for i, seg in enumerate(data["segments"]):
if i == 0:
chapters.append((0.0, "Introduction"))
continue
prev = data["segments"][i - 1]
gap = seg["start"] - prev["end"]
if gap > 2.0: # 2+ second pause = likely chapter boundary
chapters.append((seg["start"], seg["text"][:50]))
# Output as ffmetadata for embedding
print(";FFMETADATA1")
for i, (start, title) in enumerate(chapters):
end = chapters[i + 1][0] if i + 1 < len(chapters) else data["segments"][-1]["end"]
print(f"\n[CHAPTER]\nTIMEBASE=1/1000\nSTART={int(start*1000)}\nEND={int(end*1000)}\ntitle={title}")Embed chapters into MP4
python3 generate_chapters.py > chapters.txt
ffmpeg -i video.mp4 -i chapters.txt -map_metadata 1 -codec copy video_with_chapters.mp4Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

