MMH3 Fun Controlnet Params
The map that keeps tiled MiniMax H3 upscales from drifting
- control_net
- vae
- control_video
- fun_control_param
Tiling an upscale is where workflows quietly go wrong. You split the frame, sample each piece, stitch it back - and if you're running any real denoise, every tile happily invents its own version of the scene. The classic fix is a Tile ControlNet: feed the low-res source in as the condition so each tile is pulled back toward the same image. This node is that idea for MiniMax H3 video, packaged as a settings bundle for the MMH3 Ultimate Upscale node in the Comfyui-MMH3-UltimateUpscale pack.
The pack's whole pitch is upscaling finished H3 clips on a VRAM-limited GPU via temporal chunking plus spatial tiling, so peak memory stays at one tile. That works - but the tiling itself is the weak spot when your denoise is high. Without guidance, a tile at 40% denoise drifts toward whatever it hallucinates, and the seam blending has nothing to hold onto. MMH3FunControlnetParams gives each tile a crop of the source video so it stays honest.
How it works
Like every *Params node in this pack, it doesn't sample anything itself. It bundles a ControlNet, a control video, and timing settings into one fun_control_param handle the main node consumes. The clever part is what happens downstream: the main node crops the low-res control video per temporal chunk, then per spatial tile, upscales each crop to the tile's footprint, and builds a fresh ControlNet copy per tile - the hint cache is keyed on size only, so tiles can't share one object. Each tile is therefore guided toward its own region of the source, not the whole frame.
control_upscale_mode trades peak memory against up-front work:
per_chunk(default) - upscales only the current chunk's control frames before processing that chunk.per_tile- upscales just the tile's crop right before sampling. Lowest peak memory, most redundant work.all- upscales the whole control video up front, then crops during tiling. Original behaviour, highest peak memory.
Inputs and outputs that matter
control_net- the MiniMax H3 Fun ControlNet, loaded viaControlNet Loader/DiffControlNet Loader. The code hard-checks this is aMiniMaxH3ControlNet; anything else raises a ValueError, so don't reach for an SDXL controlnet.vae- required; the controlnet encodes the control video into latent space and needs a VAE to do it.control_video- the control video at its original low resolution, as frames[T, H, W, C]. Feed it pre-upscale; the node handles resizing.upscale_width/upscale_height(defaults 1280×704, step 32) - the target size. These must match the upscaled generation size and the size your upscale params use, or the guidance lands in the wrong place.strength(1.0) andstart_percent/end_percent- how hard and over which denoising window the control applies. The usual ControlNet rule holds: if you only need the composition pinned, end early around 0.5–0.7.
Output is one fun_control_param, which wires into the fun_control_param input on MMH3 Ultimate Upscale.
Installing it
Through ComfyUI Manager (search "Comfyui-MMH3-UltimateUpscale") or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/bbaudio-2025/Comfyui-MMH3-UltimateUpscale
Then restart ComfyUI. There are no Python deps beyond what ComfyUI ships - but there are two real prerequisites hiding off to the side. First, ComfyUI itself must have kijai's PR #15860 merged - that's where MiniMax H3 Fun ControlNet support lives; on an older install the node errors out immediately. Second, the model side: you need the H3 checkpoint (~42 GB, the 33B model), the H3 VAE, and the H3 Fun ControlNet-Union weights. And remember the H3 Community License geofences out the US, EU, UK and Korea - if you're in one of those, the weights aren't licensed for you regardless of what the node does.
Where people get burned
The width/height mismatch is the classic: set the upscale params to one size and the conditioning to another, and you get control guidance that's subtly off - nothing errors, the video just looks "wrong" in a way that's hard to blame on one setting. Keep the three (conditioning generation size, upscale params, this node) in lockstep. Also worth knowing: this pack is explicitly vibe-coded and moves fast, so pin a ComfyUI version that works for you rather than chasing every update.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| control_net | CONTROL_NET | The MiniMax H3 Fun ControlNet (load with 'ControlNet Loader'/'DiffControlNet Loader'). | |
| vae | VAE | VAE used to encode the control video into latent space. Required by the MiniMax H3 Fun ControlNet. | |
| control_video | IMAGE | ControlNet-Union control video at its ORIGINAL LOW resolution (the preprocessed low-res video, before upscaling), as a sequence of frames [frames, H, W, C]. | |
| upscale_width | INT | 128032–100000 | Target upscaled pixel width of the control video. Must match the upscaled generation size (and the width used by the upscale params). |
| upscale_height | INT | 70432–100000 | Target upscaled pixel height of the control video. Must match the upscaled generation size (and the height used by the upscale params). |
| control_upscale_mode | COMBO | per_chunk | How the low-res control frames are upscaled in batches. 'per_chunk' (default): upscale only the current temporal chunk's control frames before processing that chunk. 'per_tile': upscale only the current tile's control crop before sampling that tile - lowest peak memory. 'all': upscale the whole control video up front, then crop during tiling - highest peak memory (the original behaviour). |
| strength | FLOAT | 1.000–10 | How strongly the control video guides each piece's generation. |
| start_percent | FLOAT | 0.0000–1 | Denoising step fraction at which the control starts taking effect. |
| end_percent | FLOAT | 1.0000–1 | Denoising step fraction at which the control stops taking effect. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| fun_control_param | H3_FUN_CONTROL_PARAM | Fun ControlNet settings consumed by 'MMH3 Ultimate Upscale'. |