How Animated GIFs Actually Work — From Canvas Frames to LZW Compression
The GIF format is 39 years old and still everywhere. Here's what happens between clicking 'Export' and getting a file — frame capture, color quantization, LZW compression, and why your GIF is 4MB.
Why GIFs Still Exist
The Graphics Interchange Format was created by CompuServe in 1987 [CompuServe, 1987]. It supports animation, transparency, and lossless compression. It is limited to 256 colors per frame. It has no audio. It produces large files. By every technical measure, it should have been replaced decades ago.
And yet: Discord, Slack, iMessage, Twitter, Reddit, and email all support GIFs natively. GIPHY serves over 10 billion GIFs per day [GIPHY, 2020]. The format persists because it works everywhere, requires no codec, and plays automatically. No other format has this combination of universal support and zero-friction playback.
Understanding how GIFs work is useful beyond trivia — it explains why your exported GIF is 4MB, why gradients look banded, and what you can do about it.
Step 1: Frame Capture
An animated GIF is a sequence of images (frames) displayed in order with a delay between each. To create one from a canvas animation, you need to capture the canvas state at regular intervals.
In a browser, this means reading pixel data from an HTML <canvas> element at each frame time — typically via canvas.toDataURL() or ctx.getImageData(). The animation is advanced to the target time, the canvas is rendered, and the pixels are captured. The key constraint: you must wait for the browser's paint cycle (requestAnimationFrame) before reading pixels, otherwise you capture a stale buffer.
A typical GIF at 15 FPS for 3 seconds requires 45 frame captures. At 1080×1080 resolution, each frame is approximately 4.7 million pixels.
Step 2: Color Quantization
GIF supports a maximum of 256 colors per frame, stored in a color table (palette). A typical canvas frame has thousands of distinct colors. Reducing to 256 without visible degradation is the hardest part of GIF encoding.
The standard approach is the median cut algorithm [Heckbert, 1982]: sort all pixels by their reddest channel, split the list at the median, repeat for green and blue, recursively dividing color space into 256 regions. Each region's average becomes a palette entry. This is what gif.js — the library PinePaper uses — implements in Web Workers for parallelism [Rubaxa, gif.js].
Color quantization is why GIFs handle flat-color graphics well but struggle with photographs and gradients. A gradient across 1080 pixels might use 500+ distinct colors. Compressing to 256 produces visible banding — discrete steps where the gradient should be smooth.
What you can do about it: Use fewer colors in your design. Flat shapes, solid fills, and text quantize well. Smooth gradients and photographic textures don't. If your GIF has banding, simplify the palette, not the resolution.
Step 3: LZW Compression
Each frame's pixel indices (references into the 256-color palette) are compressed using Lempel-Ziv-Welch (LZW) compression [Welch, 1984]. LZW builds a dictionary of repeated byte sequences as it scans the data. When it encounters a sequence it has seen before, it outputs the dictionary index instead of the raw bytes.
This means GIF compression is most effective when there are large areas of repeated color — solid backgrounds, flat shapes, text on a uniform surface. Complex textures with pixel-level variation produce poor compression ratios because the LZW dictionary finds few repeated sequences.
Practical implication: A 1080×1080 GIF of white text on a black background might compress to 200KB. The same resolution GIF of a complex photograph might be 8MB. The file size depends more on visual complexity than on resolution or frame count.
Step 4: Frame Disposal and Optimization
GIF frames can specify a disposal method: whether to clear the canvas before drawing the next frame, leave the previous frame visible, or restore to the background. Smart GIF encoders use frame differencing — encoding only the pixels that changed between frames, not the entire frame.
If your animation has a static background with a small moving element, an optimized GIF encodes the background once and only updates the region where the element moved. This dramatically reduces file size. PinePaper's encoder uses gif.js which applies this optimization automatically.
The Numbers
For a typical PinePaper animation (1080×1080, 15 FPS, 3 seconds, dark background with animated text):
| Component | Size |
|---|---|
| Raw frames (45 × 4.7M pixels × 3 bytes) | ~634 MB |
| After quantization (256 colors, 1 byte/pixel) | ~211 MB |
| After LZW compression | ~2-4 MB |
| With frame differencing | ~1-2 MB |
The compression ratio from raw to final is approximately 300:1 to 600:1. Most of this comes from color quantization (3:1) and LZW (50:1 to 100:1).
When to Use GIF vs Other Formats
| Format | Best for | Limitation |
|---|---|---|
| GIF | Universal support, auto-play, messaging apps | 256 colors, large files, no audio |
| WebM (VP9) | Best quality, smallest files, web | Limited support in Safari, iMessage |
| MP4 (H.264) | Social media, video players | Requires codec, no transparency |
| APNG | Full color animation with transparency | Limited support in older browsers |
GIF is the right choice when you need universal compatibility and auto-play. For quality or file size, WebM or MP4 are better.
Try It
Open PinePaper Studio, create a design, and export as GIF. Observe how file size changes as you:
- Increase frame count (more frames = larger file, proportionally)
- Add gradients (poor quantization = larger file)
- Use solid colors (good quantization = smaller file)
- Increase canvas size (more pixels per frame = larger file)
Each change is a measurement of the compression pipeline. You're not just making a GIF — you're observing how information theory applies to your design.
References
- CompuServe (1987). Graphics Interchange Format Specification, Version 87a.
- GIPHY (2020). GIPHY Annual Report: 10 Billion Daily Serves.
- Heckbert, P. (1982). Color Image Quantization for Frame Buffer Display. Computer Graphics (SIGGRAPH), 16(3), 297-307.
- Rubaxa. gif.js — JavaScript GIF encoder using Web Workers. github.com/jnordberg/gif.js.
- Welch, T.A. (1984). A Technique for High-Performance Data Compression. IEEE Computer, 17(6), 8-19.
PinePaper's GIF export is free — no watermark, no signup. Open pinepaper.studio/editor and export your first animation.
Ready to create?
Start making animated GIFs, videos, and graphics — free, no signup.
Open PinePaper Editor