Nodes/ComfyUI-FL-MiniMaxH3/FL MiniMax H3 Motion Refine
ComfyUI Node

FL MiniMax H3 Motion Refine

Stretch the Fast Parts, Refine Them, Then Put the Clock Back

By filliptm·Created about a month ago·Updated 2 days ago· 17
FL MiniMax H3 Motion Refine
  • model
  • latent
  • vae
  • positive
  • audio_vae
  • baseline_images
  • baseline_audio
  • shot_plan
  • images
  • report
target_long_side0
strength0.50
motion_coveragebalanced
steps25
context_budget0
seed20260902
context_overlap17
sampler_nameres_multistep
schedulersimple
max_hold4
audio_strength0.50
expand_to_endtrue
upscale_methodlanczos

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:

  1. 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).
  2. 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.
  3. Expand the frame count onto that map, snapped to H3's 17k+5 grid, with a 39-frame internal floor.
  4. 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.
  5. Partially denoise with H3V2VInit as the init, running the tail of the schedule.
  6. 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 uniform or off.
  • 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 off vs balanced, 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.

CategoryFL/MiniMax H3/Sampling

Inputs (21)

NameTypeDefaultDescription
modelMODEL
latentLATENTCompleted native H3 video/audio latent, not an empty latent or temporal reshot.
vaeVAE
target_long_sideINT00–163840 keeps source size. Otherwise upscale the long edge; dimensions align to 32 pixels.
strengthFLOAT0.500.05–1Fraction of the full schedule to run. 25 steps x 0.5 = 12 refinement steps, not 25.
motion_coverageCOMBObalancedOff benchmarks spatial refinement without temporal stretching. Uniform uses max_hold everywhere.
stepsINT254–100
context_budgetINT00–100000 = 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.
seedINT202609020–18446744073709550000
context_overlapINT170–1000
sampler_nameCOMBOres_multistep44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38
schedulerCOMBOsimple9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3
max_holdINT42–8Used only by uniform coverage. Adaptive coverage presets own their hold limits.
audio_strengthFLOAT0.500–1Refinement freedom for the stretched baseline audio conditioning. Export keeps the original soundtrack separately.
expand_to_endBOOLEANtrueExtend a short unheld tail through the last motion burst, matching H3 Time Smear.
upscale_methodCOMBOlanczos3 options: lanczos, bicubic, bilinear
positiveoptCONDITIONINGRequired without shot_plan. Shot-plan mode uses each shot's own conditioning instead.
audio_vaeoptVAERequired when the timeline expands; not needed with coverage off.
baseline_imagesoptIMAGEOptional shared decode of this exact source latent. Connect the same images used by the before panel.
baseline_audiooptAUDIOOptional shared decode of this exact source latent's soundtrack.
shot_planoptFL_H3_SHOT_PLANConnect the exact plan used by Beat KSampler, including Shot Motion Context when present. Baseline images/audio then refer to the assembled timeline.

Outputs (2)

NameTypeDescription
imagesIMAGE
reportSTRING