Mask Contour Processor
This node grows spiky rays out of your inpainting mask
- mask
- MASK
Mask Contour Processor takes any binary mask and pushes wavy, tapering rays outward from its edge, like a sunburst drawn around your selection. The pitch is that this "extends mask boundaries" to give inpainting better context at the seam. The truth is closer to: it's a mask-grow with personality, and whether the personality helps your inpaint is genuinely up for debate.
Before you get attached, know the situation: this is a v0.1 node from an individual dev (codeprimate, aka Patrick Morgan - a real, active r/StableDiffusion regular, which is more than you can say for a lot of one-off nodes), with zero search impressions. Nobody's community-tested it. You're the test. Fine, that's half the fun.
How it works
The class docstring calls the output "decorative flame-like contour effects," which is the honest version - this clearly started life as a browser-canvas effect demo (there's a whole web/ folder) and got repurposed into a mask node. The mechanism, straight from the source:
- It finds the mask's centroid.
- It scans every row and every column looking for 0→1 transitions to find the edge pixels, then sorts them clockwise around the centroid.
- It thins those thousands of edge pixels down to
line_countevenly spaced points. - From each point it draws a ray pointing away from the centroid: a sine-wobbling line whose amplitude decays as it travels and whose width tapers, rendered with Pillow and added back onto the original mask.
- The whole thing gets a Gaussian blur of
blur_amount.
The output is still a MASK, same dimensions, same batch size. So mechanically it's a mask preprocessor: whatever you wire it before - a Set Latent Mask → VAE Encode inpaint chain, or a sampler mask - now sees a mask with an organic, irregular fringe instead of a clean hard edge.
The inputs that matter
mask- your source mask. Any MASK works.line_length(0–3, default 0.5) - this one's easy to misread. Ray length isdistance from edge point to centroid × line_length, so it's relative: 1.0 means rays reach back to the center of the mask, 0.5 means halfway. Keep it well under 1 for a modest fringe.line_count(1–40, default 16) - how many rays. Low values look sparse and spiky; 25–35 gets dense and flame-like.line_width(0–0.1, default 0.015) - also relative. The actual stroke ismax(1, mask_circumference × line_width), so the same number gives thin rays on a small mask and chunky ones on a big one. This is the number that makes people think the node is broken; see below.blur_amount(0–50, default 2) - the feathering. For inpainting you want this higher; 0 leaves the rays as hard edges.
Output: one MASK, same batch as the input.
Does it actually help inpainting?
The idea underneath is legit. The whole reason "only masked" inpaint crops in padding and why everyone feathers their masks is that the model wants context around the region, and hard mask edges make seams visible - the KB's inpainting notes hammer this. Extending the mask outward gives the model more ground to blend against. So the direction is right.
But the flame geometry is decorative, and the boring route gets you there with more predictability: ComfyUI's built-in mask blur/dilate nodes (or Impact Pack's mask ops) give you a smooth, feathered grow you can reason about. Reach for Mask Contour Processor when you want an organic, spiky boundary - a costume, a stain, a tree canopy, an object whose edge shouldn't be a clean geometric line. And test it: does it improve your inpaint or just make the mask weird? You'll know in one run.
Install and gotchas
ComfyUI Manager (search "Mask Contour Processor"), or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/codeprimate/ComfyUI-MaskContourProcessor
cd ComfyUI-MaskContourProcessor
pip install -r requirements.txt
Restart ComfyUI. No model downloads, no heavy deps - requirements is just numpy, torch, and Pillow, which ComfyUI already ships. Two real gotchas:
- It's CPU-bound Python. Edge detection is two full passes of per-pixel loops. Small masks are instant; at the README's stated ceiling of 4096×4096 it'll chug. Work on a downscaled mask and upscale if needed.
line_widthfeels dead until it doesn't. Because it's scaled by circumference, on a small mask you'll see nothing until you push toward 0.05–0.1. On a big mask the default 0.015 is already chunky. Move it around before you conclude it's broken.
Start at the defaults, nudge line_length down to 0.3, crank blur_amount to 8–12 for an inpainting pass, and judge the seam - not the sparkle.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| mask | MASK | — | |
| line_length | FLOAT | 0.500–3 | — |
| line_count | INT | 161–40 | — |
| line_width | FLOAT | 0.0150–0.1 | — |
| blur_amount | FLOAT | 2.00–50 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| MASK | MASK | — |