📐 Latent Upscaler Pro
Land your Hires pass on a real grid, not 1824×1248
- samples
- latent
- width
- height
The Hires-fix step everyone skips past
Hires fix is two passes: generate small, scale the latent up, sample again at low denoise to let the model put real detail in. The middle step is the boring one, and it's where the damage happens. Core's Latent Upscale does exactly what you ask - multiply the latent by 1.5 and interpolate - and your architecture has opinions about that number.
At 1.5×, an SDXL 1216×832 bucket wants to become 1824×1248. Neither number divides by 64. You get a second pass at a size the model never saw, and the classic symptoms people blame on the upscaler: soft frames, seam lines, faint grid tiling, a border that goes slightly weird. "Divisible by 64" isn't folklore - it's the constraint Flux carries natively and SDXL carries in practice, and it's why "generate at native resolution, then upscale" is the standard advice.
📐 Latent Upscaler Pro does one unglamorous thing about it: it does the arithmetic before it interpolates.
How it works
It reads the latent's current size, works out the pixel dimensions you asked for (current pixels × scale_by in By Factor mode, your numbers in Target Size, aspect ratio preserved toward longest_edge in Longest Edge), then rounds that result to a multiple of your chosen snap_to step - 64 by default, with 32, 16, 8 and Disabled (Exact) available in the source. Only then does it hand the latent to ComfyUI's own common_upscale with your upscale_method.
Two details worth knowing. It assumes the standard 8× spatial compression - one latent pixel is eight image pixels - so a 1856×1280 target decodes from a 232×160 latent, and that's what width/height report. And if your latent arrives with a noise_mask, the mask is rescaled alongside it instead of being silently dropped, which is the difference between a clean masked second pass and a strange square appearing in your inpaint. Video latents (5D, B, C, F, H, W) get folded into the batch, resized, and put back.
Concretely, the same 1216×832 at 1.5×:
python -c "print(1856//8, 1280//8)" # 232 160 -> the latent tensor you actually get
Inputs and outputs
Nine inputs, but a beginner sets three:
mode-By Factor(the usual one),Target Size,Longest Edge.scale_by- 0.05–8.0, default 1.5. The hires sweet spot is 1.5–2× with a second-pass denoise of 0.3–0.5; above 0.5 you're changing the composition, not adding detail.snap_to-64 pxby default (safe for U-Net and DiT alike);16 pxis the author's pick when you want even latents for Flux,8 pxwhen you want one-latent-pixel granularity.Disabled (Exact)turns the whole feature off.
round_mode is the quiet one: nearest at 1.5× on the example above gives you 1856×1280, down gives 1792×1216, up gives 1856×1280. Pick a direction and stick to it if you want a batch of images that are all the same size.
The outputs are latent, width and height. Wire latent into your second sampler (or a noise-mask node, or VAE Decode). The two INTs are the honest final pixel size - feed them into a filename pattern or a parallel branch rather than recomputing the maths in your head and getting it wrong by four pixels.
Installing it
Both nodes here live in FiL_Design_ImageMind. In ComfyUI Manager, search FiL_Design_ImageMind and install; or:
cd ComfyUI/custom_nodes
git clone https://github.com/FiL-Design-Ai/FiL_Design_ImageMind.git
pip install -r FiL_Design_ImageMind/requirements.txt
Portable builds should use their own interpreter - python_embeded\python.exe -m pip install -r ComfyUI\custom_nodes\FiL_Design_ImageMind\requirements.txt - or just run install_requirements.bat in the pack folder, which finds the right Python for you. Restart ComfyUI; the node is under 🎨 FiL Design/🖼️ Image.
The dependency list is light (requests, aiohttp, PyYAML, Pillow, numpy, pydantic) and this node downloads no models - it works on a latent you already have. One real requirement: ComfyUI 0.3.60 or newer, because the pack is written against the V3 node API. The half of the README about API keys and LLM providers doesn't apply to this node at all.
Where it bites
Target Size squashes. Only Longest Edge preserves aspect ratio. Ask for 1024×1024 with a 16:9 latent in the node and you get a stretched picture, then you blame the sampler. Use By Factor for upscaling; use Target Size only when you genuinely want those exact dimensions.
Nothing appears in the node list. That's almost always ComfyUI being older than 0.3.60 - the pack's nodes register via comfy_api.latest, and an older core simply won't load them. Check the startup console for the import error before you reinstall anything.
The panel is missing but the node runs. The widgets you see are a bundled Vue panel, not native ones; if frontend/dist didn't come down with the clone, the node still executes.
ls ComfyUI/custom_nodes/FiL_Design_ImageMind/frontend/dist | head
You turned snapping off and it got worse. Disabled (Exact) plus bicubic is just core's Latent Upscale with extra steps. Snapping is the product here; leave it at 64 unless you know why you're moving it.
Worth saying plainly: this pack is young and has essentially no forum trail, so the README and the shipped code are your documentation. Read the snap_to tooltip, it's accurate.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| samples | LATENT | Input latent to upscale. | |
| mode | COMBO | By Factor | Scaling mode: 'By Factor' uses multiplier, 'Target Size' scales to exact dimensions, 'Longest Edge' scales preserving aspect ratio. |
| scale_by | FLOAT | 1.500.05–8 | Upscale factor used when mode is 'By Factor'. |
| target_width | INT | 102464–8192 | Target width in pixels (used in 'Target Size' mode). |
| target_height | INT | 102464–8192 | Target height in pixels (used in 'Target Size' mode). |
| longest_edge | INT | 1536128–8192 | Longest edge in pixels (used in 'Longest Edge' mode). |
| upscale_method | COMBO | bislerp | Interpolation method for latent tensors. 'bislerp' is standard for diffusion latents. |
| snap_to | COMBO | 64 px (U-Net & DiT Safe) | Grid snapping rule. 64 px eliminates border artifacts on SD1.5/SDXL and DiT; 16 px guarantees even latents for Flux. |
| round_mode | COMBO | nearest | Rounding direction when snapping to the grid. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| latent | LATENT | Resized latent tensor with clean boundary alignment. |
| width | INT | Resulting image width in pixels (divisible by chosen snap). |
| height | INT | Resulting image height in pixels (divisible by chosen snap). |