Mask Sort By Position
Sort masks left-to-right so 'the second character' finally means something
- masks
- masks
- debug_image
"Apply this to the leftmost character" is a maddening thing to wire up in ComfyUI, because segmentation doesn't return masks in any useful order. It returns them in whatever order the model felt like. Mask Sort By Position fixes that: it sorts a list of masks by where they actually sit in the frame, so you can reliably address subjects as "first from the left," "top-most," and so on.
That ordering is what makes the rest of the pack usable. Feed the sorted list into Mask Pick By Index and 0 becomes "leftmost" and -1 becomes "rightmost" regardless of how many subjects were detected. This is the node that turns position into an address.
How it works
Each mask gets assigned a reference point, and the list is sorted by those points. Two modes for the point:
centroid- the value-weighted center of the mask. Soft or feathered masks are handled correctly (brighter pixels pull the point toward them); a plain binary mask reduces to the geometric mean. This is the sensible default.extreme_point- the outermost pixel along the primary sort direction, e.g. the leftmost pixel when sorting left-to-right. Good when you care about where a mask starts, not where its mass is.
From there: sort_left_to_right and sort_top_to_bottom set each axis's direction, and primary_axis_horizontal decides which axis sorts first, with the other breaking ties. The sort is stable, so full ties fall back to original order - you won't get random reshuffling on identical masks.
Inputs that matter
You'll touch four of these, and can ignore the rest:
masks- the list to sort (convert a batch with Mask Batch To List first).reference_point-centroidorextreme_point, described above.sort_left_to_right/sort_top_to_bottom- direction per axis.primary_axis_horizontal- which axis wins when two masks share a coordinate.
The remaining three - flatten_before_sort, drop_below_threshold, and threshold - exist for fiddly cases: flatten_before_sort binarizes each mask before computing its sort point, and drop_below_threshold ignores faint pixels. Worth knowing they only affect sorting; the output masks are always your originals, just reordered. Easy to misread them as editing the masks.
The debug output
The second output, debug_image, is a white canvas with a black dot marking each mask's sort point, drawn in sorted order. This is not decoration - wire it into a PreviewImage once and you'll instantly see whether "leftmost" is what you think it is. Particularly with extreme_point on feathered masks, where a stray faint pixel far from the subject can claim the extreme; that's exactly when flatten_before_sort earns its keep.
Installation and notes
Same as the rest of the pack - clone, restart, no extra deps:
cd ComfyUI/custom_nodes
git clone https://github.com/INuBq8/ComfyUI-MultiMaskOps
Nodes land under MultiMaskOps; Manager search "MultiMaskOps" is the easier route once the listing is live. Empty masks sort to the origin (0, 0) by design, so a blank mask will sort as "top-left" - deduplicate or drop empties first if that skews your order. The pack is young (one commit as of mid-2026) and this node has no usage history to speak of, but the source is a clean ~30 lines of sort logic, and the debug output makes it self-verifying.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| masks | MASK | A list of masks to sort by spatial position. | |
| reference_point | COMBO | Which point of each mask to sort by. 'centroid' = value-weighted center of the mask. 'extreme_point' = the outermost pixel along the primary sort direction (e.g. leftmost pixel when sorting left-to-right). | |
| sort_left_to_right | BOOLEAN | true | Horizontal direction. True = left to right, False = right to left. |
| sort_top_to_bottom | BOOLEAN | true | Vertical direction. True = top to bottom, False = bottom to top. |
| primary_axis_horizontal | BOOLEAN | true | Which axis sorts first. True = sort horizontally first, then vertically to break ties. False = vertical first, then horizontal. |
| flatten_before_sort | BOOLEAN | false | If enabled, each mask is binarized at 'threshold' before its sort point is computed. Only affects sorting; output masks are unchanged. |
| drop_below_threshold | BOOLEAN | false | If enabled (and not flattening), pixels below 'threshold' are ignored when computing the sort point (a thresholded ReLU). Only affects sorting; output masks are unchanged. |
| threshold | FLOAT | 0.500–1 | Cutoff used by flatten_before_sort and drop_below_threshold to decide which pixels count when computing each mask's sort point. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| masks | MASK | The input masks reordered by spatial position. |
| debug_image | IMAGE | A white image with a black dot marking each mask's sort reference point, in sorted order. For debugging. |