{"id":16527263,"url":"https://github.com/zignis/declus","last_synced_at":"2025-06-28T18:07:31.401Z","repository":{"id":37104617,"uuid":"464763987","full_name":"zignis/declus","owner":"zignis","description":"Procedural image animations","archived":false,"fork":false,"pushed_at":"2024-02-26T13:06:38.000Z","size":23488,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-23T09:06:09.105Z","etag":null,"topics":["animations","encoder","gif","image"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zignis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2022-03-01T06:00:31.000Z","updated_at":"2024-03-16T15:33:09.000Z","dependencies_parsed_at":"2024-02-26T14:28:41.715Z","dependency_job_id":"8c34282e-601d-4942-b823-37e6c544fdec","html_url":"https://github.com/zignis/declus","commit_stats":null,"previous_names":["hexm7/declus"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/zignis/declus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zignis%2Fdeclus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zignis%2Fdeclus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zignis%2Fdeclus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zignis%2Fdeclus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zignis","download_url":"https://codeload.github.com/zignis/declus/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zignis%2Fdeclus/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261449763,"owners_count":23159803,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animations","encoder","gif","image"],"created_at":"2024-10-11T17:34:18.699Z","updated_at":"2025-06-28T18:07:31.374Z","avatar_url":"https://github.com/zignis.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Declus - GIF manipulation\n\n![Typescript](https://img.shields.io/badge/TypeScript-007ACC?style=for-the-badge\u0026logo=typescript\u0026logoColor=white)\n![npm](https://img.shields.io/npm/v/declus?style=for-the-badge)\n![npm](https://img.shields.io/npm/dm/declus?style=for-the-badge)\n![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/zignis/declus?style=for-the-badge)\n![GitHub](https://img.shields.io/github/license/zignis/declus?style=for-the-badge)\n![GitHub Repo stars](https://img.shields.io/github/stars/zignis/declus?style=for-the-badge)\n![GitHub forks](https://img.shields.io/github/forks/zignis/declus?style=for-the-badge)\n![GitHub Sponsors](https://img.shields.io/github/sponsors/zignis?style=for-the-badge)\n\n## Playing with GIF images made much easier\n\n### Installation \u0026 Usage\n\n```console\nnpm i declus\n```\n\n```js\nconst declus = require('declus');\n\n// Using callback\ndeclus(options)\n  .then((buffer) =\u003e {\n    ...\n  })\n  .catch(console.error);\n\n// Inside an async function, using await\nconst buffer = await declus(options);\n```\n\n| :warning: Requires access to write extracted frames to a directory. If file-system is restricted, use the `inMemory` option to store extracted frames in memory |\n| --- |\n\n### Getting started\n\nBasic example\n\n```js\nconst fs = require('fs');\nconst declus = require('declus');\n\ndeclus({\n  height: 360,\n  width: 640,\n  baseLayer: {\n    data: 'https://raw.githubusercontent.com/zignis/declus/master/assets/sample.gif',\n  },\n  layers: [\n    {\n      data: 'https://raw.githubusercontent.com/zignis/declus/master/assets/transparentKitten.png',\n    }\n  ],\n  stretchLayers: true,\n}).then((buffer) =\u003e {\n  fs.createWriteStream('./myImage.gif')\n    .write(buffer);\n});\n```\n\nAccepts Buffer, absolute URLs and paths to images\n\n```js\ndata: myBuffer,\ndata: './sampleImage.gif',\n```\n\n### Layer options\n\n```js\nlayer: {\n  data: Buffer || URL || Path, // Required\n  marginLeft: Number,\n  marginTop: Number,\n  width: Number,\n  height: Number,\n  drawFunction: function(context, layerImg, index, totalFrames),\n  skipFunction: function(index, totalFrames),\n  skipIndexes: Array,\n}\n```\n\n- `data` - Layer data, can be an image buffer, URL or path.\n- `marginLeft` - Left layer margin relative to the base width.\n- `marginTop` - Top layer margin relative to the base height.\n- `width` - Layer width.\n- `height` - Layer height.\n- `drawFunction` - A custom function to draw the layer onto the base layer.\n\n```js\n{\n  drawFunction: function(context, layerImg, index, totalFrames) {\n    const drawProgress = (index / totalFrames).toFixed(1);\n\n    context.drawImage(\n      layerImg,\n      width * drawProgress,\n      height * drawProgress,\n      64,\n      64,\n    );\n  },\n}\n```\n\n- `skipFunction` - Function to decide wether or not to skip the current frame. Return `true` to skip and `false` to render the frame.\n\n```js\n{\n  skipFunction: function(index, totalFrames) {\n    // Skip all frames with even index\n    if (index % 2 === 0) return true;\n    return false;\n  },\n}\n```\n\n- `skipIndexes` - Frames indexes to skip layers.\n\n```js\n{\n  skipIndexes: [5, 15, 25, 50],\n}\n```\n\n### Options\n\n#### *`width`  number\n\nWidth of the output image.\n\n#### *`height` number\n\nHeight of the output image.\n\n#### *`baseLayer` object\n\nAn object with data to build the base layer.\n\nCheck [baseLayer options](#layer-options).\n\n#### `layers` array\n\nAn array of layer objects. The stacking order is defined by the position of the layer in the array.\n\nCheck [layer options](#layer-options).\n\n#### [`repeat`](https://github.com/twolfson/gif-encoder#setrepeatn) number\n\nAmount of times to repeat the output GIF.\n\n- `-1`: play once\n- `0`: default, loop indefinitely\n- `Positive number`: loop specific times\n\n#### [`quality`](https://github.com/twolfson/gif-encoder#setqualityquality) number\n\nThe quality of output GIF (computational/performance trade-off).\n\n- `1`: best colors, worst performance\n- `20`: suggested maximum but there is no limit\n- `10`: default, provided an even trade-off\n\n#### [`delay`](https://github.com/twolfson/gif-encoder#gifsetdelayms) number, ms\n\nAmount of milliseconds to delay between frames.\n\n#### [`frameRate`](https://github.com/twolfson/gif-encoder#setframerateframespersecond) number\n\nFrames per second.\n\n| :warning: `delay` and `frameRate` cannot be used together |\n| --- |\n\n#### `alpha` boolean\n\nWether or not to have a transparent background.\n\n#### [`alphaColor`](https://github.com/twolfson/gif-encoder#settransparentcolor) number, hexadecimal\n\nDefines the color which represents transparency in the output GIF.\n\n#### [`coalesce`](https://github.com/transitive-bullshit/gif-extract-frames#optscoalesce) boolean\n\nWhether or not to perform inter-frame coalescing, defaults to `true`.\n\n#### `stretchLayers` boolean\n\nWhether or not to stretch the layers to their maximum, defaults to `false`.\n\n#### [`encoderOptions`](https://github.com/twolfson/gif-encoder#documentation) object\n\nOptions passed to [gif-encoder](https://github.com/twolfson/gif-encoder).\n\n- `highWaterMark`: Number, in bytes, to store in internal buffer. Defaults to `64kB`. Increase if you face `GIF memory limit exceeded` error.\n\n#### `outputDir` string\n\nDirectory to store temporary frames extracted from the GIF, defaults to `.` (root). A new folder is created and automatically gets removed after the encoding has been finished.\n\n#### `inMemory` boolean\n\nWhether or not to extract frames to memory store instead of writing them to a directory. If `true`, the GIF image will render faster as the frames will be written and read from the memory instead of a directory at cost of increasing memory usage such as when dealing with large images. Useful when you do not have access to write to the file system. Defaults to `false`.\n\n#### `frameExtension` string\n\nExtension of the extracted frames from the GIF, defaults to `png`.\n\nAllowed formats:\n\n- `png`\n- `jpg`\n- `gif`(static)\n\n### Events\n\n#### `initCanvasContext` function(context)\n\nA function called during the initialization of the Canvas context.\n\n#### `beforeBaseLayerDraw` function(context, layerImg, index, totalFrames)\n\nA function called each time before a frame of the base layer is drawn.\n\n#### `afterBaseLayerDraw` function(context, layerImg, index, totalFrames)\n\nA function called each time after a frame of the base layer is drawn.\n\n#### `beforeLayerDraw` function(context, layerImg, index, totalFrames, layerIndex)\n\nA function called each time before a frame of a layer is drawn.\n\n#### `afterLayerDraw` function(context, layerImg, index, totalFrames, layerIndex)\n\nA function called each time after a frame of a layer is drawn.\n\n#### [`encoderOnData`](https://github.com/twolfson/gif-encoder#event-data) function(buffer)\n\nEmits a Buffer containing either header bytes, frame bytes, or footer bytes.\n\n#### [`encoderOnEnd`](https://github.com/twolfson/gif-encoder#event-end) function\n\nSignifies end of the encoding has been reached.\n\n#### [`encoderOnError`](https://github.com/twolfson/gif-encoder#event-error) function(error)\n\nEmits an Error when internal buffer is exceeded.\n\n#### [`encoderOnReadable`](https://github.com/twolfson/gif-encoder#event-readable) function\n\nEmits when the stream is ready to be `.read()` from.\n\n#### [`encoderOnWriteHeader`](https://github.com/twolfson/gif-encoder#event-writeheaderstartstop) function\n\nEmits when at the start and end of `.writeHeader()`.\n\n#### [`encoderOnFrame`](https://github.com/twolfson/gif-encoder#event-framestartstop) function\n\nEmits when a new frame is being rendered.\n\n#### [`encoderOnFinish`](https://github.com/twolfson/gif-encoder#event-finishstartstop) function\n\nEmits when encoding has been finished.\n\n### Credits\n\n- [@transitive-bullshit](https://github.com/transitive-bullshit) for [gif-extract-frames](https://github.com/transitive-bullshit/gif-extract-frames)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzignis%2Fdeclus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzignis%2Fdeclus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzignis%2Fdeclus/lists"}