Nodes/ComfyUI-ScaleLockedResidualDiffusion/Scale-Locked Residual KSampler
ComfyUI Node

Scale-Locked Residual KSampler

Your model is great at 1MP and a mess at 4MP — this sampler is why

By xmarre·Created 6 months ago·Updated 6 months ago· 2
Scale-Locked Residual KSampler
  • model
  • positive
  • negative
  • latent_image
  • lock_mask
  • manifold_mask
  • output
  • lowres_planner
  • denoised_output
seed0
steps24
cfg1.0
sampler_name
scheduler
denoise1.00
target_megapixels1.00
lock_strength0.85
lock_strength_start0.95
lock_strength_end0.25
lock_schedule
lock_schedule_hold0.00
lock_schedule_power2.0
coarse_cutoff0.33
mid_band_cutoff0.60
mid_band_strength0.35
mid_band_strength_start1.00
mid_band_strength_end0.00
mid_band_schedule
mid_band_schedule_hold0.00
mid_band_schedule_power2.0
manifold_enabledfalse
manifold_strength0.45
manifold_strength_start1.00
manifold_strength_end0.00
manifold_schedule
manifold_schedule_hold0.00
manifold_schedule_power2.0
manifold_cutoff0.18
manifold_radial_strength1.00
manifold_anisotropy0.15
manifold_translation_strength1.00
manifold_anchor_mix0.18
manifold_mean_anchor_mix0.12
manifold_contrast_restore0.10
manifold_energy_tether0.00
manifold_channel_tether0.00
manifold_energy_gain_cap1.75
manifold_max_shift_px3.0
nested_noise_strength0.35
add_noisetrue
pin_anchorstrue
sampler_guard

Every model has a resolution it's actually happy at. SDXL lives around 1MP, Flux is comfortable at 1–2MP, and the moment you push to 4MP the same prompt stops being "the same image, sharper" and becomes a re-plan: composition shifts, faces change, and somewhere in there a character picks up a third arm. The old fixes don't really solve it - hi-res fix at 0.3–0.5 denoise preserves the composition by refusing to add much, and the high-res pass just re-dreams everything above your denoise cutoff. ScaleLockedResidualKSampler is a different answer: run a low-res planner pass, record exactly what it decided, then sample high-res with a lock that stops the model from re-planning the coarse structure while still letting it add real high-frequency detail.

It's the main node of the ComfyUI-ScaleLockedResidualDiffusion pack from xmarre (same author as the DoRA-Dynamic-LoRA-Loader, and about as small-time). It's an honest MVP - the README says as much, which is more than most node packs admit - but the failure mode it targets is real. The KB's troubleshooting notes "generating above native resolution causes repeated patterns or duplicated anatomy" and this is a genuine attempt to attack that at the sampling level instead of bolting a second pass on top.

How it works

Give it a target_megapixels and it downscales your latent to that size, runs a full low-res planner pass with your prompt, and caches the per-step denoised x0 trajectory. Then it builds the high-res noise field using nested noise - coarse structure that matches the low-res branch, with extra high-frequency noise layered on top so the detail pass isn't starting from a resized copy. The final high-res sampling runs through a patched guider that:

  • locks the low-frequency (coarse) denoised structure toward the planner trajectory,
  • applies a second, looser mid-band lock for medium-scale shape,
  • preserves the base model's high-frequency residual detail,
  • optionally does the whole thing only inside a lock_mask you supply.

The lock isn't constant - it follows a schedule (lock_strength_start down to lock_strength_end), so the model gets anchored hard early and released late. hold_then_drop with a lock_schedule_hold around 0.35–0.45 is the README's recommended shape: strong early anchor, a late knee where detail gets freedom.

The inputs that actually matter

It takes all the standard sampler inputs - model, positive, negative, latent_image, seed, steps, cfg, sampler_name, scheduler, denoise - plus the SLRD knobs. You'll set a handful and ignore the rest:

  • target_megapixels - planner resolution. The README's first-settings list for a ~4MP target (Flux.2 Klein 9B style) uses 1.0.
  • lock_strength - how hard the coarse lock pulls. 0.85 default; push toward 0.95 if you still see drift.
  • coarse_cutoff - lower = stronger global structure control. 0.33 default, 0.25 if drift persists.
  • mid_band_strength / mid_band_cutoff - the looser medium-scale lock. These are your first freedom dials when things feel too locked.
  • nested_noise_strength - extra detail freedom. More = less "same image", so don't chase it too hard.
  • lock_mask (optional MASK) - focus the lock on face / body / hands. The README straight-up recommends one for anatomy-sensitive work.
  • sampler_guard - warn / error / off. The pack only has a conservative safe-set of samplers it's confident about, and warns by default if you pick outside it.

