MiniMax H3 Motion Fix
Why your spinning kick is a smear, and the node that slows it down to redraw it
- model
- positive
- negative
- vae
- source
- latent
- reel
- reel
- pass
MiniMax H3 smears bursty motion - a backflip, a sword arc, a whip-fast turn - into mush, and no seed, steps or sampler fixes it. The cause is structural: one latent time token spans four pixel frames, and four frames of a fast limb need four different poses a single token cannot hold - and re-denoising can't recover poses that were never generated. H3 leads the open-weights image-to-video arena and it still can't draw a kick.
MiniMax H3 Motion Fix is the pack's answer, and like the rest of the internal nodes you don't add it - it's is_dev_only, hidden from node search, and written into the graph when you flip the Motion fix chip on a card (H3 only, never on footage; on a lone shot it's a pill on the row).
How it actually works
The idea is test-time and slightly sneaky: if the model can't hold the poses at this speed, give it a longer clock. The finished pass is retimed by repeating frames where the motion is too hot, the slowed copy is encoded with the video VAE and sampled again from partway down the schedule - video-to-video, so the choreography survives and the rendering is re-rolled - then the original clock comes back by keeping the first frame of every hold group. Every returned frame is generated, never interpolated.
Which frames to hold comes off the pass's own latent: the third difference of latent values over time per token, normalised so H3's uneven (1, 4, 4, 4, 4) token spans don't skew the ranking. Hot tokens get up to four copies, and valleys inside one burst get bridged rather than left as a dip.
That core method is matlowai's Motion Lab (ComfyUI-MAINodes); the pack is upfront that this is a clean reimplementation written from the published method, with the dials its author measured. Five frames at either end are never held, are frozen through the second pass and have their original pixels spliced back byte-for-byte, so the fix can't become a seam step of its own.
The inputs you'll actually touch
Everything here is normally wired by the pack from the shot's own sampler row, but two dials are worth setting by hand:
denoise(default 0.5) - how much of the schedule runs over the slowed init. The tooltip is the whole story: 0.5–0.8 keeps the choreography and re-rolls the rendering, lower keeps the smear, higher invents its own choreography.abstain(default 2.5) - the gate. A pass whose peak frame-to-frame change, at thumbnail scale on 0–255, is under this is left alone and says so in the render history;0fixes every pass. It matters more than the rest put together, because the method's own profile-contrast measure ranked a static fern higher than a spinning kick - forced through the pass, the fern came back sharper and moving unnaturally. Measured 4.4 on the kick, 1.9 on the fern: the gate is the difference between a feature and a tax. The settings page exposes it asmotion_fix_abstain.
The rest: model, positive, negative, vae (the video VAE that encodes the slowed clip), source (the pass as written by the reel node), latent (the sampler's AV latent - only its motion profile is read), head (frames trimmed off the front of the latent when the pass was written), plus seed, steps, cfg, sampler_name, scheduler and reel inherited from the shot. Outputs are reel and pass. The node runs after the one that put the pass on the reel, so it returns the reel with that pass replaced in place, which is what lets a later seam inherit the fixed frames; the soundtrack rides through untouched.
Install
Nothing separate - the node ships with the pack. Manager → search "Continuity", or:
cd ComfyUI/custom_nodes
git clone https://github.com/roadmaus/ComfyUI-Continuity
Restart. No pip install - the pack declares zero Python dependencies. You do need the H3 weights: the checkpoint in models/diffusion_models and minimax_h3_video_vae_fp16.safetensors in models/vae. Missing files are refused before the queue starts, naming the file and the folder.
What it costs, and where it hurts
Measured on a 2-second turbo card: 30 of 56 frames held, the clip slowed to 124 frames, and the second pass cost about twice the card's own sampling time. Per-step cost isn't linear in token count (attention dominates), so a more violent clip pays more than proportionally.
Two things error rather than silently do nothing: hand latent anything but H3's nested (video, audio) AV latent and it raises "expected MiniMax H3's AV latent", and the slowed clip has to land on H3's 17k+5 grid.
The evidence is thin: two measured clips, and the fix hasn't been tried on a pan, which will clear the motion gate on camera movement alone. Start with the gate at its default and A/B one card.
Inputs (15)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| positive | CONDITIONING | — | |
| negative | CONDITIONING | — | |
| vae | VAE | — | |
| source | MMC_PASS | The pass as written by the reel node. | |
| latent | LATENT | The sampler's AV latent the pass was decoded from; only its motion profile is read. | |
| head | INT | 00–64 | Frames trimmed off the front of the latent when the pass was written. |
| seed | INT | 00–18446744073709550000 | — |
| steps | INT | 201–200 | — |
| cfg | FLOAT | 1.000–30 | — |
| sampler_name | COMBO | 44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38 | |
| scheduler | COMBO | 9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3 | |
| denoise | FLOAT | 0.500.05–0.99 | How much of the schedule runs over the slowed init. 0.5–0.8 keeps the choreography and re-rolls the rendering; lower keeps the smear, higher invents. |
| abstain | FLOAT | 2.50–50 | A pass whose peak frame-to-frame change, at thumbnail scale on 0-255, is under this is left alone. 0 fixes every pass. |
| reel | MMC_REEL | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| reel | MMC_REEL | — |
| pass | MMC_PASS | — |