Latent Rotate (Portrait / Landscape)
Portrait and Landscape Latents From a Single Node
- latent
- LATENT
If you've ever queued the same prompt twice just to see it at portrait and then at landscape, this tiny node is for you. Latent Rotate (Portrait / Landscape) takes one latent in and hands your graph a list of latents out - 0°, 90°, or both - so ComfyUI samples each orientation in a single run. No re-wiring, no resizing the canvas between runs, no filename-suffix hacks. It lives in a one-node pack called latent-rotate-90, and its whole job is deterministic orientation comparison.
Worth being clear about what the name does and doesn't mean. Fed a blank EmptyLatentImage, rotation is content-neutral: an empty latent is zeros, and rotating zeros gives you zeros with swapped dimensions. So in a plain txt2img setup, "Both" doesn't produce a rotated copy of your portrait - it queues a fresh generation at the landscape resolution. Feed it a real latent instead (an encoded image, or a partially-denoised pass) and the rotation is literal: torch.rot90 genuinely spins the picture 90° before the next sampling stage.
Why 0° and 90°, and nothing else
Diffusion models work on a grid-aligned latent space - compressed 8x per side by the VAE. Only 90° rotations preserve that grid without interpolation artifacts; rotate 45° and you're smearing the latent and asking the model to fix your mess. And 180° and 270° add no compositional information, so the author cut them. That's the "opinionated" in the README, and it's defensible.
There's a nice side effect: SDXL was trained on a ladder of aspect ratios "and their rotations," so 832x1216 and its 90° rotation 1216x832 are both native to the model. Rotating a portrait latent lands you on a landscape ratio the model actually knows, not some random dimension it'll fumble.
How it works
The whole node is one short function (the README credits ChatGPT for the code, and honestly that's the vibe - tidy, opinionated, no cruft). For "Portrait Only" it passes the samples through unchanged; for "Landscape Only" it runs torch.rot90(samples, k=-1, dims=(2, 3)) - a 90° clockwise turn in the height/width plane. Each latent gets stamped with rotation and orientation metadata as it goes.
The clever part is the output: flagged as a list, so ComfyUI executes every downstream node once per entry. One queue, two KSampler passes, two images. No batch hacks, no queue tricks.
The two inputs and one output
- latent - the LATENT you're working from. EmptyLatentImage for a fresh portrait/landscape pair; a real encoded latent if you want an actual rotation.
- mode -
Portrait Only(0°),Landscape Only(90°), orBoth(0° + 90°).Bothis the entire reason this pack exists. - output - one LATENT, always a list, even with a single entry; wire it into a KSampler like any other latent. Dotted or stacked port? That's just ComfyUI saying "this is a list" - normal, not an error.
Installing it
Easiest install you'll hit all week: no Python dependencies beyond torch, no model downloads, no config. Through ComfyUI Manager, search latent-rotate-90 and install, then restart. Or clone it by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/tardigrade1001/latent-rotate-90
Restart ComfyUI and the node appears under latent → geometry. That's it.
Getting the most out of it
Fix your seed. The node prints a console reminder for a reason: orientation comparison only means anything if the KSampler seed, sampler, steps, and CFG are identical across both passes. Same seed, same blank start, two orientations - that's a clean A/B of composition rather than a reroll. The rotation/orientation metadata it stamps is a courtesy; stock KSampler and VAE Decode just pass it through.
Also know "landscape is harder" is real, not a you problem. Whole r/StableDiffusion threads document landscape-orientation people with broken necks and backwards feet - base models are trained overwhelmingly on portrait people shots, and many LoRAs fall apart at landscape ratios. Treat Both as a cheap first filter; if the prompt alone can't hold a subject in landscape, reach for ControlNet instead of blaming the node.
Troubleshooting
- Untagged output files - deliberate. The author refuses filename suffixes on principle ("orientation is visually obvious"), which is fine until you've run 20 seeds and can't tell 0° from 90° in your output folder. Feed a STRING node into your filename logic if you need tags.
- VRAM worries - unfounded. The model loads once; latents are processed sequentially, not duplicated, so
Bothdoesn't double your footprint. - Node missing after install - restart ComfyUI; Manager won't hot-reload it.
Honest verdict: it's a one-trick pack, but it's a good trick if you do aspect A/B testing, print work, or anything that needs both orientations of one concept in a single queue. Zero deps, zero risk, five minutes to try.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| latent | LATENT | — | |
| mode | COMBO | 3 options: Portrait Only, Landscape Only, Both |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| LATENT | LATENT | — |