Purpose
Remove inter-word and inter-sentence pauses from a talking-head clip so the delivery is tight and creator-native. Gaps above a configurable threshold are deleted; a small pad of audio/video is kept around each speech segment to preserve natural sentence starts and endings. The result is a re-encoded single video with all keep-segments concatenated.
This is the jump-cut transition type described in CREATOR_GRAMMAR.md §3 — the standard breath-removal edit for the creator-talking-head archetype.
Inputs
--source(required) — path to source video file.--words(mutually exclusive with--auto) — path to a word-timestamps JSON file in the shape output bytranscribe-audio-fal:[{"text": "Hey", "start": 0.12, "end": 0.45}, ...]--auto(mutually exclusive with--words) — derive speech segments automatically usingffmpeg silencedetect(no transcript needed).--gap-threshold(optional, default0.35) — gaps longer than this many seconds between speech are candidates for removal.--pad(optional, default0.08) — seconds of audio/video to keep on each side of a speech segment (prevents clipping first/last phoneme).--output(required) — path for the output video file (.mp4).--crf(optional, default18) — x264 quality.
Workflow
- Verify
ffmpegandffprobeare on PATH. - Build speech segments:
--wordsmode: merge consecutive word timestamps where inter-word gap ≤gap-thresholdinto contiguous speech blocks. Applypadto each block's start/end (clamped to clip bounds).--automode: runffmpeg -af silencedetect=noise=-35dB:d=<gap-threshold>on the source, parsesilence_start/silence_endlines from stderr, invert to get speech segments. Applypad.
- If no speech segments are found, copy source to output unchanged and write manifest with a warning.
- For each keep-segment: trim with
ffmpeg -ss <start> -i <source> -t <dur> -c:v libx264 -crf <crf> -preset fast -pix_fmt yuv420p -c:a aac -b:a 192k. - Write an ffmpeg concat list (
concat.txt) and runffmpeg -f concat -safe 0 -i concat.txt -c copyto join. - Clean up temporary segment files.
- Write
manifest.jsonto the same directory as--outputlisting every removed range and total time removed.
Run:
python3 skills/atoms/editing/create-jump-cuts/scripts/jump_cut.py \
--source /path/to/raw.mp4 \
(--words /path/to/words.json | --auto) \
--output /path/to/tight.mp4 \
[--gap-threshold 0.35] [--pad 0.08] [--crf 18]
Output
<output>.mp4— re-encoded video with pauses removed.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,errorsremoved_ranges— array of{start, end, duration_s}for every deleted gaptotal_removed_seconds— sum of all removed gap durationssource_duration_seconds— original clip lengthoutput_duration_seconds— final clip length
Quality Checks
- Output file exists and is non-zero size.
ffprobeconfirms output is playable H.264/yuv420p.- Output duration ≈ source duration minus
total_removed_seconds(±0.3s tolerance for pad/encode rounding). manifest.jsonlists all removed ranges and the total savings.- No speech content is cut — only silence/pause gaps above threshold.
- If
--wordsis provided, every word boundary is preserved within pad tolerance.
Failure Modes
ffmpeg/ffprobenot installed — install viabrew install ffmpeg.- Source missing or unreadable — script exits with clear error before processing.
- No silence detected (
--automode on a clip with no pauses) — output equals source; manifest records warning, statuspass. - Mutually exclusive flags both provided (
--words+--auto) — script exits with argument error. - Corrupt or empty words JSON — script exits with clear parse error.
- Concat step fails — individual segment files are left in place for debugging; manifest records error.
- Very short source (<1s) — processed normally; output may equal source if no gaps found.