MiniMax-H3 Reference Caption
Turn an image, clip or sound into a reference_assets line
- image
- audio
- video
- clip
- options
- reference_assets
- caption
Every guide-based writer in this pack is text-only. For I2VA, FL2VA, L2VA and Ref2VA you need words describing your reference frames and sounds, and this is the node that writes them: connect an image, an audio clip or a video, and a small multimodal model describes it into one labeled line of reference_assets.
The numbers sell it. On a 3.4 GB Qwen2.5-Omni-3B: 3 seconds for a frame, 2 for an audio clip, 5 for a video. That's the "this is cheap enough to be a routine part of the workflow" range, not the "go make a coffee" range. It runs through the same llama.cpp binaries the rest of the pack fetches, so a machine that has run one rewrite has the runtime already - there is literally nothing to install for this node.
How it works
The role you pick sets both the label and the question the model is asked. They differ on purpose:
Subject- the features that must stay consistent across shots: build, hair, clothing and their colors, carried objects.Picture- the frame as a shot: style, shot size, camera angle, placement, environment, lighting.Video- subjects, actions in order, camera movement, cuts and pacing.Audio- the sound, not the words. The instruction says outright "do not transcribe." A voice-timbre reference needs the timbre - age, delivery, rate - not a transcript. If you also want spoken words verbatim for a<d>block, that's an ASR job (run Whisper alongside) and paste the line in.
Outputs are reference_assets (the labeled line, ready for a writer's reference_assets input or the next caption node's previous) and caption (just the description text).
Inputs to know
role,model,length,seed- required.modeldefaults to Qwen2.5-Omni-3B; the 7B writes better prose if the 3B's captions feel flat.image/audio/video- connect one. An IMAGE batch is sampled tomax_frames(8 by default), spread evenly.description- type it yourself and no model runs at all. Six words is faster than loading a model, so this is the fastest path in the whole node.instruction- override the role's question entirely, if you want to ask something specific.previous- chain nodes by wiring one caption'sreference_assetsinto the next one'sprevious. Each label is numbered within its own category, which is the guide's rule: four assets come out asPicture 1,Picture 2,Video 1,Audio 1- not 1 through 4.context_size- 0 sizes the context from the references and your card. This matters more than it looks: llama.cpp reserves the whole KV cache up front, and a model trained for 256k context will ask for tens of GB of it before looking at a pixel. Type a number to say it yourself; too small a value fails the run outright rather than truncating.
Install
Same pack, same two lines:
cd ComfyUI/custom_nodes
git clone https://github.com/pytraveler/MiniMax-H3-Prompt-Rewriter-ComfyUI
(Or ComfyUI Manager → search "MiniMax-H3".) First run fetches the model and its mmproj.
Where people get burned
- Not every multimodal GGUF works here. llama.cpp's
mtmdhas to understand the projector format, and some current models abort while loading it (Gemma 4's does, outright, with Google's own file and unsloth's alike). Themodellist only holds pairs that have actually been run - a model and itsmmprojsitting together inmodels/LLMgets offered automatically, so you can try another without editing anything. Ones that don't work fail loudly, not silently. clipis the power move. Connect a multimodal text encoder fromCLIPLoader(Qwen3-VL or Gemma-4) and the asset is described by that model instead of the GGUF - which stays loaded between runs, so a shot full of references costs one load instead of one per asset. Only Gemma-4 E2B/E4B/12B can hear audio; wire audio into a vision-only encoder and the node refuses before running.- The Audio role doesn't transcribe. If you expected words back, that's not a bug. It's the difference between a timbre reference and a script.
Inputs (15)
| Name | Type | Default | Description |
|---|---|---|---|
| role | COMBO | Picture | Subject: a person, object or place to reuse. Picture: this frame is a concrete first/last/key frame. Video: a clip whose structure or content is reused. Audio: a sound or voice reference. The role picks both the label and what the model is asked for. |
| model | COMBO | A multimodal GGUF and its projector. Entries prefixed 'on disk:' are pairs already in your ComfyUI model folders. Not every multimodal GGUF works: llama.cpp's mtmd has to understand the projector, and some current models abort while loading it. Ignored entirely while 'clip' is connected. | |
| length | COMBO | standard | How much the model is asked to write. |
| seed | INT | 420–4294967295 | — |
| imageopt | IMAGE | A frame, or a batch of frames from a clip. | |
| audioopt | AUDIO | — | |
| videoopt | VIDEO | — | |
| clipopt | CLIP | A multimodal text encoder loaded by 'CLIPLoader' — Qwen3-VL or Gemma-4. Connect it and this asset is described by that model instead of by 'model', which stays loaded between runs rather than being read off disk each time. Only Gemma-4 E2B, E4B and 12B can hear audio. Leave it unconnected and nothing changes. | |
| previousopt | STRING | reference_assets from the previous caption node in the chain. | |
| descriptionopt | STRING | Type the description yourself and no model is run at all — the fastest way to add an asset you can describe in a few words. | |
| instructionopt | STRING | Override what the model is asked. Empty uses the role's own question. | |
| max_framesopt | INT | 81–64 | How many frames to take from an IMAGE batch, spread evenly. All of them would overflow the context and the wall clock. |
| context_sizeopt | INT | 00–131072 | 0 sizes the context from the references and the card: llama.cpp reserves the whole KV cache up front, and a model trained for 256k would ask for tens of GB of it before looking at anything. Set a number to say it yourself; too small a value fails the run outright rather than truncating. |
| optionsopt | H3_REWRITER_OPTIONS | — | |
| bypassopt | BOOLEAN | false | Pass 'previous' through unchanged and run no model at all, which drops this asset from the chain without unwiring it. Numbering stays correct: each node numbers what it receives, so the assets after this one close the gap. 'caption' comes back empty. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| reference_assets | STRING | — |
| caption | STRING | — |