How to convert video to high-quality gif
- Step 1Pre-trim your clip if it is longer than a few seconds — GIF has no audio and balloons in size with duration — a 256-colour frame is heavy. The GIF tool converts the whole clip you give it (there is no in-tool trim). Cut to the exact moment first with the lossless trimmer, which stream-copies at a keyframe with no re-encode.
- Step 2Drop the trimmed clip onto the converter — Accepts
.mp4,.mov,.mkv,.webm,.avi,.m4v, and.ts. The file is read into FFmpeg.wasm in your browser — nothing uploads. Free tier allows one file up to 1 GB; Pro allows 5 files up to 10 GB each. - Step 3Set the width to your target display size — Default is 480 px wide (height auto). For a README or chat embed, 480–600 px is plenty. Going above ~720 px multiplies the colour count per frame and the file size — keep it as small as the destination allows.
- Step 4Set the frame rate for the motion you need — Default 15 FPS reads as smooth motion at GIF sizes. Drop to 10 for talking-head or slow pans to shrink the file; the slider caps at 30. Every extra frame is a full 256-colour image, so FPS is the single biggest lever on file size after width.
- Step 5Run the two-pass encode — Pass 1 generates the per-clip palette PNG with
palettegen=stats_mode=diff; pass 2 maps frames onto it withpaletteuseand Bayer dithering. The render dashboard shows progress; longer or higher-resolution clips take longer because every frame is sampled twice. - Step 6Download and check the file size against the destination — The result is a single
.gif. If it is too large for Slack (no inline-autoplay over a size threshold) or a README, lower the width or FPS and re-run, or convert to animated WebP which is roughly 30% of the GIF size at the same quality.
What the converter actually controls
The complete option surface for video-to-gif, read from the tool client and processor. There are exactly two controls — no trim, crop, loop-count, or caption inside this tool.
| Control | Range | Default | What it changes |
|---|---|---|---|
| FPS | 5 – 30 | 15 | Frames sampled per second via the fps= filter. Higher = smoother motion and a much larger file (each frame is a full 256-colour image) |
| Width (px) | 120 – 1080 | 480 | Output width via scale=W:-1:flags=lanczos. Height auto-scales to preserve aspect ratio |
| Height | auto | -1 | Not a control — computed from width to keep the source aspect ratio. You cannot set a fixed height here |
| Palette | fixed | 256 colours | Always two-pass palettegen=stats_mode=diff → paletteuse=dither=bayer:bayer_scale=5. Not user-adjustable |
The two-pass pipeline, step by step
Exactly what FFmpeg.wasm runs per conversion. Both passes use Lanczos scaling and the chosen FPS.
| Pass | Filter chain | Output | Why |
|---|---|---|---|
| 1 · Palette | fps=FPS,scale=W:-1:flags=lanczos,palettegen=stats_mode=diff | 256-colour palette PNG (temporary) | stats_mode=diff weights colours by what changes between frames, so motion areas get more palette budget |
| 2 · Encode | fps=FPS,scale=W:-1:flags=lanczos[v];[v][1:v]paletteuse=dither=bayer:bayer_scale=5 | Final .gif | Maps every frame onto the custom palette with Bayer ordered dithering to hide the 256-colour ceiling |
Free vs paid limits (video family)
Source-clip size and batch limits by tier, from lib/tier-limits.ts. Limits are file-size and file-count — there is no duration cap.
| Tier | Max source file | Files at once |
|---|---|---|
| Free | 1 GB | 1 |
| Pro | 10 GB | 5 |
| Pro-media | 100 GB | 50 |
| Developer | 100 GB | unlimited |
Cookbook
Concrete recipes for getting a sharp, small GIF out of the two-pass converter. Each shows the settings and the FFmpeg pipeline JAD runs under the hood.
Gradient-heavy clip that banded in other converters
A sunset pan that turned into visible colour stripes in a single-pass online converter. The two-pass palette samples the actual sunset colours, so the gradient stays smooth.
Settings: Width 480, FPS 15
Pass 1 (palette from your clip):
-vf fps=15,scale=480:-1:flags=lanczos,palettegen=stats_mode=diff
Pass 2 (map frames onto it):
-lavfi fps=15,scale=480:-1:flags=lanczos[v];
[v][1:v]paletteuse=dither=bayer:bayer_scale=5
Result: out.gif — gradient banding gone, colours sampled
from the sunset rather than a generic web palette.Shrink a too-large GIF without re-shooting
First export was 12 MB. Lower width and FPS, re-run — file size drops roughly with (width^2 x fps).
First export: Width 720, FPS 24 -> ~12 MB Retry: Width 480, FPS 12 -> ~3-4 MB Why: GIF size scales with pixels-per-frame (width^2) and frame count (fps x seconds). Halving width and fps cuts size by roughly 4x x 2x = ~8x in the best case.
UI screen-recording where text must stay readable
Lanczos scaling keeps text edges crisp on downscale. Keep width close to the native capture width so glyphs don't soften.
Capture width 1280 -> set GIF Width 640 (half) FPS 12 (UI cursor motion reads fine at 12) Keeps scale=640:-1:flags=lanczos -> sharp text. Going to Width 320 would soften small fonts; keep the GIF width >= half the captured width for legible UI.
Trim-then-GIF for a 2-second reaction moment
The GIF tool has no trim. Cut the exact 2 seconds first with the lossless trimmer, then convert only that clip.
Step 1: lossless-trimmer -> reaction_2s.mp4
(stream-copy, snaps to nearest keyframe)
Step 2: video-to-gif on reaction_2s.mp4
Width 400, FPS 15 -> reaction.gif
Result: a tiny GIF because only 2 seconds x 15 fps
= ~30 frames are encoded, not the whole source.Compare GIF vs animated WebP for a web embed
When the destination is a modern browser (not legacy chat), WebP is ~30% of the GIF size at the same quality. Use the GIF only where WebP isn't supported.
Same clip, Width 480, FPS 15: video-to-gif -> clip.gif (baseline size) video-to-webp -> clip.webp (~30% of the GIF) Use GIF for: Slack/Discord/Reddit/older chat, README Use WebP for: website hero, Telegram, Signal, modern web
Edge cases and what actually happens
GIF is larger than the source MP4
ExpectedGIF is an old lossless-ish 256-colour-per-frame format with no inter-frame video compression beyond simple frame differencing. A 5 MB H.264 MP4 can easily become a 15 MB GIF. This is normal — lower the width and FPS, or use video-to-webp for a 30%-of-GIF result.
Clip has audio
By designGIF has no audio track, so any sound in the source is silently dropped. There is no warning because GIF cannot carry audio — if you need sound, keep the clip as video or use video-to-webp (also silent) and pair it with the original clip.
You wanted to trim but converted the whole clip
By designThis tool has only FPS and Width controls — no in/out points. It converts the entire file you drop in, so a 2-minute clip becomes a huge GIF. Trim first with the lossless trimmer or video-splitter, then convert the short clip.
Set a width above 1080
ClampedThe width control is capped at 1080 px. GIF was never meant for large frames — past a few hundred pixels the file size becomes impractical for chat or README embeds. If you genuinely need a large animated loop, animated WebP supports larger frames far more efficiently.
Fine dithering noise looks grainy on flat colour
Expecteddither=bayer:bayer_scale=5 adds an ordered dither pattern to mask the 256-colour limit; on large flat regions (a solid brand colour) the pattern can read as faint texture. This is the standard trade-off for smooth gradients elsewhere — the dither setting is fixed, so reduce the colour complexity of the source or accept the slight grain.
Source codec FFmpeg.wasm can't decode
Decode errorCommon containers (.mp4, .mov, .mkv, .webm, .avi, .m4v, .ts) decode fine. An exotic or DRM-protected codec inside the container can fail the first pass with a decode error. Re-encode the source to standard H.264 MP4 first using the transcoder, then convert.
Very long clip at high FPS is slow
ExpectedBoth passes sample every frame, so a long clip at 30 FPS does roughly double the work of the same clip at 15 FPS. FFmpeg.wasm is CPU-bound in the browser. Lower the FPS or trim shorter for faster turnaround — there is no size cap forcing this, just wall-clock time.
Variable-frame-rate (VFR) source
NormalisedThe fps= filter resamples to a constant frame rate, so VFR phone recordings (which vary their frame rate to save power) are normalised to your chosen FPS. Motion stays correct; you don't need to convert VFR to CFR beforehand.
Transparent / alpha source
FlattenedGIF supports only 1-bit (on/off) transparency, not the smooth alpha of WebM/ProRes. Semi-transparent edges flatten against an opaque background and can show hard fringing. For true smooth alpha, use video-to-webp, which preserves a full alpha channel.
Frequently asked questions
What makes this 'high quality' compared to other GIF converters?
Two things, both verifiable in the pipeline: a per-clip palette and Lanczos scaling. Most quick converters use a single generic 256-colour palette for every video, which bands gradients. JAD runs palettegen=stats_mode=diff to build a palette from your actual clip's colours, then paletteuse with Bayer dithering, and scales with flags=lanczos so downscaled text and edges stay crisp.
What options can I actually change?
Exactly two: FPS (5–30, default 15) and Width in pixels (120–1080, default 480). Height auto-scales to preserve aspect ratio. The palette, dithering, and scaler are fixed at the high-quality settings — there are no quality sliders, loop-count controls, or trim points in this tool.
Does the GIF loop?
Yes — GIFs are inherently looping by default, and every platform that autoplays GIFs (Slack, Discord, Reddit, GitHub) loops them. There is no loop-count control in this tool; the output is a standard looping GIF.
Why is my GIF bigger than the original video?
Because GIF stores each frame as a near-lossless 256-colour image with only basic frame differencing — it has nothing like H.264's motion compression. A small MP4 routinely becomes a larger GIF. Lower the width and FPS to shrink it, or convert to animated WebP, which is roughly 30% of the GIF size at the same visual quality.
How do I trim the clip before converting?
Trim first, then convert — this tool has no in/out points. Use the lossless trimmer for an instant keyframe cut with no re-encode, or video-splitter to slice a long recording. Feed the short clip into the GIF tool so only the frames you want get encoded.
Can I add captions to the GIF?
Not in this tool. Burn captions into the video first with the subtitle burner (it hard-renders an SRT/VTT into the frames), then convert the captioned video to GIF here. See the captioned-GIF recipe.
What input formats does it accept?
MP4, MOV, MKV, WebM, AVI, M4V, and TS. They are decoded by FFmpeg.wasm in your browser. If an exotic codec inside the container fails to decode, re-encode to standard H.264 MP4 with the transcoder first.
Is my video uploaded anywhere?
No. The entire two-pass conversion runs in your browser through FFmpeg.wasm. Your clip is read locally, processed locally, and the GIF is downloaded locally — nothing is sent to a server, which is why there is no upload progress bar and the size limit is your machine, not a network.
What's the largest video I can convert?
Free tier allows one source file up to 1 GB; Pro is 10 GB and 5 files; Pro-media is 100 GB and 50 files; Developer is 100 GB with unlimited files. There is no duration cap — limits are file-size and file-count only. Practically, you'll hit an impractical GIF size long before the source limit.
Why does FFmpeg run twice?
Pass one analyses your clip and writes a 256-colour palette tuned to its colours (palettegen=stats_mode=diff). Pass two re-reads the clip and maps every frame onto that palette (paletteuse). A single pass would have to guess a generic palette before seeing the colours, which is exactly what causes banding in lesser converters.
Should I use GIF or WebP?
Use GIF where you need maximum compatibility — Slack, Discord, Reddit, older chat clients, and GitHub READMEs all autoplay GIF. Use animated WebP for websites and modern messengers (Telegram, Signal): it's roughly 30% of the GIF file size at the same quality and supports full alpha.
Can I make the GIF smaller without losing the moment?
Yes — lower the FPS before the width. Dropping from 24 to 12 FPS halves the frame count with little perceptual loss on most motion, and is usually less visible than shrinking the width. For UI recordings, 10–12 FPS reads fine. Combine a modest FPS with a 480 px width for a chat-friendly file.
Privacy first
Every JAD Video tool runs entirely in your browser via WebCodecs and FFmpeg (WebAssembly). Your video files never leave your device — verified by zero outbound network requests during processing.