claude-video-edit — Video Editing Operations
Pre-Flight
Before every operation that writes a file:
- Run
bash scripts/preflight.sh "$INPUT" "$OUTPUT" - If it fails, stop and report the error to the user
- For encoding operations, run
bash scripts/detect_gpu.shto choose encoder
Operations
Trimming
Lossless trim (keyframe-aligned, instant, no re-encode):
ffmpeg -n -ss HH:MM:SS -i "$INPUT" -t DURATION -c copy "$OUTPUT"
Note: -ss BEFORE -i for fast seeking. Duration in seconds or HH:MM:SS.
Frame-accurate trim (re-encodes, precise to any frame):
ffmpeg -n -i "$INPUT" -ss HH:MM:SS -t DURATION -c:v libx264 -crf 20 -c:a aac "$OUTPUT"
Note: -ss AFTER -i for frame accuracy. Use when precision matters.
Remove first/last N seconds:
- Remove first 10s:
-ss 10 -c copy - Remove last 10s: get duration with ffprobe, then trim to
duration - 10
Splitting
Split at specific time:
ffmpeg -n -i "$INPUT" -t 60 -c copy part1.mp4
ffmpeg -n -i "$INPUT" -ss 60 -c copy part2.mp4
Split into equal segments:
ffmpeg -n -i "$INPUT" -f segment -segment_time 300 -c copy -reset_timestamps 1 "segment_%03d.mp4"
Split at scene boundaries (load references/analyze.md for PySceneDetect):
scenedetect -i "$INPUT" detect-adaptive -t 3.0 split-video
Concatenation
Same codec (no re-encode):
printf "file '%s'\n" file1.mp4 file2.mp4 file3.mp4 > /tmp/concat_list.txt
ffmpeg -n -f concat -safe 0 -i /tmp/concat_list.txt -c copy "$OUTPUT"
rm /tmp/concat_list.txt
Different codecs (re-encodes):
ffmpeg -n -i file1.mp4 -i file2.mp4 -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1" "$OUTPUT"
Speed Changes
Speed up 2x (with audio pitch correction):
ffmpeg -n -i "$INPUT" -vf "setpts=0.5*PTS" -af "atempo=2.0" "$OUTPUT"
Slow down 0.5x:
ffmpeg -n -i "$INPUT" -vf "setpts=2.0*PTS" -af "atempo=0.5" "$OUTPUT"
Speed factors: For atempo, valid range is 0.5–100.0. For extreme changes, chain: atempo=2.0,atempo=2.0 = 4x.
Frame interpolation slow-motion (AI-generated intermediate frames):
ffmpeg -n -i "$INPUT" -vf "minterpolate=fps=60:mi_mode=mci:mc_mode=aobmc:vsbmc=1" "$OUTPUT"
Warning: Very slow (~0.05x realtime). Best for short clips.
Cropping, Scaling, Rotation
Crop (width:height:x:y):
ffmpeg -n -i "$INPUT" -vf "crop=640:480:100:50" "$OUTPUT"
Scale (keep aspect ratio, even dimensions):
ffmpeg -n -i "$INPUT" -vf "scale=1280:-2:flags=lanczos" "$OUTPUT"
Scale to exact size with padding (letterbox):
ffmpeg -n -i "$INPUT" -vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black" "$OUTPUT"
Rotate 90° clockwise: -vf "transpose=1"
Rotate 90° counter-clockwise: -vf "transpose=2"
Rotate 180°: -vf "transpose=1,transpose=1"
Arbitrary angle: -vf "rotate=PI/6:fillcolor=black"
Flip horizontal: -vf "hflip" | Vertical: -vf "vflip"
Overlays and Watermarks
Image watermark (bottom-right with 10px margin):
ffmpeg -n -i "$INPUT" -i logo.png -filter_complex "overlay=W-w-10:H-h-10" "$OUTPUT"
Picture-in-picture (small video in corner):
ffmpeg -n -i "$INPUT" -i pip.mp4 -filter_complex "[1:v]scale=320:180[pip];[0:v][pip]overlay=10:10" "$OUTPUT"
Text overlay:
ffmpeg -n -i "$INPUT" -vf "drawtext=text='My Title':fontsize=48:fontcolor=white:x=(w-tw)/2:y=50:fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:box=1:boxcolor=black@0.5:boxborderw=8" "$OUTPUT"
Timed text (show between 5s and 15s):
-vf "drawtext=text='Hello':enable='between(t,5,15)':fontsize=36:fontcolor=white:x=10:y=10"
Green Screen (Chromakey)
ffmpeg -n -i greenscreen.mp4 -i background.mp4 -filter_complex \
"[0:v]chromakey=0x00FF00:0.1:0.2[fg];[1:v][fg]overlay" "$OUTPUT"
Adjust color hex, similarity (0.1), and blend (0.2) for best results.
Video Stabilization
Two-pass process using vidstab:
# Pass 1: Analyze motion
ffmpeg -i "$INPUT" -vf vidstabdetect=shakiness=5:accuracy=15:result=/tmp/transforms.trf -f null -
# Pass 2: Apply stabilization + sharpening
ffmpeg -n -i "$INPUT" -vf "vidstabtransform=smoothing=10:input=/tmp/transforms.trf,unsharp=5:5:0.8:5:5:0.3" "$OUTPUT"
rm /tmp/transforms.trf
shakiness 1-10 (how shaky is source), smoothing (higher = smoother camera, may crop edges).
Transitions
Cross-fade between two clips (44+ transition types available):
ffmpeg -n -i first.mp4 -i second.mp4 -filter_complex \
"xfade=transition=fade:duration=2:offset=5" "$OUTPUT"
Available xfade transitions: fade, dissolve, wipeleft, wiperight, wipeup, wipedown, slideleft, slideright, slideup, slidedown, circlecrop, rectcrop, distance, fadeblack, fadewhite, radial, smoothleft, smoothright, smoothup, smoothdown, circleopen, circleclose, vertopen, vertclose, horzopen, horzclose, diagtl, diagtr, diagbl, diagbr, hlslice, hrslice, vuslice, vdslice, pixelize, squeezeh, squeezev, zoomin, fadegrays, wipetl, wipetr, wipebl, wipebr, coverleft, coverright, coverup, coverdown, revealleft, revealright, revealup, revealdown.
Fade in/out:
# Fade in first 2 seconds
ffmpeg -n -i "$INPUT" -vf "fade=t=in:st=0:d=2" -af "afade=t=in:st=0:d=2" "$OUTPUT"
# Fade out last 2 seconds (get duration first with ffprobe)
ffmpeg -n -i "$INPUT" -vf "fade=t=out:st=OFFSET:d=2" -af "afade=t=out:st=OFFSET:d=2" "$OUTPUT"
Color Correction
Load references/filters.md for the full filter catalog. Quick reference:
- Brightness/contrast:
-vf "eq=brightness=0.06:contrast=1.2:saturation=1.3" - Tone curves preset:
-vf "curves=preset=lighter"(also: darker, increase_contrast, vintage, etc.) - Color balance:
-vf "colorbalance=rs=0.3:gs=-0.1:bs=0.0" - 3D LUT:
-vf "lut3d=file=my_lut.cube" - Grayscale:
-vf "colorchannelmixer=.3:.4:.3:0:.3:.4:.3:0:.3:.4:.3" - Blur:
-vf "gblur=sigma=10" - Sharpen:
-vf "unsharp=5:5:1.0:5:5:0.0" - Denoise:
-vf "hqdn3d=4:3:6:4.5"(fast) or-vf "nlmeans=s=3.5:p=7:r=15"(best quality)
Contact Sheet / Thumbnail Grid
ffmpeg -n -i "$INPUT" -vf "select=not(mod(n\,100)),scale=320:180,tile=4x4" -frames:v 1 contact_sheet.png
Extract Single Frame
ffmpeg -n -ss 00:01:30 -i "$INPUT" -frames:v 1 -q:v 2 thumbnail.jpg
Privacy Blur (Face/Region Censoring)
Blur entire face region (static coordinates — use ffprobe or MediaPipe to find face bounding box):
ffmpeg -n -i "$INPUT" -vf "delogo=x=200:y=100:w=150:h=150" "$OUTPUT"
Box blur a region (more control):
ffmpeg -n -i "$INPUT" -filter_complex \
"[0:v]crop=150:150:200:100,boxblur=10[blur];[0:v][blur]overlay=200:100" "$OUTPUT"
Blur with time range (only blur between 5s and 15s):
ffmpeg -n -i "$INPUT" -filter_complex \
"[0:v]split[main][copy];[copy]crop=150:150:200:100,boxblur=10[blur];[main][blur]overlay=200:100:enable='between(t,5,15)'" "$OUTPUT"
Full-frame blur (for B-roll background):
ffmpeg -n -i "$INPUT" -vf "boxblur=20:5" "$OUTPUT"
For AI-powered face detection + tracking blur across frames, use python3 scripts/face_tracker.py
with MediaPipe BlazeFace (CPU, no VRAM needed). The face_tracker outputs bounding boxes per frame
that can drive the overlay blur coordinates.
LUT Color Grading
Apply a .cube LUT file:
ffmpeg -n -i "$INPUT" -vf "lut3d=file=my_grade.cube" "$OUTPUT"
Apply with intensity control (blend between original and graded):
ffmpeg -n -i "$INPUT" -filter_complex \
"[0:v]split[a][b];[b]lut3d=file=my_grade.cube[graded];[a][graded]blend=all_mode=normal:all_opacity=0.7" "$OUTPUT"
Common LUT sources: Download .cube files from sites like lutify.me, filtergrade.com, or create custom LUTs in DaVinci Resolve. Place LUT files alongside the project or use absolute paths.
Supported formats: .cube (most common), .3dl, .dat, .m3d
Motion Tracking Text Overlay
Static text that follows a position (manual keyframes):
ffmpeg -n -i "$INPUT" -vf "drawtext=text='Label':fontsize=24:fontcolor=white:\
x='if(lt(t,5),100+t*20,200)':y='if(lt(t,5),50+t*10,100)':\
fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:\
box=1:boxcolor=black@0.5:boxborderw=4" "$OUTPUT"
Text with expression-based movement (smooth sine wave):
ffmpeg -n -i "$INPUT" -vf "drawtext=text='Moving Text':fontsize=36:fontcolor=white:\
x='w/2-tw/2+50*sin(t*2)':y='h/2-th/2+30*cos(t*2)':\
fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" "$OUTPUT"
For complex tracking (follow a face or object through a video), combine scripts/face_tracker.py
bounding box output with per-frame drawtext coordinates. Export face centers from the tracker,
then generate a drawtext filter with frame-by-frame x/y expressions.
Output Naming Convention
When user doesn't specify output name, derive it from input:
video.mp4→video_trimmed.mp4,video_stabilized.mp4,video_2x.mp4, etc.- For batch:
video_001.mp4,video_002.mp4, etc.