WAS Adaptive Difference Latent Upscale (Damped)
Blocky where it's flat, smooth where it isn't
- latent
- latent
- mask
- mask_preview
Upscaling a latent while it's still a latent is the cheap half of every hires-fix pass. It's also where the compromises live. Nearest-neighbour keeps flat areas crisp and edges ugly. Bilinear is smooth everywhere and soft everywhere. You pick one, pump the second sampler's denoise until the softness goes away, and quietly accept that you changed the composition doing it.
This node tries both and takes the smooth one only where they disagree. That's the whole idea, and it's a good one: flat regions keep the crispness of the blocky enlargement, and edges and texture get the interpolated version. No ringing along every boundary, no global mush.
How it decides
The node enlarges the latent twice - once nearest, once with your smooth_mode - and measures the difference between them. That disagreement is the detail map: where the two agree, the picture is flat and the blocky version is free. Where they disagree, there's structure and you want the smooth one.
diff_blur_sigma (0.6 by default) spreads that map before it decides anything, because a per-block difference map switches on and off block by block and looks like noise; 0.0 gives the busiest, most switchy result. threshold is where the changeover happens - 0.12 by default, leaving flat areas crisp and treating edges - and softness (0.05) is how gradual the changeover is. Drop softness to 0.005 and you get a hard switch you can see as a rim.
weight_power bends the finished blend map after it's built: above 1.0 pulls it toward the blocky enlargement everywhere but the strongest edges, below 1.0 spreads the smooth version into weaker detail. weight_blur_sigma softens the map once it's decided, which is the fix when treated areas come out with visible outlines of their own.
scale goes 1 to 8, and results round to whole latent blocks. At 1.0 you're not enlarging at all - you're just applying the damping pass, which is a genuinely useful trick on its own.
The damping half - the bit that earns the "(Damped)" in the name
Upscaling leaves a halo around hard edges; that's not specific to this node, it's what resampling does. So there's a second pass behind enable_directional_damping (on by default) that takes fine detail back out along strong boundaries. damping_strength 0.35 is "takes the edge off a halo", 0.0 turns the pass off, 1.0 flattens detail there completely.
Where it's allowed to act is damping_gate_mode: none lets it act on every boundary it finds, weight confines it to the areas the blend already treated, and weight_sqrt sits in between. Then the usual cluster of detection controls - damping_grad_blur_sigma to stop texture being mistaken for an edge, damping_threshold and damping_softness for how strong a boundary has to be and how gradually the mask fades in, damping_power to bend the mask, damping_mask_blur_sigma so the damped strip doesn't get a border of its own. damping_highpass_sigma decides which detail counts as fine enough to remove: 1.0 takes out ringing and leaves the shapes, larger values start blurring structure.
Video latents, and seeing what it did
Two temporal_ema values - one for the blend map, one for the damping mask - carry a fraction of each frame's map over from the frames before it, so on a video latent the treated areas don't shimmer. They do nothing on a single image, and 0.0 treats every frame on its own.
The outputs are latent, plus mask and mask_preview so a setting can be seen rather than guessed at. preview_mode picks which map leaves the node: weight shows where the smooth enlargement was used, damp shows where detail was removed, and both puts them side by side in the preview while sending the damping map to the mask output. output_mask_pixel_scale (default 8) is how many preview pixels each latent block becomes - 8 matches what most VAEs decode to, so the preview lines up with the finished picture. It affects the preview only, never the mask itself.
Installing it
Part of WAS Node Suite v3 (MIT, WASasquatch; 468 nodes):
cd ComfyUI/custom_nodes
git clone https://github.com/WASasquatch/was-node-suite-comfyui.git
ComfyUI Manager, search WAS Node Suite v3, is the recommended install. ComfyUI 0.14.0+ and Python 3.10+; no pip packages, no downloads, no build step. This node is one of the 27 in the extras group, on by default - if latent upscalers are missing from your Add Node menu, check features.extras in <ComfyUI user dir>/was-node-suite/config.yaml. And if you're following a two-year-old tutorial telling you to pip-install OpenCV and scikit-image first: that was v2, and it's the reason the pack's search results are full of import errors that no longer apply.
Using it in a hires pass
Latent upscale by 1.5–2×, then a second sampler at low denoise (0.3–0.5) to add the detail the interpolation didn't invent. This node is the middle of that sandwich, and it's the reason you can get away with a slightly lower denoise than usual: you didn't resample everything into mush, so the second pass has less to fix. Try scale 2.0, defaults elsewhere, and turn on preview_mode weight once to see how much of your image is being treated - if it's most of the frame, your threshold is too low and you've bought a bilinear upscale with extra steps.
Inputs (21)
| Name | Type | Default | Description |
|---|---|---|---|
| latent | LATENT | The latent to enlarge. A video latent with a time axis is handled frame by frame. | |
| scale | FLOAT | 2.001–8 | How much larger the result is. 2.0 doubles both sides, 1.5 adds half again, 1.0 leaves the size alone and only applies the damping. Sizes are rounded to whole latent blocks. |
| smooth_mode | COMBO | bilinear | How the smooth half of the blend is enlarged. `bilinear` is the safe default; `bicubic` is sharper and can overshoot slightly at a hard edge; `area` averages the source region and is the softest of the three. |
| diff_blur_sigma | FLOAT | 0.600–8 | How far the disagreement between the two enlargements is spread before it decides anything, in latent blocks. A little blur keeps the blend from switching on and off block by block; 0.0 uses the raw per-block difference and gives the busiest map. |
| threshold | FLOAT | 0.1200–1 | How much disagreement counts as detail. Below this the blocky enlargement is kept, above it the smooth one takes over. Lower values smooth more of the picture; 0.12 leaves flat areas crisp and treats edges. |
| softness | FLOAT | 0.0500.0005–1 | How gradual the changeover at the threshold is. Small values such as 0.005 give a hard switch that can be seen as a rim; 0.05 fades between the two enlargements over a comfortable range. |
| weight_power | FLOAT | 1.000.1–6 | Bends the blend map after it is built. Above 1.0 pulls it towards the blocky enlargement everywhere but the strongest edges; below 1.0 spreads the smooth enlargement into weaker detail. 1.0 leaves the map as measured. |
| weight_blur_sigma | FLOAT | 0.000–8 | Softens the finished blend map, in latent blocks. Raise it when the treated areas have visible outlines of their own; 0.0 leaves the map alone. |
| temporal_ema | FLOAT | 0.000–0.99 | How much each frame of a video latent carries over from the frames before it, which stops the blend map flickering. 0.0 treats every frame on its own; 0.5 is a light smoothing; 0.9 is heavy and can smear the map behind fast motion. Ignored on a single image. |
| enable_directional_damping | BOOLEAN | true | Whether the second pass runs, which takes fine detail back out along strong boundaries. It is what removes the halo that an upscale leaves around hard edges. Turn it off to see the blend on its own, or when the source is already soft. |
| damping_strength | FLOAT | 0.350–1 | How much fine detail is removed where the damping mask is fully on. 0.0 removes none and turns the pass off; 0.35 takes the edge off a halo; 1.0 flattens the detail there completely. |
| damping_gate_mode | COMBO | weight_sqrt | Where the damping is allowed to act. `none` lets it act on every boundary it finds. `weight` confines it to the areas the blend already treated. `weight_sqrt` is in between, allowing some damping in areas the blend touched only lightly. |
| damping_grad_blur_sigma | FLOAT | 0.000–8 | Blur applied before boundaries are looked for, in latent blocks. Raise it so that texture is not mistaken for an edge; 0.0 finds the finest boundaries. |
| damping_threshold | FLOAT | 0.2500–1 | How strong a boundary has to be to be damped, measured against the strongest one in the picture. 0.25 catches the clear outlines; lower values reach into texture as well. |
| damping_softness | FLOAT | 0.0800.0005–1 | How gradually the damping fades in around that threshold. Small values give a hard-edged mask; 0.08 fades over a comfortable range. |
| damping_power | FLOAT | 1.000.1–6 | Bends the damping mask. Above 1.0 confines the damping to the very strongest boundaries; below 1.0 spreads it over more of the picture. 1.0 leaves the mask as measured. |
| damping_mask_blur_sigma | FLOAT | 0.600–8 | Softens the damping mask before it is used, in latent blocks. A little blur keeps the damped strip from having a visible border of its own; 0.0 uses the mask as found. |
| damping_highpass_sigma | FLOAT | 1.000–8 | Which detail counts as fine enough to be removed, in latent blocks. 1.0 takes out ringing while leaving the shapes; larger values reach into broader structure and start to blur. 0.0 removes the whole signal under the mask instead. |
| damping_temporal_ema | FLOAT | 0.250–0.99 | How much of the damping mask each frame of a video latent carries over from the frames before it, so damped areas do not shimmer. 0.0 treats every frame on its own. Ignored on a single image. |
| preview_mode | COMBO | both | Which map leaves the node. `weight` shows where the smooth enlargement was used, `damp` shows where fine detail was removed, `both` puts the two side by side in the preview and sends the damping map to the mask output. |
| output_mask_pixel_scale | INT | 81–16 | How many preview pixels each latent block becomes. 8 matches the size the latent decodes to on most VAEs, so the preview lines up with the finished picture; 1 gives the small raw map. This affects the preview image only, never the mask output. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| latent | LATENT | The enlarged latent, ready for a sampler or a decode. |
| mask | MASK | The map the node worked from, at latent resolution: the damping map on `damp` and `both`, the blend map on `weight`. Useful for driving another node from the same areas this one treated. |
| mask_preview | IMAGE | The same map as a viewable image, enlarged by output_mask_pixel_scale. On `both` the blend map is on the left and the damping map on the right. |