Nodes/comfyui-properpixelart/Proper Pixel Art Config
ComfyUI Node

Proper Pixel Art Config

The 35-knob escape hatch (ignore it until detection fails)

By unclepomedev·Created 23 days ago·Updated 2 days ago· 1
Proper Pixel Art Config
    • config
    ◄crop_border_pixels2►
    ◄canny_low50►
    ◄canny_high200►
    ◄closure_kernel_size8►
    ◄cluster_threshold4►
    ◄angle_threshold_deg15►
    ◄trim_outlier_fraction0.20►
    ◄snap_linestrue►
    ◄snap_search_window_ratio0.35►
    ◄snap_min_search_window2►
    ◄snap_strength_threshold0.50►
    ◄anchor_snap_window2►
    ◄max_axis_width_ratio1.8►
    ◄validate_widthtrue►
    ◄width_keep_tolerance1.5►
    ◄width_replace_tolerance0.20►
    ◄profile_width_min_gaps5►
    ◄split_leftover_fraction0.40►
    ◄rho1.0►
    ◄theta_deg1.0►
    ◄hough_threshold100►
    ◄min_line_len50►
    ◄max_line_gap10►
    ◄alpha_threshold128►
    ◄transparency_majority_fraction0.50►
    ◄quantize_methodMAXCOVERAGE►
    ◄ditherNONE►
    ◄kmeans0►
    ◄bin_size52►
    ◄merge_distance12►
    ◄merge_linkagecomplete►
    ◄max_linkage_colors4096►
    ◄top_colors_limit8►
    ◄thumbnail_w160►
    ◄thumbnail_h160►

    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) and hough_threshold (100) - the line detector wants long, well-voted lines. Lowering these helps small or sparse sprites.
    • cluster_threshold (4) and angle_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, MAXCOVERAGE or FASTOCTREE, straight from Pillow.
    • dither - NONE or FLOYDSTEINBERG. 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.

    Categoryimage/Proper Pixel Art

    Inputs (35)

    NameTypeDefaultDescription
    crop_border_pixelsINT2Number of border pixels trimmed before edge detection.
    canny_lowINT50Lower Canny edge detection threshold.
    canny_highINT200Upper Canny edge detection threshold.
    closure_kernel_sizeINT8Kernel size for morphological closing.
    cluster_thresholdINT4Maximum distance in pixels to merge nearby grid lines.
    angle_threshold_degFLOAT15Tolerance angle in degrees for accepting vertical and horizontal lines.
    trim_outlier_fractionFLOAT0.20Tail fraction of grid gap outliers trimmed when estimating pixel width.
    snap_linesBOOLEANtrueAlign detected lines to local edge energy peaks.
    snap_search_window_ratioFLOAT0.35Ratio of estimated pixel width used as snap search half-window.
    snap_min_search_windowINT2Minimum snap search half-window in pixels.
    snap_strength_thresholdFLOAT0.50Minimum normalized gradient magnitude along a candidate line to trigger snapping.
    anchor_snap_windowINT2Search half-window in pixels when snapping the grid origin to an edge anchor.
    max_axis_width_ratioFLOAT1.8Maximum allowed ratio between horizontal and vertical pixel widths.
    validate_widthBOOLEANtrueCheck estimated grid spacing against edge profile peaks.
    width_keep_toleranceFLOAT1.5Relative tolerance within which profile-validated width is preferred.
    width_replace_toleranceFLOAT0.20Relative error threshold for replacing an inconsistent grid width.
    profile_width_min_gapsINT5Minimum number of line gaps required to accept a profile-based width estimate.
    split_leftover_fractionFLOAT0.40Fraction of remaining interval length above which a line gap is further split.
    rhoFLOAT1.0Hough transform distance resolution in pixels.
    theta_degFLOAT1.0Hough transform angle resolution in degrees.
    hough_thresholdINT100Minimum accumulator votes to accept a line in Hough transform.
    min_line_lenINT50Minimum line length in pixels to accept in Hough transform.
    max_line_gapINT10Maximum gap between line segments in pixels to join them in Hough transform.
    alpha_thresholdINT1280–255Alpha threshold above or equal to which a pixel is considered opaque.
    transparency_majority_fractionFLOAT0.500–1Fraction of transparent pixels in a cell required to treat the cell as transparent.
    quantize_methodCOMBOMAXCOVERAGEPIL.Image.Quantize method name for color quantization.
    ditherCOMBONONEDithering mode applied during color quantization.
    kmeansINT0Number of KMeans iterations for quantization clustering (0 disables KMeans).
    bin_sizeINT52RGB bin size used when clustering dominant cell colors.
    merge_distanceINT12Maximum RGB Euclidean distance between colors merged into a single cluster.
    merge_linkageCOMBOcompleteLinkage criterion used for hierarchical agglomerative color clustering.
    max_linkage_colorsINT4096Upper limit on the number of candidate colors before switching to fast merge.
    top_colors_limitINT8Number of common opaque colors sampled when picking a background color.
    thumbnail_wINT160Width downscale size for color analysis.
    thumbnail_hINT160Height downscale size for color analysis.

    Outputs (1)

    NameTypeDescription
    configCOMFYUI_PROPERPIXELART_CONFIGAdvanced configuration object for Proper Pixel Art nodes.