Nodes/D2 Nodes ComfyUI/D2 Random Mask
ComfyUI Node

D2 Random Mask

A rectangle that lands somewhere new every time you queue

By da2el-ai·Created 2 years ago·Updated 2 days ago· 68
D2 Random Mask
    • width
    • height
    • mask
    • mask_x
    • mask_y
    • mask_w
    • mask_h
    width1024
    height1024
    min_width512
    max_width512
    min_height512
    max_height512
    seed0

    This is a utility node and it makes no apology for it: it emits one rectangular MASK plus the pixel coordinates of that rectangle, and it puts the rectangle somewhere new every run. Nothing here detects anything - for that you want the Impact Pack. This is for when you want a region, randomly placed, and nobody cares which one.

    What you'd actually use it for

    Three honest cases. First, testing an inpaint chain: paint one mask by hand and you've tested one spot on one image. A random mask runs your pipeline over a different part of the frame every queue, which is how you find the seams and size mismatches a hand-placed box quietly avoids. Second, randomised crop and detail passes - feed mask_x/mask_y/mask_w/mask_h into a crop node and every run pulls a different patch, which is real dataset augmentation and a cheap way to check a checkpoint is consistent across the whole frame. Third, composite smoke tests: if it survives the box landing anywhere, it survives the box landing where you wanted it.

    How it works

    The node has its own random.Random(seed) instance rather than touching the global random module. That matters: other random pickers in the graph use the global generator, and mutating it drags unrelated nodes' results around with it.

    Per run it draws a width and a height independently - inclusive randint between your min and max, clamped to 1…canvas size - then picks a uniform top-left corner from 0…width-w and 0…height-h. Size first, corner constrained to what's left: the rectangle can never poke outside the canvas, it just comes out smaller than asked if your min_width exceeds the frame. The mask itself is a float32 tensor of shape (1, height, width) with the rectangle set to 1.0. Hard edges, no feather - GrowMask or MaskBlur if you need the seam softened (4–12px is the usual range for inpaint seams).

    Inputs and outputs

    Set these:

    • width / height - the mask canvas, in steps of 8, default 1024×1024. Match this to your latents, or the mask arrives at a different resolution than the thing you're masking.
    • min_width / max_width / min_height / max_height - the rectangle's pixel dimensions, 1–16384. Defaults are 512/512/512/512, i.e. a fixed 512×512 square wandering the frame. Widen the gap between min and max if you want the size to vary too.
    • seed - it carries the control_after_generate widget, which is what makes the node re-roll between queues. Set it to fixed to lock a region you liked.

    min and max in either direction get swapped rather than rejected, so typing them backwards costs you nothing.

    Outputs: width and height (passthroughs of your inputs, handy for sizing a matching latent or an inpaint encode without a second pair of widgets), then the good ones - mask, and mask_x / mask_y / mask_w / mask_h, the pixel rectangle the node actually rolled. Those four are the difference between "a random mask" and "a random region I can crop": wire them into a crop node's x/y/width/height and you can pull the patch out for a detail pass.

    Install

    It ships in D2 Nodes ComfyUI. Manager → search the pack title → install → restart, or:

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

    Two tiny Python deps (piexif, charset-normalizer), no models. This node is new enough that it arrived in a commit alongside D2 Random Point, so if it isn't in your node list, update the pack - and if you're on a ComfyUI older than the V3 schema era (pre-v32.0.0 of the pack, roughly), update ComfyUI rather than pinning the pack back.

    Common issues

    "It doesn't randomise." Check the seed's control setting first - on fixed you get the same rectangle forever, which is correct behaviour and also the most common confusion. Second: ComfyUI caches nodes by input signature, and this one dodges that cache precisely because the control rewrites the seed between queues, so a wired-in seed is your job to change. And mind the standing control_after_generate trap - with the control firing after a run, the number in the box is the one the next queue will use, so a good seed is already gone by the time you see the result. ComfyUI's global "widget control mode" set to Before fixes that everywhere.

    The mask is a solid band that doesn't fit. Your min size exceeded the canvas and got clamped. A min_width of 4096 on a 1024-wide canvas just becomes 1024.

    Downstream complains about the mask shape. The mask is built at the node's width/height, not at whatever your latent is. Wire the same width/height values through, or feed the passthrough outputs where they're accepted.

    CategoryD2/Image

    Inputs (7)

    NameTypeDefaultDescription
    widthINT10248–16384
    heightINT10248–16384
    min_widthINT5121–16384
    max_widthINT5121–16384
    min_heightINT5121–16384
    max_heightINT5121–16384
    seedINT00–18446744073709550000

    Outputs (7)

    NameTypeDescription
    widthINT
    heightINT
    maskMASK
    mask_xINT
    mask_yINT
    mask_wINT
    mask_hINT