plugins/gif/skills/gif/SKILL.md
Convert a video or screen recording to GIF. Handles HDR recordings, macOS filenames with spaces, and ffmpeg two-pass palette compression. Do NOT use for frame extraction (use /frames instead).
npx skillsauth add ramonclaudio/skills gifInstall 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.
ultrathink
Convert screen recordings to compressed GIFs using ffmpeg's two-pass palette method. Handles HDR (HDR10/PQ) recordings from macOS automatically.
which ffmpeg 2>/dev/null && ffmpeg -version 2>&1 | head -1 || echo "NOT INSTALLED - run: brew install ffmpeg"If ffmpeg is NOT INSTALLED, stop immediately and tell the user to install it. Do not attempt any conversion.
| Setting | Value | Notes |
|---------|-------|-------|
| FPS | 10 | Good for screen recordings |
| Width | 640px | Lanczos scaling |
| Speed | 1x | No speedup |
| Palette | stats_mode=diff | Optimizes for static areas |
| Dither | bayer:bayer_scale=5 | Good quality, small file |
Parse arguments from the user's invocation:
--speed N → playback speed multiplier (default: 1). Use 2-4x for long demos.--width N → override scale width (default: 640)--fps N → override frame rate (default: 10)--full → no scaling, keep original resolution--crop → crop out macOS screen recording overlay (top bar). Probe dimensions first, then apply crop=in_w:in_h-PIXELS:0:PIXELS to remove the top PIXELS.Parse the video path from $ARGUMENTS.
IMPORTANT: File paths with spaces, timestamps, and special characters are problematic. ALWAYS use the glob+copy pattern.
Extract a unique identifier from the user's path (like a timestamp) and use glob:
/bin/cp -f /path/to/dir/*UNIQUE_PART* /tmp/video.mov && \
ffprobe -v error -select_streams v:0 \
-show_entries stream=width,height,r_frame_rate,duration \
-show_entries stream=color_transfer \
-of default=noprint_wrappers=1 /tmp/video.mov
Example for Screen Recording 2026-01-29 at 12.33.07 PM.mov:
/bin/cp -f ~/Desktop/Screen*12.33.07* /tmp/video.mov && \
ffprobe -v error -select_streams v:0 \
-show_entries stream=width,height,r_frame_rate,duration \
-show_entries stream=color_transfer \
-of default=noprint_wrappers=1 /tmp/video.mov
Check the color_transfer value:
smpte2084 → HDR recording, must convert to SDR first (Step 1b)bt709, unknown, etc.) → SDR, skip to Step 2macOS screen recordings on XDR displays use HDR10 (PQ/BT.2020/10-bit). The base Homebrew ffmpeg cannot tone-map PQ without the zimg library. Use macOS-native avconvert instead. It uses AVFoundation which handles HDR to SDR tone mapping correctly.
avconvert -s /tmp/video.mov -o /tmp/video_sdr.mov -p PresetHighestQuality --replace --progress
Then use /tmp/video_sdr.mov as input for Step 2 instead of /tmp/video.mov.
Verify conversion:
ffprobe -v error -select_streams v:0 -show_entries stream=color_transfer -of csv=p=0 /tmp/video_sdr.mov
Should output bt709 (not smpte2084).
Use /tmp/video_sdr.mov if HDR was detected, otherwise /tmp/video.mov. Substitute the input path as INPUT below.
Build the filter chain from arguments. Omit setpts when speed is 1. Omit crop when not requested.
Filter chain order: setpts → crop → fps → scale → palettegen/paletteuse
With defaults (fps=10, width=640, speed=1):
mkdir -p /tmp/gif-output && \
ffmpeg -y -v warning -i INPUT \
-vf "fps=10,scale=640:-1:flags=lanczos,palettegen=stats_mode=diff" \
-update 1 /tmp/gif-output/palette.png && \
ffmpeg -y -v warning -i INPUT -i /tmp/gif-output/palette.png \
-lavfi "fps=10,scale=640:-1:flags=lanczos[x];[x][1:v]paletteuse=dither=bayer:bayer_scale=5" \
-loop 0 /tmp/gif-output/output.gif && \
du -h /tmp/gif-output/output.gif
With --speed 3 (3x speedup):
mkdir -p /tmp/gif-output && \
ffmpeg -y -v warning -i INPUT \
-vf "setpts=PTS/3,fps=10,scale=640:-1:flags=lanczos,palettegen=stats_mode=diff" \
-update 1 /tmp/gif-output/palette.png && \
ffmpeg -y -v warning -i INPUT -i /tmp/gif-output/palette.png \
-lavfi "setpts=PTS/3,fps=10,scale=640:-1:flags=lanczos[x];[x][1:v]paletteuse=dither=bayer:bayer_scale=5" \
-loop 0 /tmp/gif-output/output.gif && \
du -h /tmp/gif-output/output.gif
With --full (no scaling):
mkdir -p /tmp/gif-output && \
ffmpeg -y -v warning -i INPUT \
-vf "fps=10,palettegen=stats_mode=diff" \
-update 1 /tmp/gif-output/palette.png && \
ffmpeg -y -v warning -i INPUT -i /tmp/gif-output/palette.png \
-lavfi "fps=10[x];[x][1:v]paletteuse=dither=bayer:bayer_scale=5" \
-loop 0 /tmp/gif-output/output.gif && \
du -h /tmp/gif-output/output.gif
With --crop (remove macOS recording overlay):
Insert crop before fps. The macOS recording bar is typically ~60px on retina displays:
# crop=in_w:in_h-PIXELS:0:PIXELS removes top PIXELS from source
"setpts=PTS/3,crop=in_w:in_h-60:0:60,fps=10,scale=640:-1:flags=lanczos,palettegen=stats_mode=diff"
Report the output path and file size. Then open:
open /tmp/gif-output/output.gif # macOS
For large or long videos:
| Technique | Command modification |
|-----------|---------------------|
| Speed up | setpts=PTS/3 for 3x (fewer frames = smaller file) |
| Lower FPS | fps=5 (for long videos) |
| Smaller width | scale=480:-1 or scale=320:-1 |
| Trim to range | Add -ss 00:00:05 -t 10 before -i to grab 10s starting at 5s |
| Crop region | Add crop=w:h:x:y to the filter chain |
| Remove overlay | crop=in_w:in_h-60:0:60 removes top 60px (macOS recording bar) |
avconvert is macOS-only. On Linux, HDR tone mapping requires ffmpeg built with zimg or libplacebo, which Homebrew/apt default builds lack.--full on retina screen recordings (2880x1800+) produces GIFs over 100MB. Always warn about file size when skipping the scale filter./tmp/gif-output/palette.png and /tmp/gif-output/output.gif but never cleans them up. Repeated runs overwrite, but stale files persist across sessions.scale=640:-1 fails when the source height is odd after scaling. Use scale=640:-2 to force even dimensions.--crop assumes 60px for the macOS recording bar, but this varies by display scale and macOS version. Always probe actual dimensions and let the user confirm the crop value.tools
Search indexed reference codebases (Convex, Expo, Next.js, Better Auth, Remotion, etc) via the qmd MCP query tool. Use when looking up framework APIs, finding code examples in third-party repos, or answering questions about external libraries that aren't in the current working directory.
development
Adds a reference collection to qmd. Accepts a GitHub URL, owner/repo shorthand, or a local directory path. Auto-detects file types, sets ignore globs, indexes with AST chunking, embeds, and verifies. Use when adding a new reference codebase or local notes folder for search.
tools
--- name: techdebt description: Lightweight end-of-session tech debt sweep. Finds duplicated code, dead exports, unused deps, stale TODOs, and bloated files. Use when user asks for "tech debt", "cleanup", "dead code", "unused exports", "code sweep", or end-of-session hygiene. Do NOT use for full codebase audits (use /audit instead). argument-hint: [--dry-run] [path/to/scope] context: fork agent: general-purpose allowed-tools: - Read - Edit - Glob - Grep - Bash(git *) - Bash(wc *) -
development
Use this skill when the user asks to orchestrate a team, use multiple agents, or parallelize work across Claude Code sessions. Decomposes tasks, spawns teammates, and coordinates execution.