FL MiniMax H3 Motion Refine
Stretch the Fast Parts, Refine Them, Then Put the Clock Back
- model
- latent
- vae
- positive
- audio_vae
- baseline_images
- baseline_audio
- shot_plan
- images
- report
Here's the problem this node exists for. You've got a finished H3 clip that mostly looks great, except the fast bits - a whip pan, a hand flick, a running figure - are smeared, and the whole thing is at whatever resolution you could afford on the first pass. Normal img2img refinement over video makes it worse, because a low-denoise pass at 24 fps can't invent motion detail that was never sampled densely enough.
Motion Refine's answer is a temporal trick: temporarily give the fast frames more time, refine there, then squeeze back to original timing. It's the single most interesting node in the pack and the fiddliest.
How it works
The node is a wrapper. At run time it expands into internal sub-nodes (Motion Shot, Motion Prepare, Motion Sample, Motion Collect), and it needs ComfyUI-MAINodes for four operations: H3JerkOracle, H3TimeSmear, H3AudioSmear, H3V2VInit. It also calls two H3 VAE methods, encode_h3_frame_sequence and decode_h3_selected, which don't exist in stock releases.
The pipeline, roughly:
- Decode the source latent (or reuse
baseline_images- the example workflow calls those "shared decodes of the same source latent" to avoid doing the work twice). - Ask the jerk oracle how much each interval is moving, and turn that into a hold map: motion-heavy spans get held for more frames, still ones for fewer.
- Expand the frame count onto that map, snapped to H3's
17k+5grid, with a 39-frame internal floor. - Re-encode the stretched frame sequence, smear and re-encode the audio, and retime your conditioning - temporal masks and image-anchor times included - onto the stretched clock.
- Partially denoise with
H3V2VInitas the init, running the tail of the schedule. - Decode only the frames that map back to the original clock.
That last step is the promise and the caveat in one. Recovery restores timing, not original pixels. The README says so and the node's own report repeats it: no frame-accurate restoration, no flicker-free guarantee.
The inputs you actually set
Connect latent (a completed native H3 video/audio latent - not an empty latent, not a temporal reshoot), the H3 model, the video vae, and audio_vae (required whenever the timeline stretches; only optional if you run coverage off). Then connect positive, unless you're in shot-plan mode where each shot carries its own conditioning.
target_long_side at 0 keeps source size. Set it to a multiple of 32 and you also get a spatial upscale, in pixels, before refinement - the honest two-birds version of this node, and the second "bird" is why people reach for it at all.
strength is not KSampler's denoise. It's the fraction of the schedule you run: 25 steps × 0.5 = 12 refinement steps. motion_coverage picks the presets - balanced, economical, wide, or uniform (which uses your max_hold), or off for a spatial-only benchmark. context_budget at 0 samples the whole expanded clip like the reference workflow; 124 is the example's suggested window budget. It cuts per-window model work and is explicitly not a cap on total latent, VAE or host memory.
Outputs are images and report. Keep your original soundtrack wired straight to Create Video at 24 fps; this node doesn't output audio.
Install
Manager, search FL MiniMax H3. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/filliptm/ComfyUI-FL-MiniMaxH3.git
Restart, and start from the workflow in the repo at examples/FL-H3-Motion-Refine.json - it wires the cached baseline render separately from the compact refinement pass, which is the whole design. Plug in your own model files (minimax_h3_ref2va_*, a Qwen3-VL MiniMax encoder, minimax_h3_video_vae_fp16, minimax_h3_audio_vae_fp32) and your own reference image. Install ComfyUI-MAINodes too, and update it if it's old.
Where people get burned
- Missing MAINodes gives you a named RuntimeError, not a crash - it lists which of the four operations it couldn't find. If it complains about a missing
H3TimeSmear.plan, that's the version check: update MAINodes. - Stale ComfyUI. The pack imports ComfyUI's H3 module at load time, so on a build without native H3 support you don't get one broken node, you get none of them.
- The cache is doing you a favour - don't break it. Preparation and sampling are two nodes cached separately. Changing seed, steps, strength, sampler, scheduler or audio strength reuses the preparation; changing the source, the VAEs, coverage or resize inputs throws it away. That's why the README tells you to keep the baseline sampler outside this node.
- Adaptive coverage needs at least 22 source frames. Short clip? Use
uniformoroff. - Memory. The node holds full source images and the expanded latents at once. A 2× spatial upscale means roughly 4× the video tokens downstream. Video is the one place where 12–16 GB genuinely becomes 24 GB, and this is that place.
- Don't use it to paper over a bad generation. Fix the baseline and refinement seeds, run coverage
offvsbalanced, then again at a larger target size. If the improvement isn't visible in that A/B, the clip needed a better first pass, not more refinement.
One last thing, and it's not a technicality: MiniMax's H3 weights are under a community licence whose Applicable Territory excludes the US, EU, UK and South Korea - outputs included.
Inputs (21)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| latent | LATENT | Completed native H3 video/audio latent, not an empty latent or temporal reshot. | |
| vae | VAE | — | |
| target_long_side | INT | 00–16384 | 0 keeps source size. Otherwise upscale the long edge; dimensions align to 32 pixels. |
| strength | FLOAT | 0.500.05–1 | Fraction of the full schedule to run. 25 steps x 0.5 = 12 refinement steps, not 25. |
| motion_coverage | COMBO | balanced | Off benchmarks spatial refinement without temporal stretching. Uniform uses max_hold everywhere. |
| steps | INT | 254–100 | — |
| context_budget | INT | 00–10000 | 0 = whole expanded clip (matches the reference workflow). Otherwise a frame-equivalent window budget, snapped down. A causal anchor may add one latent position. Not a total VRAM cap. |
| seed | INT | 202609020–18446744073709550000 | — |
| context_overlap | INT | 170–1000 | — |
| sampler_name | COMBO | res_multistep | 44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38 |
| scheduler | COMBO | simple | 9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3 |
| max_hold | INT | 42–8 | Used only by uniform coverage. Adaptive coverage presets own their hold limits. |
| audio_strength | FLOAT | 0.500–1 | Refinement freedom for the stretched baseline audio conditioning. Export keeps the original soundtrack separately. |
| expand_to_end | BOOLEAN | true | Extend a short unheld tail through the last motion burst, matching H3 Time Smear. |
| upscale_method | COMBO | lanczos | 3 options: lanczos, bicubic, bilinear |
| positiveopt | CONDITIONING | Required without shot_plan. Shot-plan mode uses each shot's own conditioning instead. | |
| audio_vaeopt | VAE | Required when the timeline expands; not needed with coverage off. | |
| baseline_imagesopt | IMAGE | Optional shared decode of this exact source latent. Connect the same images used by the before panel. | |
| baseline_audioopt | AUDIO | Optional shared decode of this exact source latent's soundtrack. | |
| shot_planopt | FL_H3_SHOT_PLAN | Connect the exact plan used by Beat KSampler, including Shot Motion Context when present. Baseline images/audio then refer to the assembled timeline. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | — |
| report | STRING | — |