--- license: apache-2.0 tags: - comfyui - minimax-h3 - video-generation - text-to-video - workflow - audio-video pipeline_tag: text-to-video --- # MiniMax-H3 Seamless Chain A ComfyUI node pack and two workflows that render a multi-shot MiniMax-H3 scene as **one continuous take**: no visible cut at the shot boundaries, no colour shift between shots, and continuous audio across the whole piece. MiniMax-H3 natively generates blocks of roughly 10-15 seconds. This pack chains those blocks into arbitrarily long scenes and hands back a single master video with a single master audio track. Released as **v2.7.0** of the ComfyUI-H3-Multishot pack. ## v2.7.0 - per-subject voices, flf_chain fixed, chain leveller, ComfyUI 0.34 - **Per-subject voice refs** (`voice_ref_2` / `voice_ref_3`, both samplers): each character keeps their own voice across a chained scene - verified blind across a full chain, no cross-speaker bleed. - **flf_chain fix:** the memory bank stood in flf chains and pinned a clip of shot 1 (which opens on boundary plate 0) into every later shot as an unbound reference - PLATE0 bled back in from shot 2 onward. The bank now stands down automatically in flf_chain; plates alone carry the continuity there. - **H3ChainNormalize:** post-chain texture + colour leveller - the 2.6.0 long-take ratchet limit is addressed. - **refresh_pin splice alignment**, **x0 clamp dial** (`x0_clamp_window`, dose cap 0.30), in-loop latent upscale + `refresh_renoise` + `pin_noise_ramp` + `auto_chunk_ffn`. - **ComfyUI 0.34 supported:** native interior keyframe anchors detected; the pack's layout patch stands down automatically on 0.34, unchanged on older cores. - **Engine-aware writer:** separate H3 (`[English] ...`) and LTX (quoted dialogue) system prompts for every mode via an appended `engine` widget. ## v2.6.0 adds the extend take: one prompt, one continuous speech, as long as you want Set **`take_seconds`** on MASTER CONTROLS (or open `H3_Extend_Take`, now the main workflow, shipped at 1280x736 with a 30-second take) and give the writer one premise. The panel sizes a window for your card and the number of windows that fills the time; the writer's new **extend take** join style writes ONE continuous speech and cuts it across the windows at sentence boundaries; the chain continues it under `context_pin` in H3's own voice — no TTS, no airlock, no per-shot dialogue budgeting. Verified before shipping: seven writer-driven renders including a 65-second, 7-window take, every join continued the speech, reviewed blind as one uninterrupted take. Also in 2.6.0: reference photographs now win over the writer's prose (the writer points at the photos instead of describing a face - same-seed measured), auto refs reach the sampler on their own (a second gate downstream used to discard them silently), three reserve-planning fixes from the 24 GB test lab and a writer fix for silent shots echoing the voice anchor. Full notes in the changelog below. **Known limit (2.6.0):** the chain's texture ratchet is not fully solved for long takes - measured about +13% fine texture per join at 736x1280 with the anti-drift set on. Under ~4 windows (~30-40 s) it is slight; at 7 windows it is visible sharpening. Keep extend takes to ~4 windows for now; a pin-side fix is in progress for 2.6.1. ## v2.5 is the memory release Four new memory systems, all measured, two of them fully automatic: - **The driver-headroom rule (automatic).** High-resolution renders used to take anywhere from 27 minutes to 3 hours for identical work — a lottery caused by the Windows driver demoting GPU memory when the card fills past roughly 95%. The pack now detects that zone and deliberately streams a few GB of weights instead of riding the ceiling. The lottery render became 15 minutes, every time. Nothing to configure. - **`low_ram_master`.** Long chains used to hold every finished shot in system RAM until the final join — tens of GB at the very last step. Switch it on and shots stream to lossless disk staging as they finish; peak RAM becomes about two shots regardless of chain length, with verified-identical output (42.8 dB against the RAM path — codec noise). - **Remote text encoder.** The text encoder runs for seconds per shot and holds 15+ GB the rest of the time. Point the new node at any second PC running ComfyUI with this pack and that memory leaves your render card — identical results, verified across machines, with a local cache so repeated text never touches the network. One flag on the switches panel turns it on; it ships off. - **`H3 TAE Decode`.** 2-second full-resolution draft previews from a 9 MB tiny decoder, versus about a minute per shot through the real VAE. For seed hunts and batch triage, never finals. Plus a Speed Boosters panel (Spectrum, TeaCache, block cache, EasyCache — each measured and eye-tested, with honest notes about which distort people), and new defaults tuned for 16-24 GB cards. Details in the changelog below. ## What this repository contains - `ComfyUI-H3-Multishot/` - the ComfyUI custom-node pack (samplers, loaders, studio controls, LoRA stack, GGUF architecture patch). - `workflows/` - three ready-to-load ComfyUI graphs: - `H3_Seamless_Chain_v2.json` - the full workflow: master controls, LLM prompt writer, speed boosters, remote encoder lane, anchors. - `H3_Seamless_Chain_CORE.json` - the same chain with **zero third-party dependencies**. - `H3_Keyframes.json` - a single clip with anchors at chosen frame positions. - `INSTALL.md`, `SETTINGS.md`, `PROMPTING.md` - install steps, the full settings reference, and the boundary/prompt rules. ## What this repository does not contain **No model weights.** Nothing here is a checkpoint, a text encoder, a VAE or a LoRA. Download the weights separately: | Component | Where | |---|---| | MiniMax-H3 checkpoint (`ref2va` shipped, `fl2va` also chains), GGUF quants | [joeygambino/MiniMax-H3-GGUF](https://huggingface.co/joeygambino/MiniMax-H3-GGUF) | | Text encoder, video VAE, audio VAE | [Comfy-Org/MiniMax-H3](https://huggingface.co/Comfy-Org/MiniMax-H3) | GGUF sizing guide from the quant repo: `Q8_0` for 32 GB cards, `Q5_1` for 24-32 GB, `Q4_0` for 16 GB. The `curve` variants are pruned-form requants. The `ref2va` checkpoint is only needed for the reference/bank workflows. It is **not** required for seamless chaining. ### Nodes added in 2.1 | Node | What it does | |---|---| | `RiftPromptSource` | One dropdown over LPFF-style `.txt` briefs and passthrough `.json` scripts. Emits `story_idea` / `character` / `count`. Reads `input/rift_prompts/`, and still reads the older `input/joyecho_prompts/` so existing folders keep working. | | `RiftScriptPicker` | JSON script dropdown, and the speaker/voice stash `RiftPromptSource` feeds. | | *(not a node)* `unload_model_after` | A switch **added to the LLM prompt writer** (`JoyEcho_LLMEnhance`). On, the writer frees its own model from Ollama once the script is written, so the video model gets the card. Uses the writer's existing `base_url` and `model_name` — nothing to keep in sync. Added in memory at startup by this pack, so the writer's own package is not modified; the switch simply appears on the node. Off by default. Ollama's OpenAI-compatible endpoint has no `keep_alive` field and its shim never sets one, so without this the model sits for the server default of five minutes — your whole first shot. | `JoyEcho_PromptSource` and `JoyEcho_ScriptPicker` still resolve as deprecated aliases, so graphs saved against 2.0 open unchanged. They were never published under those names — that was the 2.0 bug. ### The prompt writer needs a model you actually have The full workflow points at a local Ollama with `model_name = qwen3:14b`. **Pull it before the first queue** or the run stops with `LLM API error 404: model 'qwen3:14b' not found`: ``` ollama pull qwen3:14b ``` Any OpenAI-compatible endpoint works — its URL in `base_url`, its exact tag in `model_name` (`ollama list` prints the tags you have). A remote endpoint is often better: a local writer large enough to be good competes with H3 for the same card and on under 32 GB will evict the model mid-render. When you do run local, turn on `unload_model_after` on the writer — it frees the model as soon as the script is written. No LLM at all? Set `use_file_prompts` to manual entry, delete the writer, and feed your own `---`-separated shot script into the sampler's `script` input. The CORE workflow already works this way. **Try a render with every switch off and the reserve at `0` before touching any of this.** The activation reserve measures each shape and conditioning payload as it renders and sizes the pool itself, and it holds on 24 GB cards as well as 32 GB. A hand-set reserve *overrides* that measurement. These switches are for digging out of a spill the console has already named. ## Requirements Always required: - **ComfyUI v0.30.0 or newer** (native MiniMax-H3 support). The **CORE** workflow needs nothing else. It uses only this pack plus ComfyUI built-ins (`LoadImage`, `LoadAudio`, `SaveVideo`, `SaveAudio`, `CreateVideo`, `VAELoader`, `PrimitiveFloat`, `Note`). The **FULL** workflow additionally uses: | Pack | Needed for | |---|---| | ComfyUI_JoyAI_Echo_GGUF_Nodes | the LLM prompt writer — **ships in the release zip**, modified with attribution; use that copy, not upstream | | [ComfyUI-H3-Motion-Context](https://github.com/NikoDemon80/ComfyUI-H3-Motion-Context) | `continuity=context_pin`, the shipped default | | [RES4LYF](https://github.com/ClownsharkBatwing/RES4LYF) | the `beta57` scheduler the full workflow ships with | | ComfyUI-sol-attn + comfyui-minimax-h3-blockcache-T8 | the VRAM/SPEED patch switches | | [ComfyUI-Custom-Scripts](https://github.com/pythongosssss/ComfyUI-Custom-Scripts) | the on-canvas script preview | ComfyUI validates **every** node class in a graph before it will queue, so a missing pack stops the whole workflow — even for switches that ship OFF. Each pack can be removed instead (one-widget change or node deletion, documented in `INSTALL.md`); e.g. no RES4LYF → `scheduler=beta` (measured cost: lip-sync 8/10 vs 10/10, all else equal), no Motion-Context → `continuity=first_frame`. GGUF users also need [ComfyUI-GGUF](https://github.com/city96/ComfyUI-GGUF), then run `apply_gguf_arch_patch.py` once to teach it the `minimax_h3` architecture. ## Install 1. Search **H3 Multishot** in ComfyUI-Manager and install it - the pack is on the Comfy Registry as `comfyui-h3-multishot`. You can also copy `ComfyUI-H3-Multishot/` into `ComfyUI/custom_nodes/` by hand, or use Manager's Install via Git URL with `https://github.com/jlucasmcrell/ComfyUI-H3-Multishot`. The Registry carries the node pack only; the LLM prompt writer the full workflow uses ships in this repo under `nodes/`. 2. Place the MiniMax-H3 checkpoint, text encoder and VAEs in the usual ComfyUI model folders. 3. Restart ComfyUI. 4. Load `workflows/H3_Seamless_Chain_CORE.json` (no extra packs) or `workflows/H3_Seamless_Chain_v2.json` (full). 5. GGUF only: install ComfyUI-GGUF and run `apply_gguf_arch_patch.py` once. Full detail is in `INSTALL.md`. ## Usage 1. Open a Seamless Chain workflow. 2. Set the **MASTER CONTROLS** panel (`H3StudioControls`): resolution, frames per shot, steps. One node drives both the sampler and the prompt writer's dialogue pacing, so the writer knows how much dialogue fits a shot. 3. Write your script into the sampler: **one prompt per shot, `---` between shots**. JSON of the form `{"prompts": [...]}` is also accepted. In the FULL workflow you can instead let the LLM lane write the shots for you. 4. Leave `continuity` on the shipped default and hit Queue. 5. The master video lands in `output/video/H3CHAIN/` with a paired audio file. `preview_first_shot` is ON by default so you can judge shot 1 before paying for the whole chain. ### Shipped defaults | Setting | Default | |---|---| | Resolution | 736x1280 portrait (the model distorts faces below ~1 MP) | | Frames per shot | 192 (8 s at 24 fps) | | Steps | 14 | | Sampler / scheduler | `euler` / `beta57` (full; RES4LYF) — CORE ships stock `beta` | | Continuity | `context_pin` | | Checkpoint | `ref2va` `curve-Q5_1` GGUF (~14 GB) — `fl2va` also chains, see below | | Anti-drift | `chain_gain_control=flatten`, `master_normalize=luma+contrast`, `pin_renorm` ON, `memory_frames` 0 | | Bank | OFF | | Speed boosters | all OFF. Spectrum/TeaCache/EasyCache are real speed (-14 to -29%) but can distort people; block cache is inert at 14 steps (0 hits measured) | | `low_ram_master` | OFF — turn ON for long chains or under 32 GB system RAM | | `preview_first_shot` | ON | | Mux | 24 fps | | Output | `output/video/H3CHAIN/` + paired audio | These defaults target a 16-24 GB card at the best speed/quality mix. Every booster except block cache changes what people look like — leave them off unless you have compared for yourself. ## How the chaining works Two mechanisms ship in the pack. Both produce a single master; they differ in what crosses the boundary. ### 1. `first_frame` chain - `H3MultishotSampler` Each shot's **last frame** is handed to the next shot as its **first frame**, through `fl2va`'s trained continuation task. That is the model doing what it was trained to do, not a hand-rolled trick. The duplicated boundary frame is trimmed, and the seam audio gets a 40 ms equal-power weld so the join does not click. No third-party dependency. This is what the CORE workflow uses. ### 2. `context_pin` - `H3MultishotMemorySampler`, `continuity=context_pin` The previous shot's **last 22 frames ride into the next shot as raw latents** - bit-identical, with no VAE round trip - placed at interior keyframe coordinates, alongside a timeline-placed audio reference. The model regenerates that overlap as its own head; the regenerated 0.92 s is trimmed on decode, so what survives is the original tail followed by continuous new material. Requires the third-party ComfyUI-H3-Motion-Context pack. As of v2.1.1 the two packs coexist cleanly — this pack's payload wrapper declares Motion-Context's compatibility marker, so load order does not matter. `seamless` and `seamless_tail` are legacy comparison modes: `seamless` is a soft latent-only pin that often reads as a cut, and `seamless_tail` conflicts with Motion-Context and stops up front, before sampling, when that pack is installed. ### Why identity holds with no reference images Two mechanisms stack: 1. **The frame relay.** Every shot after the first begins from an actual rendered picture of the character. Faces and wardrobe propagate as *pixels*, not as a re-imagining from text. 2. **Byte-identical text.** The prompt writer repeats each character's appearance block **verbatim** in every shot. The frame pins the specific instance; the repeated text pins the category so the model cannot drift the description out from under the pixels. This was verified on a 40-second two-character scene with **zero reference images supplied**. ## Settings reference `SETTINGS.md` in the release carries the complete list. The dials that matter most: | Dial | Notes | |---|---| | `shot_count` | `0` = one shot per prompt in the script. | | `seed_per_shot` | **Leave ON.** Measured: per-shot seeds hold the face; a single seed shared across all shots drifted both face and voice. | | `continuity` | `first_frame` or `context_pin` (see above). | | `chain_gain_control` | Set to `flatten` on chains past roughly 5 shots. Texture ratchets about 1.3x per join otherwise, so late shots come out visibly over-sharpened. | | `color_level` | `off` / `mvgd` / `scene`. Levels each shot's colour and exposure statistics to shot 1's settled tail (a fixed reference - matching neighbour-to-neighbour re-accumulates drift). Usually unnecessary; for long chains that drift warm or cool. | | `self_anchor_voice`, `voice_ref` | Voice identity across the chain (the v1.5 headline feature). | | `output_scale` | Lanczos resize of each shot AFTER decode - resolution, not detail. Works with every continuity mode including `context_pin`; applied per shot and after the bank takes its clip, so conditioning and VRAM are unchanged. Measured 1.78x faster than native for the same output size, and visibly softer. | | `upscale_model` | Optional `UPSCALE_MODEL` link (ESRGAN and friends via ComfyUI's own loader). Synthesizes detail rather than resizing. Its invented texture never reaches the memory bank, so it cannot feed the sharpening ratchet. | | `reference_image_size` | `match` or `max`. | | `preview_first_shot` | Renders shot 1 alone first so you can abort early. | ### MASTER CONTROLS (`H3StudioControls`) One node sets resolution, frames per shot and steps for **both** the sampler and the prompt writer, so the writer's dialogue budget always matches the shot length actually being rendered. ### VRAM/SPEED panel (`H3StudioSwitches` + reserve control) Three lazily gated switches: memory-efficient attention, chunked feed-forward, and the remote text encoder (speed boosters have their own node). The gates are lazy, so a switch left OFF never executes its path - and all OFF is exactly the verified recipe. The panel keeps its 2.5.x eight output slots so saved graphs keep working; the removed ones always emit False. The activation-reserve heuristic decides how much VRAM to hold back. Its cache keys include a conditioning-**payload** signature (keyframes / audio refs / two-pass), so a bare shot 1 and a reference-laden shot 2 are measured separately instead of sharing one wrong number. Measured pools are no longer overridden by a fixed floor, the first run of a new payload variant estimates from a measured sibling, and a VRAM spill into system RAM is now detected and named in the console - previously it only showed up as an unexplained ~5x slowdown. ## Prompt and boundary rules These are render-verified. The FULL workflow's prompt writer applies them automatically through its `join_style` control, which appends them to the system prompt. **Hand-written scripts must follow them manually.** - **AIRLOCK.** Every shot after the first opens holding the previous shot's exact closing arrangement, and gives about **2 quiet seconds** before anyone speaks - a breath, a weight shift, real micro-motion, not a freeze. - **The first ~1 second of every chained shot is discarded replay.** Dialogue starting at frame 0 loses its opening syllables. - **LAND SETTLED.** End each shot back in a stable arrangement, dialogue finished, about 2 seconds spare. - **A spoken line never straddles two shots.** Budget: dialogue plus 4 seconds of quiet must fit inside the shot. 243 frames fits one long line; 124 does not. - **Repeat verbatim.** Each character's appearance description *and* the room/lighting description, word for word, in every shot. - **Keep fps at 24.** Other rates audibly shift voice accents. `PROMPTING.md` has worked examples. ## New in v2.6.0 - the extend take ### One prompt, one continuous speech, as long as you want Type a length into MASTER CONTROLS `take_seconds`. The panel picks the largest window whose activation pool fits with most of the weights resident on your card (`window = auto`; wire the loader's MODEL into the panel for a real weight size) and the count that fills the time; the writer's new **extend take** join style writes ONE speech and cuts it across the windows only at sentence boundaries; the memory sampler chains them under `context_pin`. H3 continues the speech across every join in its own voice. Verified: seven writer-driven renders at 141/192/243-frame windows plus a 65 s / 7-window take — every join continued, zero repeats, zero clipped words. `take_seconds = 0` is the old behaviour exactly. Also new: `audio_pin_frames` on the memory sampler (audio reference window independent of the picture pin; 96 = the JoyEcho 4 s audio memory; neutral at n=1, ships 0), the standalone `H3ExtendTake` node, the `H3_Extend_Take` workflow. ### Fixed: reserve planning (from the 24 GB test lab) The bare-to-payload x1.6 no longer fires between the two samplers' differently-named payload signatures; a first run at a new shape borrows measurements only from the same quant family (GGUF figures do not transfer to w4a8/int8 — a cross-family borrow under-reserved a first run into driver paging); the streamed master's metadata is the API graph again. ### Fixed: silent shots echoing the voice anchor A silent shot whose framing boilerplate said "visible lip movement clearly readable", with shot 1's voice riding along as `