Proper Pixel Art Config
The 35-knob escape hatch (ignore it until detection fails)
- config
This node looks terrifying and does nothing on its own. Thirty-five widgets, one output, and if you drop it on the canvas and hit Queue you get an empty run and no image. That's not a bug - it's a config carrier, the plumbing pattern where a bundle of values gets packed into a single wire so the graph doesn't turn into a spiderweb of loose numbers.
In practice: you don't need this node until the pixelation is visibly wrong, and then you only touch one or two of its knobs.
What it's for
Proper Pixel Art Config builds the advanced PixelateConfig object that the other two nodes in the pack accept on their optional config input - both Proper Pixel Art and Proper Pixel Art Video / GIF. It exposes the deeper algorithm parameters (edge detection, line finding, grid width validation, color quantization, transparency handling) that the main nodes deliberately hide, so you can tune the mesh detection instead of just overriding its result with a manual pixel_width.
Its one output is config (type COMFYUI_PROPERPIXELART_CONFIG), and it only plugs into the config input on the other nodes.
How it works
Nothing is computed when this node runs. It just assembles and passes along settings: the mesh-detection group (Canny thresholds, morphological closing, Hough resolution, line clustering, profile snapping, width validation, border trimming), the color group (alpha thresholding, quantization method, dithering, color clustering), and the thumbnail sizes used for color analysis.
One consequence worth knowing before you spend an evening on the color knobs: num_colors on the main node wins. At num_colors = 0 the pipeline is forced into upstream's dominant-color mode, and quantize_method, dither and kmeans here have no effect. Set num_colors to 1 or more first, then tune them.
The knobs that actually earn their place
When it can't find the grid at all (output looks like a slightly soft version of the input, or blocks are half the size they should be):
canny_low/canny_high(50 / 200) - if your art is low-contrast, faint edges never register. Lower both.min_line_len(50) andhough_threshold(100) - the line detector wants long, well-voted lines. Lowering these helps small or sparse sprites.cluster_threshold(4) andangle_threshold_deg(15) - how close lines must be to merge, and how far off vertical/horizontal a line may be and still count.crop_border_pixels(2) - raise it if your source has a frame, a letterbox bar or a painted border poisoning edge detection.max_axis_width_ratio(1.8) - pixels are assumed square; this caps how mismatched the two axes may be before one is distrusted.validate_width,width_keep_tolerance,width_replace_tolerance,profile_width_min_gaps- the reconstruction-error check that stops the estimator locking onto double the true pixel width. Leave these alone unless nothing else works.
When the transparency is wrong - soft anti-aliased fringes turning into hard opaque cells, or background refusing to key out:
alpha_threshold(128) - at or above this alpha, a pixel counts as opaque.transparency_majority_fraction(0.5) - what fraction of a cell must be transparent before the whole cell goes transparent. Raise it to keep more, lower it to punch out more.
When the colors are wrong (only with num_colors ≥ 1 on the main node):
quantize_method-MEDIANCUT,MAXCOVERAGEorFASTOCTREE, straight from Pillow.dither-NONEorFLOYDSTEINBERG. Dithering fakes extra shades inside a tiny palette; it also makes the result look like 1993, which may be the point.kmeans(0 = off) - extra k-means iterations for the quantization clusters. Slower, sometimes cleaner.
Otherwise bin_size, merge_distance, merge_linkage and max_linkage_colors control how near-duplicate colors collapse into one - that's what makes flat areas flat - top_colors_limit with thumbnail_w/thumbnail_h controls the color sampling used to pick a background color, and rho/theta_deg are Hough resolution for people who enjoy that.
Install
Same pack, so the same install - ComfyUI Manager, search ComfyUI-ProperPixelArt, restart. By hand:
cd ComfyUI/custom_nodes
git clone https://github.com/unclepomedev/ComfyUI-ProperPixelArt
cd ComfyUI-ProperPixelArt
pip install -r requirements.txt
No models, no checkpoints, no API key. It wants Python ≥3.12 and a recent ComfyUI, since the pack is built on the modern node API.
Troubleshooting
"I added the node and nothing happened." Correct - it has no output image and nothing to execute. It only matters once it's wired into the config input.
"Knobs changed nothing." Usual causes: the config wire isn't connected, you're tuning palette knobs while num_colors = 0, or a manual pixel_width is still set on the main node.
"I want to change the palette size here." You can't - num_colors is a main-node input; this node controls how quantization happens, not how many colors.
"How do I see what it actually did?" This node won't show you. Set intermediate_dir on the main node instead: it dumps a visualization of each algorithm stage into numbered subfolders of your ComfyUI output directory. Change one config value, re-run, compare the stages.
Inputs (35)
| Name | Type | Default | Description |
|---|---|---|---|
| crop_border_pixels | INT | 2 | Number of border pixels trimmed before edge detection. |
| canny_low | INT | 50 | Lower Canny edge detection threshold. |
| canny_high | INT | 200 | Upper Canny edge detection threshold. |
| closure_kernel_size | INT | 8 | Kernel size for morphological closing. |
| cluster_threshold | INT | 4 | Maximum distance in pixels to merge nearby grid lines. |
| angle_threshold_deg | FLOAT | 15 | Tolerance angle in degrees for accepting vertical and horizontal lines. |
| trim_outlier_fraction | FLOAT | 0.20 | Tail fraction of grid gap outliers trimmed when estimating pixel width. |
| snap_lines | BOOLEAN | true | Align detected lines to local edge energy peaks. |
| snap_search_window_ratio | FLOAT | 0.35 | Ratio of estimated pixel width used as snap search half-window. |
| snap_min_search_window | INT | 2 | Minimum snap search half-window in pixels. |
| snap_strength_threshold | FLOAT | 0.50 | Minimum normalized gradient magnitude along a candidate line to trigger snapping. |
| anchor_snap_window | INT | 2 | Search half-window in pixels when snapping the grid origin to an edge anchor. |
| max_axis_width_ratio | FLOAT | 1.8 | Maximum allowed ratio between horizontal and vertical pixel widths. |
| validate_width | BOOLEAN | true | Check estimated grid spacing against edge profile peaks. |
| width_keep_tolerance | FLOAT | 1.5 | Relative tolerance within which profile-validated width is preferred. |
| width_replace_tolerance | FLOAT | 0.20 | Relative error threshold for replacing an inconsistent grid width. |
| profile_width_min_gaps | INT | 5 | Minimum number of line gaps required to accept a profile-based width estimate. |
| split_leftover_fraction | FLOAT | 0.40 | Fraction of remaining interval length above which a line gap is further split. |
| rho | FLOAT | 1.0 | Hough transform distance resolution in pixels. |
| theta_deg | FLOAT | 1.0 | Hough transform angle resolution in degrees. |
| hough_threshold | INT | 100 | Minimum accumulator votes to accept a line in Hough transform. |
| min_line_len | INT | 50 | Minimum line length in pixels to accept in Hough transform. |
| max_line_gap | INT | 10 | Maximum gap between line segments in pixels to join them in Hough transform. |
| alpha_threshold | INT | 1280–255 | Alpha threshold above or equal to which a pixel is considered opaque. |
| transparency_majority_fraction | FLOAT | 0.500–1 | Fraction of transparent pixels in a cell required to treat the cell as transparent. |
| quantize_method | COMBO | MAXCOVERAGE | PIL.Image.Quantize method name for color quantization. |
| dither | COMBO | NONE | Dithering mode applied during color quantization. |
| kmeans | INT | 0 | Number of KMeans iterations for quantization clustering (0 disables KMeans). |
| bin_size | INT | 52 | RGB bin size used when clustering dominant cell colors. |
| merge_distance | INT | 12 | Maximum RGB Euclidean distance between colors merged into a single cluster. |
| merge_linkage | COMBO | complete | Linkage criterion used for hierarchical agglomerative color clustering. |
| max_linkage_colors | INT | 4096 | Upper limit on the number of candidate colors before switching to fast merge. |
| top_colors_limit | INT | 8 | Number of common opaque colors sampled when picking a background color. |
| thumbnail_w | INT | 160 | Width downscale size for color analysis. |
| thumbnail_h | INT | 160 | Height downscale size for color analysis. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| config | COMFYUI_PROPERPIXELART_CONFIG | Advanced configuration object for Proper Pixel Art nodes. |