Clean Up AI or Upscaled Pixel Art — Palette, Anti-Aliasing, Scale
AI "pixel art" usually has too many colours, soft edges and pixels that are not all the same size. This workflow fixes the first two and measures the third honestly: it tells you the scale, or says that no clean grid exists.

- PNG framesMeasured· Pillow
- PaletteMeasured· re-import
- pixel-lab.jsonUNVERIFIED
What it does
- Palette lock: reduce to 2–256 colours (or a palette you import) across every frame.
- Anti-alias remover: in-between edge pixels snap to one of the two palette colours they sit between; the silhouette does not move.
- Stray pixels, tiny clusters and single-pixel holes found as candidates first, fixed only when ticked.
- Pixel-perfect check: exact integer scale and offset, non-integer scale estimate, blurred-edge count; 1× recovery only when an exact grid is proven.
How to do it
- Drop the image or frames.
- Lock a palette with the colour count you want.
- Turn on the anti-alias remover and the cleanups you need.
- Check the scale report, then export.
Outputs and how each was checked
"Measured" means the downloaded file was opened again outside the page (Pillow, numpy or an independent parser) and the property was measured. Loading these files in a game engine was not tested.
| Target | Files | Check |
|---|---|---|
| PNG frames | anim_N.png · 1×–8× nearest | Measured PillowEvery exported colour re-read from the PNGs lies inside the locked palette. |
| Palette | .gpl · .hex (Lospec) · .json | Measured re-importEach format was exported and imported back through the UI: 16 → 16 colours. |
| pixel-lab.json | generic frames + palette | UNVERIFIEDGeneric JSON; not loaded in any engine. |
Evidence
8 anti-aliased frames → one 16-colour palette with 0 exported colours outside it; an unchanged region identical in all 8 frames with dithering off and with Bayer 4×4; the anti-alias remover took 271 colours to 16 without moving a single silhouette pixel; integer scale, offset and 2.5× non-integer scaling detected exactly.
Limits
- Frames larger than 4096 × 4096 are refused: every pass runs on the main thread, and there is no cancel button yet.
- A sprite sheet is treated as one image; cut it into frames first (sprite sheet cutter).
- With a dithering mode on, the cleanup counts include dither pixels; set dithering to None first.
- The exported JSON is generic; importing it into Godot or Unity was not tested.
Questions
Does it fix "mixels" (pixels of different sizes)?
No. It does not re-grid or redraw off-grid pixels; the checker only reports that no exact grid exists. Nothing here is generative.
Will my sprite's outline move?
No. The anti-alias remover changed 0 alpha pixels in the test while reducing 271 colours to 16.
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).