---
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 `