Nodes/ComfyUI-PixelArt-Unfaker/Unfake Pixel Art (AI to Real)
ComfyUI Node

Unfake Pixel Art (AI to Real)

Your AI 'pixel art' is fake. This node makes it real

By CalaKuad1·Created 7 months ago·Updated 11 days ago· 16
Unfake Pixel Art (AI to Real)
  • image
  • pixel_art_image
  • manifest
  • mask
  • upscaled_image
◄target_width64►
◄target_height64►
◄manual_scale_factor0►
◄remove_backgroundtrue►
◄background_tolerance10►
◄max_colors16►
◄cleanup_jaggiesfalse►
◄downscale_methodnearest►
◄scale_detection_methodedge_aware►
◄ea_tile_grid_size3►
◄ea_min_peak_distance5►
◄ea_peak_prominence_factor0.10►
◄upscale_preview_factor8►
◄fit_modecrop►
◄merge_similar_colors24►

Every pixel-art model on Civitai has the same dirty secret: it doesn't output pixel art. It outputs an image that looks like pixel art from a distance - off-grid, blurry, and carrying hundreds of near-duplicate colors from compression and hallucinated shading. Squint and it's fine. Zoom in, or try to drop it into a game engine, and the grid falls apart. Unfake Pixel Art (AI to Real) is the fix: a postprocessing node that detects the real pseudo-pixel grid hiding in that mush, snaps it into true alignment, and quantizes it down to an honest, retro palette.

This is a ComfyUI port of jenissimo's unfake.js, which blew up on r/StableDiffusion in mid-2025 (+600 votes, 116 comments) for a reason - the demo genuinely makes AI garbage into usable sprites. Tauraloke's ComfyUI-Unfake-Pixels did the first rough port; this pack (CalaKuad1) is the more complete rewrite, adding background removal, exact target sizing, and an in-node preview. No model files, no API, no key - it's pure math running on CPU.

How it works

The node runs a fixed pipeline, and understanding the order explains most of your troubleshooting:

  1. Background removal (if enabled) - takes the most common corner color, and using connected components deletes only the exterior region, not matching colors trapped inside the subject. It's heuristic, not a BiRefNet-style model, so it's free and instant but blunt.
  2. Scale detection - the clever part. It splits the image into tiles, runs a Sobel edge profile on the most informative ones, and finds the repeating peak distance. That spacing is your pixel size, even when the grid is blurry or upscaled.
  3. Optimal crop - shifts the crop by the smallest offset that lands every pixel on the detected grid, killing half-pixels.
  4. Downscale + quantize - reduces the image by the detected scale, then runs K-Means clustering to cap the palette (default 16 colors).
  5. Jaggy cleanup - replaces isolated noise pixels with their neighbors' average for cleaner lines.

The inputs that matter

You'll touch maybe four of these. The rest have sane defaults.

  • target_width / target_height (default 64 each) - set both to your final resolution and the node computes scale, crops, and pads to hit it exactly. Set both to 0 to keep the auto-detected original aspect. Gotcha from the source: it's all-or-nothing - one zero and the pair stops forcing the target.
  • manual_scale_factor - override when auto-detection botches it. If your input is 1024 and you want 16, that's a scale of 64. The README is honest that noisy textures like dirt and ores defeat the auto-detector.
  • remove_background + background_tolerance - turn this off if your subject touches a corner, or the "background" color shows up inside the art.
  • max_colors (2–256) - palette cap; 8–16 is authentic retro, 32+ drifts toward "AI mush" again.
  • downscale_method - nearest is crisp and punchy; dominant averages each block's most common color, which is gentler on gradients.

The ea_* knobs (ea_tile_grid_size, ea_min_peak_distance, ea_peak_prominence_factor) tune the edge detection. Leave them alone until you've confirmed a bad detection.

Outputs

pixel_art_image (IMAGE) - your cleaned sprite. Wire it to a Save Image or preview. The node also renders an 8x nearest-neighbor preview (the upscale_preview_factor input) inside the UI so it doesn't look 16×16-tiny in the graph.

