Nodes/WhiteRabbit/๐Ÿ‡ Pixel Hold
ComfyUI Node

๐Ÿ‡ Pixel Hold

The flicker suppressor that locks your background down

By Artificial-SweetenerยทCreated about a year agoยทUpdated about a month agoยท 83
๐Ÿ‡ Pixel Hold
  • frames
  • reference
  • images
  • mask_preview
โ—„ref_sourceexternalโ–บ
โ—„ref_index0โ–บ
โ—„linearizetrueโ–บ
โ—„auto_lumatrueโ–บ
โ—„auto_k2.5โ–บ
โ—„tau_luma0.0059โ–บ
โ—„tau_grad0.020โ–บ
โ—„modetileโ–บ
โ—„tile_size32โ–บ
โ—„score_model1_tileโ–บ
โ—„edge_bandtrueโ–บ
โ—„band_radius4โ–บ
โ—„tau_edge_low0.0059โ–บ
โ—„tau_edge_high0.0235โ–บ
โ—„applyallโ–บ
โ—„dilate1โ–บ
โ—„feather_sigma2.0โ–บ
โ—„process_onautoโ–บ
โ—„gpu_clear_every0โ–บ

Every local video generator has the same tell: flat areas shimmer. Backgrounds, walls, skies - regions the model decided were "smooth" come out with a micro-flicker frame to frame, and once you see it you can't unsee it. Pixel Hold is the node that cleans that up. It locks each frame's stable regions to a chosen reference - an external image, or a frame from the clip itself - and only lets pixels change when the change is big enough to be real motion. Small fluctuations get pinned; actual movement passes through untouched.

The author's description is precise: it reduces "micro-flicker/static shimmer sometimes introduced by diffusion." And it has a creative second life, because the reference doesn't have to be the clip - hand it an external image and it'll hold everything in the frame that isn't moving to that image. That's the difference between "clean up the flicker" and "make the static background a specific picture."

How it works

For each frame, the node measures how much changed relative to the reference, region by region, and builds a mask of "changed enough to matter." Pixels under the mask keep their new values; everything else gets held at the reference. The sensitivity machinery is what makes it usable:

  • auto_luma (on by default) adapts the brightness threshold per frame, so it doesn't need hand-tuning per clip. auto_k (default 2.5) sets how aggressively it locks - 2โ€“3 is the typical range.
  • mode - tile (default) measures change in blocks (fast and robust), pixel does it per-pixel (finer, noisier).
  • edge_band - protects a belt around strong edges so the lock doesn't create wobbly, stretchy boundaries where motion meets static regions. This is the setting that keeps hard edges from smearing.
  • apply - hold the whole image (all) or only its low-frequency part (lowfreq), which is a lighter touch for videos that just need the flat areas steadied.
  • linearize (on by default) works in linear color for steadier results on flat areas.
  • dilate / feather_sigma - expand and soften the mask edges so the hold blends in instead of leaving a hard seam.
  • process_on - auto/CPU/GPU. Auto pushes to GPU for very large frames; gpu_clear_every frees VRAM every N frames if you're running long clips.

The inputs and outputs

  • frames - your clip.
  • ref_source - external (use the reference image) or batch_index (use frame ref_index of the clip as the reference). External references get resized to match if sizes differ.
  • images (output) - the stabilized clip.
  • mask_preview (output) - an IMAGE of the hold mask, so you can see exactly what got locked and what passed through. Wire this to a preview node while tuning.

Installing it

WhiteRabbit pack, one-time install:

cd ComfyUI/custom_nodes
git clone https://github.com/Artificial-Sweetener/comfyui-WhiteRabbit
cd comfyui-WhiteRabbit
python -m pip install -r requirements.txt

or ComfyUI Manager โ†’ "WhiteRabbit". The pack's only pip dependency is torchlanc; it targets ComfyUI's v3 node API, so keep ComfyUI updated.

Where people get burned

  • Locking everything. If the mask preview shows almost the whole frame held, your thresholds are too loose (or the clip genuinely has no motion). Check mask_preview first - that's what it's for.
  • Expecting it to fix moving backgrounds. It holds static regions. A panning camera means nothing is static, and the node can't invent stillness.
  • Using it after compression artifacts are baked in. It reduces shimmer; it won't un-blur a compressed sky. Run it on the cleanest version of the clip you have.

Run it as a post pass before encoding and the difference is the difference between "AI video" and "finished video." The flicker is the giveaway every time.

Categoryvideo utils

Inputs (21)

NameTypeDefaultDescription
framesIMAGEYour clip (framesร—Hร—Wร—C, values 0โ€“1).
ref_sourceCOMBOexternalPick the reference: an external image or a frame from this clip.
ref_indexINT00โ€“999999If using a frame from this clip, which frame to use as the reference.
linearizeBOOLEANtrueWork in linear color for steadier results on flat areas.
auto_lumaBOOLEANtrueAuto sensitivity for brightness changes (adapts per frame).
auto_kFLOAT2.50.5โ€“6Auto strength. Higher = lock more to the reference (2โ€“3 is typical).
tau_lumaFLOAT0.00590โ€“0.01568627450980392Manual brightness threshold when Auto is OFF. Lower = stricter (more locking).
tau_gradFLOAT0.0200โ€“1How much edge change to allow. Lower protects edges more.
modeCOMBOtileTile: fast & robust. Pixel: finer but noisier.
tile_sizeINT328โ€“256Tile size when using Tile mode.
score_modeCOMBOl1_tileHow tiles measure change: mean abs diff (fast) or median abs dev (robust).
edge_bandBOOLEANtrueProtect a belt around strong edges to avoid wobble/stretch.
band_radiusINT40โ€“64Width of the protected belt (pixels).
tau_edge_lowFLOAT0.00590โ€“0.25Treat as low-motion below this level (edge belt).
tau_edge_highFLOAT0.02350โ€“0.5Treat as high-motion above this level (edge belt).
applyCOMBOallHold the whole image (All) or only its smooth part (Low-freq).
dilateINT10โ€“16Expand the mask (pixels).
feather_sigmaFLOAT2.00โ€“16Soften mask edges (pixels).
process_onCOMBOautoChoose CPU/GPU. Auto switches to GPU on very large frames.
gpu_clear_everyINT00โ€“1000If >0 and using GPU, free memory every N frames.
referenceoptIMAGEOptional external reference (1ร—Hร—Wร—C). If sizes differ, it will be resized to match.

Outputs (2)

NameTypeDescription
imagesIMAGEโ€”
mask_previewIMAGEโ€”