Pipeline SuperScaler
The node that swallows your 12-node upscale chain
- image_in
- mask_in
- model_pass_1
- vae_pass_1
- positive_pass_1
- negative_pass_1
- model_pass_2
- vae_pass_2
- positive_pass_2
- negative_pass_2
- model_pass_3
- vae_pass_3
- positive_pass_3
- negative_pass_3
- image_out
Generative upscaling in ComfyUI is normally a pile of nodes: an upscale, a VAE encode, a sampler, a decode, then a second pass on top, then a sharpen and a grain node bolted on the end. SuperScaler_Pipeline exists to collapse that pile into one collapsible box. You feed it an image, wire in a model, VAE and conditioning, and it runs a latent refine, up to two tiled generative upscales, frequency-split sharpening and film grain, then hands you a finished image_out - no Ultimate SD Upscale + tile-ControlNet + post-fx sprawl in between.
Where it sits in the upscaling picture matters. "Upscale" covers two different jobs: adding pixels (ESRGAN, Lanczos) and inventing detail (SUPIR, SeedVR2, tile-ControlNet). SuperScaler is firmly the second kind - it's not a model, it's a workflow, and it ships no weights. It downloads nothing and reuses whatever checkpoint, VAE and conditioning you already have loaded.
How it works
The node is four passes in sequence, each one toggled on or off (the JS drops each disabled section's widgets out of the UI, which is why the node doesn't look as terrifying as the parameter list suggests):
- Pass 1, latent refine. VAE-encode, nearest-neighbor upscale the latent, sample, decode. A gentle img2img pass for refining before the real upscale. Off by default.
- Pass 2 & 3, tiled generative upscales. This is the meat. It first does a plain bicubic upscale in pixel space, then chops that into overlapping tiles. Each tile is VAE-encoded, sampled through
nodes.common_ksampler, decoded, multiplied by a feather mask, and blended over its neighbors - overlapping regions are averaged so you don't get visible seams. Tiling is what keeps big 2x+2x upscales on low-VRAM cards: peak memory is roughly one tile, not the whole image. The same seed runs through every tile, which is what stops adjacent tiles from going their own way and producing seams that even the feather mask can't hide. - Pass 4, post-FX. Frequency-split sharpen (
scipy.ndimage.gaussian_filter) - blur a copy, subtract it to isolate the high-frequency detail, boost that, recombine. That's the trick that sharpens without halos. Then optional grain:poisson,gaussianorperlinnoise, withsaturation_mixto desaturate it andadaptive_grainto push more grain into shadows, because perfectly smooth skin reads as plastic.
There's also a masked final blend: feed a mask_in and the protected areas get swapped for a clean bicubic upscale of your original, so skies and smooth surfaces don't collect generative noise. Trap for newcomers: the mask logic is inverted from ComfyUI's usual convention. Black protects (clean upscale), white gets the full treatment. mask_blend_weight at 1.0 fully replaces the protected area, 0.5 gives a 50/50 mix, 0.0 does nothing.
The inputs that matter
You mostly live on these few, per pass:
enable_tiled_pass_2- the workhorse. On by default.tiled_upscale_by_2/tiled_denoise_2- how much you scale and how much the sampler is allowed to invent. 0.25–0.35 is the sweet spot for adding detail; above that and it starts rewriting your image.tile_size_2/tile_overlap_2- larger tiles = fewer passes but more VRAM; more overlap = fewer seams but more redundant work.seed- one global seed drives all three generative passes, with the standard fixed/increment/randomize control.
Note the defaults: pass 2 uses CFG 1.0 and 8 steps, which is a guidance-distilled (Flux-style) model's territory. On SDXL you'll want to raise tiled_cfg_2 toward 6–7 or you'll get mush.
Installing it
ComfyUI Manager → search "SuperScaler", or:
cd ComfyUI/custom_nodes
git clone https://github.com/tritant/ComfyUI_SuperScaler
Restart ComfyUI. No model downloads - it uses your existing checkpoints. One real gotcha: the node imports scipy at module load, but the pack's pyproject.toml declares no dependencies, so Manager won't always pull it in. If the node refuses to appear, install it yourself:
pip install scipy
Where people get burned
The most common failure is leaving Pass 1 on without wiring its model inputs - the node skips any pass whose model/VAE/conditioning aren't connected, so your "refine" silently never runs. Watch the console, too: it logs every tile (PASS 2: Inférence de la tuile 12/45... - the author's French leaks through, harmless). A 4K upscale is a lot of sequential tiles, so this is not a fast node; it's a patient, VRAM-bounded one. That's the honest trade: convenience and memory fit, at the cost of speed you'd only notice on a big image. For one-off "make it 4K and film-like" jobs it's the node I'd actually reach for over rebuilding the chain from scratch.
Inputs (50)
| Name | Type | Default | Description |
|---|---|---|---|
| image_in | IMAGE | — | |
| mask_inopt | MASK | — | |
| enable_latent_passopt | BOOLEAN | false | — |
| model_pass_1opt | MODEL | — | |
| vae_pass_1opt | VAE | — | |
| positive_pass_1opt | CONDITIONING | — | |
| negative_pass_1opt | CONDITIONING | — | |
| latent_upscale_byopt | FLOAT | 1.11–4 | — |
| latent_denoiseopt | FLOAT | 0.200–1 | — |
| latent_sampler_nameopt | COMBO | 44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38 | |
| latent_scheduleropt | COMBO | 9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3 | |
| latent_stepsopt | INT | 61–1000 | — |
| latent_cfgopt | FLOAT | 1.000–100 | — |
| enable_tiled_pass_2opt | BOOLEAN | true | — |
| model_pass_2opt | MODEL | — | |
| vae_pass_2opt | VAE | — | |
| positive_pass_2opt | CONDITIONING | — | |
| negative_pass_2opt | CONDITIONING | — | |
| tiled_upscale_by_2opt | FLOAT | 2.01–8 | — |
| tiled_denoise_2opt | FLOAT | 0.250–1 | — |
| tile_size_2opt | INT | 960256–2048 | — |
| tile_overlap_2opt | INT | 6432–512 | — |
| tiled_sampler_name_2opt | COMBO | 44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38 | |
| tiled_scheduler_2opt | COMBO | 9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3 | |
| tiled_steps_2opt | INT | 81–1000 | — |
| tiled_cfg_2opt | FLOAT | 1.000–100 | — |
| enable_tiled_pass_3opt | BOOLEAN | false | — |
| model_pass_3opt | MODEL | — | |
| vae_pass_3opt | VAE | — | |
| positive_pass_3opt | CONDITIONING | — | |
| negative_pass_3opt | CONDITIONING | — | |
| tiled_upscale_by_3opt | FLOAT | 2.01–8 | — |
| tiled_denoise_3opt | FLOAT | 0.250–1 | — |
| tile_size_3opt | INT | 960256–2048 | — |
| tile_overlap_3opt | INT | 6432–512 | — |
| tiled_sampler_name_3opt | COMBO | 44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38 | |
| tiled_scheduler_3opt | COMBO | 9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3 | |
| tiled_steps_3opt | INT | 81–1000 | — |
| tiled_cfg_3opt | FLOAT | 1.000–100 | — |
| enable_sharpenopt | BOOLEAN | false | — |
| sharpen_amountopt | FLOAT | 1.000–5 | — |
| sharpen_radiusopt | INT | 11–20 | — |
| enable_grainopt | BOOLEAN | false | — |
| grain_typeopt | COMBO | poisson | 3 options: poisson, gaussian, perlin |
| grain_intensityopt | FLOAT | 0.0140.001–1 | — |
| grain_sizeopt | FLOAT | 1.31–16 | — |
| saturation_mixopt | FLOAT | 0.200–1 | — |
| adaptive_grainopt | FLOAT | 0.150–2 | — |
| mask_blend_weightopt | FLOAT | 1.000–1 | — |
| seedopt | INT | 00–18446744073709550000 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image_out | IMAGE | — |