Pixel Snapper Alternative — Cleanup Tools Measured
Several free tools promise to snap fake pixel art back onto a real grid. We ran Sprite Fusion's Pixel Snapper, unfake.js and perfectPixel with their own defaults on the same 69 degraded CC0 sprites whose true 1× image is known, scored every output the same way, and list here where Nerulio loses as well as where it wins.
Sprite Fusion’s Pixel Snapper, unfake.js and perfectPixel all turn “fake” pixel art — upscaled, resized or generated — into a 1× image on a grid, but they measure differently and fail differently. Pixel Snapper (Rust, command line and web page) always snaps and quantizes, to 16 colours by default; unfake.js (JavaScript library and browser tool) works with whole-number scales and also vectorizes; perfectPixel (Python) finds the grid by FFT and gives up below 4 px cells. Nerulio’s Cleanup panel runs in a browser editor, shows the grid with a confidence first and does not snap when unsure.

- .asepriteVerified· Aseprite 1.3.18
- Palette filesMeasured· read back
- Engine bundlesVerified· Godot 4.7.2 · Unity 6000.5
- Frame PNG · .nerulioPlain files
What each tool actually does
Pixel Snapper (MIT, by Hugo Duprez) is written in Rust. Its command line is spritefusion-pixel-snapper input.png output.png 16: it detects a pixel size, snaps to it and quantizes to a fixed palette — 16 colours by default, or your own hex colours with --palette; --pixel-size overrides the detection. The same engine runs on spritefusion.com. Its README targets generated art for tilemaps and game assets.
unfake.js (MIT) is a JavaScript library with a browser tool: runs-based or edge-aware scale detection, dominant, median or content-adaptive downscaling, colour quantization and morphological cleanup — plus a vectorizer that turns images into SVG. perfectPixel (MIT, pip install perfect-pixel) finds the grid with an FFT, refines it with Sobel edges and samples by center, median or majority; there is a ComfyUI node and a web demo.
Nerulio proves integer block grids exactly, measures fractional and smooth resizes with a lattice (a least-squares inverse for bilinear), follows uneven pseudo-pixels by edge tracking, and labels the result sure, likely or unsure; only sure and likely grids are applied. The output is a new sprite inside a pixel editor, where the pixels any tool gets wrong can be fixed by hand.
- Quantize
- Reduce the picture to a fixed number of colours (a palette).
- Grid detection
- Finding the cell size (and offset) of the fake pixels.
- Confidence
- Whether the tool says how sure it is — Nerulio does; the others return their result either way.
What it does
- The cases: 13 CC0 sprites and tiles (Kenney, Eris, GrafxKid, DezrasDragons and others), each degraded in a known way — nearest ×2 to ×8, fractional nearest, bilinear, bicubic and Lanczos resizes, JPEG, blur and simulated generated art with uneven pseudo-pixels.
- The score: exact pixels at the best shift of up to 2 px, pixels within Oklab ΔE 0.02, and whether the output has the true size exactly or within 1 px. Failed runs count as zero, so no tool looks better by skipping hard cases.
- Seven real images made by image generators have no ground truth. Nerulio judged all seven unsure and left them at their size, showing its weak candidate; the other tools always returned a guess, and for the same three images unfake.js picked a pixel size of 3 while Pixel Snapper and perfectPixel picked about 6.
- Nerulio shows the measured grid and a confidence before anything changes, and the result becomes a new sprite in an editor, where stray pixels, palette and outline can be fixed by hand.
- Scripts and data to re-run everything are in the repository (docs/pixel-bench), with the exact tool versions and settings.
Same 69 cases, same scoring
Overall results; failed runs count as misses. docs/STUDIO-PIXEL.md §5 and docs/pixel-bench/H2H.md §3.
| Tool | Exact size | Size ±1 px | Exact pixels | Within ΔE 0.02 | Failed runs |
|---|---|---|---|---|---|
| Nerulio, defaults | 81 % | 90 % | 63.2 % | 75.4 % | 0 |
| Nerulio, background kept | 81 % | 90 % | 74.0 % | 91.1 % | 0 |
| unfake.js (library defaults) | 25 % | 41 % | 44.6 % | 64.6 % | 0 |
| unfake.js (browser tool, grid auto) | 26 % | 42 % | 40.7 % | 64.8 % | 0 |
| perfectPixel | 30 % | 43 % | 33.9 % | 55.9 % | 15 |
| Sprite Fusion Pixel Snapper | 6 % | 28 % | 33.4 % | 54.7 % | 0 |
Source of these numbers: docs/STUDIO-PIXEL.md §5, docs/pixel-bench/H2H.md
Where Pixel Snapper, unfake.js and perfectPixel is the better choice
- They are libraries you can script: Pixel Snapper in Rust with a command line, unfake.js in JavaScript, perfectPixel in Python. Nerulio's cleanup runs only inside the Studio, with no command line.
- On JPEG input with default settings, unfake.js kept more pixels within ΔE 0.02 (74.6 %) than Nerulio's defaults (48.4 %); Nerulio needs the background kept to reach 84.0 %.
- They always return an answer for a generated image, while Nerulio leaves an unsure picture at its size until you type the pixel size.
- perfectPixel found the exact size of simulated generated art twice as often (40 % against 20 %), and when it detects the grid of a clean nearest-neighbour upscale its result is exact.
How to do it
- Drop the upscaled or generated picture on this page; it opens in the Pixel workspace.
- Press Measure in the Cleanup panel and read the verdict: an exact block grid, a fractional or smooth resize, or unsure with a suggested size.
- For an unsure picture, zoom in on the drawn grid and type the pixel size you see; set the colour limit or quantize to a palette if the colours are noisy.
- Preview, Apply as a new sprite, then touch up single pixels with the pencil before exporting.
When to use which
| Option | When it is the better choice |
|---|---|
| Pixel Snapper | You want a result for every image with a fixed palette size in one command, or you already use spritefusion.com. In our runs it did best with large cells (the ×5 and ×7 tile cases came back with every pixel right, at a size within 1 px) and on simulated generated art (size within 1 px in 80 % of cases); on whole-number upscales it over-segmented and never hit the exact size. |
| unfake.js | Clean whole-number upscales inside a JavaScript pipeline: with the grid set to auto it found 85 % of the exact sizes on nearest ×2–×8. It also vectorizes images to SVG, which Nerulio does not do. |
| perfectPixel | Python or ComfyUI batches with cells of 4 px or more: when it detects the grid of a clean upscale the result is exact (10 perfect cases), and it found the exact size of simulated generated art in 40 % of cases. Below its default min_size of 4 px it returns nothing (11 of its 15 failures). |
| Nerulio Cleanup panel | Fractional and smooth resizes (exact size in 100 % and 93 % of those cases), animations that must share one grid and one palette, and when you want to see the grid before anything changes. |
| Redraw by hand | Generated concept art where no tool finds a consistent grid; on simulated generated art no tool got more than 70.3 % of pixels exact. |
Engine exports and how each was checked
"Verified" means the exported files were loaded by the real engine or tool on real CC0 assets and the result was compared with the source. Anything that was not loaded is labelled as such.
| Target | Files | Check |
|---|---|---|
| .aseprite | layers · blend · opacity · locked · indexed palette · frames · tags | Verified Aseprite 1.3.18The real Aseprite command line reopened the file as INDEXED with 2 layers, Multiply at opacity 160 and the locked layer not editable; the frames are pixel-identical. |
| Palette files | .gpl · .pal · .hex · .ase · .act · .json | Measured read backEach format was written and read back identical; Aseprite's own .gpl, .pal, .hex and .act and a real Adobe .ase (16 colours) were read. |
| Engine bundles | Godot 4 · Unity 6 · Phaser 3/4 · PixiJS 8 … through Pack & Export | Verified Godot 4.7.2 · Unity 6000.5The sprite you drew is packed in Pack & Export; those engine files were loaded in each engine on real CC0 assets (47 of 49 runs pass; the 2 failures are a Phaser 3.90 bug the Phaser 3 preset avoids). |
| Frame PNG · .nerulio | PNG-8 with the palette when an indexed frame fits it · project file | Plain filesPlain files for any tool; no engine run is claimed for them. |
Evidence
Cleanup benchmark, 69 CC0 cases with a known 1× original: the exact size found for 81 % (±1 px: 90 %) and 74.0 % of pixels exact with the background kept; the best competitor found 30 % of sizes (perfectPixel) and the best exact-pixel score was 44.6 % (unfake.js). An Aseprite-made ×4 nearest upscale came back 100 % exact and a ×3.78 bilinear resize 99.7 %, both with the size found automatically. A 1 px outline and a drop shadow matched Aseprite pixel for pixel (1846 and 705 px). .aseprite files written here reopen in Aseprite 1.3.18 as indexed, with their layers, blend mode and lock.
Limits
- No command line or library: Nerulio’s cleanup runs only inside the Studio in a browser.
- No SVG vectorizer.
- On real generated images it leaves the size unchanged until you type one — all 7 in our test.
- Default settings remove a solid border background, which costs exact pixels on art whose background is part of the picture (63.2 % vs 74.0 % with the background kept).
- Not in the Pixel workspace (Aseprite has them): layer groups, linked cels, tilemap layers, reference layers, RotSprite and free rotation or scaling of a selection (only flips and 90°), gradient, spray, contour and text tools, custom brushes (square or round, 1–16 px), tiled drawing, Lua scripting and a command line.
- The symmetry axis is typed, not dragged on the canvas. On touch there is no right button, so the background colour needs the swap button or X.
- Cleanup: JPEG input comes back close (84 % of pixels within ΔE 0.02 with the background kept) but rarely exact (12 %); simulated generated art gets the exact size 20 % of the time (±1 px: 80 %); none of 7 real generated images was snapped automatically — you type the pixel size the panel suggests.
- Indexed conversion picks the nearest colour in Oklab, not Aseprite's RGB distance: 68 % of the test sprite's pixels got a different (perceptually closer) pick. The Lospec search is the only network request and asks first.
Versions and sources
Competitors as run on 2026-09-23/24 with their own defaults: Pixel Snapper = the WebAssembly build fetched from spritefusion.com (repository at ae20461, 1.0.0), 16 colours — byte identity with the live page was not confirmed; unfake.js at b2bee10 (library defaults, browser-tool defaults, and grid auto); perfectPixel 0.1.4 (72096de) with OpenCV, which drops alpha. Nerulio’s runs 2026-09-25 (docs/pixel-bench/H2H.md, docs/STUDIO-PIXEL.md §5). Tool descriptions come from each project’s README.
Official documentation used
Questions
Which tool is best for images from an image generator?
None is reliable yet. On simulated generated art perfectPixel found the exact size most often (40 %, Nerulio 20 %), and Nerulio, perfectPixel and Pixel Snapper were within 1 px in 80 % of the cases. Exact pixels differ most: 70.3 % for Nerulio with the background kept, under 7 % for every other tool.
Why does Nerulio refuse to snap some images?
When the grid evidence is weak it says unsure instead of guessing. The panel still shows the best candidate and the grid it implies, so you can type that size and apply it; the competitors output their guess without saying how sure they are.
Were the competitors run fairly?
Each ran with its own defaults, the way a visitor would use it: Pixel Snapper through the site's own WebAssembly build with 16 colours, unfake.js through its library and its browser tool, perfectPixel through its Python package. Settings and versions are in docs/pixel-bench/H2H.md.
Is it free, and do I need an account?
Everything on these pages is free and works without an account. There is no watermark and no export that is held back.
Are my sprites uploaded?
No. The Studio decodes, packs and exports in this browser tab. Projects are autosaved in the browser (IndexedDB) and can be saved as a .nerulio file.
Does it need Aseprite or an engine plugin installed?
No. .aseprite files are read and written in the browser, and each engine bundle carries what that engine needs (for Godot, the import settings and scene; for Unity and the Godot TileSet, a small editor script).