Library / SDK
jenissimo/unfake.js avatar
jenissimo/unfake.js

unfake.js: cleaning AI pixel art and vectorizing images in the browser

Fix AI pixel art and vector images right in your browser

919 stars59 forksJavaScriptMIT

At a glance

What is it?
unfake.js is an MIT-licensed JavaScript library with two modes, a pixel art processor and an image vectorizer, plus a browser tool and a Rust/WebAssembly core. It is aimed at people who generate images with AI and need clean assets out of them.
Who is it for?
Adopt unfake.js if you generate pixel art or raster images with AI and want the cleanup step to run in the browser or inside a JavaScript pipeline, and if you accept that the library is a wrapper around imagetracer.js and libimagequant rather than a self-contained tracer. Do not adopt it if you need a maintained CLI, a documented Node API, or a stable public interface for the Rust crates; the README documents only the browser tool and two library functions.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 57 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem unfake.js targets: AI images that are almost pixel art

Generative models produce images that look like pixel art but are not on a pixel grid. The README names the symptoms directly: inconsistent pixel sizes, color bleeding, and other artifacts. An image that appears to be 1x pixel art at a glance may actually be an upscaled render at some arbitrary factor, with anti-aliased edges and hundreds of near-duplicate colors. Feeding that into a game engine or a sprite pipeline produces blurry edges, palette drift, and a file far larger than the art warrants.

The library exists to reverse that. It has two modes, a pixel art processor and an image vectorizer, and the README frames the whole project as bridging "the gap between AI-generated images and clean, usable assets." The audience is narrow and specific: people who already have AI-generated images and want to convert them into something a game, a UI, or a print pipeline can consume. It is not a generator, not an editor, and not a general image-processing toolkit.

How the pixel art pipeline works: scale detection, downscaling, quantization

The pixel art mode runs a sequence of stages, and the README is explicit about most of them. First comes intelligent scale detection, which guesses the true pixel size of an upscaled image using either a runs-based or an edge-aware algorithm, or accepts a manual scale factor. That detected scale drives the next stage, content-aware downscaling, which reduces the image to native 1x using methods named dominant, median, and content-adaptive. The stated goal is to avoid introducing new colors or blurriness.

Grid snapping then crops the image so it aligns with the detected pixel grid. Color quantization reduces the palette to a maximum number of colors using imagequant (libimagequant) inside the WASM core, and a fixed custom palette can be supplied instead. Optional post-processing covers morphological cleanup for filling holes and removing noise, jaggy cleanup, and alpha binarization for sharp transparency.

The architecture behind this is a Rust workspace. Cargo.toml lists three members: crates/unfake-core, crates/unfake-cli, and crates/unfake-wasm. Release v1.2.0 is labelled "Rust/WebAssembly core", so the heavy image operations live in Rust and are compiled to WASM for the browser. The JavaScript layer in lib/index.js exposes processImage and vectorizeImage as the two entry points. The package.json scripts confirm the build path: core:build runs cargo build --release, core:wasm runs a Bun script, and core:test runs cargo test.

The vectorizer is a wrapper around imagetracer.js, and that shapes what it can do

The vectorizer mode converts PNG and JPG into SVG. The README describes it plainly as "an intelligent wrapper around imagetracer.js with extensive pre- and post-processing capabilities powered by the unfake-core WASM filters." That sentence is the most important design fact in the project. The tracing itself is not unfake.js code. What unfake.js adds is everything around it.

That surrounding work is a pipeline. Noise reduction runs first, using filters such as Bilateral or Median blur to smooth outlines before tracing. Smart color quantization reduces the palette before tracing, and can auto-detect the number of colors rather than requiring a fixed value. Transparent images get a temporary background during processing to avoid edge artifacts, which is then removed from the final SVG. After quantization, a gentle blur softens jagged edges before the trace. The tracing step exposes imagetracer.js options directly, and the README names ltres and qtres as examples. Finally, the palette is extracted from the generated SVG.

The trade-off is honest but real: the quality ceiling of the output is largely imagetracer.js's ceiling, and the API surface for tracing is imagetracer.js's API surface. If you already know that tracer and dislike its output, unfake.js improves the input to it rather than replacing it.

Installing and running the browser tool

The README does not describe an npm install for the library. It points to the online demo at jenissimo.itch.io/unfaker as a no-install option, and to the ComfyUI node and the unfake.py Python port as integrations. For local use, the documented path is the browser tool in the /browser-tool directory, and the README is emphatic that it needs a local HTTP server. ES module imports and importmaps do not work over file:// in modern browsers.

The README gives three ways to start a server. From the project root, Python 3 works:

bash
python -m http.server 8080
# or
python3 -m http.server 8080

Then open http://localhost:8080/browser-tool/ in the browser. A Node.js alternative uses http-server on the same port:

bash
npx http-server -p 8080

The README also mentions VSCode Live Server, where you click "Go Live" and select the browser-tool folder. Once the page loads, you upload an image by dragging it onto the window, choosing a file, or pasting from the clipboard. The Tweakpane panel adjusts processing parameters in real time, a before/after view shows the original and result side by side, and a magnifier lets you inspect pixel-level detail on both. The palette editor lets you replace colors interactively. Output is a .png download for pixel art or an .svg for vector mode, and both can be copied to the clipboard.

Using processImage from JavaScript

