MiniMax-H3 Universal Rewriter
Both H3 LoRA rewriters in one node — one tab is all it takes to switch
- duration
- options
- first_frame
- last_frame
- reference_video
- reference_audio
- aspect_ratio
- rewritten_prompt
- integrated_multimodal_description
- overall_soundscape
- non_diegetic_music
- subject_definitions
- summary
- retention_analysis
- detailed_description
This pack ships two LoRA rewriters, and they are not two settings of one thing. The 27B is text: Qwen3.6-27B, one task, and a reference frame reaches it only as a sentence somebody wrote. The 8B is multimodal: Qwen3-VL-8B, four tasks, and the picture itself. Different base, different size, different download - which is exactly why choosing between them by hand is tedious. The prompt is the same prompt, the aspect ratio is the same ratio, the duration is the same duration; trying the other adapter used to mean retyping all of it into a second node and keeping the two in step. This node puts a tab at the top where a click swaps the adapter and everything else stays where it is.
The two original nodes (Prompt Rewriter and Prompt Rewriter 8B) are unchanged and still there. Nothing you've already built stops working; this is the "trying both" node.
What the tab carries, and what it doesn't
The design is ruthlessly minimal: the tab holds only what differs between the adapters.
- Belongs to the tab:
model_27b/model_8b,quantization_27b/quantization_8b. - Shared between them:
prompt,task,resolution,duration,greedy,seed,keep_model_loaded,bypass,options, and both frame inputs.
The widget the other tab uses is hidden, not reset - so it's still set to whatever you last chose when you switch back, even across a save and load.
Three things to know before you rely on it
The 27B tab is text-only, honestly displayed. On that tab the task strip shows T2VA lit with the three frame tasks greyed out, and clicking does nothing at all - the value the 8B tab had is still there when you switch back. Run the 27B tab with frames connected and the node tells you on itself that it's not reading them, and where to put them instead. There's deliberately no captioner on the 27B tab: folding a frame description into prompt does reach that adapter, and it's not wasted - the props and light in it turn up in the shots. But the picture gets absorbed into the scene rather than pinned to 0.00 seconds, which is exactly what the LoRA's own page says: T2VA is finished there and FL2VA is not. When the picture has to be a frame, the 8B tab is the one that was trained for it.
duration is 4–15 seconds and that's not a slider range you can raise. Both adapters were trained on it; a number outside it is a worse prompt, not a longer video. MiniMax-H3 gets the length from its own settings, not from this line.
It needs a recent ComfyUI. It's written against the v3 node API. On an older install it goes missing and the rest of the pack registers as before - and if the interface script doesn't load, the tab strip, task switch and ratio picker fall back to the plain dropdowns they're built on. The node runs exactly the same either way.
Inputs and outputs
Same outputs as both rewriters - rewritten_prompt, integrated_multimodal_description, overall_soundscape, non_diegetic_music - so it's interchangeable with either one downstream. Inputs you'll actually touch:
lora- the tab, as a widget:27B LoRAor8B LoRA.task- shared; on the 8B tab picks among T2VA/I2VA/FL2VA/L2VA.first_frame/last_frame- shared IMAGE inputs, each row with its own checkbox. A switched-off row counts as unplugged - that's how you park a picture without dragging the wire off. On the 27B tab they're unread, as above.keep_model_loaded- honoured on every route except one: a GGUF 8B base running a frame task goes throughllama-mtmd-cli, and the model leaves with the subprocess.
Install
Same pack, same story - ComfyUI Manager (search "MiniMax-H3") or:
cd ComfyUI/custom_nodes
git clone https://github.com/pytraveler/MiniMax-H3-Prompt-Rewriter-ComfyUI
Weights are fetched on first use per tab. If you're weighing which adapter to actually run: the 27B is the better writer and the 8B is a third of the download with real frame tasks - this node exists so you don't have to commit before you've tried both.
Inputs (24)
| Name | Type | Default | Description |
|---|---|---|---|
| lora | COMBO | 27B LoRA | Which prompt-rewriter LoRA runs. '27B LoRA' is lightx2v's original on Qwen3.6-27B: text in, T2VA out, about 16 GB of VRAM at nf4 and the strongest writer of the three. '8B LoRA' is the multimodal one on Qwen3-VL-8B: it reads the frames itself and writes the alignment line from what it sees, at about a third of the download. 'Omni LoRA' is the third, on Qwen2.5-Omni-7B: it reads the frames too, and it is the one that also hears -- though the sound, the clips and the six-field Ref2AV task are on the Prompt Rewriter Omni node, not here. Switching keeps everything but the base model and its quantization. |
| task | COMBO | T2VA | T2VA: text alone, no frames. I2VA: 'first_frame' is the first frame. FL2VA: both frames. L2VA: 'last_frame' is the final frame. Ref2VA: everything connected is a reference the target video reuses, written with the six-field full-reference prompt -- Omni tab only, being the one adapter trained on it. The 27B tab writes T2VA whatever this says, and leaves it alone, so it is still here when you switch back. |
| resolution | COMBO | 16:9 | Target aspect ratio the rewrite is composed for. It has no socket on purpose: a ratio arriving from the graph belongs on 'aspect_ratio', which reads the spellings other nodes use and overrides this while it is connected. |
| duration | FLOAT,INT | 100.1–600 | Target clip length in seconds; drives shot count and pacing. Both adapters were trained on clips of a few seconds, so a number far past that is a worse prompt rather than a longer video -- MiniMax-H3 gets the length from its own settings, not from this line. Right-click the node for 'duration': the default value back, or a new upper end for the widget. It offers 30 seconds until you change it and the server takes up to 600, because a widget's range is fixed when the node is declared and one number cannot suit every graph -- MiniMax's own guide is written around clips of a few seconds, while the stretched pipelines the community has built run well past that. What you set is remembered with the workflow. |
| prompt | STRING | The short prompt to expand into an H3 audio-video description. | |
| model_27b | COMBO | Base model for the 27B adapter. Entries prefixed 'on disk:' are already downloaded; the rest are fetched on first use. GGUF entries need no extra install: without llama-cpp-python the node fetches the official llama.cpp binaries. Belongs to this tab, so the 8B tab keeps its own. | |
| model_8b | COMBO | Base model for the 8B adapter -- a Qwen3-VL-8B, either as a GGUF pair (the model and its projector, from one conversion) or as the official safetensors folder the adapter was trained on. Only the 8B fits this LoRA; another size is refused by name and number before anything is downloaded. Belongs to this tab. | |
| quantization_27b | COMBO | nf4 | How to load an unquantized 27B checkpoint: nf4 needs about 16 GB of VRAM, int8 about 28, bfloat16 about 54. Ignored for GGUF models and for checkpoints that are already quantized. Belongs to this tab. |
| quantization_8b | COMBO | nf4 | How to load an unquantized 8B checkpoint: nf4 needs about 8 GB of VRAM, int8 about 13, bfloat16 about 20. Ignored for GGUF models and for checkpoints that are already quantized. Belongs to this tab. |
| greedy | BOOLEAN | true | Deterministic decoding. Turn off to sample; see the options node. |
| seed | INT | 420–4294967295 | — |
| keep_model_loaded | BOOLEAN | false | Keep the model in VRAM after the rewrite. Honoured on every route except one: a GGUF 8B or Omni base running a task with frames goes through llama-mtmd-cli, and the model leaves with the subprocess. Leave it off when the same GPU has to run MiniMax-H3 video generation afterwards. |
| optionsopt | H3_REWRITER_OPTIONS | — | |
| first_frameopt | IMAGE | The exact first frame, for I2VA and FL2VA. The model looks at it and anchors the opening shot to what is actually in the picture. Unread on the 27B tab, which takes text alone: describe it with the caption node and put that in 'prompt' if you want it there. | |
| last_frameopt | IMAGE | The exact final frame, for L2VA and FL2VA. Connect this one rather than 'first_frame' for L2VA -- which end of the clip a picture belongs to is what the model is told. Unread on the 27B tab, which takes text alone: describe it with the caption node and put that in 'prompt' if you want it there. | |
| frame_switchesopt | STRING | {} | Which frame rows are switched off, as JSON, written by the checkboxes on the input rows. It is kept as a widget so the state travels with the workflow and through the API; the interface hides it. A row missing from the map is on. A switched-off frame counts as unplugged, which is how you park a picture without dragging the wire off. |
| bypassopt | BOOLEAN | false | Hand 'prompt' straight to the output and run no model at all: nothing is downloaded, nothing is loaded, no VRAM is touched. This is what ComfyUI's own bypass (Ctrl+B) cannot do here - it only forwards a connected link, and every input this node writes from is a widget, so bypassing the node the usual way leaves the nodes downstream with nothing. The section outputs come back empty. |
| model_omniopt | COMBO | Base model for the Omni adapter -- a Qwen2.5-Omni-7B, either as a GGUF pair (the model and its projector) or as the official safetensors folder. Its projector carries an audio encoder as well as a vision one; a Qwen2.5-VL of the same size looks identical by the numbers and is marked 'vision only' in the list, because the adapter would attach to it and then write about sound it never heard. Belongs to this tab. | |
| quantization_omniopt | COMBO | nf4 | How to load an unquantized Qwen2.5-Omni-7B: nf4 needs about 9 GB of VRAM, int8 about 12, bfloat16 about 20. bitsandbytes buys VRAM here, not speed: measured on this adapter, int8 generates at about a third of bfloat16's rate and nf4 at four fifths, because both dequantize on every matmul. Pick the largest your card holds. Ignored for GGUF models and for checkpoints that are already quantized. Belongs to this tab. |
| reference_videoopt | VIDEO | A clip the target video reuses, for Ref2VA on the Omni tab. Sampled into frames and shown to the model as <Video 1>. Read by nothing else: the 27B and 8B adapters were never trained on a clip, and the four frame tasks take pictures alone. | |
| reference_audioopt | AUDIO | A sound the target video reuses, for Ref2VA on the Omni tab, shown to the model as <Audio 1>. This is the one input in the pack that reaches a rewriter as sound rather than as a sentence about it, and only the Omni adapter can hear it. | |
| aspect_ratioopt | STRING,COMBO | Optional, and it overrides the picker while something is connected. Reads a ratio ('16:9'), a frame size ('3840x1080') or a bare number ('1.78'), and a label around the pair is fine -- '3:4 (Portrait Standard)' reads as 3:4. A size within 2% of a listed ratio is called by its name, so 1376x768 arrives as 16:9 rather than as 43:24. | |
| repeat_lastopt | BOOLEAN | false | Hand back a prompt this node already has instead of running the model again. By default that is the node's own last answer: with nothing kept yet it runs once, keeps what it wrote and says so, and from then on returns that same text for as long as the switch is on, whatever else you change. Pick something in the library window and this switch hands that saved prompt on instead -- the window chooses which prompt, this switch is what makes it happen. Off is always a real run. The session store is in memory only, one answer per node: it is not saved with the workflow and does not survive a restart, while a saved prompt does both. 'bypass' still wins over all of it. |
| library_pickopt | STRING | Which saved prompt this node hands on instead of writing one, as JSON written by the library window. It is a widget so the choice is saved with the workflow and reaches an API run: a pick the graph does not carry is a graph that reproduces something else. It applies only while 'repeat_last' is on. That switch is what hands a kept prompt on at all; this says which one, and empty means the node's own last answer. |
Outputs (8)
| Name | Type | Description |
|---|---|---|
| rewritten_prompt | STRING | — |
| integrated_multimodal_description | STRING | — |
| overall_soundscape | STRING | — |
| non_diegetic_music | STRING | — |
| subject_definitions | STRING | — |
| summary | STRING | — |
| retention_analysis | STRING | — |
| detailed_description | STRING | — |