Flux: Locked Progressive Upscale 3-Stage (RES4LYF)
The Flux Upscale That Doesn't Redraw Your Image
- model
- latent
- positive
- negative
- vae
- sampler
- base_sampler
- refine_sampler
- upscale_model
- latent
- image
- seed
If you've ever upscaled a Flux image and watched the face subtly become a different person on the second pass, you know the problem this node exists to kill. Normal latent upscaling re-noises the whole image, so the model is free to drift composition, faces, and text every time you jump up in resolution. This single node - Flux: Locked Progressive Upscale 3-Stage (RES4LYF) - is a one-node pipeline that generates at a small base size, walks it up to full res with locked-noise progressive stages, and finishes with an optional refine pass. Feed it an empty latent and a finished image comes out the other end.
What it is
It's a Flux port of ComfyUI-ZImageTurboProgressiveLockedUpscale, reworked so every stage samples through comfy.sample.sample_custom with a SAMPLER object you wire in, instead of the built-in KSampler. Practically: plug in a RES4LYF ClownSampler and you get the whole engine - eta, SDE noise modes, res_2m/res_3s, bongmath - with none of it hardcoded into this node. You tune the sampler on the ClownSampler, not here.
How the locking works
Four mechanics, all latent-shape based so they're model-agnostic:
- Progressive scale ladder - the total upscale is split into small steps each ≤
max_step_scaleinstead of one big jump. - Locked noise - the noise for the new resolution keeps the previous stage's coarse modes exactly and only injects fresh noise in the orthogonal (high-frequency) complement. It's still statistically N(0,I), so the sampler behaves normally - but composition survives.
- Pixel-space lifting - between stages the latent is decoded, upscaled (with your
upscale_modelif provided, else bicubic), and re-encoded, so detail rides on real pixels. - Sigma-sliced partial denoise - each upscale stage runs only the tail of the schedule, so the model refines rather than redraws.
The inputs that matter
The shared three you actually set: model, latent, and sampler. The latent decides the mode - feed an empty EmptyLatentImage (say 144×208) and Stage 1 runs a full base generation; feed a VAE Encode of an existing image and Stage 1 is skipped, leaving just upscale + refine. The sampler input is where your ClownSampler goes; base_sampler and refine_sampler override it per stage if you want an eta=0.5 base and a clean eta=0.0 refine. Keep cfg at 1.0 for distilled Flux and drive guidance with a FluxGuidance node on the positive conditioning.
Stage 2 knobs a beginner actually touches: upscale_factor (default 6.0, the total upscale), max_step_scale (1.6 - smaller means more, gentler stages; the stage count is roughly ceil(log(factor)/log(max_step_scale))), and the tail-step ramp, where tail_steps_first_upscale/tail_steps_last_upscale (6 and 3 by default) go from a stronger refine on the small first stage to a lighter touch on the last. upscale_model is optional - drop a RealESRGAN in for the pixel-space lifts instead of bicubic.
Stage 3's refine_enter_sigma is the one to tune: it decides how deep into the schedule the refine starts. Lower = less denoise = more preservation. Flux's flow sigmas differ from Z-Image's, so start around 0.5–0.8 and raise it for a stronger refine. Outputs are latent, image, and seed.
Install
ComfyUI Manager → Install via Git URL, or:
cd ComfyUI/custom_nodes
git clone https://github.com/lookuters22/ComfyUI-FluxProgressiveLockedUpscale
Then restart. No extra Python dependencies - it only uses what ComfyUI already ships. Do install RES4LYF too, because it's the intended pairing and there's a real gotcha hiding here: the default schedulers (beta57, ays_kl) come from RES4LYF's extended scheduler list. Without it, the dropdown falls back to stock schedulers and the node's defaults don't resolve the way the README assumes.
Where people trip
The refine_enter_sigma retune is the big one - porting the Z-Image default straight over gives you a stronger or weaker refine than you want, and it's the first thing to move if faces feel plastic. The stage-count math also surprises: 6.0 factor at 1.6 max isn't "one 6× jump," it's ~4 small stages, which is exactly why starting from a ~140×200 base is cheap and fast. And note everything currently shares one Flux model - cross-model setups like a Z-Image base with Flux refine are planned (the pixel-space handoffs are built for it) but not here yet.
One more thing worth knowing before you build your dream workflow on this: RES4LYF itself is AGPL-3.0 with a rider that bars commercial image-generation services without a separate license. This node is MIT, but the sampler you pair it with carries that baggage.
Inputs (23)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| latent | LATENT | — | |
| positive | CONDITIONING | — | |
| negative | CONDITIONING | — | |
| vae | VAE | — | |
| sampler | SAMPLER | Main SAMPLER (RES4LYF ClownSampler). Used for the UPSCALE stages, and as the fallback for the base/refine stages if no dedicated sampler is wired. | |
| cfg | FLOAT | 1.01–30 | Keep 1.0 for guidance-distilled Flux (use a FluxGuidance node on conditioning). |
| seed | INT | 00–18446744073709550000 | — |
| base_steps | INT | 201–99 | STAGE 1 (base generation, only if an EMPTY latent is fed). Full schedule length. |
| base_scheduler | COMBO | beta57 | STAGE 1 scheduler for the from-noise base generation. |
| upscale_factor | FLOAT | 6.001–24 | STAGE 2. Total upscale. Number of internal stages = ceil(log(factor)/log(max_step_scale)). |
| max_step_scale | FLOAT | 1.601.1–6 | STAGE 2. Max per-stage upscale ratio. Smaller = more, gentler stages. |
| upscale_steps | INT | 204–99 | STAGE 2. Base schedule length; each stage runs only its tail. |
| upscale_scheduler | COMBO | beta57 | STAGE 2 scheduler (beta57 / ays_kl / comfy schedulers all work). |
| tail_steps_first_upscale | INT | 61–24 | STAGE 2. Tail steps for the first (smallest) upscale. More = stronger refine. |
| tail_steps_last_upscale | INT | 31–24 | STAGE 2. Tail steps for the last (largest) upscale. Fewer = lighter touch. |
| enable_refine | BOOLEAN | true | STAGE 3 on/off. When off, the node returns the upscale result directly. |
| refine_steps | INT | 201–99 | STAGE 3 schedule length. Executed steps depend on refine_enter_sigma. |
| refine_scheduler | COMBO | beta57 | STAGE 3 scheduler. |
| refine_enter_sigma | FLOAT | 0.600.01–15 | STAGE 3. Enter the schedule at this sigma. Lower = less denoise = more preservation. Retune for Flux's flow sigmas (often higher than the Z-Image default). |
| base_sampleropt | SAMPLER | STAGE 1 sampler override. If unconnected, the main 'sampler' is used. | |
| refine_sampleropt | SAMPLER | STAGE 3 sampler override. If unconnected, the main 'sampler' is used. | |
| upscale_modelopt | UPSCALE_MODEL | STAGE 2. Pixel-space upscaler (e.g. RealESRGAN) used between stages instead of bicubic. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| latent | LATENT | — |
| image | IMAGE | — |
| seed | INT | — |