The library is written as ES modules, and the README shows importing the default export from lib/index.js. The pixel processing example passes a File object plus options for maxColors, detectMethod, downscaleMethod, snapGrid, and a cleanup object with morph and jaggy flags. detectMethod accepts 'auto', 'runs', or 'edge'. The call returns a destructured object with png, imageData, palette, and manifest. The README states that png is a Uint8Array of the final PNG file, which you wrap in a Blob and turn into an object URL.

javascript
import unfake from './lib/index.js';

const options = {
    file: file,
    maxColors: 32,
    detectMethod: 'auto',
    downscaleMethod: 'dominant',
    snapGrid: true,
    cleanup: { morph: true, jaggy: true }
};

const { png, imageData, palette, manifest } = await unfake.processImage(options);

The vectorization example follows the same shape but with a different options object. It enables preProcess with filter 'bilateral' and value 15, enables quantize with maxColors set to 'auto' or a number, and passes ltres and qtres through to imagetracer.js. It returns svg, palette, and manifest. Note the asymmetry: processImage returns png and imageData, vectorizeImage returns svg. The manifest field appears in both, but the README does not explain what it contains, so treat it as undocumented.

Where unfake.js is the wrong tool

The most obvious limitation is that the library has no documented package distribution. package.json has "private": true and the version field reads 1.3.0, while the latest release listed is v1.2.0. There is no files field, no main or exports entry, and no install instructions in the README. The documented integration path is copying lib/index.js into your own project or using one of the external integrations. If you want a versioned dependency from a registry, the README does not tell you how to get one.

Second, the browser tool is the only documented front end. It requires a local server, and the README warns about this in a callout rather than in passing. Anyone expecting to double-click an HTML file and have it work will be stuck.

The Rust side is also unevenly documented. Cargo.toml declares crates/unfake-cli, and package.json has a core:build script and a core:eval script that runs cargo run --release -- eval-bghira experiments/data/bghira. That suggests an evaluation harness exists for a dataset called bghira, but the README does not describe the CLI, its flags, or its output. If your workflow is command-line batch processing rather than browser or JavaScript, the README gives you no path.

Finally, the vectorizer inherits imagetracer.js's behavior. For photographic input or images with gradients, tracing produces many small polygons and large SVG files. The README does not claim otherwise, and it does not present the vectorizer as suitable for photographic work.

unfake.py as the alternative, and how it differs

The README itself points to unfake.py, a Python port by a different author, described as "a blazing fast Python implementation with Rust-accelerated quantization, offering a 10-20% speedup over the JS version." That is the direct alternative, and the difference is mostly about where the code runs. unfake.py is a Python package, so it fits pipelines that already run in Python, such as ComfyUI workflows or batch scripts on a server. unfake.js is aimed at the browser and at JavaScript consumers, with the browser tool as the primary interface and ES module imports as the library interface.

The speed claim comes from the README's description of the Python port, not from a benchmark run here. The quantization in both cases is Rust-accelerated; the difference is the language binding and the surrounding pipeline. Note also that the ComfyUI integration linked in the README is a separate repository, ComfyUI-Unfake-Pixels, which wraps unfake.js rather than unfake.py. If you want unfake.js inside ComfyUI, that node is the documented route.

Licence, maintenance, and what upgrades cost

The repository is MIT-licensed. Cargo.toml sets license = "MIT" at the workspace level, and the LICENSE file sits at the repository root. MIT is permissive, so embedding the library in a closed product is generally compatible with the licence terms; the usual obligation is preserving the copyright notice and licence text. That is a statement about the licence text, not legal advice, and the dependencies matter too: the README names imagetracer.js and libimagequant, and their licences are not described in the README.

The last push to the repository was on 2026-07-24, and the repository is not archived. The version in package.json is 1.3.0 while the most recent listed release is v1.2.0, so releases and the working tree are not in lockstep. For upgrade cost, the practical point is that the browser tool and the library are separate surfaces. The browser tool is a local directory you serve yourself, so upgrading means replacing files. The library is imported by relative path, so an upgrade can change the shape of the returned objects; the README documents png, imageData, palette, and manifest for processImage and svg, palette, and manifest for vectorizeImage, but does not promise stability. If you depend on the Rust crates directly, note that the workspace version is 0.2.0, which signals pre-1.0 churn.

Editorial conclusion

Adopt unfake.js if you generate pixel art or raster images with AI and want the cleanup step to run in the browser or inside a JavaScript pipeline, and if you accept that the library is a wrapper around imagetracer.js and libimagequant rather than a self-contained tracer. Do not adopt it if you need a maintained CLI, a documented Node API, or a stable public interface for the Rust crates; the README documents only the browser tool and two library functions. Verify first that the browser tool runs from a local server rather than file://, and check whether the Python port unfake.py fits better if your pipeline is not JavaScript.

Frequently asked questions

How do I install unfake.js?

The README does not document an npm install. It points to the online demo at jenissimo.itch.io/unfaker for no-install use, and to the browser tool in the /browser-tool directory for local use, which requires serving the project over a local HTTP server because ES module imports do not work over file://.

Does unfake.js work with ComfyUI?

Yes, via a separate repository. The README links ComfyUI-Unfake-Pixels as a ComfyUI node that uses unfake.js directly in ComfyUI workflows.

What is the difference between unfake.js and unfake.py?

unfake.py is a Python port described in the README as a fast Python implementation with Rust-accelerated quantization, offering a 10-20% speedup over the JS version. unfake.js targets the browser and JavaScript consumers, with a browser tool and ES module imports; unfake.py targets Python pipelines.

Official sources

  1. jenissimo/unfake.js on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Community notes

Community notes