Nodes/ComfyUI-MLUT/Palette Apply
ComfyUI Node

Palette Apply

The deterministic pass that turns AI output into real pixel art

By TrophiHunter·Created 3 months ago·Updated 3 months ago· 0
Palette Apply
  • image
  • depth
  • image
  • name
category
source
sub
mode
amount1.00
max_colors0
invert_depthtrue
focus_distance0.50
fade_near0.20
fade_far0.20
blend_power_near1.00
blend_power_far1.00

Here's a sentence the pixel-art community keeps having to say: diffusion models don't make pixel art. They produce soft, full-color, off-grid pixels that look like pixel art from across the room. The real artifact is made afterward, by a deterministic pass - reduce to a limited palette, then dither to fake the shades in between. Palette Apply is that pass, as a ComfyUI node, from the same little pack (ComfyUI-MLUT) as the MLUT LUT nodes.

It's not only for pixel art. Lock an image to 16 colors for a stylized posterize look, push every element in a composited shot onto one palette so it reads as a single grade, or emulate a retro hardware palette. But pixel art is the job this node exists for, so that's where this article leans.

What it does

Drop a swatch - .aco (Photoshop), .act (the old Adobe palette format), .ase (Procreate/aseprite-style), or a palette PNG where every pixel is one color - into the SWATCH/ folder, and Palette Apply remaps every pixel of your image to the nearest swatch color. That's the whole algorithm. The craft is all in how the ties get broken, which is the mode input:

  • nearest - hard posterize. The most "styled," the most banded. Instant pixel-art look.
  • blue_noise - dithers with a pattern-free blue-noise field before quantizing. Reads as fine natural grain, and it's vectorized so it's fast. The one I'd reach for.
  • ordered - a 4×4 Bayer threshold, the structured crosshatch look.
  • floyd_steinberg - proper error diffusion, best tone, but serial and CPU-bound, so the slowest. Fine on small images, a drag on big ones.

The dither amplitude auto-scales to how spread out your palette's colors are (it measures the mean distance between neighboring swatches), so a 4-color PICO-8 palette gets chunkier noise than a 256-color one. That's a thoughtful touch you don't have to tune. amount blends the whole result back over the original - 1.0 is full posterize, 0.3 is a subtle "locked to this palette" tint.

The inputs

  • category - SWATCH is the one you care about.
  • source - set via the Browse… button, which opens a folder tree of your swatches. No typing paths.
  • sub - for .ase files that hold multiple named palettes; pick a group or leave (default).
  • mode / amount - covered above.
  • max_colors - optional; evenly subsamples a big palette down to N colors before mapping. 0 = use them all.

Outputs: the remapped image and a name STRING with the resolved swatch label - useful if you want the palette choice baked into a saved filename.

Installing

Same as the rest of the pack - no dependencies to speak of, since numpy/torch/Pillow already ship with ComfyUI:

cd ComfyUI/custom_nodes
git clone https://github.com/TrophiHunter/ComfyUI-MLUT

Then restart. There's no extra download step for this node (that gotcha belongs to the MLUT LUT category), but the SWATCH/ folder also ships empty - you bring the palettes. Subfolders to any depth are fine, and the catalog rebuilds itself at startup.

Troubleshooting

  • Category dropdown empty - no files in SWATCH/ yet. Add some and restart.
  • Image unchanged, no error - a palette that failed to load (or a file with no usable colors) makes the node print [MLUT] to the console and pass the image through untouched. Check the console, not the node.
  • floyd_steinberg is crawling - it's the serial path. Downscale before the node or switch to blue_noise, which gets most of the look at a fraction of the cost.

One honest caveat: this pack is a small, quiet project with barely any community chatter around it, so past the README you're mostly on your own. But the node is well-built, and for "make my image actually look pixel-art," it's the cleanest deterministic answer in ComfyUI right now - which is exactly what the "the model can't do it, the post-process can" philosophy demands.

Categoryimage/color

Inputs (14)

NameTypeDefaultDescription
imageIMAGE
categoryCOMBO1 options: <none>
sourceSTRING
subCOMBO1 options: (default)
modeCOMBO4 options: nearest, blue_noise, ordered, floyd_steinberg
amountFLOAT1.000–1
max_colorsoptINT00–1024
depthoptIMAGE
invert_depthoptBOOLEANtrue
focus_distanceoptFLOAT0.500–1
fade_nearoptFLOAT0.200–1
fade_faroptFLOAT0.200–1
blend_power_nearoptFLOAT1.000.01–5
blend_power_faroptFLOAT1.000.01–5

Outputs (2)

NameTypeDescription
imageIMAGE
nameSTRING