Face Avoid
Keep Text Off People's Faces — This Node Picks a Safe Spot for You
- mask
- vertical_pos_100_top
The problem Face Avoid solves is the one you hit the moment you put a caption on any image with a person in it: the text lands on their face, every single time. It's worse in ComfyUI than anywhere else, because there's no drag tool - you place text with numbers, and you don't know what the numbers mean until the image comes out. FaceAvoidRandomY reads a face mask, figures out where the face actually is in the frame, and hands back a vertical position that stays clear of it. It's one small piece of the ComfySnap pack, and it's the piece that makes the pack's text overlay node actually usable on portraits.
How it works
You feed it a mask (white = face) and it does the math: binarize the mask at centroid_threshold, find the vertical center of mass of the face, then convert that to a 0–100 scale where 100 = top and 0 = bottom. From there, avoid_threshold carves out a forbidden zone of ±that many units around the face center. If generate_random is on (the default), it rolls a uniform random position inside the allowed regions - top third or bottom third, whichever is big enough - so you get variety instead of the same caption spot on every frame. If generate_random is off, it just returns the face center, which is useful for mirroring the face's position somewhere deliberately.
Two implementation details worth knowing. It only reads mask[0] - the first mask in a batch - so a batch of faces means only the first one gets avoided. And if the mask is empty or all-black, it defaults to 50 (middle), because there's no face to avoid.
The inputs you'll actually touch
- mask (MASK) - from a face detector. The pack's example workflow uses UltralyticsDetectorProvider with
bbox/face_yolov8m.ptfeeding BboxDetectorCombined_v2, but any mask source (SAM, a manual mask editor) works. - avoid_threshold - how much clearance around the face. Default 15 is reasonable; crank it up for big faces.
- seed and generate_random - toggle randomness off when you want deterministic placement.
- vertical_adjustment - nudges the detected face center manually, in the same 100=top scale.
The README also talks about a second "avoid zone" input, avoid_zone2_y_*. Heads up: that's not in the shipped code. The actual node exposes only the six inputs above - don't go hunting for it in your workflow.
What it outputs and where it goes
One FLOAT, named vertical_pos_100_top. That's a position on the same 100=top scale the rest of the pack uses, so the natural wire is straight into SnapTextOverlay's custom_vertical_percentage input - which is exactly how the pack's bundled example workflow is built: detect face → mask → Face Avoid → text overlay. Watch the direction of the scale; it's the opposite of most UI sliders you're used to, and mixing it up puts your caption right on the face you were trying to save.
Installing it
Face Avoid ships in the ComfySnap pack, which is not in ComfyUI Manager - that's the one real install gotcha. Search Manager all you want; it won't be there. Clone it:
cd ComfyUI/custom_nodes
git clone https://github.com/SignalCha1n/comfyui-ComfySnap
Restart ComfyUI and the node appears under the ComfySnap category. No model downloads, no API keys, nothing to configure - the pack only needs torch, numpy, and PIL, all of which a standard ComfyUI already ships. One caution, because custom nodes run arbitrary code on load: install from the repo URL above, not from a random copy someone pasted into a Discord.
Where it bites
If your mask isn't a 3D (batch, height, width) tensor, the node raises an error - a face detector's mask output is usually right, but a bare grayscale image won't be. And remember it's computing a number, not painting anything: if nothing downstream is using vertical_pos_100_top, nothing visibly happens. It's a helper node, not a magic one - but for keeping captions off faces, it's the difference between "text over eyes" and a caption that actually fits.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| mask | MASK | — | |
| centroid_threshold | FLOAT | 0.500.01–1 | — |
| vertical_adjustment | FLOAT | 0-100–100 | — |
| avoid_threshold | FLOAT | 15.00–50 | — |
| seed | INT | 00–18446744073709550000 | — |
| generate_random | BOOLEAN | true | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| vertical_pos_100_top | FLOAT | — |