Nodes/comfyui-properpixelart/Proper Pixel Art
ComfyUI Node

Proper Pixel Art

Turn smudged AI 'pixel art' into actual pixels

By unclepomedev·Created 23 days ago·Updated 2 days ago· 1
Proper Pixel Art
  • image
  • config
  • IMAGE
◄num_colors0►
◄initial_upscale_factor2►
◄pixel_width0►
◄scale_result1►
◄transparent_backgroundfalse►
◄intermediate_dir►

You asked for pixel art, you got something that reads as pixel art from across the room and falls apart the second you zoom in. Equal-sized square cells, a small palette, no blur, no half-transparent fringe - that's the medium, and diffusion can't hit it. The model works in a continuous latent at a fraction of your resolution, so it physically cannot land on a grid. Every serious pixel-art workflow ends the same way: a deterministic pass that finds the grid, picks one color per cell, and drops the palette.

What it actually does

Proper Pixel Art is the main node of ComfyUI-ProperPixelArt, a thin unofficial wrapper around Kenneth Allen's proper-pixel-art (MIT; also on PyPI as ppa). IMAGE tensor in, RGBA IMAGE tensors out, genuinely one pixel per block at true resolution - no checkpoint, no model download, no API key, no GPU. It's OpenCV, NumPy, Pillow and SciPy doing geometry and color, so it gives the same answer twice. Think of it as the missing step between your sampler and your Save Image node, not as a generator.

How it works

The upstream algorithm assumes your image is approximately on a grid - exactly the failure mode of AI pixel art, where blocks are 14 pixels wide in one place and 16 in another. In rough order:

  1. Trim border pixels, fill mostly-transparent pixels with a background color - that cleans up the ragged edges models love.
  2. Nearest-neighbor upscale by initial_upscale_factor (default 2×) before edge detection, to make the mesh easier to see.
  3. Canny edge detection, then morphological closing to seal small gaps.
  4. A probabilistic Hough transform finds near-vertical and near-horizontal lines; nearby lines cluster, then snap to peaks in the gradient projection profile - the axes where pixel boundaries actually sit.
  5. Estimate pixel width per axis from median line gaps, profile peaks or autocorrelation, then validate that estimate by reconstruction error (within-cell color variance). That's what stops it locking onto twice the true pixel width.
  6. Fill in the mesh between detected lines and rebuild, one representative color per cell.

Color is where num_colors comes in. At 0 the node uses upstream's dominant mode: it keeps your colors, but merges near-duplicates so flat areas collapse to one clean color. At 1 or more it switches to Pillow palette quantization - the classic "reduce to 16 colors" step, optionally with Floyd–Steinberg dithering from the config node.

Inputs worth touching

image is the only wired input you must connect. Then:

  • num_colors (default 0) - 0 preserves colors, 1–256 quantizes. Upstream's docs single out palette size as the parameter most likely to need tuning; try a few values if the result looks muddy.
  • initial_upscale_factor (1–8, default 2) - raise it if detected spacing is too large. Your first move when detection fails.
  • pixel_width (default 0 = auto) - when auto-detect still guesses wrong, zoom in, count the pixels in a block yourself, and type the number here. Manual override beats arguing with the estimator.
  • scale_result (1–20, default 1) - integer nearest-neighbor upscale of the output. That's a display upscale, not a neural one; 8× on a 32×32 sprite gives you a clean 256×256 you can actually look at.
  • transparent_background - makes pixels matching the most common boundary color transparent, i.e. cuts the flat backdrop off a sprite.
  • config and intermediate_dir are optional. intermediate_dir dumps visualization images of each algorithm stage into numbered subfolders under your ComfyUI output dir - the best debugging tool here, and empty means off.

Output

One output, IMAGE, and it's a list: each image in your batch is processed independently and comes back as its own result, so a 4-image batch saves four files downstream rather than one stacked batch. Wire it into Save Image, Preview Image, or anything else that eats IMAGE.

Install

ComfyUI Manager, search ComfyUI-ProperPixelArt, install, restart. Or by hand:

cd ComfyUI/custom_nodes
git clone https://github.com/unclepomedev/ComfyUI-ProperPixelArt
cd ComfyUI-ProperPixelArt
pip install -r requirements.txt

That requirements file is one line - proper-pixel-art>=2.0.0,<3.0.0 - and drags in opencv-python-headless, Pillow, NumPy, SciPy, PyYAML and PyAV with it. The pack declares Python ≥3.12, so on an old ComfyUI environment the install can fail outright, and the nodes never appear.

Where people get burned

Nothing shows up in the node list → your ComfyUI is older than the ≥0.38.2 this pack asks for (it's built on the newer node API), or the pip step never ran.

The output looks like a smooth half-resolution image → detection grabbed roughly double the real pixel width. Set pixel_width manually.

Sparse art, few straight lines, or soft anti-aliased edges → Hough needs enough line evidence, and small sprites are the hard case. The config node exists for exactly this.

Sprites still have a fuzzy halo → transparent_background keys on one boundary color, so it won't fully clean anti-aliased edges; transparency thresholds live in the config node.

Path gotcha: intermediate_dir resolves inside ComfyUI's output directory, and anything that escapes it errors out.

Categoryimage/Proper Pixel Art

Inputs (8)

NameTypeDefaultDescription
imageIMAGESource image tensor to convert to true-resolution pixel art.
num_colorsINT00–256Number of colors to quantize the image to. 0 keeps dominant colors (preserves all colors), while 1 or more quantizes to that many colors using palette method.
initial_upscale_factorINT21–8Initial image upscale factor before grid detection. Useful if detected spacing is too large.
pixel_widthINT00–256Width of pixels in the input image. 0 auto-detects pixel width.
scale_resultINT11–20Width of pixels in the output image. 1 means no scaling.
transparent_backgroundBOOLEANfalseMakes pixels matching the most common boundary color transparent.
configoptCOMFYUI_PROPERPIXELART_CONFIGOptional advanced configuration overriding algorithm defaults.
intermediate_diroptSTRINGSubfolder in the ComfyUI output directory to save intermediate algorithm visualization images into numbered subfolders (0, 1, ...) for each image. Empty disables saving.

Outputs (1)

NameTypeDescription
IMAGEIMAGEList of pixelated true-resolution images as RGBA tensors.