PixelOETorch
The pixelizer that needs no model — and no API
- img
- image
PixelOETorch is the node that turns a normal render into clean, chunky pixel art - the kind that reads as an actual game sprite instead of "image, but smaller." It's a wrapper around KohakuBlueleaf's PixelOE, which is about the closest thing the community has to a gold-standard pixelizer. And here's the part that surprises people: there's no AI in it, no model file, no VRAM worth mentioning, no API key. It's classical image processing, and it runs in milliseconds.
If that sounds like it's competing with paid pixel-art APIs - yeah, that's exactly what happened. In October 2025, r/StableDiffusion had a moment about it: RealAstropulse (the dev behind PixelOE's k-centroid mode) tore into Fal's paid "image2pixel" model as "literally just downscaling and bad quant," pointing out PixelOE is miles better and runs client-side. That thread is the product pitch for this node. Squares alone aren't pixel art; the hard part is keeping detail and edges through the downscale, and that's the part PixelOE solves.
What the wrapper actually is
Honest framing: this pack is a barebones re-export, and the author says as much in the README - "I cannot promise any support, if there is someone who wants to make a proper node, please do." PixelOE itself ships its own ComfyUI nodes, including an OutlineExpansion node and a PreResize node you don't get here. Installing KohakuBlueleaf/PixelOE directly gets you more. The one concrete reason to pick this wrapper: shared workflows that reference the PixelOETorch class by name. That class only exists here, and a workflow with a missing node usually just breaks silently. If a saved workflow asks for it, this pack is how you satisfy it.
The inputs that matter
It takes one IMAGE and outputs one IMAGE (image), ready to wire into an upscaler or Save Image. You don't need to touch all the sliders. The few that do the real work:
- target_size (256): how many pixel blocks the final art gets on its short axis. Higher keeps more detail, lower gets chunkier. The single most important dial.
- patch_size (6) and pixel_size (6): the sampling grid and the final pixel-block size. In practice you usually leave them matched at the default.
- mode:
contrast(default) is the good one - it picks the most representative pixel per patch and is what makes PixelOE look better than a plain resize.center,k-centroid,bicubic,nearestare the alternatives;nearestis there if you want the dumb, fast baseline. - do_quant (off) + num_colors (32) + quant_mode + dither_mode: this is the classic-sprite palette reduction. Turn
do_quanton, dropnum_colorsto 16–32, and you get that crisp Game Boy-ish palette instead of gradients.do_color_match(on by default) pulls the original image's palette back through so the result keeps its mood.
Two flags worth knowing: thickness controls the outline-expansion pass (set to 0 to disable it entirely), and torch_compile is on by default - it makes the kernels fast on the second run onward, at the cost of a slow first call.
How it works
PixelOE's trick is contrast-aware outline expansion, then downsampling. First it works out which edges and bright/dark details matter (via local contrast weighting) and literally thickens them with morphological erode/dilate operations, so they survive the resolution drop. Then it downsamples in LAB color space: luminance is handled per-patch by picking a representative pixel based on local distribution - that's the contrast mode - while color channels get a median filter. Details survive, gradients don't mush, and the result reads as deliberate pixel art rather than a downscale.
Install
Easiest path is ComfyUI Manager - search "PixelOE" or "ComfyUI-PixelOE-Wrapper" and install. Manually:
cd ComfyUI/custom_nodes
git clone --recursive https://github.com/A4P7J1N7M05OT/ComfyUI-PixelOE-Wrapper
then restart ComfyUI. No model files to fetch - that's the whole appeal. Dependencies are torch, numpy, and opencv-python, all of which a working ComfyUI already has.
Where people get burned
The --recursive above isn't decoration. PixelOE is vendored in as a git submodule, and a plain git clone leaves that directory empty - which makes the whole node fail to register, with no obvious error until you check the console. If you cloned without it, git submodule update --init --recursive fixes it.
Two smaller traps. Keep pixel_size at 1 or above here; setting it to 0 (which the legacy PixelOE node tolerates) just errors. And it's a single-image node - feed it a batch and the squeeze/permute in the source chokes, so process frames one at a time if you're animating sprites. Otherwise it's one of the least-fussy post-processing nodes around.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| img | IMAGE | — | |
| mode | COMBO | 5 options: contrast, center, k-centroid, bicubic, nearest | |
| target_size | INT | 2560–4096 | — |
| patch_size | INT | 60–4096 | — |
| pixel_size | INT | 60–4096 | — |
| thickness | INT | 30–4096 | — |
| do_color_match | BOOLEAN | true | — |
| do_quant | BOOLEAN | false | — |
| num_colors | INT | 321–256 | — |
| quant_mode | COMBO | 3 options: kmeans, weighted-kmeans, repeat-kmeans | |
| dither_mode | COMBO | 3 options: ordered, error_diffusion, no | |
| torch_compile | BOOLEAN | true | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |