Resolution for 2-Stage Upscale with crop
Compute a clean base resolution for a two-stage upscale
- original_width
- original_height
- generation_width
- generation_height
- factor
- min_value
- max_value
- compression_factor
This is the little arithmetic node that makes a two-stage (a.k.a. hires) upscale workflow behave. You know the target size you want - say a 2560x1440 final image - but you can't generate there directly without the model falling apart. So you generate smaller, then upscale. The annoying part is working out what smaller resolution to render at, and making sure it's a clean multiple that the latent and VAE won't choke on. That's this node's entire reason to exist. In the menu it's labelled Resolution for 2-Stage Upscale with crop.
It's the least glamorous node in the pack and, going by search interest, quietly the most useful one.
How it works
You give it your final target width and height plus a factor, and it works backward to the generation resolution. It divides the target down by the factor and snaps the result to a multiple of alignment - so if you ask for alignment 16, generation_width and generation_height come out divisible by 16. That rounding is the whole point: models want dimensions that divide cleanly (8 for SD 1.5/SDXL, 64 for Flux), and an off-by-a-few-pixels latent is where you get VAE seams and crop errors.
It also passes your original dimensions through and reports the factor and a compression_factor so a downstream upscale node knows exactly how far to scale back up.
The inputs and outputs that matter
width/height- your final target resolution, not the generation size.factor(default 2) - how much you'll upscale by. Factor 2 means generate at half-size, upscale 2x.alignment(default 16) - the rounding multiple. Use 8 for SDXL, 64 for Flux, to match what your model wants.
Outputs: generation_width and generation_height feed your Empty Latent; original_width and original_height carry the target through; factor and compression_factor go to your upscale node; min_value and max_value give you the shorter and longer edge of the generation size, handy for upscalers that want a target long-edge.
Installing it
ComfyUI Manager: search ComfyUI_Nimbus-Pack, install, restart. Small pack - if it's not indexed, clone it:
cd ComfyUI/custom_nodes
git clone https://github.com/sergekatzmann/ComfyUI_Nimbus-Pack.git
pip install -r ComfyUI_Nimbus-Pack/requirements.txt
Restart. Pure Python, no models, no heavy deps.
Common issues & troubleshooting
Set alignment to match your model, not by habit. SDXL and SD 1.5 want multiples of 8; Flux is stricter and wants divisible by 64. If you leave alignment at 16 on a Flux graph you may still hit a dimension error downstream. Match the node's rounding to the backbone.
Remember which side is which. width/height are the final size you want out; generation_width/generation_height are what you render at first. Wire the generation outputs into your latent and the originals into your upscaler's target - swap them and you'll generate huge (defeating the point) or upscale to a tiny image.
Why bother at all? Because the two-stage pattern is the standard cure for the native-resolution problem: generate at a size close to what the model was trained on, then upscale with ESRGAN, a tiled upscaler, or a second-pass sampler. This node just does the dimension bookkeeping so both stages line up.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| width | INT | 25601–8192 | — |
| height | INT | 14401–8192 | — |
| alignment | INT | 161–64 | — |
| factor | FLOAT | 2.00.1–8 | — |
Outputs (8)
| Name | Type | Description |
|---|---|---|
| original_width | INT | — |
| original_height | INT | — |
| generation_width | INT | — |
| generation_height | INT | — |
| factor | FLOAT | — |
| min_value | INT | — |
| max_value | INT | — |
| compression_factor | INT | — |