Blog how-to
How to make a GIF from a video file (the palette pipeline in 2026)
GIFs are 35 years old and still in everyone's chat. The palette pipeline cuts file size by 3-5× over naive conversion. Frame rate, dimensions, dithering — the practical version.
GIFs predate the modern web. They were specified in 1987, hit their cultural peak around 2014, and somehow remain the default animation format in chat platforms three decades after their compression scheme became obsolete. They’re inefficient and ugly compared to modern video, but they autoplay everywhere without a click — and that’s enough to keep them shipping.
This guide is the practical version: when GIF is the right answer (sometimes), what makes a “good” GIF vs a “bad” one technically (the palette pipeline), the math for frame rate vs file size, and the click path in Video Forge’s Smart Actions.
TL;DR
A naive ffmpeg input.mp4 output.gif produces a 5-10 MB GIF for a clip
that should be 1-2 MB. The fix is the palette pipeline — a two-pass
approach where the first pass analyzes the colors in the source and
generates a custom 256-color palette, and the second pass encodes the
GIF using that palette with dithering. This cuts file size 3-5× at
identical perceived quality.
For chat-share GIFs (Discord, Slack, Reddit, Twitter):
| Spec | Value |
|---|---|
| Frame rate | 10-15 fps |
| Dimensions | 480px wide (or narrower) |
| Palette | Generated per-clip, 256 colors |
| Dither | sierra2_4a (the ffmpeg default; good quality, fast) |
| Target file size | Under 8 MB for Reddit, under 8 MB for Slack |
In Video Forge: Tools → Make GIF → pick quality level (Low / Medium / High). The High quality option runs the palette pipeline; Low and Medium take shortcuts for speed.
What makes GIFs technically bad
GIF’s compression has three structural weaknesses that show up immediately as oversized files and visible artifacts:
- 256 colors per frame, max. Most real-world video has tens of thousands of distinct colors per frame (gradients, lighting, noise). GIF has to quantize all of those down to 256, which creates banding in skies, faces, and gradients.
- No inter-frame compression. Modern video codecs only encode the differences between frames (motion vectors + residuals). GIF encodes each frame as a separate image, then compresses with LZW. Anything with motion is brutally inefficient.
- LZW compression is 1985-era. LZW was good for text and simple graphics in 1985 but is dominated by every modern compression scheme for natural images. PNG with the same color depth compresses significantly better; modern video codecs are in a different league.
The combined effect: a 5-second 480×270 clip is roughly:
| Format | Typical size | Quality |
|---|---|---|
| H.264 MP4 | 250 KB | Sharp, full color |
| WebM (VP9) | 200 KB | Sharp, full color |
| AV1 | 180 KB | Sharp, full color |
| Naive GIF | 4-6 MB | Banded, color-shifted |
| Palette-pipeline GIF | 1-2 MB | Slight banding, acceptable |
The palette pipeline doesn’t fix GIF’s fundamental issues, but it cuts the file size in half by giving the encoder a per-clip palette optimized for the actual colors present.
The palette pipeline explained
The default ffmpeg conversion looks like this:
ffmpeg -i input.mp4 output.gif
That produces a GIF using ffmpeg’s built-in generic palette — a 256-color palette derived from a standard color space rather than the actual clip. For most real video, that palette is wrong for half the scene (no skin tones, no specific blues, etc.), forcing visible color quantization.
The palette pipeline runs two ffmpeg invocations:
# Pass 1: analyze the source and write an optimized palette
ffmpeg -i input.mp4 -vf "fps=15,scale=480:-1:flags=lanczos,palettegen=max_colors=256" palette.png
# Pass 2: encode the GIF using the custom palette + dithering
ffmpeg -i input.mp4 -i palette.png -filter_complex \
"fps=15,scale=480:-1:flags=lanczos[v];[v][1:v]paletteuse=dither=sierra2_4a" \
output.gif
What each piece does:
fps=15— drops the frame rate to 15 (from whatever the source is). Most chat-share GIFs look fine at 10-15 fps.scale=480:-1— resizes width to 480, scales height proportionally.flags=lanczos— high-quality resampling filter. Worth it for the 3-5% file size win over the default bilinear.palettegen=max_colors=256— generates an optimized 256-color palette based on the actual colors in the source video. This is the magic step.paletteuse=dither=sierra2_4a— uses the custom palette and applies Sierra dithering to make the limited color range look less banded.
The result is typically 3-5× smaller than the naive conversion at identical visual quality. Sometimes the visual quality is better, because the custom palette actually contains the colors present in the clip.
Frame rate vs file size
GIF file size scales close to linearly with frame rate. Dropping from 30 fps to 15 fps roughly halves the file size; dropping to 10 fps cuts it by another third.
The eye reads animation as smooth above ~12 fps, and reads it as plausibly fluid at 24 fps (standard film). For GIFs specifically:
| Frame rate | Use case | File size impact |
|---|---|---|
| 10 fps | Reaction GIFs, dialogue, slow movement | Baseline (smallest) |
| 12 fps | Default for most chat shares | +20% |
| 15 fps | Sports, action, fast movement | +50% |
| 24 fps | Cinematic, smooth | +140% |
| 30 fps | Almost never needed for GIF | +200% |
For Discord / Slack / Reddit / Twitter shares, 10-12 fps is the right default. The motion looks fine and the file is small enough not to trigger upload caps.
Dimensions
Most chat platforms display GIFs at a fixed width — typically 400-500 pixels. Encoding wider than that is wasted bytes. The right widths:
| Platform | Display width | Encode at |
|---|---|---|
| Discord | ~400px | 480px (small headroom) |
| Slack | ~360px | 400px |
| Twitter / X | up to 1080px | 600-720px |
| up to 1080px | 600-720px | |
| Email signatures / docs | varies wildly | 320-480px |
Heights scale proportionally. The 480px-wide / -1 (auto-height) is the right default for chat platforms.
Dithering
Dithering is the technique of placing pixels of different colors next to each other so the eye blends them into a third color the palette doesn’t actually contain. It’s how GIF (and 256-color GIFs specifically) manage to show gradients and skin tones that don’t quantize cleanly to a 256-color set.
Without dithering, you get visible banding — discrete jumps between palette colors in any smooth region. With it, you get a soft, slightly noisy texture that the eye reads as a continuous gradient.
ffmpeg’s dithering options for paletteuse:
none— no dithering, smallest file, most banding.bayer— ordered dithering, fast, visible texture pattern.floyd_steinberg— high quality, slow.sierra2/sierra2_4a— modern error-diffusion, good quality at reasonable speed. The ffmpeg default.
For most chat-share GIFs, sierra2_4a is the right choice. Video Forge
uses it by default.
The step-by-step in Video Forge
Make GIF is a smart action — runs outside the main job queue because it’s a single fast operation:
- Drop your video (or have one loaded).
- Open Tools → Make GIF.
- Pick a quality level:
- Low — generic palette, 320px wide, 10 fps. Fastest, largest file for the visual quality.
- Medium — palette pipeline, 400px wide, 12 fps. Good balance.
- High — palette pipeline + lanczos resampling, 480px wide, 15 fps. Best quality, ~2x the encode time of Low.
- (Optional) Trim the clip — most GIFs should be 2-5 seconds. Trim before generating.
- Click Make GIF. Output suffixed
_anim.giflands next to the source.
The size estimate is shown live as you change quality and dimensions. A 5-second 480p source clip typically lands at 1-2 MB on High, 600 KB on Medium, 400 KB on Low.
Doing it with ffmpeg directly
The palette pipeline:
# Pass 1: palette
ffmpeg -i input.mp4 -vf "fps=12,scale=480:-1:flags=lanczos,palettegen=max_colors=256" -y palette.png
# Pass 2: GIF
ffmpeg -i input.mp4 -i palette.png -filter_complex \
"fps=12,scale=480:-1:flags=lanczos[v];[v][1:v]paletteuse=dither=sierra2_4a" \
-y output.gif
For a quick-and-dirty single-command version that produces a passable GIF without the palette pipeline:
ffmpeg -i input.mp4 -vf "fps=12,scale=480:-1:flags=lanczos" -y output.gif
That’s 2-3x larger than the palette-pipeline version but takes one command instead of two. Acceptable for one-off conversions where speed matters more than file size.
When NOT to use GIF
GIF is the wrong answer most of the time in 2026. The cases where it’s still right:
| Use case | Why GIF wins |
|---|---|
| Discord / Slack reactions | Autoplay inline; video requires click |
| Reddit / X inline embeds | Same — autoplay without click |
| Docs / README files | Many docs platforms render GIF inline; video tag is unreliable |
| Email signatures | Most clients block video |
| iOS keyboard / chat sticker | GIF is the format keyboards understand |
For these cases, do the palette pipeline and ship.
For everything else — web pages, social posts, blog hero animations, landing-page eye-candy — short MP4 or WebM is dramatically better: smaller, sharper, and autoplay-able with the right HTML attributes.
The trade is essentially: do you control the playback environment? If yes, video. If no (someone else’s chat, someone else’s docs), GIF.
Common mistakes
- Not running the palette pipeline. This is the single biggest file-size win and most online “convert MP4 to GIF” tutorials skip it.
- Leaving the source frame rate. 60 fps GIFs are five times larger than 12 fps GIFs for content that reads fine at 12 fps.
- Not scaling down. Encoding at the source 1080p width and relying on display-time downscaling is brutally wasteful.
- Optimizing for video quality. GIFs aren’t going to look like video. The goal is “small file that autoplays inline.” Accept visible color quantization; it’s the format.
- Picking GIF when MP4 would do. Many chat platforms now autoplay
inline video — Discord does for
.mp4. Check first.
What about WebP?
WebP is the modern “GIF replacement” format — supports animation, modern compression, much smaller files at the same visual quality.
Where it works: Discord, Slack, most modern browsers, every chat
platform that doesn’t specifically reject .webp. Where it doesn’t:
iOS keyboards (still expect .gif), older email clients, some
documentation generators.
For chat sharing specifically, WebP is a 30-60% file size win over GIF. Worth using when the recipient platform supports it. Video Forge generates WebP as an option in the Make GIF panel for Discord-friendly sharing.
FAQ
How do I convert a video to a GIF? The fastest sensible way: run the ffmpeg palette pipeline (two-pass — generate palette, then encode with that palette + dithering). Cuts file size 3-5x vs the naive single-command version. Or use a tool like Video Forge’s Tools → Make GIF panel.
Why are GIFs so much larger than equivalent videos? GIF uses 1985-era LZW compression, is limited to 256 colors per frame, and has no inter-frame motion compensation. Modern video codecs use both spatial and temporal compression and 16M+ colors. A 5-second clip is 10× larger as GIF than as H.264 MP4.
What’s the best frame rate for a GIF? 10-15 fps for chat-share GIFs. The eye reads animation as smooth above ~12 fps, and dropping from 30 fps halves file size at no perceptual cost.
Should I still use GIF in 2026? For inline chat / Reddit / X autoplay and documentation pages: yes. For everything else: short MP4 or WebM is smaller, sharper, and more efficient.
Does Video Forge generate optimized GIFs? Yes — the Make GIF smart action’s “High” quality runs the palette pipeline with Sierra dithering. Output is 3-5x smaller than naive conversion at equal visual quality.
Video Forge bundles GIF generation as a smart action with three quality levels — High runs the full palette pipeline for ~2 MB GIFs that don’t blow Discord’s cap. 10 conversions are free on macOS and Windows; ffmpeg is bundled. See also the audio extraction guide for the other smart action, or the Discord compression guide for the video-output version of the same chat-sharing problem.