Nodes/D2 Nodes ComfyUI/D2 Create Masks
ComfyUI Node

D2 Create Masks

Drag rectangles on the node, get one MASK socket per region

By da2el-ai·Created 2 years ago·Updated 2 days ago· 68
D2 Create Masks
  • canvas
  • image
  • width
  • height
  • mask_1
mask_count1
select_mask1
width1024
height1024
image
masks[]

ComfyUI's built-in mask editor gives you one mask per image and a full-screen paint window to make it in. D2 Create Masks gives you a little canvas inside the node - image as background, up to sixteen rectangles you drag around - and then hands you mask_1, mask_2, mask_3… as separate MASK outputs. That's the whole pitch, and it's a real one: one mask per region means one inpaint pass per region, each with its own prompt and denoise.

Why separate masks instead of one painted mask

Mask-based inpainting lost most of its territory to instruction-editing models (Kontext, Qwen-Image-Edit) between 2025 and 2026, but it kept what they can't do: the pixels outside the mask come back bit-identical, and denoise stays a dial rather than a sentence. The place that bites is a face you want to fix differently than the hands, or a background you want swapped without re-rolling the subject. One combined mask forces one pass over everything; three rectangles wired to three inpaint branches lets each region keep its own prompt, CFG and denoise - the loop the detailer packs automate, minus the detector deciding where the boxes go.

That's the honest trade. Impact Pack's FaceDetailer finds faces for you; this is the manual version - you place the box, on a canvas you can see.

How it works

Everything you drag is stored as relative geometry - x, y, w, h in the 0.0–1.0 range - inside the masks string widget as JSON. Nothing becomes pixels until you hit queue, and then the backend just makes a float32 tensor of shape (1, height, width) and sets the rectangle's interior to 1.0. Hard-edged, no feathering; for soft seams you add MaskBlur or GrowMask downstream.

The relative storage is why changing width/height rescales the rectangles instead of flinging them off the canvas, and why masks is safe to ignore - it rewrites itself on every drag. The canvas you interact with is a frontend-only widget (D2_MASK_CANVAS); the JSON is the real data.

The inputs that matter

  • mask_count (1–16) - how many masks exist, and therefore how many mask_1 … mask_N output sockets appear. Raise it, drag a new box, done. Lowering it keeps the leftover rectangles in the JSON, so raising it again restores them.
  • select_mask - which rectangle is "active". Purely frontend, but useful: clicking a rectangle sets it, and setting it puts the resize handles on that rectangle. When two rectangles sit exactly on top of each other, this is the only way to grab the one underneath.
  • width / height - the mask grid, in steps of 8, up to 16384. Also sets the canvas aspect ratio in the UI.
  • image - a dropdown of everything in ComfyUI/input. Leave it empty for a black canvas, or drag/drop (or paste, or use the upload button) an image straight onto the node; the node then adopts that image's size for width/height.

canvas and masks are internal. Don't hand-edit masks: a corrupted JSON doesn't raise, it silently falls back to the default rectangles, so you'd watch your boxes snap back to the middle with no explanation.

Outputs are image, width, height, and mask_1 (plus mask_2, mask_3, … as mask_count goes up). Wire a mask_N into Set Latent Noise Mask, InpaintModelConditioning, or any MaskComposite chain; width/height are there so a matching Empty Latent can be sized from the same numbers.

Install

In ComfyUI Manager search for the pack title, D2 Nodes ComfyUI (registry publisher da2el), install, restart. Or clone it:

cd ComfyUI/custom_nodes
git clone https://github.com/da2el-ai/D2-nodes-ComfyUI
# then pip install -r D2-nodes-ComfyUI/requirements.txt in ComfyUI's python env
# and restart ComfyUI

No model downloads and no heavy dependencies - requirements.txt is two tiny packages (piexif, charset-normalizer). If you already have ComfyUI-d2-size-selector, ComfyUI-d2-steps or ComfyUI-d2-xyplot-utils installed, remove them: the author folded those into this pack and says so in the notice.

Common issues

The node is missing from the D2/Image menu after a manual clone. piexif is imported at module load of image_util.py, and the whole D2/Image module goes down with it if that import fails - run the pip line above and restart.

Nothing works on an older ComfyUI. Since v32.0.0 the pack targets ComfyUI's V3 node schema (comfy_api.latest, io.ComfyNode, comfy_entrypoint) - the modern backend API, not the frontend rewrite - so it needs a reasonably current ComfyUI. If yours is pinned old, install a release tag below 32.0.0.

The node renders but you can't drag anything. The canvas is JavaScript. Restart ComfyUI fully and hard-refresh the browser (Ctrl-Shift-R); a half-loaded frontend leaves the widget blank.

Masks don't line up with the image output. Dragging an image onto the node sets width/height for you; typing new values afterwards moves the mask grid while the output image stays at its original resolution. Re-drop the image, or match the numbers.

CategoryD2/Image

Inputs (7)

NameTypeDefaultDescription
mask_countINT11–16
select_maskINT11–16
widthINT10248–16384
heightINT10248–16384
imageCOMBO2 options: , example.png
canvasoptD2_MASK_CANVAS
masksoptSTRING[]

Outputs (4)

NameTypeDescription
imageIMAGE
widthINT
heightINT
mask_1MASK