ControlNetHadamard
ControlNet per-pair, not per-everything
- conds
- control_net
- image
- CONDITIONING
The name is math-flavored (a Hadamard product is element-wise pairing - multiply slot N of one list with slot N of another), and that's exactly the point. ControlNetHadamard takes a list of conditionings and a list of images and applies your ControlNet to each pair: conditioning #1 gets image #1, conditioning #2 gets image #2, and so on. Nothing more, nothing less.
Why does that matter? A stock ControlNetApply applies one ControlNet to one conditioning. The moment you have several prompts and several control images, you'd normally reach for a nested apply chain - and if you're not careful you end up applying every image to every conditioning, a cross product that quietly multiplies your batch and burns VRAM. This node is the one-to-one version, and it asserts that your lists match so you don't silently misalign.
How it works
It's a subclass of the core ControlNetApply, so the per-pair work is identical to stock. The difference is in the plumbing:
- conds - a
CONDITIONINGlist (fromCLIPEncodeMultiple, or split lists elsewhere). - control_net - one ControlNet model.
- image - an
IMAGElist, same length as conds. - strength - float 0–10, default 1, applied uniformly.
It checks len(images) == len(conds) and raises "lists sizes do not match" if not. Then it walks the pairs and returns a CONDITIONING list - same order, each entry with the ControlNet conditioning applied.
The classic setup: CLIPEncodeMultiple → conds, an image loader that emits an image list (e.g. a UnGridify or a list from a batch loader) → image, one ControlNetLoader → control_net. Everything stays aligned, and your KSampler gets exactly one conditioning per prompt.
Where people get burned
List alignment. The node won't let lengths differ - good - but it also can't know if your intent is misaligned. If image #3 was supposed to pair with prompt #4, you get silent wrongness. Build the two lists from the same source order and verify once.
Also, strength is global across the whole batch, so you can't give pair #1 strength 0.8 and pair #2 strength 0.4 with this node alone. That's what the manual variant's per-image wiring helps with if you need per-slot control... actually no - the manual variant still shares one strength. Keep that in mind: batch-specific strength means core nodes.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_bmad_nodes
cd comfyui_bmad_nodes
pip install -r requirements.txt
or install "comfyui_bmad_nodes" via ComfyUI Manager and restart. No extra downloads beyond the pack's shared requirements. If your ControlNet-in-a-loop workflows keep multiplying batches by accident, this is the node that fixes the math.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| conds | CONDITIONING | — | |
| control_net | CONTROL_NET | — | |
| image | IMAGE | — | |
| strength | FLOAT | 1.000–10 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| CONDITIONING | CONDITIONING | — |