EmAySee Mask Universal XY
Expand, shrink, and punch holes in one node
- mask
- MASK
EmAySee Mask Universal XY is the one mask-shaping node you'll actually reach for. It combines two operations from this pack into a single pass: you can expand or shrink a mask independently on the X and Y axes and punch a rectangular hole out of its center, all in one node. That's the entire toolbox most masked-inpainting prep needs, minus the wire spaghetti of chaining three separate nodes.
The workflow that wants this is the classic detailer/inpaint-prep cycle. You've got a mask that hugs a subject too tightly - you want to expand it by a few pixels so the sampler has room to blend edges and doesn't leave a hard seam. Or the mask overshoots and you want to pull it in. Or you're doing a "keep the center, redraw the outline" pass and need to hollow the mask out. Universal XY does all three, and you can combine them in one execution: expand the edges 24px and punch a hole down the middle in the same step.
How it works
The expand/shrink half is real morphological dilation and erosion done with max pooling, applied per-axis. Expand positive values grow the mask outward using a max-pool kernel sized to your pixel amount; negative values erode it (it max-pools the inverted mask, then inverts back, which is the standard trick for erosion). The hole half is simpler: it finds the center of the mask's white region and zeroes out a rectangle of your chosen width and height there.
The two operations are independent and both are optional - set expand_x and expand_y to 0 and skip the hole by leaving hole_width/hole_height at 0, and it returns your mask untouched.
The inputs that matter
Five inputs, and the naming is honest:
mask- the MASK you're reshaping.expand_x/expand_y- integers from −1024 to 1024, default 0. Positive grows, negative shrinks, per axis. In pixels, not percent.hole_width/hole_height- integers from 0 to 8192, default 0. Zero means no hole. The hole is centered on the mask's content, not the canvas - the node computes the centroid of the white pixels and punches there, which is what you want for a centered subject.
The single output is the reshaped MASK. It feeds straight into a masked sampler, a MaskUnion to combine with other regions, or EmAySee_MaskOverlay when you want to eyeball the result first.
Installing it
Part of the EmAySee pack, installed like any custom node collection:
# ComfyUI Manager: search "ComfyUI_EmAySee_CustomNodes" and install
# or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/EmAySee/ComfyUI_EmAySee_CustomNodes
Restart ComfyUI afterward. The pack ships no requirements.txt; this node only needs torch, so install is clean apart from the pack's loud startup banner.
Common issues
Two things trip people up. First, expansion and erosion here are axis-aligned rectangles in effect - a heavily concave mask gets its edges grown, but the shape's interior details don't expand "with" the boundary the way a true distance-transform would. For most detailer work that's fine. Second, the hole is always centered on the content's centroid, not on where you think the middle is - if your subject is off-center, so is the hole, and there's no offset parameter to fix it. Work around it by reshaping the input mask first or accepting the centered hole. Also worth knowing: this node and EmAySee_MaskExpandShrinkXY share the same expand/shrink code, so if you only ever expand or shrink, either one works - Universal XY is the one to use when you want the hole too.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| mask | MASK | — | |
| expand_x | INT | 0-1024–1024 | — |
| expand_y | INT | 0-1024–1024 | — |
| hole_width | INT | 00–8192 | — |
| hole_height | INT | 00–8192 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| MASK | MASK | — |