MiniMax-H3 Universal Rewriter
Both H3 LoRA rewriters in one node — one tab is all it takes to switch
- options
- first_frame
- last_frame
- rewritten_prompt
- integrated_multimodal_description
- overall_soundscape
- non_diegetic_music
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 (17)
| 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 better writer of the two. '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. 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. Only the 8B LoRA was trained on the frame tasks, so 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. |
| duration | INT | 104–15 | Target clip length in seconds; drives shot count and pacing. The range is what both adapters were trained on, and a number outside it is a worse prompt rather than a longer video -- MiniMax-H3 gets the length from its own settings, not from this line. |
| 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 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. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| rewritten_prompt | STRING | — |
| integrated_multimodal_description | STRING | — |
| overall_soundscape | STRING | — |
| non_diegetic_music | STRING | — |