Nodes/D2 Nodes ComfyUI/D2 Random Point
ComfyUI Node

D2 Random Point

One random X/Y pair, in pixels or as a fraction

By da2el-ai·Created 2 years ago·Updated 2 days ago· 68
D2 Random Point
    • width
    • height
    • x
    • y
    width1024
    height1024
    min_x0.00
    max_x1.00
    min_y0.00
    max_y1.00
    modeabsolute
    number_typeint
    seed0

    A random point is a small thing to want, and typing coordinates by hand is a small annoyance - until you're running a workflow forty times and quietly reusing the same crop origin for all forty. D2 Random Point outputs one X/Y pair, as absolute pixels or as a 0–1 fraction, re-rolled every queue. No canvas, no mask, no pixels.

    What it's for

    Coordinate sockets. Anywhere a node asks you to type an x and a y - a crop origin, a paste position, a region anchor - right-click that widget, hit Convert widget to input, and drop this node's x/y onto the new sockets. Now the position is defined once and randomised per run instead of retyped.

    If you know where you want the point, this is the wrong tool - D2 Create Point, same pack, gives you a canvas to click on. Random Point is for when any point in a range will do.

    The outputs are typed as the wildcard *, deliberately: the runtime type changes with the mode, so a wildcard socket means flipping mode or number_type doesn't tear your wires out, and x plugs into an INT or FLOAT input regardless. It also means ComfyUI won't warn you if the consumer wanted a different type.

    How it works

    The design decision worth understanding: min_x/max_x/min_y/max_y are always fractions, 0.0 to 1.0, in both modes. The node draws a uniform random value in that range, then converts. So your box keeps meaning the same part of the frame when width/height change, and switching mode doesn't move anything - 0.75 relative is 768 absolute at a width of 1024.

    The conversion:

    • mode: absolute + number_type: intint(round(rel * size)) - a whole pixel.
    • mode: absolute + number_type: floatrel * size, unrounded.
    • mode: relative → the fraction itself, and number_type is ignored. Rounding a fraction to an int would leave you with 0 or 1, so the author skips it.

    Reversed ranges get swapped instead of erroring, and out-of-range values get clamped - the widget limits you, upstream wired inputs don't.

    Inputs and outputs

    What you actually set:

    • width / height - the coordinate space, default 1024×1024, multiples of 8. This is what "absolute" is absolute to; it's not a canvas, the node draws nothing.
    • min_x / max_x / min_y / max_y - the box the point can land in, as fractions, step 0.01. Defaults cover the whole frame. min_y: 0.6, max_y: 0.95 gives you "somewhere in the lower third", which is the kind of thing this node is actually for.
    • mode - absolute or relative.
    • number_type - int or float, absolute mode only.
    • seed - carries control_after_generate, which is what makes it re-roll between queues. fixed reproduces a result.

    Outputs are width, height, x, y. The size passthroughs exist so a downstream crop or latent can be sized from the same place as the point rather than from a second pair of widgets.

    Install

    Part of D2 Nodes ComfyUI. 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 inside ComfyUI's python env, then restart
    

    The pack's requirements.txt is two tiny packages (piexif, charset-normalizer) and there are no model downloads. Install them even though this node needs neither - piexif is imported when the pack's image module loads, so a bare clone can take the whole D2/Image category down, this node included. Since v32.0.0 the pack targets ComfyUI's V3 node schema, so you need a current ComfyUI; on an old one, update the app, not the pack.

    Common issues

    Same point every run. The seed's control is on fixed - that's also how you get reproducibility, find a point you like and lock it. And note the standing control_after_generate trap: with the control firing after a run, the number shown is the seed the next queue will use, so flip ComfyUI's global "widget control mode" to Before if you plan on catching good seeds. (ComfyUI caches nodes by input signature, and that seed control is exactly what changes it - convert the seed into a wired input and the node stops re-rolling on its own.)

    x is always 0 or 1. You're in relative mode expecting pixels, or in absolute mode with the range still at its defaults and a tiny width. Check mode first.

    Downstream wants an int and gets a float. Wildcard sockets don't validate; set number_type to int when the consumer is a pixel-index widget. And note absolute + int can return exactly width or height - the range is inclusive of the edge, not size - 1 - so keep a little margin if your consumer indexes pixels.

    CategoryD2/Image

    Inputs (9)

    NameTypeDefaultDescription
    widthINT10248–16384
    heightINT10248–16384
    min_xFLOAT0.000–1
    max_xFLOAT1.000–1
    min_yFLOAT0.000–1
    max_yFLOAT1.000–1
    modeCOMBOabsolute2 options: absolute, relative
    number_typeCOMBOint2 options: int, float
    seedINT00–18446744073709550000

    Outputs (4)

    NameTypeDescription
    widthINT
    heightINT
    x*
    y*