| name | gif-editing |
| description | Use when a user wants simple GIF edits: static overlays, crop/resize, palette or duration fixes, optimization, frame extraction, preview/debug exports, or converting local media into a GIF; not for pinned/snap-to-object tracking. |
| version | 1.1.0 |
| author | Hermes Agent |
| license | Apache-2.0 |
| platforms | ["linux","macos","windows"] |
| metadata | {"hermes":{"tags":["GIF","Media","Editing","Pillow","FFmpeg","Optimization"],"related_skills":["gif-search","gif-pinned-overlay-tracking","slack-gif-creator","youtube-video-download"]}} |
GIF Editing
Overview
Lean router skill for ordinary GIF edits. Use it for static overlays, cropping, resizing, palette cleanup, duration/loop fixes, frame extraction, optimization, and preview/debug exports.
Do not let this skill compete with the tracked-overlay workflow. If the user says the asset should be pinned, snapped, attached, follow an object, follow a pixel signature, or scale with a moving area, load gif-pinned-overlay-tracking and use its canonical scripts.
Routing
| User need | Use |
|---|
| Find a GIF from Tenor/Giphy | gif-search |
| Download video/media from a URL | youtube-video-download or yt-dlp directly |
| Static logo/sticker/watermark on every frame | this skill |
| Crop, resize, optimize, convert, extract frames | this skill |
| Logo/sticker follows a moving object | gif-pinned-overlay-tracking |
| Slack-specific GIF sizing or emoji constraints | slack-gif-creator |
Core workflow
- Preserve the source; write a new output path.
- Normalize the source locally.
- Web page URLs are often not media URLs; resolve them before editing.
- If converting video to GIF, use an ffmpeg palette pass rather than a one-shot conversion.
- Prepare overlays as RGBA and preserve transparency until final quantization.
- Edit frame-by-frame with Pillow for per-frame compositing, or ffmpeg for format/size/fps operations.
- Preserve frame durations and loop count unless the user asks to change speed.
- Export debug artifacts when placement is uncertain: first frame, mid frame, contact sheet, or preview HTML.
- Verify output before reporting success.
Useful commands
Resolve a page URL to media when needed:
yt-dlp --no-playlist --force-overwrites -o 'gif_work/source.%(ext)s' '<url>'
Video to GIF with a palette pass:
ffmpeg -y -i source.mp4 -vf "fps=15,scale=640:-1:flags=lanczos,palettegen" palette.png
ffmpeg -y -i source.mp4 -i palette.png -lavfi "fps=15,scale=640:-1:flags=lanczos[x];[x][1:v]paletteuse" output.gif
Use one-off Python dependencies without mutating the user's environment:
uv run --with pillow python your_edit_script.py
Pitfalls
- Tenor/Giphy page URLs are not always direct GIF URLs. Resolve/download the underlying media first.
- GIF variants can have different dimensions. Inspect frame 0 before choosing coordinates.
- For transparent overlays, composite in RGBA and only quantize at export; otherwise logos can gain white/black boxes or jagged edges.
- Preserve durations. Re-saving every frame at a default duration can make the GIF too fast or too slow.
- Do not use keyframe interpolation or static coordinates when the user asked for a true snap/pin to a moving object; route to
gif-pinned-overlay-tracking.
- In CLI sessions, report absolute paths plainly. Do not emit platform-specific
MEDIA:/path tags.
Verification checklist
- Output exists and is separate from the source.
- Dimensions, frame count, durations, and loop match the intended result.
- Overlay transparency survived.
- Visual placement is checked on frame 0 and at least one mid/late frame.
- File size is reasonable for the target platform.
- Any generated debug/preview path is reported plainly.
Script ownership
This skill intentionally has no bundled tracking scripts. The canonical script-backed workflow for object-following overlays lives in gif-pinned-overlay-tracking. Keep deterministic tracking machinery there so public packages do not duplicate and rot.