Nodes/Polyhedron Suite/⬡ Polyhedron Apply Control
ComfyUI Node

⬡ Polyhedron Apply Control

The ControlNet your video model doesn't know it has

By PolyhedronAI·Created 5 months ago·Updated about 17 hours ago· 7
⬡ Polyhedron Apply Control
  • model
  • vae
  • control
  • mask
  • source
  • control_patch
  • model
  • info
◄control_modelminimax_h3_fun_controlnet_union_2.0_pruned_int8_convrot.safetensors · 4.2 GB · not installed►
◄strength1.00►
◄start0.00►
◄end1.00►
◄pick-1►

You've got a lovely pose video and a depth pass, and the model is cheerfully ignoring both. That's not a bug in your prompt - nothing on the MODEL line is listening yet. ⬡ Polyhedron Apply Control is the node that makes it listen: it hangs a Fun ControlNet Union off the model, so your control frames actually steer the sample.

What it's doing, mechanically

It clones your model, loads a Fun ControlNet Union file from models/model_patches, encodes your control frames through the VAE you hand it, and registers a control patch on the clone for a slice of the sampling. You get a patched MODEL out; the sampler downstream is none the wiser.

A couple of things fall out of that which are worth knowing before you wire it:

  • The family comes from the file, not from you. A video union patches frame by frame, an image union works per batch item. If the file says video and your model is an image model, the node stops with a message telling you to pick the matching file rather than producing something strange.
  • start and end are fractions of the schedule, converted to sigma. Not steps, not percentages of your step count as you typed it - the node asks the model's sampling object for the sigma at 0.0 and at 0.6 and holds the control between them.
  • Nothing wired, nothing applied. Strength 0, or no control/mask at all, and it hands the model back untouched and says "not applied" in info. Nice for A/B-ing without deleting wires.

The inputs you'll actually touch

Required: model (after your LoRAs, before the sampler), vae (the model's video VAE - it's what turns your PNGs into something the patch can use), control_model, strength, start, end, pick.

The two that decide whether your result is good or mush are strength and end. Strength adds up across nodes - chain a pose Apply and a depth Apply and the author's advice is to keep the sum near 1, e.g. pose 0.7 + depth 0.3. And end around 0.6 leaves the last steps free to invent texture, which is the single biggest quality lever on any ControlNet. Modern unions also publish lower recommended weights than the SD-era 1.0 default, so start under 1 and climb.

pick is the sleeper. -1 means the whole control; 0, 1, 2… takes only that frame - and the matching frame of mask and source. That's how you get one direction of a ring render to sit as one row of a turntable.

Optional pins: control (your maps), mask + source for masked regeneration (white = regenerate, black = keep), and control_patch if you loaded a patch somewhere else and want to override the dropdown.

Outputs are model - into the sampler, or into the next Apply Control - and info, which is a plain string telling you the model, family, frame count, size and step range. Wire it into a Show Text node and stop guessing.

A workflow that works

Media Loader → Control Fit → Control Map (pose) ─┐
                                                 ├→ Apply Control → Sampler
Load Model → LoRA Engine ───────────────────────┘

Fit first, map second, patch third. If you want a saved template of the control before committing to a render, wire Control Map's control into a Save node - the maps are just images.

Install

Manager, searching "Polyhedron Suite", or by hand:

cd ComfyUI/custom_nodes
git clone https://github.com/PolyhedronAI/ComfyUI-PolyhedronLoRAStack.git
# restart ComfyUI

requirements.txt in this pack is a comment block saying none required - no torch pin, no xformers, no surprise. The control files are the real download: the combo lists each union with its size, marks the ones you don't have as not installed, and offers a sha256-checked Download on the node's line. A run never downloads. Put files in models/model_patches by hand and they show up in the list too.

Where people get burned

End before start. The node refuses outright (end (0.40) lies before start (0.60)), which is friendlier than the silent nothing you get from most stacks.

Frames off the grid. Your control clip is 97 frames, the latent wants 17n+5. Apply Control will fit what it can at run time - cut, or hold the last frame - and the info output warns you when the count is off-grid. If you want it exact, snap it upstream with Control Fit instead of letting the union improvise.

The wrong union family. Loading the Qwen image union against an H3 video model throws the family-mismatch error. It's a two-second fix but it looks like a crash the first time.

It won't steer a model it wasn't trained for. A Fun union is a trained adapter for one base family; the H3 file patching SDXL sensibly is not a thing. And these nodes expect a current ComfyUI - the README says master, and the control-patch classes are core, not vendored here.

CategoryPolyhedron/Control

Inputs (11)

NameTypeDefaultDescription
modelMODELThe model to steer (after LoRAs, before the sampler).
vaeVAEThe model's (video) VAE -- it encodes the control frames.
control_modelCOMBOminimax_h3_fun_controlnet_union_2.0_pruned_int8_convrot.safetensors · 4.2 GB · not installedA Fun ControlNet Union file in models/model_patches. The family (video or image) is read from the file. A file marked 'not installed' is fetched by the Download on the node's line.
strengthFLOAT1.000–4How hard the control pulls. Several Apply nodes add up: keep their sum near 1 (e.g. pose 0.7 + depth 0.3).
startFLOAT0.000–1Fraction of the sampling where the control starts (0 = from the first step).
endFLOAT1.000–1Fraction where it stops. Around 0.6 leaves the last steps free for texture.
pickINT-1-1–100000-1 = the whole control (video: frame by frame; image batch: item by item). 0, 1, 2 ... = only that frame of the control (and of mask / source) -- e.g. one direction of a ring render for one row of a turntable (0 = S, 1 = SE ...).
controloptIMAGEControl frames (Control Map). Video: one per frame; image batch: one per item, or one for all.
maskoptMASKInpainting: white = regenerate under the control, black = keep.
sourceoptIMAGEInpainting: the frames behind the mask (kept where it is black).
control_patchoptMODEL_PATCHOverrides control_model: a patch loaded elsewhere.

Outputs (2)

NameTypeDescription
modelMODELThe model with the control -- into the sampler (or the next Apply Control).
infoSTRINGControl model, family, frames, range.