Nodes/ComfyUI-latent-ops/LatentOperationMul
ComfyUI Node

LatentOperationMul

Multiply one latent by another latent, element by element

By hnmr293·Created about a year ago·Updated about a year ago· 2
LatentOperationMul
  • value
  • op

Most "multiply the latent" nodes take a number. This one takes a latent. LatentOperationMul multiplies your incoming latent by another latent, element-wise - think of it as a per-position, per-channel gain map instead of a global scalar. It's the smarter sibling of LatentOperationMulBroadcast (which does latent * value), and it only makes sense once you understand what the pack is actually handing you.

The mechanism

The code is the whole story:

def mul(latent, **kwargs):
    return latent * value

It's literally latent * value where value is captured from the LATENT you feed in at build time. The closure holds onto that tensor, so whatever latent you wired into the value input gets baked into the operation when the node runs - and it needs to be broadcastable against the latent it's applied to later. ComfyUI latents are 4D tensors shaped [batch, channels, height, width], so the practical use is a same-shaped latent: you generate or derive a "mask latent," and use it as a spatial/channel gain map to modulate another latent. A smooth latent mask multiplied against your main latent is a crude-but-real attention: it boosts some regions, dims others, no decode-encode round trip.

Inputs and the two gotchas

  • value (required, type LATENT) - the multiplying latent. That's it. There's no alpha, no scalar, no optional anything.

Gotcha one: this is not the scalar multiply. If you want latent * 0.7, that's LatentOperationMulBroadcast. Confusingly, MulBroadcast is the simpler one - broadcast here means "broadcast a scalar," not "multiply latents together." This node is the element-wise-latent variant, and the naming is easy to flip around.

Gotcha two, and it's the pack-wide one: the output is op of type LATENT_OPERATION - a deferred callable. LatentOperationMul does not apply the multiplication. It builds an operation that some other node has to execute, and ComfyUI-latent-ops ships no apply node. You feed the op into a consumer of LATENT_OPERATION (Sonar's SonarApplyLatentOperationCFG is the one that actually exists in the wild) or write your own apply node. Straight into a VAE Decode and you'll get a type error, not an image.

Why you'd bother

This pack is hnmr293's personal latent-manipulation workbench - the same dev who wrote sd-webui-cutoff and llul - and there's no community around it to lean on. Within that context, Mul is the node for when "scale everything the same amount" is too dumb: multiply by a second latent to apply a spatially varying influence, or to implement a cheap latent-space blend/mix. If you're a beginner, though, MulBroadcast is almost certainly the one you actually want until you have a concrete reason to modulate per-position. Start with the scalar, graduate to this when the workflow demands it.

Install

Same as every node in the pack. 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 that ComfyUI already has. Everything lands under hnmr/latent_ops. And when a node's README line and its code disagree - which happens more than it should in this pack - the code in custom_nodes/ComfyUI-latent-ops/latent_ops/ops.py is the truth.

Categoryhnmr/latent_ops

Inputs (1)

NameTypeDefaultDescription
valueLATENT

Outputs (1)

NameTypeDescription
opLATENT_OPERATION