
Extract Frames
Pull first and last frames at every shot cut from a video so you can storyboard, review edits, or feed stills into downstream creative pipelines.
Install
npx skills add https://github.com/gupsammy/claudest --skill extract-framesWhat is this skill?
- Adaptive scene detection to find shot boundaries automatically
- Extract first frame, last frame (--last), or both (--all) per shot
- Optional --shots N,N filter and --threshold override for scene sensitivity
- Phase 0 setup: ffprobe metadata, fps/duration parsing, output dir beside video
- Allowed tools: ffprobe, ffmpeg, awk, mkdir with AskUserQuestion for threshold confirm
Adoption & trust: 1 installs on skills.sh; 253 GitHub stars; 3/3 security scanners passed (skills.sh audits); trending (+100% hot-view momentum).
Recommended Skills
Journey fit
Build is where you wire ffmpeg/ffprobe automation into your content toolchain; frame extraction is production integration work, not distribution. Integrations matches CLI media tooling (ffmpeg, ffprobe, awk) orchestrated by the agent rather than shipping a consumer app feature.
Common Questions / FAQ
Is Extract Frames safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Extract Frames
# Extract Frames ## Arguments Parse the user's request for: - **video path** (required): path to the video file - **--last**: extract last frame of each shot instead of first - **--first --last** or **--all**: extract both first and last frames - **--shots N,N,N**: only process specific shot numbers (1-indexed) - **--threshold X**: override auto-detected threshold (skip user confirmation) Default: extract first frame of every shot. ## Workflow ### Phase 0: Setup 1. Validate the video file exists. 2. Get video metadata via ffprobe: ```bash ffprobe -v error -show_entries format=duration -show_entries stream=r_frame_rate,width,height,codec_name -of default "$INPUT" ``` 3. Parse fps (needed for last-frame calculation) and duration. 4. Create output directory next to the video: `{video_basename}_frames/`. If it already exists, check for `scores.txt` — if present, skip Phase 1. ### Phase 1: Score Dump Dump per-frame scene scores for the entire video: ```bash ffmpeg -i "$INPUT" -vf "select='gte(scene,0)',metadata=print:file=$OUTPUT_DIR/scores.txt" -fps_mode vfr -f null - 2>&1 ``` This is the expensive step. The output file `scores.txt` contains blocks like: ``` frame:0 pts:0 pts_time:0.000000 lavfi.scene_score=0.000000 ``` ### Phase 2: Cut Detection Parse scores.txt with this awk one-liner to get distribution + all candidate frames: ```bash awk ' /pts_time/ { split($0, a, "pts_time:"); ts=a[2]+0 } /scene_score/ { split($0, a, "="); score=a[2]+0; if (score < 0.01) b1++; else if (score < 0.05) b2++; else if (score < 0.10) b3++; else if (score < 0.20) b4++; else b5++; total++; if (score > max) max=score; if (score > 0.05) printf " ts=%.3fs score=%.6f\n", ts, score; } END { print "\n--- Distribution ---"; printf "< 0.01: %d (%.1f%%)\n", b1, b1/total*100; printf "0.01 - 0.05: %d (%.1f%%)\n", b2, b2/total*100; printf "0.05 - 0.10: %d (%.1f%%)\n", b3, b3/total*100; printf "0.10 - 0.20: %d (%.1f%%)\n", b4, b4/total*100; printf "0.20+: %d (%.1f%%)\n", b5, b5/total*100; printf "Max score: %.6f\n", max; }' "$OUTPUT_DIR/scores.txt" ``` **Step 2a — Startup artifact filter:** Discard any frames in the first 0.5s where `score > 0.05` (a fixed preliminary value — the final user-confirmed threshold is not known yet). Fade-ins from black or codec initialization commonly produce score=1.0 spikes at t=0.03-0.08s that are not real cuts. After discarding these, recompute max score from the remaining frames. **Step 2b — Branch on max score.** If max score (after startup filter) < 0.05, the video has no cuts: - Report: "No shot boundaries detected — single continuous shot." - Extract only frame at t=0 (or t=1.0s if t=0 is a black frame — check file size, <50KB indicates black). - Skip threshold confirmation. **Step 2c — Gap analysis and threshold.** If max score >= 0.05, use the raw candidates (all frames with score > 0.05, after startup filter) to find the noise ceiling and the lowest-scoring candidate. Place the proposed threshold at the midpoint of the gap. Present to user via AskUserQuestion: - Score distribution summary - Gap analysis (noise ceiling → lowest cut, gap width) - Proposed threshold and resulting shot count - Options: Accept proposed (Recommended), Lower threshold, Higher threshold, Custom value If `--threshold` was provided, skip confirmation and