MiniMax H3 Frame Rate Adjustment (Ac)
Your MiniMax H3 Clip Isn't Stuck at 24 FPS — It's Just a Different Clock
- model
- positive
- av_latent
- model
- positive
- av_latent
- model_fps
- duration_seconds
- report_json
MiniMax H3 generates 4–15 second clips at 24 FPS with native stereo audio - video and sound decoded out of one joint latent, which is the whole reason people put up with a 33B model and a licence that geofences half the West. The "24 FPS" part is the bit that feels like a wall. It isn't. It's a clock the model reads, and MiniMax H3 Frame Rate Adjustment (Ac) lets you hand it a different one.
To be clear about what this buys you (the README is refreshingly blunt about it): it does not interpolate, add frames, or reduce steps, VRAM or runtime, and it doesn't promise 31 FPS looks better than 24. It retimes. Same frame count, same sampling cost, different playback duration.
What it's actually changing
H3 packs video and audio into one sequence, and they run on different clocks: video tokens sit on the documented 24 FPS timeline, the audio latent ticks at 40 Hz. Given F decoded frames - H3's valid counts follow the 17k + 5 grid (5, 22, 39, 56, … 124, 141 …) - and your model_fps, the node computes duration = F / fps, asks for round(duration × 40) audio slots, and scales video time coordinates by 40 / fps.
Mechanically it does three things. It resizes the audio latent's time axis before sampling - trimmed if the new duration is shorter, zero-padded if longer - so the model generates sound at the new length rather than repitching anything decoded. It tags the conditioning with the frame count and target FPS. And it returns a cloned model whose extra_conds is wrapped (the add_object_patch call in runtime.py), so the packed layout's video position_ids aren't rewritten now - they're rewritten at sampling time, scaled by 40 / fps.
It refuses to guess, which is the right call: wrong temporal coordinates corrupt silently, so a non-H3 model gets rejected outright.
Inputs and outputs worth knowing
Four inputs. model, positive and av_latent are the three H3 lines you insert yourself into; model_fps is the only widget - default 24, clamped to 12–120, and its tooltip says outright that anything else is experimental.
model goes on to your guider (and to BasicScheduler too, if you use one; the node doesn't touch Sigmas), positive to the guider, av_latent to the sampler. Slot it after your LoRA and attention patches and before the guider.
Then the outputs people forget. Wire model_fps into the fps field of CreateVideo or your VHS combiner instead of retyping the number, or a file written on a different clock hands you the drift back. duration_seconds is the real duration after grid alignment. report_json is the honest one: audio latent length before and after, endpoint error in milliseconds against its 12.5 ms limit, and a flag whenever you're off 24.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/AharaOoO/ComfyUI-MiniMaxH3-FrameRate-Adjustment-Ac.git
Restart ComfyUI, or search MiniMax H3 Frame Rate Adjustment (Ac) in ComfyUI Manager. No pip dependencies at all - requirements.txt is just comments - and the README says not to install or upgrade torch for it. In an ecosystem where dependency hell is the number one complaint, a pack that ships zero requirements is a small mercy. It does need ComfyUI >= 0.31.0 and the comfy_api.latest node API. The bundled example workflow also expects KJNodes, Sol-Attn and VideoHelperSuite, and references model and LoRA files it doesn't ship.
Common issues
"Nothing changed." Nine times out of ten you wired the latent or conditioning straight from the H3 node into the sampler and only took the model output. All three paths have to go through this node.
"My audio drifts." The fps on your save/combine node must equal model_fps. Then check report_json: the audio clock is quantised to 40 Hz, so the endpoint can land up to ~12.5 ms off. Want it exactly zero? Pick an fps where frame_count / fps is a whole number of 40ths - hence the README's 124 frames @ 31 = 4.0000 s and 192 @ 48 = 4.0000 s, against 124 @ 24 = 5.1667 s.
Compatibility errors. A flat SetLatentNoiseMask upstream gets you "cannot retime a flat MiniMax H3 noise_mask when audio length changes" - the mask has lost the video/audio boundary and the node won't guess. Point it at a Wan, LTX or SVD model instead of H3 and it says so. Both are guards working as designed; feed it an unmasked native H3 latent and a real H3 model patch.
Breakage above 30 FPS. Expected, and the README says so: 37–48 is high-risk for flicker, colour drift and unstable motion; 49+ is boundary testing only. Distilled LoRAs and approximate attention are separate techniques whose errors compound with out-of-distribution temporal coordinates. If it breaks, return to 24 FPS and exact attention, then change one variable at a time on a fixed seed.
The honest use here isn't "make H3 high FPS." It's duration control without re-sampling: keep your 124 frames and choose whether they play for 5.2 seconds or exactly 4. If you want genuinely smooth 60 FPS motion, this isn't the tool - that's frame interpolation as a second pass, a different job and a different node.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| positive | CONDITIONING | — | |
| av_latent | LATENT | — | |
| model_fps | FLOAT | 2412–120 | 24 is H3's documented native rate. Other values retime MM-RoPE and are experimental; set CreateVideo/SaveVideo to the same FPS. |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| model | MODEL | — |
| positive | CONDITIONING | — |
| av_latent | LATENT | — |
| model_fps | FLOAT | — |
| duration_seconds | FLOAT | — |
| report_json | STRING | — |