Outputs are output (final high-res latent), lowres_planner (the planner's result - look at it once, it's educational), and denoised_output (final denoised x0 when available).

Install

cd ComfyUI/custom_nodes
git clone https://github.com/xmarre/ComfyUI-ScaleLockedResidualDiffusion

Restart ComfyUI. Or search ComfyUI-ScaleLockedResidualDiffusion in ComfyUI Manager and hit install. No extra Python dependencies, no model downloads - it's pure sampler logic on ComfyUI + PyTorch.

Troubleshooting

  • Still drifting → raise lock_strength, lower coarse_cutoff, and add a lock_mask over the anatomy-critical regions.
  • Too constrained / looks like a downscaled planner → lower mid_band_strength, raise mid_band_cutoff, lower lock_strength or lock_strength_end. You over-locked.
  • An unsupported sampler → switch sampler_guard to error to fail loudly instead of silently sampling with degraded alignment, or stick to the safe list (euler, heun, ddim, dpmpp_2m, lcm, and the cfg_pp variants).
  • No anchor error → a zero-step or edge-case run; check your steps and denoise.

One honest caveat: this is not multi-stage progressive upscaling, and there's no automatic pose/anatomy mask extraction - the README lists both as not-yet-implemented. It's a two-pass sampler with a smart lock, and it's very good at exactly that.

Categorysampling/scale_locked

Inputs (49)

NameTypeDefaultDescription
modelMODEL
positiveCONDITIONING
negativeCONDITIONING
latent_imageLATENT
seedINT00–18446744073709550000
stepsINT241–10000
cfgFLOAT1.00–100
sampler_nameCOMBO44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38
schedulerCOMBO9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3
denoiseFLOAT1.000–1
target_megapixelsFLOAT1.000.1–16
lock_strengthFLOAT0.850–1
lock_strength_startFLOAT0.950–1
lock_strength_endFLOAT0.250–1
lock_scheduleCOMBO10 options: linear, cosine, flat, smoothstep, smootherstep, ease_in, +4
lock_schedule_holdFLOAT0.000–0.95
lock_schedule_powerFLOAT2.00.1–8
coarse_cutoffFLOAT0.330.05–1
mid_band_cutoffFLOAT0.600.05–1
mid_band_strengthFLOAT0.350–2
mid_band_strength_startFLOAT1.000–1
mid_band_strength_endFLOAT0.000–1
mid_band_scheduleCOMBO11 options: linked, linear, cosine, flat, smoothstep, smootherstep, +5
mid_band_schedule_holdFLOAT0.000–0.95
mid_band_schedule_powerFLOAT2.00.1–8
manifold_enabledBOOLEANfalse
manifold_strengthFLOAT0.450–1
manifold_strength_startFLOAT1.000–1
manifold_strength_endFLOAT0.000–1
manifold_scheduleCOMBO10 options: linear, cosine, flat, smoothstep, smootherstep, ease_in, +4
manifold_schedule_holdFLOAT0.000–0.95
manifold_schedule_powerFLOAT2.00.1–8
manifold_cutoffFLOAT0.180.05–1
manifold_radial_strengthFLOAT1.000–3
manifold_anisotropyFLOAT0.150–2
manifold_translation_strengthFLOAT1.000–3
manifold_anchor_mixFLOAT0.180–1
manifold_mean_anchor_mixFLOAT0.120–1
manifold_contrast_restoreFLOAT0.100–1
manifold_energy_tetherFLOAT0.000–1
manifold_channel_tetherFLOAT0.000–1
manifold_energy_gain_capFLOAT1.751–4
manifold_max_shift_pxFLOAT3.00–64
nested_noise_strengthFLOAT0.350–4
add_noiseBOOLEANtrue
pin_anchorsBOOLEANtrue
sampler_guardCOMBO3 options: warn, error, off
lock_maskoptMASK
manifold_maskoptMASK

Outputs (3)

NameTypeDescription
outputLATENT
lowres_plannerLATENT
denoised_outputLATENT