Support
Everything here is free and stays free — the format spec, the nodes, the workflows, the cartridges, the LoRAs. If it saved you a night of debugging (it contains several hundred of mine), tips keep the 5090 warm:
🔁 Liberapay (recurring)
⚡ Or right here: the Civitai tip button on this page sends Buzz directly.
Three ways to drive MiniMax-H3, and a VRAM fix that makes it usable on a 32 GB card. Chain shots from a script into one long piece; pin keyframes anywhere in a clip; or drive identity from reference images, video and voice. All in one node pack, all producing video and audio.
Keyframes at any position
Stock ComfyUI pins H3 keyframes to the first and last frame only and raises only first/last keyframe anchors are supported for anything else.
That is a positional-maths limit, not a model limit. Both stock cases are the same expression, because sum(_video_t_spans(latent_t)) == FRAME_RESCALE * frame_count:
cond_t = text_len + FRAME_RESCALE * pixel_index— which is defined for every frame, not just the two endpoints. So you can hand H3 up to six anchor images and say when each one should happen, as fractions (0, 0.5, 1) or absolute frame indices.
Measured on an RTX 5090, 243 frames, one anchor at pixel frame 121: the rendered frame most resembling the anchor image was frame 122 — the requested position, off by one — arrived at by continuous motion with no cut (peak frame-to-frame change 2.3× the median), and the audio ran unbroken straight through it. A three-anchor run at 0 / 0.5 / 1 landed the second and third on frames 121 and 242 exactly.
The patch is applied in memory — it does not edit any ComfyUI file. It self-tests against the stock formula before committing and rolls itself back if first/last positions do not reproduce exactly, so a future ComfyUI change degrades to “interior anchors unavailable” rather than to broken renders.
It moves, or it cuts — and your images decide which
Anchor images with a plausible camera path between them (same place, different angle or framing) make H3 interpolate: a real move that arrives on time. Images with no possible path — a kitchen and a diner — make it cut, then hold.
That is the model being sensible, not a limitation of the node: stock first/last does exactly the same thing when given such a pair. And the cut case earns its keep, because it is a timed shot change inside a single generation — one generation means one continuous audio stream, so the voice does not get re-derived and there is no seam to hide.
Saying when: percentages, indices and ranges
Anchor positions take whichever form suits the shot:
0%, 50%, 100% percentages
0, 121, 242 absolute frame indices
0-9, 352-361 inclusive ranges
30%-20% descending: reverses that section of the batchRanges matter when you have a burst of frames rather than a single anchor — several frames clustered at each end to pin a complex move, or a run kept from a source video. For that there is an images_batch input that takes any number of anchors, and it adds to the six individual slots rather than replacing them.
Both of those came from @poltergeisha360, who asked for the batch input here on Civitai and then wrote both features and sent pull requests. The percentage syntax also fixes a genuine trap of mine: a bare 1 used to mean the last frame, not frame 1, so addressing an early frame absolutely meant writing 1.0001. Saved workflows keep working — a bare non-integer at or below 1.0 is unambiguous and still reads the old way, while an all-integer 0, 1 takes the new absolute meaning and logs a warning rather than silently anchoring a different frame.
Models in subfolders show up
Both loaders scan diffusion_models and text_encoders recursively, so a GGUF filed under gguf/ appears in the dropdown. It did not before, while ComfyUI-GGUF's own loader listed the same file fine — the scan exists because .gguf is not in ComfyUI's supported_pt_extensions, so the normal file list never returns it.
Which workflow
A script of several shots, chained into one piece —
H3_Multishot_AIO.jsonSpecific frames at specific times, one continuous take —
H3_Keyframes.json2–5 minutes without identity drifting —
H3_Multishot_MEMORY.jsonIdentity from reference images, video or voice — Hard Mode, a separate download
Reference-to-video has landed, as its own release: MiniMax-H3 Hard Mode — identity from reference images, video and audio instead of a start frame, up to 9 images, 3 videos, 3 soundtracks and 3 standalone audio clips. It uses this pack's nodes, so install this first. On Hugging Face and GitHub. Also on Civitai.
References and keyframes are mutually exclusive — worth knowing before you wire the two together. This is ComfyUI core behaviour, not a choice made here: model_base.py assigns cond_video_latents for references, discarding keyframe latents while the keyframe layout rows survive — the packed sequence then desyncs into a shape-mismatch crash. There is no “reference images plus start frame” mode. Pick one per shot.
~4× faster on 32 GB cards
The text encoder is evicted before sampling. The Qwen3-VL encoder (~16.5 GB even at Q4) and the H3 DiT (~25 GB) do not co-fit on a 32 GB card, so the DiT was loading partially and streaming ~19 GB from system RAM on every sampling step. If you have ever seen this in your log:
loaded partially; 6423 MB usable, 5847 MB loaded, 19363 MB offloadedthat was it. Measured on an RTX 5090 — 960×544, 124 frames, 20 steps, ref2va-Q5_1, one reference image: 12.3 min with the encoder evicted. The un-evicted run of that same render was killed past 90 min without finishing, so there is no honest completion time to quote against it. Every sampler in this pack evicts, including the keyframes node, and prints TE evicted; NN.N GB free for the DiT.
Treat this as a cliff, not a curve. The encoder (~16.5 GB at Q4) and the DiT (~25 GB) do not co-fit in 32 GB, so either the DiT is resident and you get normal speed, or it streams ~19 GB every sampling step. The size of the slowdown depends on how far over your card you are, not on resolution or frame count directly — one speed-up ratio would not generalise, so there is not one here.
Quick fixes — read this first
Red / missing nodes when a workflow loads
Why: pack not installed, or ComfyUI not restarted.
Fix: install ComfyUI-H3-Multishot (Manager > Install via Git URL), restart, then hard-refresh the browser tab — the frontend caches node definitions.GGUF errors with “unknown model architecture”
Why: ComfyUI-GGUF does not know MiniMax-H3 out of the box.
Fix: runpython apply_gguf_arch_patch.pyfrom the pack folder (one line, idempotent), restart. This is for the DiT only — the text encoder is Qwen3-VL and needs no patch.
Only want the DiT working? The patch is also downloadable on its own (2 KB) if you are running ComfyUI's built-in MiniMax-H3 nodes with the safetensors encoder and do not need this pack at all. It is included here, so installing this pack is enough.Reference audio crashes the sampler with a shape mismatch
Why: your clip is mono. The audio VAE encodes[B, 2, L]and the layout reserves exactly two channels, so a mono reference produces half the rows it reserved and dies deep inside the model with no useful message. Nothing in stock converts it.
Fix: the H3 Reference Audio node — forces stereo 32 kHz and trims length. It is already wired in the hard-mode workflow.The model ignores my reference image
Why: reference blocks are labelled in the prompt and the numbering is 1-based while the input slots are 0-based —ref_image_0is<Picture 1>. If you never name it in the text, the model has no reason to bind it.
Fix: write<Picture 1> is the woman. <Picture 2> is the room.Note a reference video with a soundtrack consumes an<Audio j>ordinal before your standalone clips.Multi-shot ignores my reference image entirely
Why: missingmmproj. It is required for chaining, not just for reference images — chaining feeds the previous shot's last frame through the encoder's vision path.
Fix: download the-mmprojfile alongside the encoder and keep both filenames exactly as downloaded, in the same folder. The loader pairs them by name.Length change errors out
Why: H3 hard constraint — frame counts live on a 17k+5 grid.
Fix: 226, 243, 260… the widget steps by 17 so it keeps you legal. 243 ≈ 10s; 362 ≈ 15s is the trained ceiling.Speech turns to gibberish
Why: usually an under-filled shot, not an over-long one. Speech runs about 2.5 words/second, so a 243-frame shot wants roughly 22–25 spoken words; give it eight and the model invents sound to fill the dead air.
Fix: match dialogue length to shot length, and if you want silence, script it (“she listens, saying nothing”).An object morphs into something else at a seam
Why: chaining hands each shot the previous final frame. If shot 1 ends on the cameraman holding his camcorder and shot 2 is filmed FROM that camcorder, the model must explain a device in a hand that should not be in frame — so it invents one.
Fix: end every shot on what the NEXT shot expects to see.Out of VRAM, or renders crawl
Why: 33B of weights — and see the eviction section above.
Fix: use the GGUFs, Q5_1 for 24–32 GB, Q4_0 for 16 GB. The file does not need to fit in VRAM; ComfyUI streams the overflow. Expect ~10 min per 10s shot on a 5090-class card.
Writing a script — this is most of the quality
The identity lock is description density, not assertion. Every shot is an independent conditioning pass: the model rebuilds the person from your text each time. Writing “the same woman, same face, same wardrobe” asserts continuity without supplying what is needed to rebuild it, and the face drifts. Re-describing 6–8 concrete attributes verbatim in every shot is what actually holds it:
She is an attractive American woman in her mid twenties with warm hazel
eyes, a friendly confident smile, light freckles, shoulder-length auburn
hair tucked behind one ear, small gold stud earrings, and a relaxed
sage-green blouse. Her voice is a clear warm young woman's voice in a
casual American accent.Do the same for the voice: one short concrete line, repeated verbatim. Flowing prose beats SHOT: / Audio: labels.
What you need
ComfyUI v0.30.0+ (native MiniMax H3 support)
The node pack: ComfyUI-H3-Multishot
DiT weights: MiniMax-H3 GGUF (or on Hugging Face) (Q5_1 / Q4_0, both flavours) — or the originals
Text encoder: MiniMax-H3 Text Encoder GGUF (or on Hugging Face) — take the mmproj file too
VAEs: Comfy-Org/MiniMax-H3
For GGUF: ComfyUI-GGUF + the included one-line patch
A word on expectations
MiniMax-H3 is a 33B joint audio+video model and this pack started days after the weights landed. It works, and the measurements on this page are from real renders on one consumer GPU — but you may still need to tune to YOUR machine. If you get stuck, comment here or open a GitHub issue. I answer.
Everything else I've published
Support
Everything I publish is free and stays free. If it saved you a night of debugging, tips keep the 5090 warm: Ko-fi · GitHub Sponsors · Liberapay.
Description
v1.2 adds keyframes anywhere in the clip, not just the first and last frame — plus a hard mode for reference-to-video, and two controls ComfyUI reads but no stock node ever sets.
Keyframes at any position
Stock ComfyUI pins H3 keyframes to frame 0 and frame N−1, and raises only first/last keyframe anchors are supported for anything else. That turns out to be a positional-maths limit, not a model limit. Both stock cases are the same expression, because sum(_video_t_spans(latent_t)) == FRAME_RESCALE * frame_count:
cond_t = text_len + FRAME_RESCALE * pixel_indexwhich is defined for every frame. The new H3 Keyframes (any position) node takes up to six anchors, positioned as fractions (0, 0.5, 1) or absolute frame indices.
Measured on an RTX 5090, 243 frames, one anchor at pixel frame 121: the rendered frame most resembling the anchor image was frame 122 — the requested position, off by one — reached by continuous motion with no cut (peak frame-to-frame change 2.3× the median), and the audio ran unbroken straight through it.
The patch is applied in memory. It does not edit any ComfyUI file. It self-tests against the stock formula before committing and rolls itself back if first/last positions do not reproduce exactly — so a future ComfyUI change degrades to “interior anchors unavailable” rather than to broken renders.
It moves, or it cuts — and your images decide which
Anchor images with a plausible camera path between them (same place, different angle or framing) make H3 interpolate: a real move that arrives on time. Images with no possible path — a kitchen and a diner — make it cut, then hold.
That is not a limitation of this node. Stock first/last does exactly the same thing with such a pair; it is the model doing the only sensible thing. And the cut case has its own use: a timed shot change inside a single generation, which means the audio runs continuously across it, with no per-shot voice re-derivation and no seam.
Reference-to-video groundwork
The two nodes below are what reference workflows need. The hard-mode graph itself is built but has not been rendered yet, so it is not in this release — it ships when it has a render behind it.
References and keyframes are mutually exclusive, in ComfyUI core rather than by choice here. model_base.py assigns cond_video_latents for refs, discarding any keyframe latents while the keyframe layout rows survive — the packed sequence then desyncs into a shape-mismatch crash. There is no “reference images plus start frame” mode. Pick one per shot.
Two things that are easy to get wrong and are documented on the canvas: reference tags are 1-based in the prompt (<Picture 1>) while the input slots are 0-based (ref_image_0); and a reference video with a soundtrack consumes an <Audio j> ordinal before your standalone clips.
Two more nodes
H3 Reference Audio (stereo guard) — the audio VAE encodes
[B, 2, L]and the layout reserves exactly two channels, so a mono reference produces half the rows it reserved and dies deep inside the model with no useful error. Nothing in stock converts it. This forces stereo 32 kHz and trims length.H3 Condition Strength — exposes
minimax_visual_cond_noise_augandminimax_audio_cond_noise_aug, which core reads but no stock node writes, so they sat at 0.999 / 1.0 permanently. They blend noise into the conditioning latents and set the timestep the condition rows occupy: an anchor-strength dial.
Still in the box from v1.1
Image-to-video via an optional
start_image.~4× faster on 32 GB cards. The text encoder is evicted before sampling — encoder (~16.5 GB) and DiT (~25 GB) do not co-fit, so the DiT was loading partially and streaming ~19 GB from system RAM every step. RTX 5090: ~60 min to ~15 min, same render. The keyframes node does this too.
Long-form memory sampler for 2–5 minute pieces.
Audio seams crossfaded;
seed_per_shoton by default.
Links
Support
Everything I publish is free and stays free. If it saved you a night of debugging, tips keep the 5090 warm: Ko-fi · GitHub Sponsors · Liberapay.
FAQ
Comments (35)
Could we have first frame I2V support? 🙏
I will put it on the list for today's work. ;)
I'd like to see keyframes not just first/last
v1.1 added with I2V
@joeygambino ty for the quick update
@brnfd24434343d I'm definitely experimenting.
what about reference mode?
@Thimon That is the next workflow on its way soon.
@brnfd24434343d v1.2 uploaded with keyframes
Awesome work. I know the seed keeps audio consistency. Is it possible to use the other minimax ref model and include audio samples or include audio from video (so you can pipe in a video file you like) and keep the same voice?
@JustTrying2026 I am working on another workflow that uses the R2V models that should fix this issue. The audio consistency seems to be model-related. You will see a widget in the Generate node in the current workflow to keep the same seed or vary it, which was my attempt to get it to be consistent - and sometimes it works, if you also describe the voice word for word in every shot, but it's still not great. New workflow should be up today though.
@joeygambino Waiting for the ref to video update! just tested a 1 minute video with text to video and its awesome, cant imagine the increased consistency with ref to video!
@Psi_Clone Working on it as we speak!
@joeygambino i got some stuff going if you wanna take a look https://github.com/Shrek3OnVH5/MiniMax-H3-NativeAudio-MusicVideo-Workflow/commit/11a95f6 , optimizations letting me do 1.0mp at 20 steps within <15 minutes per 10 seconds (5070ti 32gb) , ref2vid, audio lock, combinations, gguf support
@PrettyAIGirls I will check it out!
@joeygambino Unfortunately, the new hard mode doesn't chain prompts similar to how this one does. I was hoping it would chain prompts and also follow the reference properly in the new chains, but none the less, really amazing extending the input image capaibility.
A great WF and Node
Thank you!
Thanks! i was making my own nodes (with zero knowledge of what i was doing) but these ones are already enough for me, thanks again, i'll be publishing videos attaching this workflow :)
Awesome, thanks!
aquí tu alumno maestro voy a probar este wf, gracias a creador
Amazing work! Any chance of maybe an alternate version of the node or an alternate input that accepts a batch of images?
EDIT: I made a pull request adding this as an option, take a look on your repo if you're interested :)
For complex motion it's nice to have a few frames at the start and end for consistency in motion, but then the number of frames starts adding up quickly and it's easy to pass 6. Also it's handy if you have a video source and want to specify a set of frames to keep from the original.
On it, and thank you for the tip! I'll be working on this today as well.
@joeygambino Excellent! I appreciate your work. I also made a pull request to make working with the index ranges a little easier and to change the fractions to percentages (I got caught by frame 1 being the end of the video when I was working with absolute indices haha). Now if I could just figure out how to get MiniMax to exactly inpaint audio into the edited regions I'd have all the tools I need XD
Interesting, but I don't see the point of using quantized models; my workflow already has a 15GB text encoder and the int8 convrot that is 20GB.
Without knowing which workflow, models and hardware you're running, it's difficult to respond to this.
@joeygambino quote: "The text encoder is evicted before sampling. The Qwen3-VL encoder (~16.5 GB even at Q4) and the H3 DiT (~25 GB) do not co-fit on a 32 GB card, so the DiT was loading partially and streaming ~19 GB from system RAM on every sampling step. " Question- Only gguf text encoders can be evicted per this WF logic?
@blhll No, it's not GGUF-specific - the eviction has nothing to do with the file format. It matches on the CLIP object's ModelPatcher and calls model_unload() on it. Every ComfyUI CLIP carries one no matter how it was loaded, so a safetensors encoder is freed by exactly the same call. The reason it comes up mostly with GGUF is just that GGUF is what people are running at these sizes; the loader node in the pack takes both formats and neither is treated differently.
One thing worth knowing, since it's the failure mode that actually bites: if the node cannot match your CLIP against the loaded models, it falls back to unloading everything. That's still safe where it sits - conditioning is fully computed by then, and the VAE reloads on demand after sampling - but it's blunter than intended. It tells you which path it took in the console:
[H3FreeTE] unloaded 1 model(s); 4.2 -> 21.8 GB free <- targeted, ideal
[H3FreeTE] unloaded all models; 4.2 -> 22.1 GB free <- fallback fired
So, if the encoder does not seem to be getting freed, that line is the thing to check rather than the file format. Worth adding, because the quoted numbers are from a 32 GB card: whether you need the node at all depends on whether the encoder happens to already be unloaded when sampling starts. In a long session where earlier nodes have freed it, you may
never notice the problem. Fresh start, encoder resident, big DiT - that's when the streaming shows up. The tell is power draw rather than utilization: a card shuffling weights sits near 100% "utilization" while pulling a fraction of its rated watts.
@joeygambino yeah , I am using 24GB VRAM, plus 128 GB RAM, so using MiniMAx puts shared memory constantly at ~80% plus ofc main VRAM at 100%, thats why I am asking, if offloading text encoder will help with this :)
@blhll Oh, absolutely. I have some new fl2va and ref2va GGUFs going up later today that should help with headroom there as well. 11GB Q4_0, 14GB Q5_1, and a Q8_0 at only 20GB - so even the Q8 should leave you with a little space for VAEs and activations.
Super helpful workflow. One issue I'm having is that in my experience it seems to forget what the audio was doing in the previous segments. If I prompt for "energetic pop-rock music" it still generates that in each segment, but it's like a completely different song in each one. Also the voices have no consistency between segments. Is there a way to mitigate this?
I have a workflow in the works right now that will use the H3 rev2v models, that hopefully should help with audio consistency. I expect to have it up sometime today after a whole lot of testing.
@joeygambino Awesome, I'll be excited to try it. Your workflow works great otherwise. The only other issue I had is that there's a little bit of a "hitch" where the segments are joined but it's not a huge deal. Is there a way to avoid that? I'm using the AIO version.
@Underbash I will look at the hitch, I honestly thought I got it as smooth as possible, but the last few days I've only been working on models and demos and workflows and haven't had much time to actually generate any real renders for myself yet - but I'll check it out and see if I can get it even smoother!
@joeygambino Nice, thanks. It's not too bad, but I did notice it when there was a lot of motion going on between the transitions. Maybe that made it more noticeable, idk. Good work though!
