gif.js
gif.js is a client-side JavaScript library designed for encoding GIFs directly in the browser. It leverages modern browser APIs like Web Workers and Typed Arrays to perform image processing in the background, aiming for fast performance without blocking the main thread. Despite its original aim for efficiency, the project's last stable version is 0.2.0, released over a decade ago (published in 2016, last commit 2017). This indicates it has a virtually non-existent release cadence and is no longer actively maintained. Its key differentiators at the time were its browser-centric approach with Web Worker offloading, which was a significant performance advantage for client-side GIF generation compared to synchronous methods. It accepts image elements, canvas elements, or canvas contexts as frames. However, newer alternatives often offer better performance via WebAssembly and more modern API designs.
Common errors
-
ReferenceError: GIF is not defined
cause The `gif.js` script was not loaded into the HTML page, or was loaded incorrectly, meaning the global `GIF` constructor is not available.fixEnsure you have `<script src="dist/gif.js"></script>` in your HTML file, typically before your own scripts that try to use `GIF`. Verify the path to `gif.js` is correct. -
Uncaught ReferenceError: GIFWorker is not defined at ... (gif.js:X)
cause The `gif.worker.js` file, which is crucial for the library's functionality, could not be found or loaded by the browser.fixPlace `gif.worker.js` (from the `dist/` folder of the package) in the same directory as your `gif.js` file, or explicitly configure its path using the `workerScript` option when initializing `GIF`: `new GIF({ workerScript: '/path/to/gif.worker.js' })`. -
The image is blank, or frames are incorrect/missing in the output GIF.
cause This can happen due to various reasons, including incorrect frame data, asynchronous image loading, or not specifying `copy: true` when adding frames from a canvas context that changes.fixEnsure all image elements are fully loaded before adding them as frames. If using a canvas context, always add `copy: true` to `addFrame` options: `gif.addFrame(ctx, { copy: true })`. Also, check the `width` and `height` options; if `null`, they are determined by the first frame, which might be an issue if the first frame is invalid or not yet ready.
Warnings
- gotcha The `gif.worker.js` file is essential for the library to function, as it offloads frame processing to Web Workers. If this file is not found at the expected path, GIF generation will fail silently or with worker-related errors.
- breaking The project is abandoned, with the last update over a decade ago. It lacks modern features, performance optimizations found in newer libraries (e.g., WebAssembly-based encoders), and security updates. It may not integrate well with modern JavaScript module systems (ESM) and build tools.
- gotcha gif.js relies on specific browser features: Web Workers, File API, and Typed Arrays. Older browsers or environments that do not fully support these features will prevent the library from working correctly.
- gotcha When adding a frame directly from a CanvasRenderingContext2D (e.g., `ctx`), the `copy: true` option is crucial. If omitted, the library might try to use a reference to the context's current state, which could lead to unexpected or blank frames if the canvas content changes before the worker processes the frame.
Install
-
npm install gif.js -
yarn add gif.js -
pnpm add gif.js
Imports
- GIF
import { GIF } from 'gif.js';<!-- In your HTML: --> <script src="dist/gif.js"></script> <script> var gif = new GIF({ workers: 2, quality: 10 }); </script> - gif.worker.js
<!-- Ensure gif.worker.js is in the same directory as gif.js, or specify workerScript option --> <script src="dist/gif.js"></script> <script> var gif = new GIF({ workerScript: '/path/to/gif.worker.js' // If not in same directory }); </script>
Quickstart
<html>
<head>
<title>GIF.js Quickstart</title>
<script src="https://cdn.jsdelivr.net/npm/gif.js@0.2.0/dist/gif.js"></script>
</head>
<body>
<canvas id="myCanvas" width="200" height="200"></canvas>
<img id="myImage" src="https://via.placeholder.com/200x200.png?text=Frame+1" style="display:none;" alt="Frame 1"/>
<button id="renderGif">Render GIF</button>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const image1 = document.getElementById('myImage');
const gif = new GIF({
workers: 2,
quality: 10,
width: 200,
height: 200,
repeat: 0 // loop forever
});
// Add frame from an image element
gif.addFrame(image1, { delay: 500 });
// Add frame from a canvas element (draw something first)
ctx.fillStyle = 'blue';
ctx.fillRect(50, 50, 100, 100);
gif.addFrame(canvas, { delay: 500 });
// Add another frame by clearing and drawing something else
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI * 2);
ctx.fill();
gif.addFrame(ctx, { copy: true, delay: 500 }); // copy: true is important for context
gif.on('finished', function(blob) {
const img = document.createElement('img');
img.src = URL.createObjectURL(blob);
document.body.appendChild(img);
console.log('GIF rendered!');
});
document.getElementById('renderGif').addEventListener('click', () => {
console.log('Rendering GIF...');
gif.render();
});
</script>
</body>
</html>