skills/video-frame-extraction-analysis/SKILL.md
Extract keyframes, detect scenes, and build CLIP-indexed temporal search over video content. Activate on: keyframe extraction, scene detection, video search, video indexing, temporal analysis. NOT for: video editing/rendering (video-processing-editing), video generation (ai-video-production-master).
npx skillsauth add curiositech/windags-skills video-frame-extraction-analysisInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Extract keyframes, detect scene boundaries, and build CLIP-indexed temporal search systems for video content analysis and retrieval.
Activate on: "keyframe extraction", "scene detection", "video search", "video indexing", "find frame in video", "temporal search", "video content analysis", "scene boundary detection", "CLIP video search"
NOT for: Video editing, trimming, or rendering (video-processing-editing), video generation from text/images (ai-video-production-master), or face recognition in video (face-recognition-system-builder)
| Domain | Technologies | Notes | |--------|-------------|-------| | Frame Extraction | ffmpeg, decord, OpenCV, PyAV | decord is fastest for random access | | Scene Detection | PySceneDetect, TransNetV2 | Cut detection + gradual transition detection | | Visual Embedding | CLIP, SigLIP, InternVideo2 | Per-frame or pooled-scene embeddings | | Temporal Search | Vector DB + timestamp metadata | "Find the frame where X happens" | | Shot Analysis | Shot type classification, motion estimation | Wide/medium/close-up, camera movement | | OCR on Frames | PaddleOCR, EasyOCR, Tesseract | Extract text from slides, titles, signage |
Video File ──→ [Scene Detector] ──→ [Keyframe Selector] ──→ [CLIP Embed] ──→ [Vector DB]
│ │ │ │ │
input PySceneDetect 1 frame per scene SigLIP-large store with
mp4/mkv threshold=27 at scene midpoint 384-dim timestamp
detect cuts + every 5 sec in + scene_id
+ transitions long scenes (>30s) + metadata
# Scene detection + keyframe extraction
from scenedetect import detect, ContentDetector
import decord
import numpy as np
def extract_keyframes(video_path: str) -> list[dict]:
"""Extract one keyframe per scene with timestamps."""
# Step 1: Detect scene boundaries
scene_list = detect(video_path, ContentDetector(threshold=27))
# Step 2: Extract keyframe at midpoint of each scene
vr = decord.VideoReader(video_path)
fps = vr.get_avg_fps()
keyframes = []
for i, scene in enumerate(scene_list):
start_frame = scene[0].get_frames()
end_frame = scene[1].get_frames()
mid_frame = (start_frame + end_frame) // 2
frame = vr[mid_frame].asnumpy() # RGB numpy array
timestamp = mid_frame / fps
keyframes.append({
"frame": frame,
"frame_index": mid_frame,
"timestamp_sec": timestamp,
"scene_index": i,
"scene_duration": (end_frame - start_frame) / fps,
})
# For long scenes (>30s), add extra keyframes every 5 sec
scene_dur = (end_frame - start_frame) / fps
if scene_dur > 30:
for t in np.arange(start_frame + int(5*fps), end_frame, int(5*fps)):
extra = vr[int(t)].asnumpy()
keyframes.append({
"frame": extra,
"frame_index": int(t),
"timestamp_sec": int(t) / fps,
"scene_index": i,
"scene_duration": scene_dur,
})
return keyframes
Indexing (offline):
Video ──→ [Extract Keyframes] ──→ [SigLIP Embed] ──→ [Vector DB]
│
metadata per frame:
video_id, timestamp,
scene_id, thumbnail_path
Querying (online):
Text: "person walking through rain" ──→ [SigLIP Text Embed] ──→ [Vector Search]
│
top-k frames
with timestamps
│
"video_3.mp4 @ 01:23:45"
"video_7.mp4 @ 00:45:12"
Video ──┬──→ [Keyframes] ──→ [CLIP Embed] ──→ [Visual Index]──┐
│ │
├──→ [Audio Track] ──→ [Whisper] ──→ [Text Embed] ──→ [Text Index]──┤──→ [Fusion Search]
│ │
└──→ [Frame OCR] ──→ [Text Extract] ──→ [Text Embed]──┘
Fusion search: query hits all three indexes, reciprocal rank fusion combines results
"Explain the sales chart" →
Visual: frame with chart → timestamp 15:30
Audio: "our Q3 numbers show..." → timestamp 15:28
OCR: "Q3 Revenue: $4.2M" → timestamp 15:30
Fused result: 15:28-15:35 segment with high confidence
data-ai
license: Apache-2.0 NOT for unrelated tasks outside this domain.
development
Use when designing caching strategies (cache-aside, write-through, write-behind), implementing distributed locks, building rate limiters, leaderboards, real-time streams (XADD/consumer groups), pub/sub, or tuning eviction policies. Triggers: thundering-herd on cache miss, dogpile on key expiry, Redlock vs SET-NX-PX choice, sliding-window rate limiter, hot-key on a single cluster slot, big-key blowup, MULTI/EXEC across slots, KEYS in production. NOT for Redis Cluster operations/admin (different domain), embedded KV (SQLite, leveldb), in-process LRU caches, or Memcached.
tools
Drawing the `'use client'` boundary correctly in React Server Components apps (Next.js App Router, RSC frameworks) — leaf-pushing, slot composition, serialization rules, and environment poisoning prevention. Grounded in react.dev and Next.js 16 docs.
development
Use when designing rate limiting for an API, choosing between token bucket / sliding window / leaky bucket / fixed window, implementing it in Redis, deciding edge (Cloudflare/Upstash) vs origin enforcement, sizing per-user vs per-IP vs per-endpoint quotas, returning the right 429 response with Retry-After, or fixing the boundary-burst bug in fixed-window limiters. Triggers: 429 too many requests, INCR + EXPIRE, ZADD + ZREMRANGEBYSCORE + ZCARD, X-RateLimit-Remaining header, Cloudflare WAF rate limiting rules, Upstash @upstash/ratelimit, leaky bucket shaping vs policing, distributed rate limiter consistency. NOT for DDoS mitigation specifically (different scale), CAPTCHA / bot management, full WAF design, or per-user quota billing.