KSampler (Advanced + Perp-Neg)
The Perp-Neg sampler that ComfyUI already absorbed
- model
- clip
- positive
- negative
- latent_image
- LATENT
Here's the whole story in one sentence, so you can decide whether to keep reading: this is a late-2023 sampler for the Perp-Neg trick, it's archived, its own display name starts with "DEPRECIATED", and ComfyUI now ships Perp-Neg natively. If you're not resurrecting an old workflow, you almost certainly want the built-in Perp-Neg Guider instead. But the pack is a neat time capsule of the CFG era, and it has a twist worth knowing about.
What this node actually is
bvhari/ComfyUI_PerpNeg is a two-node pack written in the SD 1.5/SDXL days and last touched in December 2023. KSamplerAdvancedPerpNeg is a drop-in clone of the standard KSampler Advanced that was supposed to bolt Perp-Neg onto the sampling step. The README is refreshingly honest: "Experimental code, might have incompatibilities and edge cases." Then it announces the project is archived "as Perp-Neg is now available in ComfyUI itself" - and that half is still true today, which is why it's the second sentence of this article.
Here's the twist, and it's the part most write-ups miss. Read the shipped code and the node doesn't actually Perp-Neg. The sample() method accepts neg_scale, tonemap, and rescale_cfg, then ignores all three and calls ComfyUI's plain common_ksampler. No CFG patching, no perpendicular anything, and the required clip input is never touched either. The real Perp-Neg math lives in the pack's other node, PerpNegAlt, which patches the model with a custom CFG function. The README even crosses out "~Includes Tonemap and CFG Rescale options~". So the headline node is, in the code that ships, a KSampler Advanced clone with a misleading name and three dead inputs.
What Perp-Neg actually does
Quick refresher, because the name does all the marketing work. Normal sampling computes uncond + scale * (cond - uncond) - your negative prompt is the uncond prediction. Perp-Neg's insight is that when the negative overlaps the positive (blonde hair in both, say), the steering fights itself and the negative can suppress things you actually wanted. So it computes a third prediction from an empty prompt, then strips the negative direction's component along the positive direction, leaving only the part perpendicular to what you're asking for. The negative can then only push in directions that don't cancel the positive. That's the "perp" in the name.
It comes from the "Re-imagine the Negative Prompt Algorithm" paper, where the same math was pushed as a fix for the Janus problem in text-to-3D. The cost is the dealbreaker: three model passes per step instead of two, and it only does anything where real CFG is active. At CFG 1 - Flux Dev, Turbo checkpoints, every guidance-distilled release - the arithmetic collapses and the whole thing is inert. That's why the Flux-era threads about Perp-Neg were such a mixed bag; "image quality suffers dramatically" was the honest community summary, not the hype.
The inputs that matter
Because it's a KSampler Advanced clone, you already know the layout: model, positive, negative, latent_image, cfg, steps, sampler_name, scheduler, start_at_step / end_at_step, return_with_leftover_noise, and add_noise with its noise_seed. In the working sibling node, the one new dial is neg_scale (default 1.0), which scales how hard the perpendicular correction pushes - and 1.0 was widely reported as too strong outside SD, so 0.5–0.8 is the sane starting point. In this node, neg_scale, tonemap, and rescale_cfg do nothing. Output is a single LATENT, wired into the VAE decode stage like any other sampler.
Installing it (if you must)
ComfyUI Manager, search "Perp-Neg" or the pack name - or:
cd ComfyUI/custom_nodes
git clone https://github.com/bvhari/ComfyUI_PerpNeg
Then restart ComfyUI. That's the whole install: zero extra dependencies (it only imports comfy.* and latent_preview, both part of ComfyUI) and no model files to download.
What to use instead
Don't build anything new on this. If an old workflow loads it and errors, that's the archive talking - swap in the built-in Perp-Neg Guider (experimental category, feeds SamplerCustomAdvanced, and needs its own empty-text conditioning from a blank CLIPTextEncode), or skip the perpendicular idea entirely and reach for NAG when the real goal is a working negative on a distilled model. Perp-Neg was always an interesting idea with modest real-world wins; this pack is mostly a monument to how fast ComfyUI absorbs good ideas and moves on.
Inputs (17)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| clip | CLIP | — | |
| add_noise | COMBO | 2 options: enable, disable | |
| noise_seed | INT | 00–18446744073709550000 | — |
| steps | INT | 201–10000 | — |
| cfg | FLOAT | 8.000–100 | — |
| neg_scale | FLOAT | 1.000–100 | — |
| sampler_name | COMBO | 22 options: euler, euler_ancestral, heun, heunpp2, dpm_2, dpm_2_ancestral, +16 | |
| scheduler | COMBO | 6 options: normal, karras, exponential, sgm_uniform, simple, ddim_uniform | |
| positive | CONDITIONING | — | |
| negative | CONDITIONING | — | |
| latent_image | LATENT | — | |
| start_at_step | INT | 00–10000 | — |
| end_at_step | INT | 100000–10000 | — |
| return_with_leftover_noise | COMBO | 2 options: disable, enable | |
| tonemap | COMBO | 2 options: disable, enable | |
| rescale_cfg | COMBO | 2 options: disable, enable |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| LATENT | LATENT | — |