LatentOperationSigmoid
The real S-curve, for squashing latents into 0–1
- op
If you want the actual S-curve - the one that maps any real number into (0, 1) - this is the node, and don't let the pack confuse you. LatentOperationSigmoid is a true sigmoid: 1 / (1 + e^(−x)). The neighboring LatentOperationLogistic sounds like the same thing but is implemented as log-sigmoid in the source, which is a completely different beast that outputs only non-positive values. Sigmoid is the one that does what you think it does: squashes a latent into a clean 0–1 range.
The mechanism
def sigmoid(latent, **kwargs):
return torch.nn.functional.sigmoid(latent * alpha)
One input: alpha (FLOAT, default 1.0) - the input gain shared by every activation node in this pack. The latent is multiplied by alpha, then sigmoid'd. And here's the subtlety most people miss: SD/SDXL latents live roughly in ±3, and sigmoid saturates hard outside roughly ±6. At alpha = 1, sigmoid(3) ≈ 0.953 and sigmoid(−3) ≈ 0.047 - so you get a usable 0.05–0.95 mapping, but the extreme ends of the range are squashed by the curve's flat tails. If you want the full 0–1 spread, you either crank alpha (steeper curve, everything pushed to the extremes) or you don't rely on sigmoid at all and use the pack's LatentOperationNormalizeMinMax (guaranteed exact 0–1, but outlier-sensitive).
When it earns its keep
Sigmoid is the natural bridge into "this latent is a bounded signal" territory. Feed it before the pack's Latent01ToImage (which converts a 0–1 latent into an IMAGE tensor for preview) and you get a stable, roughly linear-ish brightness map. Feed it into a consumer that wants a bounded, in-(0,1) control signal and you have a smooth, differentiable-feeling knob. Compared to the pack's other squashers, sigmoid is the soft one: it never clamps hard like min-max, never collapses the negative lobe like ReLU - every value survives, just compressed toward 0 and 1 with a smooth curve. That makes it the safest "make this latent range-friendly" option if you don't need exact bounds.
The op output
Output is op of type LATENT_OPERATION - a deferred closure, exactly like every node in hnmr293/ComfyUI-latent-ops. The pack builds operations and ships no apply node, so you need a LATENT_OPERATION consumer (Sonar's SonarApplyLatentOperationCFG is the one that exists in the wild) or your own apply node. Wire op directly into a VAE Decode and you get a type mismatch - the pack's universal first trap, by design.
Install
The usual. ComfyUI Manager → search ComfyUI-latent-ops, or:
cd ComfyUI/custom_nodes
git clone https://github.com/hnmr293/ComfyUI-latent-ops
Restart. No requirements.txt, no model downloads - pure PyTorch. This is the personal latent workbench of hnmr293 (the sd-webui-cutoff / llul author); the pack has almost no community footprint, so latent_ops/functions.py is your real documentation. Everything registers under hnmr/latent_ops.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| alpha | FLOAT | 1.0000-10000–10000 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| op | LATENT_OPERATION | — |