compress-gif
A Claude Code plugin that compresses animated GIFs to a target size
(default 200 KB) without changing frame rate, dimensions, frame count,
or visibly degrading the color profile.
Every run executes two independent encoders in parallel —
gifsicle and
gifski — and writes both outputs
side by side so you can pick whichever looks better. They trade off
differently on different content: gifsicle wins on flat-color material
(screen recordings, code demos), gifski wins on gradients and photographic
content.
If the target can't be reached without violating the size-preservation
constraints, the plugin emits a best-effort output and explains the gap
rather than silently dropping frames or resizing.
Quick start
Inside a running Claude Code session, type these three slash commands:
/plugin marketplace add ankshvayt/compress-gif
/plugin install compress-gif@ankshvayt-plugins
/reload-plugins
The first command registers this GitHub repo as a marketplace. The second
installs the plugin from it. The third makes the new skill available
without needing to restart Claude Code.
Then use the skill:
/compress-gif:compress ~/demo.gif # default 200 KB target
/compress-gif:compress ~/demo.gif 150 # custom target in KB
The first time you run it, the plugin checks your environment and walks
you through installing any missing dependencies (gifsicle, optionally
gifski and ffmpeg) with your consent — no surprise brew installs.
Why this plugin
Most "compress a GIF" recipes hit small file sizes by doing things that
quietly degrade the result:
- Dropping frames → playback becomes stuttery.
- Resizing → loses the original dimensions you cared about.
- Transcoding to a different palette space → wrecks the color profile.
This plugin refuses all three. It only tunes knobs that are visually
safe — LZW encoding, perceptual lossy passes, and (as a last resort)
gentle palette reduction down to a floor of 64 colors. If even the
safest aggressive pass can't reach the target, the plugin says so
instead of resorting to the destructive shortcuts above.
It also runs two encoders every time and shows both outputs, because
gifsicle and gifski produce subtly different artifacts and the better
choice depends on the content. Running both costs a few extra seconds
and saves you from guessing.
How it works
The script applies passes in order, stopping the moment the target is
met. Whichever pass settles the result is reported as the "recipe."
gifsicle backend:
- Lossless
-O3 (structural optimization, no quality loss).
--lossy=N ladder: 20 → 40 → 60 → 80 → 120 → 160 → 200. Perceptual
tweak to the LZW step — not a resolution or frame change.
- If still over budget at
--lossy=200, gentle palette reduction:
224 → 192 → 160 → 128 → 96 → 64 colors. Stops at 64 to keep the
color profile recognizable.
gifski backend:
- Read the GIF's per-frame delays via
gifsicle --info, take the
mode, derive an FPS.
- Extract every frame as PNG via
ffmpeg (one-to-one, no rate
conversion).
gifski --quality ladder: 100 → 90 → 80 → 70 → 60 → 50 → 40 → 30
→ 20. Stops as soon as the target is met. pngquant chooses the
palette internally.
Neither backend ever passes --scale, --resize, --width, --height,
--delay, frame slicing, or --every-nth-frame. Frame count and
dimensions in the output are byte-identical to the input; per-frame
delays are preserved exactly by gifsicle and reconstructed at the
detected FPS by gifski.
What's preserved vs. what's tuned
| gifsicle | gifski |
|---|
| Lossless structural optimization | -O3 | (built in) |
| Perceptual quality dial | --lossy 20 → 200 | --quality 100 → 20 |
| Gentle palette reduction (last resort) | --colors 224 → 64 | (pngquant) |
Dimensions (--scale/--resize) | never | never |
Frame count (--every-nth-frame) | never | never |
| Per-frame delay / FPS | unchanged | reconstructed at source FPS |
| Format change (→ MP4, WebP, etc.) | never | never |
Requirements