Nodes/ComfyUI-denoise-mask-scheduler/Apply Denoise Mask Scheduler (use step)
ComfyUI Node

Apply Denoise Mask Scheduler (use step)

Kill the inpainting seam by scheduling when your mask actually bites

By MiddleKD·Created 2 years ago·Updated 2 years ago· 7
Apply Denoise Mask Scheduler (use step)
  • model
  • MODEL
start_step0
end_step20
mask_alpha1.0
scheduler_typeskip

The one-sentence version

If your masked inpainting keeps coming back with a visible border where the fix meets the untouched image, this node attacks the cause directly: instead of clamping the non-mask area to the original pixels at every single step, it schedules when the mask is actually applied during sampling. Give up a little pixel-exactness, lose the seam. That's the whole trade, and it's exactly what the pack's README says - minor alterations to parts of the non-mask area are the point, not the bug.

It's an experimental pack from a Korean developer (the source comments are in Korean) with almost no community footprint - zero mentions in the usual ComfyUI subs as of this writing. So treat it as a tool you try, not a workflow staple. It also only has one "scheduler_type" implemented, skip, with the author promising more "as effective ones are identified." You've been warned.

How it works

You're used to the mask doing one thing. This node turns it into a three-phase schedule keyed to the step index:

  • Before start_step - the mask is skipped (set to all-ones). The whole frame goes through the denoise trajectory as one region, so structure, lighting, and prompt adherence settle in with no hard boundary to fight.
  • Between start_step and end_step - the mask bites, scaled by mask_alpha. The fixed region gets regenerated, the rest is held.
  • After end_step - skipped again, so the final harmonizing steps aren't fighting a seam either.

Mechanically it's a thin layer over ComfyUI's own inpainting internals. The node stamps a denoise_mask_function into your model's model_options, then swaps in its own version of KSamplerX0Inpaint.__call__ (the sampler ComfyUI uses when a noise mask is present) so that function is actually consulted each step. It restores the original __call__ when sampling finishes, and modern ComfyUI already ships the denoise_mask_function hook natively - this pack just puts a schedule in front of it. Nothing exotic, which also means: on a plain txt2img run with no mask, this node is a silent no-op.

The inputs that matter

Of the five inputs, a beginner sets three:

  • start_step (default 0) - the first step where the mask is applied. Raise it to skip the chaotic high-noise early steps.
  • end_step (default 20) - the last step where the mask is applied. Lower it to let the final detail steps run unconstrained.
  • mask_alpha (default 1.0) - mask strength while active. At 1.0 the mask is applied at full strength; at 0.8, 20% of the original pixels bleed into the fix region, which softens edges further.

model is your checkpoint's MODEL, and scheduler_type currently only has one choice, skip - there's nothing to fiddle with there.

The one output is a MODEL, and it's the whole point: wire this MODEL into your KSampler's model input instead of the raw checkpoint. The mask still comes from your normal inpainting setup (SetLatentNoiseMask, or a mask loaded with your image) - this node never touches that.

Install

ComfyUI Manager: search for ComfyUI-denoise-mask-scheduler and install. Or from your ComfyUI directory:

cd custom_nodes
git clone https://github.com/MiddleKD/ComfyUI-denoise-mask-scheduler.git

Then restart ComfyUI. There's no requirements.txt and nothing to download - it's pure Python on top of the torch/torchvision ComfyUI already ships. The repo's example workflow references an SDXL inpainting ControlNet (inpainting_xl/diffusion_pytorch_model.fp16.safetensors) and a JuggernautXL checkpoint, but those are examples, not dependencies; standard masked inpainting works fine. The pack also registers a "Dynamic image resize" node - unrelated to this one, ignore it.

Common issues

  • Nothing changes. You're almost certainly not actually inpainting - the node only does anything when a noise mask reaches the sampler. Check your mask wiring first.
  • The window is wrong. Defaults (0–20) cover a whole 20-step run, so with defaults you get (a soft version of) plain inpainting - the scheduling is what you're buying. Pull start_step up to ~8 and end_step down to ~steps-minus-a-few and you'll feel the difference. Tune against a fixed seed, as with any inpainting pass.
  • Breaks after a ComfyUI update. It patches a core sampler class. If an update rewrites KSamplerX0Inpaint, this pack can lag - keep the repo updated via Manager and restart if you see odd sampler errors. The patch self-restores after each run, so a restart also clears any stuck state.

Should you bother?

If seams are your enemy and you can tolerate the non-mask area shifting a little, it's a genuinely clever, zero-dependency fix worth ten minutes of testing. If you need the unmasked pixels bit-identical - the one thing masked inpainting uniquely guarantees these days - this isn't the node for you; that's what crop-and-stitch workflows are for. This is the opposite philosophy, on purpose. Try it on a face fix, see if the border bothers you less than the small changes it buys.

Categorydenoise-mask-scheduler

Inputs (5)

NameTypeDefaultDescription
modelMODEL
start_stepINT00–100
end_stepINT200–100
mask_alphaFLOAT1.00–1
scheduler_typeCOMBOskip1 options: skip

Outputs (1)

NameTypeDescription
MODELMODEL