Person Selector SAM3 (native)
SAM3 masking without the second installation
- sam3_model
- sam3_clip
- current_image
- reference_1
- reference_2
- reference_3
- reference_4
- reference_5
- depth_map
- person_data
- face_masks
- head_masks
- body_masks
- aux_masks
- preview
- similarities
- matches
- matched_count
- face_count
- report
- aux_data
SAM 3 changed how masking works here. Before it, text-to-mask meant GroundingDINO to find the thing and SAM to segment it. Since November 2025 a short noun phrase goes straight in and returns every matching instance at once, which is why SAM 3 became ambient vocabulary inside eight months. The packaging is the less fun part: the popular third-party ComfyUI SAM3 nodes need Triton - a real obstacle on Windows - and the fat ones hit out-of-memory. That's the gap this node fills.
It's the person selector the pack already had - detect faces, match them to your reference images, build the mask set, hand back PERSON_DATA for a Person Detailer. The difference is what does the grounding. Instead of the comfyui-sam3 extension's model object, it drives the SAM3 that ComfyUI itself now understands: no extension, no second model load, no separate environment that can drift out of sync with ComfyUI's own.
Wiring it, which is the whole trick
One CheckpointLoaderSimple on your SAM3 checkpoint, and both of its outputs go in:
CheckpointLoaderSimple(sam3 checkpoint)
MODEL ──► sam3_model
CLIP ──► sam3_clip
The text encoder ships inside the same checkpoint, which is why the node needs the CLIP object as well - it builds its own prompts (person, face, hair, …) rather than accepting pre-encoded conditioning. Use both outputs from the same loader. A CLIP from a different checkpoint means the prompts and the vision trunk aren't speaking the same language, and you'll get noise rather than an error.
Under the hood the trunk runs once per image: the image is upscaled to 1008×1008, the ViTDet backbone encodes it, and every prompt is grounded against that single result. Trunk-once, ground-many - same split ComfyUI's own per-frame text detection uses. It's also why adding aux prompts is cheap and re-encoding is not.
The inputs that matter
threshold at 0 means auto: optimal one-to-one assignment between detected faces and your reference slots, and the tooltip recommends it. Set it above 0 and you're asking for a manual minimum similarity instead - useful when auto is matching a stranger to your reference.
match_weights blends the signals used for matching: face / hair / head, e.g. 70/15/15. There's no outfit term here - this node has no outfit_palettes input, unlike the bigger selector. Note that face detection and matching are still InsightFace (that's what det_size controls), not SAM3; SAM3 does the concept grounding.
aux_preset gives you a second mask channel from named parts: upper_body, lower_body, clothing (which means all clothing, no shoes or socks), hands, feet, arms, legs, headless_body, or custom with aux_custom_prompt. aux_threshold gates it.
Then aux_prompt - free text, second channel. Ground sunglasses, handbag, tattoo, whatever. The result is aux_data, a complete PERSON_DATA in which every mask type carries that region, so a Person Detailer hits it no matter what its mask_type is set to. Hits that overlap nobody are drawn in the preview but dropped from aux_data. One warning from the tooltip: SAM3 treats commas as separate categories, so red dress, handbag is two prompts, not one phrase.
refine_iterations (default 2) is how many SAM decoder passes sharpen each mask. 0 is faster and blockier - perfectly reasonable while you're iterating.
Outputs and what to do with them
person_data goes to the Person Detailer - that's the main line. face_masks, head_masks, body_masks and aux_masks are the same data as plain masks. preview is the annotated overlay, worth looking at before you spend render time. similarities, matches, matched_count, face_count and report are the diagnostics, and report is where a mismatch explains itself.
References are reference_1 … reference_5 - five slots, deliberately fewer than the full selector. depth_map plus depth_sort_order (front_last / front_first / off) hands the detailer a back-to-front render order so a foreground person correctly paints over a background one. This node is explicitly the slim one: no outfit palettes, no SAM2 fallback, no YOLO aux pathway, aggregation fixed to max. The trade is honest - you give up features to lose an install. If you need them, use Person Selector SAM3 with the extension.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/ping1979ping/comfyui-FVMtools
pip install insightface>=0.7.3 onnxruntime-gpu>=1.17.0 opencv-python>=4.8.0
Restart ComfyUI. You'll find it in Add Node → FVM Tools/Face. InsightFace's buffalo_l auto-downloads on first use (five ONNX files, 174 MB of them the recognizer) and parsing_bisenet.pth lands in models/gfpgan/ for the BiSeNet facial subtypes. The SAM3 checkpoint goes in models/checkpoints/ like any other, so CheckpointLoaderSimple can see it.
Common issues
It says SAM3 native prepare failed. The node prints this and continues with no masks when the trunk call throws - usually a device or dtype mismatch, not a missing model. Read the traceback right above it; it prints one on purpose.
Everything is one person, or the wrong person. Put threshold back to 0 so the auto assignment runs, and check report for per-reference similarities. Then look at match_weights: bumping hair or head helps when two people have similar faces, hurts when they don't.
Aux masks are empty. aux_threshold too high, or the phrase isn't something SAM3 can ground on its own. Try the simplest category name.
Face masks are jagged. Raise refine_iterations. The default of 2 is a compromise; 3–5 sharpens at the cost of time.
The wrong person gets painted over. Render ordering, not masking - connect a depth map and set depth_sort_order.
Inputs (19)
| Name | Type | Default | Description |
|---|---|---|---|
| sam3_model | MODEL | MODEL from CheckpointLoaderSimple on the SAM3 checkpoint | |
| sam3_clip | CLIP | CLIP from the SAME CheckpointLoaderSimple. The SAM3 text encoder is part of the checkpoint. Needed because this node builds its own prompts. | |
| current_image | IMAGE | Image(s) to process. Supports batch input. | |
| threshold | FLOAT | 0.000–1 | Face-to-reference matching threshold. 0.0 = AUTO: optimal 1:1 assignment (recommended). Above 0 = manual minimum similarity. |
| det_size | COMBO | 640 | Face detection resolution (InsightFace, not SAM3). |
| match_weights | STRING | 70/15/15 | Face/hair/head blend for reference matching, e.g. '70/15/15'. No outfit term here — this node has no outfit_palettes input. |
| aux_preset | COMBO | none | Preset aux mask type: - upper_body / lower_body: body halves - clothing: all clothing (no shoes/socks) - hands / feet / arms / legs: body parts - headless_body: body minus head (computed) - custom: uses aux_custom_prompt below |
| aux_custom_prompt | STRING | Custom SAM3 text prompt for the aux mask (aux_preset='custom'). Any noun phrase: 'shoes', 'necklace', 'backpack'. Note: SAM3 treats commas as separate categories. | |
| aux_threshold | FLOAT | 0.300.05–1 | Confidence threshold for aux detection. |
| aux_prompt | STRING | Free SAM3 text prompt for the SECOND aux channel, e.g. 'sunglasses', 'handbag', 'tattoo', 'shoes'. Result comes out as `aux_data` — a full PERSON_DATA where EVERY mask type carries the aux region, so a PersonDetailer hits it whatever its mask_type is set to. Also drawn into the preview. Empty = channel off. | |
| aux_prompt_threshold | FLOAT | 0.300.05–1 | Confidence threshold for the aux_prompt grounding. |
| refine_iterations | INT | 20–5 | SAM decoder passes that sharpen each detector mask. 0 = raw detector masks (faster, blockier edges). |
| reference_1opt | IMAGE | Reference image(s) for person 1. | |
| reference_2opt | IMAGE | Reference image(s) for person 2. | |
| reference_3opt | IMAGE | Reference image(s) for person 3. | |
| reference_4opt | IMAGE | Reference image(s) for person 4. | |
| reference_5opt | IMAGE | Reference image(s) for person 5. | |
| depth_mapopt | IMAGE | Depth map for render order sorting. | |
| depth_sort_orderopt | COMBO | front_last | Rendering order handed to the PersonDetailer. |
Outputs (12)
| Name | Type | Description |
|---|---|---|
| person_data | PERSON_DATA | — |
| face_masks | MASK | — |
| head_masks | MASK | — |
| body_masks | MASK | — |
| aux_masks | MASK | — |
| preview | IMAGE | — |
| similarities | STRING | — |
| matches | STRING | — |
| matched_count | INT | — |
| face_count | INT | — |
| report | STRING | — |
| aux_data | PERSON_DATA | — |