{"id":10947,"library":"gifuct-js","title":"Efficient JavaScript GIF Parser and Decoder","description":"gifuct-js is a lean and efficient JavaScript library specifically designed for parsing and decoding GIF files. It aims to overcome the inefficiencies and complexities found in older GIF processing libraries by providing a streamlined API focused solely on extracting raw frame data. The current stable version is 2.1.2, last updated in November 2021. The library prioritizes performance, making it suitable for resource-constrained environments like mobile hybrid applications, as exemplified by its original development for the Ruffle project. It operates by consuming GIF files as `Uint8Array` buffers and leverages `js-binary-schema-parser` internally for robust parsing. A key differentiator is its 'decode-only' approach; unlike many alternatives, it deliberately omits any built-in drawing or rendering logic, empowering developers to integrate GIF data with their preferred rendering engines (e.g., Canvas, WebGL). While it can optionally generate canvas-ready `Uint8ClampedArray` patches, it leaves full control over animation and display to the implementer. The project maintains a stable release cadence, with updates primarily focusing on parsing accuracy and performance enhancements rather than frequent new feature introductions.","status":"active","version":"2.1.2","language":"javascript","source_language":"en","source_url":"https://github.com/matt-way/gifuct-js","tags":["javascript","gif","parser","typescript"],"install":[{"cmd":"npm install gifuct-js","lang":"bash","label":"npm"},{"cmd":"yarn add gifuct-js","lang":"bash","label":"yarn"},{"cmd":"pnpm add gifuct-js","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Internal dependency for parsing the GIF binary structure.","package":"js-binary-schema-parser","optional":false}],"imports":[{"note":"Primary entry point for parsing a GIF `ArrayBuffer`. The library primarily uses named exports. `gifuct-js` ships with TypeScript types.","wrong":"const parseGIF = require('gifuct-js').parseGIF","symbol":"parseGIF","correct":"import { parseGIF } from 'gifuct-js'"},{"note":"Processes the parsed GIF structure into an array of frame data. The `buildPatch` argument (second parameter) determines if `Uint8ClampedArray` patches suitable for `CanvasRenderingContext2D.putImageData()` are generated. Understanding GIF disposal methods and `transparentIndex` is crucial for correct rendering, especially when `buildPatch` is `true` as it makes assumptions about transparency handling.","wrong":"const decompressFrames = require('gifuct-js').decompressFrames","symbol":"decompressFrames","correct":"import { decompressFrames } from 'gifuct-js'"},{"note":"TypeScript users can import these types for better type checking when working with parsed GIF data and individual frames.","symbol":"GIF and Frame types","correct":"import type { GIF, Frame } from 'gifuct-js'"}],"quickstart":{"code":"import { parseGIF, decompressFrames } from 'gifuct-js';\n\nconst gifURL = 'https://i.imgur.com/DrxJ5d8.gif'; // Replace with your GIF URL\n\nasync function loadAndDecompressGif(url) {\n  try {\n    const resp = await fetch(url);\n    if (!resp.ok) {\n      throw new Error(`HTTP error! status: ${resp.status}`);\n    }\n    const arrayBuffer = await resp.arrayBuffer();\n    const gif = parseGIF(arrayBuffer);\n    // Set buildPatch to true to get canvas-ready Uint8ClampedArray patches\n    const frames = decompressFrames(gif, true);\n\n    console.log('GIF parsed successfully. Number of frames:', frames.length);\n    // Example of accessing frame data\n    if (frames.length > 0) {\n      const firstFrame = frames[0];\n      console.log('First frame dimensions:', firstFrame.dims);\n      console.log('First frame delay (ms):', firstFrame.delay);\n      // firstFrame.patch is a Uint8ClampedArray if buildPatch was true\n      // firstFrame.pixels is an array of color table indices\n    }\n    return frames;\n  } catch (error) {\n    console.error('Failed to load or decompress GIF:', error);\n    return [];\n  }\n}\n\nloadAndDecompressGif(gifURL).then(frames => {\n  // Now you can work with the decompressed frames, e.g., draw them to a canvas\n  // For full rendering example, refer to the library's demo.\n});","lang":"typescript","description":"Demonstrates how to fetch a GIF from a URL, parse its `ArrayBuffer`, and decompress its frames (with patches) for further processing."},"warnings":[{"fix":"Ensure your GIF source (e.g., `fetch().arrayBuffer()`, `XMLHttpRequest.responseType = 'arraybuffer'`) provides an `ArrayBuffer` response type before passing it to `parseGIF`.","message":"The library expects GIF data as a `Uint8Array` or `ArrayBuffer`. Passing other formats (e.g., base64 strings, Blobs directly) will result in parsing errors.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"For precise control over transparency and blending, set `buildPatch: false` and manually process the `pixels`, `colorTable`, `transparentIndex`, and `disposalType` properties of each frame to render them onto your canvas. Refer to the GIF specification for detailed disposal method rules.","message":"When `decompressFrames` is called with `buildPatch: true`, it generates `Uint8ClampedArray` patches. This process makes assumptions about transparency handling and disposal methods, which might not always align with complex GIF specifications or desired rendering effects, potentially leading to incorrect transparency or visual artifacts (e.g., 'white blurs').","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"To get the actual RGBA color for a pixel index `i`, you must look up `frame.colorTable[frame.pixels[i]]`. Additionally, consider the `transparentIndex` if present in the frame, as that index should be rendered as fully transparent.","message":"The `pixels` property of a decompressed frame contains color table indices, not direct RGBA color values. Developers often mistakenly try to interpret these as direct pixel colors without consulting the `colorTable`.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"While `gifuct-js` aims for robustness, extremely complex or edge-case GIFs might require custom post-processing of the frame data. Refer to GitHub issues for known problematic GIF examples and community workarounds.","message":"Some complex or malformed GIFs may exhibit rendering issues, such as incomplete frames or visual corruption, due to subtleties in the GIF specification or specific implementation choices, particularly concerning graphic control extensions or multiple application blocks.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Verify that the input `ArrayBuffer` is correctly loaded from a valid GIF file and is indeed an `ArrayBuffer` type. Log the input to `parseGIF` to inspect its type and content before passing it.","cause":"`parseGIF` received an invalid or malformed `ArrayBuffer`, or an object that is not an `ArrayBuffer`.","error":"TypeError: Cannot read properties of undefined (reading 'length')"},{"fix":"For modern JavaScript environments (ESM), use `import { parseGIF, decompressFrames } from 'gifuct-js'`. For CommonJS (Node.js <14 or specific setups), use `const { parseGIF, decompressFrames } = require('gifuct-js')`.","cause":"Incorrect ES Module import syntax or attempting to use CommonJS `require` in an ES Module context (or vice versa).","error":"ReferenceError: parseGIF is not defined"},{"fix":"Review the documentation on `disposalType` and `transparentIndex`. If `buildPatch` is `true`, be aware of its assumptions. For precise rendering, process `pixels` and `colorTable` manually, handling transparency and disposal based on GIF specification, or consult the library's demo for a robust rendering example.","cause":"Misunderstanding `patch` vs `pixels` data, incorrect handling of `disposalType`, or transparency issues when drawing frames, especially when `buildPatch` is `true`.","error":"Canvas shows wrong colors/transparency or 'blurry' frames after decompression."}],"ecosystem":"npm"}