Nodes/Enigmatic Nodes/Mask Hold Until Stable
ComfyUI Node

Mask Hold Until Stable

Stop your animated crops from jittering

By enigmatice·Created 2 months ago·Updated 7 days ago· 1
Mask Hold Until Stable
  • mask
  • mask
min_area500
min_area_end500
peak_modefalse
hold_starttrue
hold_endtrue

Here's the failure mode this node exists for. You run a face-detection node over a video, you get a mask per frame, and you feed those masks to a crop node to make an animated talking-head crop. The crop shudders - every frame the detector's box wiggles by a few pixels, and the whole result looks like a shaky handheld cam with the stabilizer off. Mask Hold Until Stable takes that batch of masks and outputs a single held mask, locked to the first frame whose mask is big enough (or the biggest frame in the batch), then backfills everything before it and forward-fills everything after it. Same mask, every frame, zero jitter.

It's one node in Enigmatic Nodes, a small utility pack by the individual dev enigmatice. Pure local Python, no models, nothing to download. The whole category of "mask hygiene" nodes is thin in ComfyUI, and this is the one that solves the temporal problem rather than the spatial one.

How it works

The mechanism is refreshingly simple, and the source spells it out. The node computes the area (sum of mask values) of every frame in the batch, then picks an anchor start: by default the first frame whose area crosses min_area; in peak_mode, the frame with the largest mask above min_area. It also scans backward from the end to find the last frame above a separate min_area_end threshold. Then, if hold_start is on, every frame before the anchor gets the anchor's mask; if hold_end is on, every frame after the end anchor gets that frame's mask. If no frame ever qualifies, it passes the batch through unchanged rather than guessing.

The key design choice is that start and end thresholds are independent. Detection often locks in reliably at the start of a clip but the face shrinks or blurs near the end - so you raise min_area to wait for a solid start, and keep min_area_end low to hold until the mask has nearly disappeared.

The inputs that matter

  • mask - the batch of masks (e.g. per-frame face masks from a detection node).
  • min_area (default 500) - start anchor threshold, in pixels. Raise it for higher-resolution masks; a 1280-wide face mask has far more than 500 pixels, so don't treat the default as universal.
  • min_area_end (default 500) - end anchor threshold, tuned independently.
  • peak_mode - off: first stable frame; on: lock to the largest mask in the whole batch (handy when detection is weak at the start and strongest mid-clip).
  • hold_start / hold_end - backfill before the anchor and forward-fill after the end.

The output

One mask batch with the same frame count, held stable across the clip. Wire it straight into your crop/segment node where you'd previously wired the raw detection output.

Installing it

Same for every node in the pack:

  • ComfyUI Manager - search Enigmatic Nodes, install, restart.
  • Manual - cd ComfyUI/custom_nodes && git clone https://github.com/enigmatice/comfyui-enigmatic-nodes, then restart.

No model files. The pack declares scipy, opencv-python, numpy, Pillow, torch; ComfyUI core already ships everything except opencv-python (which you almost certainly have from another pack), and Manager installs deps for you.

Common issues

  • Nothing changes. If no frame ever crosses min_area, the node passes the batch through untouched. Lower min_area until the anchor locks in - and remember it's in pixels, so a 1024px mask needs a much bigger number than the 500 default.
  • The crop holds in the wrong place. That's peak_mode doing its job based on the biggest mask, or a low min_area locking on too early. Tune the threshold, or flip to the other mode.
  • The held crop doesn't follow movement. That's the whole point - this node freezes a mask, it doesn't track. If your subject moves a lot, pair it with something that re-detects periodically rather than expecting one mask to ride along.

One honest caveat: the pack is brand new (mid-2026, zero community footprint yet), so there's no pile of shared workflows to copy from. But for the specific agony of jittery animated crops on talking-head footage, this is the right tool, and the threshold logic is well thought out.

Categoryenigmatic

Inputs (6)

NameTypeDefaultDescription
maskMASK
min_areaINT5001–500000Minimum mask area for the START anchor. Raise this to wait for a larger masked region before locking. In peak mode this is a noise floor; the largest frame above it is used.
min_area_endINT5001–500000Minimum mask area for the END anchor. Keep this low to hold until the masked region has nearly disappeared. Independent of min_area so start and end can be tuned separately.
peak_modeBOOLEANfalseOff: lock start to the first frame that crosses min_area. On: lock start to the frame with the biggest mask in the whole batch.
hold_startBOOLEANtrueBackfill all frames before the anchor with the anchor mask.
hold_endBOOLEANtrueForward-fill all frames after the last stable frame with that frame's mask.

Outputs (1)

NameTypeDescription
maskMASK