A browser GIF is 256 colours and a full bitmap per frame
Versely encodes GIF89a locally, which is why a 10-second 480px clip can be tens of megabytes and why 1080p/60 is refused up front.
Versely encodes GIF89a locally, which is why a 10-second 480px clip can be tens of megabytes and why 1080p/60 is refused up front.
Video to GIF seeks frames on the video element, draws them to canvas, quantises to 256 colours, and packs a real GIF89a with LZW. It is not a renamed PNG sequence. It is not a server encode. The size and the caps are the format.
Each frame is a full bitmap
GIF89a can, in theory, store a frame as a rectangle of changed pixels. This encoder does not. Every frame is written at the full width and height, with disposal set to “do not dispose.” There is no local colour table and no transparency trick to skip unchanged regions. The previous frame stays on screen; the next one is another complete index map of the same canvas.
That is why memory, not disk, is the binding constraint. Encoding holds every frame as a bitmap before LZW even runs. A 1080p 60 fps range would lock the tab. The tool therefore refuses work it cannot finish: duration, frame count, and width are capped before the first seek.
The hard numbers on the page:
- Range cap: 12 seconds. Longer spans error out with the bitmap reason, not a vague “failed.”
- Frame cap: 80. Count is
min(80, max(2, round(span × fps))). - Width choices: 240, 320, or 480 pixels. Default 320.
- Frame rate: 4–12 fps. Default 8. Delay is at least two hundredths of a second per frame.
A 10-second clip at 480px and 8 fps is about 80 frames of full bitmaps. Tens of megabytes is a successful encode. The download reports the blob size; that figure is the container.
The source file may be 2 GB. Only the frame being drawn is decoded; the browser streams the rest. Encoding is the heavy step. The free tools index is full of file jobs that stay on the device. This one blows up RAM if you treat it like an MP4 re-wrap.
One 256-colour table for the whole loop
GIF is 256 colours. The encoder builds one global palette with median-cut over about 8,000 samples taken across every frame, then maps every pixel to the nearest entry. Grain is the palette, not JPEG ringing and not a failed generate. A source with a handful of flat colours survives. A graded 1080p take does not.
Because the table is global, a later frame cannot “spend” extra colours the first frame did not need. A cut from a dark interior to a neon sign shares one 256-slot budget. Posterisation on the second half is the format, not a bug in the slider.
LZW then compresses the index stream. The dictionary clears at 4,096 codes so the code size never exceeds the 12 bits the spec allows. Compression helps when neighbouring pixels share an index. It does almost nothing for photographic noise. Full bitmaps plus a 256-colour table is the megabyte problem.
A Netscape 2.0 loop extension is written so the file repeats. The encoder will not invent in-between frames or sharpen a label. If the range is the wrong shot, the GIF is the wrong shot, looping.
1080p/60 is not on the controls
1080p and 60 fps are refused up front because they are not offered. Width stops at 480. Frame rate stops at 12. Duration stops at 12 seconds. There is no “original resolution” toggle. Asking for 1080p/60 is asking the tab to allocate a stack of full-HD bitmaps at a rate the encoder cannot drain.
The 480px button exists so you can see how bad the size gets. A 10-second 480px clip can already be tens of megabytes. It is not a preview of a later 1080p pass.
Three levers shrink the bitmap stack: a shorter range (the 12-second cap is a ceiling, not a target), a narrower width (240px survives chat apps), and lower fps (4 fps is ugly on a pan and fine on a snap). Video file size will tell you what an MP4 of the same range would weigh. It will not make the GIF smaller. If the job is “cut the MP4” rather than “make a loop,” video trimmer is the other local tool: a MediaRecorder re-encode, not a bitmap per frame.
Do not raise fps to “smooth” a 480px loop. You add frames, you add megabytes, and the palette is still 256 colours.
Size is the format
A huge GIF is not evidence the encode failed. A grainy GIF is not evidence you picked the wrong width. Both are what GIF89a does when the source is a real video. Short, small, limited-colour sources work. A 1080p take does not belong in this format.
Use the tool when you already like the pixels and only the container is wrong: a reaction, a UI flicker, a three-second product turn. Trim the range first. Pick 240 or 320 unless you have a reason to pay for 480. Leave fps at 8 unless the motion is a single snap.
If the loop does not exist yet, encoding will not invent the motion. If the plate is wrong, fix the plate, then encode. Quantising to 256 colours will not rescue a melted label. The output is a .gif named from the source. The constraint you are fighting is GIF, not a hidden quality slider.
FAQ
Why is a 10-second 480px GIF tens of megabytes?
Each frame is a full bitmap, not a delta, and the colour table is 256 entries shared across the loop. Ten seconds at the 480px width is dozens of those bitmaps. LZW helps when the picture is flat. Photographic video does not compress like a UI screenshot.
Can I export 1080p or 60 fps?
No. Width buttons are 240, 320, and 480. Frame rate is 4–12 fps. Duration is capped at 12 seconds and 80 frames. 1080p/60 would lock the tab. The refusal is the cap, not a later error.
Why does the GIF look grainy compared with the MP4?
The palette. Median-cut maps every pixel to one of 256 colours for the whole file. That grain is not JPEG-style artefacting and it is not a failed model. Limited-colour sources look cleaner because they already fit the table.
Does a longer source video make a heavier GIF?
Only if you encode a longer range. The source can be 2 GB; only the current frame is decoded. File weight follows the range you set, the width, and the frame count — the bitmap stack — not the original file size.