Zura · Selection Points
The tiny converter between where you clicked and what SAM wants
- image
- positive_coords
- negative_coords
Point-prompted segmentation is one of the best UX ideas in this whole ecosystem: click the thing, get the mask. The catch is that the click has to survive a resize. You click in the editor at one resolution, the segmentation node runs at another, and if the coordinates are stored as pixels the mask lands somewhere near - but not on - the thing you clicked.
This node is the bridge. It converts normalized clicks into pixel coordinates in the image's actual raster.
How it works
You give it an image and a JSON list of points, each with x, y and include. The tooltip describes the contract as "Selection points relative to the actual image" - relative, meaning 0.0–1.0, not pixel positions.
For each point it multiplies the normalized coordinate by the real width and height, floors it, and clamps to width - 1 / height - 1 so a click on the last pixel doesn't fall off the edge. Points with include: true go into one JSON array, include: false into another. Those two strings are exactly what SAM-style segmentation nodes want on their positive and negative coordinate inputs - the familiar "green dot / red dot" idiom.
The validation is tighter than the job sounds, and each check maps to a real mistake:
- Up to 32 points. More than that and the node stops rather than quietly truncating.
- At least one positive. "Add at least one point inside the area you want to change." An all-negative prompt gives a segmenter nothing to segment, which is a confusing failure to debug downstream.
- Strict JSON. It parses with a
parse_constanthook that rejectsNaNandInfinity, and an object-pairs hook that catches duplicate keys. So{"x": 0.5, "y": 0.5, "include": true, "include": false}is an error, not a coin flip. - Single frame. The image must be exactly one frame - you place points on one opening frame, not a batch.
Inputs and outputs
image-IMAGE, single frame, 3 channels, floating point.points_json-STRING, default[]. From the studio's point picker; hand-editable if you're careful. Something like[{"x":0.42,"y":0.31,"include":true}].positive_coords-STRING, JSON like[{"x":538,"y":317}], into a segmentation node's positive coordinates input.negative_coords-STRING, same shape, negative points.
Install
cd ComfyUI/custom_nodes && git clone https://github.com/ZURAVFX/ComfyUI_zura_nodes
pip install -r ComfyUI_zura_nodes/requirements.txt
Restart. No weights, no GPU - it's arithmetic and JSON. The segmentation model it feeds is a separate thing entirely. The pack's SAM 3 masking example expects checkpoints/sam3.1_multiplex_fp16.safetensors in your models folder, and the studio itself uses SAM 3.1 for masking, so that's the file to grab if you're following the pack's workflows.
Common issues
"Add at least one point inside the area you want to change." All your points are exclusions. Add a positive one.
"Place selection points inside the image using finite positions." Either a coordinate outside 0–1, or the JSON contains NaN/Infinity - which usually means it was generated by something else and pasted in.
"Choose up to 32 selection points." More than 32 clicks. After about ten the segmenter's opinion stops changing much anyway.
"Use one opening frame to place selection points." The image input is a batch. Put a single-frame node in front of it - the picker stores one frame's worth of normalized clicks, and spreading those onto five frames would be meaningless.
The mask is offset from your clicks. If the picker recorded normalized coordinates against a cropped or padded version of the image and you're now feeding the uncropped original, the ratio is wrong. Feed the same raster the clicks were placed against.
Masks that grab too much. That's the segmenter, not this node - but the fix usually lives in the include/exclude split. One well-placed negative point on the thing the mask is wrongly swallowing does more than five positives on the thing you want.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| points_json | STRING | [] | Selection points relative to the actual image: x, y and include. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| positive_coords | STRING | — |
| negative_coords | STRING | — |