| name | add-zoom-cuts |
| description | apply punch-in, push-in, or Ken Burns zoom motion to a video clip or still image using ffmpeg crop/scale/zoompan. Use when a clip needs a creator-native emphasis move — an instant stepped tighter crop (zoom-punch), a gradual scale-up (push-in), or a slow pan-and-zoom (ken-burns). |
add-zoom-cuts
Purpose
Apply one of three zoom motion types to a clip or still image — the zoom-punch transition and camera-emphasis moves described in CREATOR_GRAMMAR.md §3 and §5:
--type | What it does | When to use |
|---|
zoom-punch | Instant stepped tighter crop at a given timestamp — the clip plays at normal scale, then snaps to a tighter crop at --at | Emphasis on a word or beat; replaces a cut to a tighter angle |
push-in | Gradual scale-up from --from-scale to --to-scale over the whole clip | Premium feel, slow approach; slow-burn reveal |
ken-burns | Slow pan + zoom via ffmpeg zoompan — works on stills or clips | Product still → motion, b-roll slow move |
Inputs
--source (required) — path to source video or image file.
--type (required) — one of zoom-punch, push-in, ken-burns.
--from-scale (optional, default 1.0) — starting scale multiplier (1.0 = no zoom).
--to-scale (optional, default 1.12) — ending/peak scale multiplier.
--at (optional, default 0) — timestamp in seconds for zoom-punch snap (ignored for other types).
--focal (optional) — focal point as x,y in 0–1 normalized coordinates (default 0.5,0.5 = center). Controls which part of the frame stays centered during zoom.
--output (required) — output video path (.mp4).
--fps (optional, default 30) — output frame rate.
--crf (optional, default 18) — x264 quality.
--duration (optional) — force output duration in seconds (required when source is an image).
Workflow
- Verify
ffmpeg and ffprobe are on PATH; verify source file exists.
- Probe source: get width, height, duration (if video). For images, use
--duration (default 4s).
- Compute crop/scale parameters from
--focal, --from-scale, --to-scale, source dimensions.
- Build ffmpeg filtergraph:
zoom-punch: use trim + setpts + scale to produce two sub-clips (before/at --at at from-scale, after --at at to-scale), then concat.
push-in: use scale=w=iw*<to_scale>:h=ih*<to_scale> + crop=iw/<to_scale>:ih/<to_scale>:... with zoompan-style lerp or overlay approach — implemented as a frame-accurate zoompan with z= expression ramping from from-scale to to-scale.
ken-burns: use ffmpeg zoompan=z='zoom+0.0015':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d=<frames>:s=<WxH>:fps=<fps>.
- Run ffmpeg with
-c:v libx264 -crf <crf> -preset fast -pix_fmt yuv420p; include audio passthrough when source has audio.
- Write
manifest.json to same directory as output.
Run:
python3 skills/atoms/editing/add-zoom-cuts/scripts/zoom_cuts.py \
--source /path/to/clip.mp4 \
--type push-in \
--to-scale 1.15 \
--output /path/to/clip-zoom.mp4
python3 skills/atoms/editing/add-zoom-cuts/scripts/zoom_cuts.py \
--source /path/to/clip.mp4 \
--type zoom-punch \
--at 2.5 \
--to-scale 1.20 \
--output /path/to/clip-punched.mp4
Output
<output>.mp4 — re-encoded video with zoom motion applied.
manifest.json (same directory as output) — includes:
skill_name, run_id, input_path, output_files, provider, model_or_tool, created_at, duration_seconds, status, warnings, errors
zoom_type, from_scale, to_scale, focal_x, focal_y, at_seconds (for zoom-punch)
source_duration_seconds, output_duration_seconds
Quality Checks
- Output file exists and is non-zero size.
ffprobe confirms output is playable H.264/yuv420p.
- Output duration matches source duration (±0.2s for video sources).
- For
zoom-punch: visible scale step at --at timestamp when scrubbed frame-by-frame.
- For
push-in: smooth continuous zoom from from-scale to to-scale.
- For
ken-burns: slow pan + zoom motion visible on playback; no black borders (crop covers overscan).
manifest.json records zoom parameters.
Failure Modes
ffmpeg / ffprobe not installed — install via brew install ffmpeg.
- Source missing or unreadable — script exits with clear error.
- Invalid
--type — script exits with usage error listing valid values.
--at past end of video (zoom-punch) — treated as applying zoom from start; warning recorded.
--to-scale < --from-scale — script exits with error.
--to-scale > 2.0 — allowed but warns; extreme zooms may introduce visible pixelation.
- Image source without
--duration — defaults to 4s; if that is wrong, pass --duration.
- Source has no audio — output produced without audio stream; not an error.