DOGMA Category Mask Gate
A one-line node that stops an unused sector from editing your image
- masks
- masks
Twenty lines of Python and it prevents one of the nastier silent failures in a six-slot detailer graph. DOGMACategoryMaskGate takes masks and a category string and returns masks - zeroed out if the category is anything like "nothing here".
The logic is literally: lowercase and trim the category; if it's in ("", "none", "__none__", "unused", "n/a"), return torch.zeros_like(masks); otherwise pass the mask through untouched. One output, masks, same shape and type as the input.
Why that matters more than it looks
The fixed-width plan nodes in this pack - the six-slot planners, the v31 audit with its slots 1 and 5-6 held at __none__ - exist so the graph can be wired once and survive a change in scene content. The cost of a fixed-width interface is that placeholder slots still have wiring, and wiring that isn't gated will happily carry last run's mask, or a stale merge, into a masking pass on an image where that object doesn't exist. In a multi-slot chain the slots feed each other; a leftover mask from sector 2 arriving at sector 5's stitch is the kind of bug you find by staring at an image wondering why a car has been retouched twice.
Gating on the category string is a cheap, explicit statement of "this slot is inactive", and unlike an empty tensor it keeps the shape the downstream nodes expect. Note that it doesn't care what the mask contains - it's a name-based switch, not a content check. If your planner emits none for a slot you actually wanted, you've gated off a real sector, and the tell is that the sector reports no regions further down the line.
Where to put it
Between each slot's mask source and the crop node, one instance per sector. Typical chain: plan/audit node → segmentation branch → this → DOGMAAdaptiveGroupedCropsV381 or DOGMAAdaptiveCropsV39 → local pass → stitch. It pairs naturally with the croppers' own safe no-op behaviour: the gate makes sure the input is empty, the cropper makes sure an empty input produces a harmless pass rather than an empty list.
There's a pleasant side effect on VRAM and time: an all-zero mask means the segmenter's output is discarded before it reaches the crop stage, so you skip the sampling work for a sector that has nothing to do. On a graph where each sector is several Klein passes, that's the difference between a twelve-minute run and a four-minute one on a scene that only has two real sectors.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/axior/ComfyUI-DOGMA-Nodes
Or ComfyUI Manager → search DOGMA Nodes, then restart ComfyUI. Nothing to pip install (the pack declares no dependencies at all). This node needs nothing beyond ComfyUI itself - it's pure tensor plumbing - so it's a fine first node to test that the pack loaded correctly: if it appears in the menu under DOGMA/Semantic Detailer, the import worked.
Common issues
A sector you wanted is now doing nothing. Your planner wrote none where you expected a category. Check the plan preview output; the gate is faithfully following instructions.
Masks still arrive from the wrong sector. The gate only zeroes on those five strings. A planner that writes __none__ with a trailing space is fine (it's trimmed), but one that writes None in prose or no objects is not - it'll pass through.
Type or shape errors downstream. torch.zeros_like preserves the input's shape and dtype, so this can't change geometry. If the crop node complains, the mask was already the wrong shape coming in.
You expected it to filter by mask content. It doesn't, and that's deliberate: a threshold on mask area would silently kill legitimate small repairs.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| masks | MASK | — | |
| category | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| masks | MASK | — |