manifest (STRING) - a dictionary string with detected_scale, crop_offset, and processing_time_ms. This is your diagnostic: if detected_scale is 1, detection failed and the node bailed to "no downscale," which is why your output still looks blurry.

Installation

ComfyUI Manager is easiest - search "PixelArt Unfaker." Or manually:

cd ComfyUI/custom_nodes
git clone https://github.com/CalaKuad1/ComfyUI-PixelArt-Unfaker
cd ComfyUI-PixelArt-Unfaker
pip install -r requirements.txt

Then restart. The dependency that matters: requirements.txt pulls in scikit-learn and scipy on top of the torch/Pillow/numpy ComfyUI already ships. If the node throws an import error, that's the missing piece. On the portable Windows build use .\python_embeded\python.exe -m pip install -r requirements.txt.

Where people get burned

Auto-detection failing is the big one - check the manifest's detected_scale and reach for manual_scale_factor. Feed it a sprite that's already clean and it can over-quantize into posterized blocks, so set max_colors honestly. And remember the background removal is corner-color logic: on busy scenes just switch it off and do transparency in a proper removal pass later. For a node this niche, it does the one job - turning fake pixel art into something a game engine will actually accept - remarkably well.

Categoryimage/postprocessing

Inputs (16)

NameTypeDefaultDescription
imageIMAGE—
target_widthINT640–4096Exact output width in art pixels (e.g. 64). 0 = derive it from target_height keeping the aspect ratio. Both 0 = auto-detect the pixel size.
target_heightINT640–4096Exact output height in art pixels (e.g. 64). 0 = derive it from target_width keeping the aspect ratio. Both 0 = auto-detect the pixel size.
manual_scale_factorINT00–128Size of one art pixel in input pixels (e.g. 16 turns 1024 into 64). 0 = auto-detect. Only used when both target sizes are 0.
remove_backgroundBOOLEANtrueMake the background transparent. The background color is taken from the image border, and only regions connected to the border are removed.
background_toleranceINT100–255Maximum per-channel difference from the background color. Raise it for noisy / JPEG backgrounds.
max_colorsINT160–256Palette size. 0 = keep all colors.
cleanup_jaggiesBOOLEANfalseReplace isolated stray pixels with the color of their neighbors (never adds new colors). May remove intentional 1-pixel details.
downscale_methodCOMBOnearestnearest: center pixel of each cell (crisp, fast). dominant: most common color of each cell (best for noisy AI images).
scale_detection_methodCOMBOedge_aware1 options: edge_aware
ea_tile_grid_sizeINT31–10Auto-detection: the image is split into NxN tiles and the most detailed half is analyzed.
ea_min_peak_distanceINT51–50Auto-detection: minimum distance between edges. Lower it if the art pixels are smaller than this.
ea_peak_prominence_factorFLOAT0.100.01–1Auto-detection: minimum edge strength, relative to the strongest edge.
upscale_preview_factorINT81–32Nearest-neighbor upscale for the node preview and the upscaled_image output (capped so the largest side stays under 4096px).
fit_modeCOMBOcropWhen the input aspect ratio differs from the target size. crop: fill the target and cut the excess. pad: fit inside and add transparent borders. stretch: distort to fill.
merge_similar_colorsINT240–100Merge palette colors closer than this RGB distance. Removes the near-identical shades that AI noise creates (speckled areas). Lower it if you lose subtle shading; 0 = off.

Outputs (4)

NameTypeDescription
pixel_art_imageIMAGEReal-size pixel art. RGBA when the background is removed or padding is added, RGB otherwise.
manifestSTRINGJSON with the detected pixel size, grid offset, output size and palette.
maskMASKComfyUI-style mask of the transparent area (1 = transparent), as returned by Load Image.
upscaled_imageIMAGEThe pixel art upscaled with nearest neighbor, ready to view or save.