MMH3 Temporal Tile Editor
Where the H3 Chain Actually Gets Built
- ref_images
- ref_video_input
- audio_bgm
- fun_control_video
- fun_control_mask
- fun_control_source_video
- temporal_tile_config
- segments_info
- ref_image_slots
- control_image_slots
MMH3 Temporal Extend Video does the sampling, but you don't configure a multi-segment H3 clip by clicking sockets on it. You do it here - in a dock panel that opens off this node, where each segment gets its own prompt, seed, references and duration, and the whole thing is serialized into a config the Extend node reads.
It's a pure-information node, and that's worth internalising. It loads no images and encodes nothing. Any audio you wire into it is forwarded verbatim to the Extend node, which owns the audio VAE. Think of it as the plan; the Extend node is the execution.
What you set, per segment
Segment 0 is special: it starts a fresh generation, either FL2VA (first frame, optional last frame) or Ref2VA (reference images). It also fixes the chain's resolution - those width/height values get rounded to multiples of 32 and are locked for every later segment once a session has stored latents. Choose them before you commit to a long run.
Later segments continue the previous tail and have one continuation knob of their own: overlap frames, the length of the carried tail. Everything else about continuation - fade, anchors, blending - is global, set on one of the two overlap nodes. That split is deliberate and it's the thing to remember when tuning: per-segment length, chain-wide behaviour.
The rest of a segment row is what you'd expect: prompt and negative, a seed (there's a randomize-per-segment option), conditioning mode (Ref2VA, or FL2VA with only a last-frame keyframe - frame 0 belongs to the seam anchor), a reference source (manual, prev_frame to take a frame of the previous segment, or none), reference image sizing (match or max, aspect preserved), and an audio reference mode: none, load (a picked file), prev (the previous segment's soundtrack), initial (the first segment's), or bgm.
Durations are grid-bound and the panel says so: the first segment must be 17n+5 frames (5, 22, 39, 56, 73, 90, 107, 124 - 124 ≈ 5.2s is the default), and later segments generate a multiple of 17 new frames (102 ≈ 4.25s by default), because H3's VAE codes 17 pixel frames per 5 latent tokens. Do the arithmetic in the panel rather than in a separate node - the panel exposes both frames and seconds.
The sockets
The required widgets are show_editor, session_name, storage_location, base_prompt, base_negative and tile_data. Two of those deserve a word. base_prompt and base_negative are shared prefixes applied to every segment, which saves you repeating a style line six times. And tile_data is the JSON the dock panel owns - if you edit it by hand, expect the panel to rewrite or sanitize what you typed.
Optional inputs: ref_images, an autogrow set of IMAGE sockets (First_or_Ref_Image_0, Last_or_Ref_Image_1, then Ref_Image_2…, up to 16), and audio_bgm, a single song for the whole chain.
audio_bgm is the more interesting one. Wire a track roughly as long as your finished video and set a segment's audio reference mode to bgm: that segment's soundtrack is cut from the song at its own position on the chain's timeline, encoded through the Extend node's audio VAE, and frozen by the audio noise-mask. The music is the audio; the model generates video on top of it while still hearing it. Encoding happens one segment at a time, so peak VRAM tracks a single segment rather than the whole song. If the music runs out mid-chain, the mask drops and the model continues it freely.
The three outputs
temporal_tile_config goes to the Extend node. segments_info is an inspectable dict - session, storage, segment count, per-segment parameters - genuinely useful for confirming what the panel actually meant. ref_image_slots carries the wired sockets to the Extend node's matching input as one record per socket, at native resolution.
That last detail is the source of a common confusion: images are never resized or merged here. One socket is one <Picture i>, and a socket fed by a batch contributes only its first image - the same convention as MiniMaxH3 Reference to Video. Resizing happens per segment, in the Extend node, according to that segment's reference image size. The row order in the panel is the prompt order, so if your prompt says <Picture 2> and the result ignores you, check the chip order first.
Sessions, previews and re-rolls
Everything about a run lives in one session folder, <temp|output/latents>/mmh3_temporal/<session_name>/ - a session.json ledger plus latents/ and previews/. Segments can be locked, meaning they're read back from disk and never re-sampled. Unlock one segment, change its seed or prompt, run again: only that segment re-samples, and its previous attempt is preserved. The panel's previews let you click and set resume_from_segment, and editor state is stored in the session, so reloading the workflow restores the panel.
Two consequences. storage_location: temp is wiped when ComfyUI restarts - fine for experimenting, wrong for a session you intend to return to; use output/latents for anything long-lived. And disk fills up quietly, which is what the panel's "clear unused latents" action is for. There's also a shared reference/conditioning cache beside the sessions, content-addressed on the model fingerprint, the source file's path/mtime/size or a pixel hash, and the encoding parameters - so references and prompts are encoded once across segments, runs and sessions, and change an input and it simply misses.
Install
ComfyUI Manager → search Comfyui-MMH3-UltimateExtend → install → restart, or:
cd ComfyUI/custom_nodes
git clone https://github.com/bbaudio-2025/Comfyui-MMH3-UltimateExtend
No pip step. If the dock panel doesn't appear after installing, reload the page - node panels only load on a fresh front-end.
Two more expectations to set: the pack is at version 0.0.2 and its README warns that sockets, parameters and on-disk formats may still change between commits. And if a segment uses bgm without an audio VAE connected on the Extend node, the run stops before sampling with an explicit error - it fails loudly instead of shipping a silent clip.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| show_editor | BOOLEAN | true | Toggle the visual dock editor panel on/off. |
| session_name | STRING | session1 | Session directory name: <temp|output/latents>/mmh3_temporal/<name>/ holding the 'latents' and 'previews' subdirectories. Every session of a storage location shares one reference/conditioning cache in the sibling 'cache' directory. |
| storage_location | COMBO | temp | Where per-segment latents (.h3latent) and preview WebPs go: <location>/mmh3_temporal/<session>/{latents,previews}, beside a shared 'cache' of reference latents and encoded conditioning reused by every session. 'temp' is cleared on restart; 'output/latents' persists. |
| base_prompt | STRING | Shared prompt prefix applied to all segments. | |
| base_negative | STRING | Shared negative prompt applied to all segments. | |
| tile_data | STRING | {} | Internal JSON managed by the dock editor. |
| ref_imagesopt | COMFY_AUTOGROW_V3 | Direct IMAGE sockets: 'First_or_Ref_Image_0', 'Last_or_Ref_Image_1', then 'Ref_Image_2'... Wiring LoadImage here is an alternative to picking files in the dock panel. Every segment uses the connected images as 'load images' references by default; slot 0 doubles as segment 0's FL2VA first frame and slot 1 as the FL2VA last frame (when no file is picked for them). Remove an image from one segment only in the editor's reference row (it stays available to the other segments). One socket is one reference picture: an input carrying a batch contributes its FIRST image only (the same convention as MiniMaxH3 Reference to Video), so the prompt's '<Picture i>' numbering is one per socket. Images are never resized or merged here - the Extend node sizes each one by the segment's 'reference image size'. The row order IS the prompt order: wired sockets come first (slot 0, slot 1, ...), the picked files after them, left to right matching the '<Picture 1>', '<Picture 2>', ... the Ref2VA prompt has to name (the editor badges each chip with its index). | |
| ref_video_inputopt | VIDEO | OPTIONAL reference video as a ComfyUI VIDEO (a file, not a decoded frame tensor) - the same socket type the native 'MiniMaxH3 Reference to Video' family and the video Load nodes speak. By keeping it a file, the Extend node only DECODES the frames each segment actually needs (no huge frame tensor ever materializes in memory). Set a segment's ref-video mode to 'auto crop input ref': each such segment then takes the slice covering its ABSOLUTE span on the chain's timeline (the sum of the PRECEDING segments' frames decides where it starts, its own new-frames decide the length), so the segment's reference video is that slice of the input. If the video carries an audio track and the 'audio_BGM' input is NOT connected, the video's own audio is used as the background music. SECOND ROLE - direct reference in frame: on any segment whose 'direct reference in frame' side is set to left/right/top/bottom, this same video is ALSO the material an edge strip of that segment's SAMPLING canvas is spliced from (resized to the strip, never stretched out of shape) and frozen by the video noise mask, so the model generates only the remaining area while seeing the strip as literal pixels. The strip is scaffolding: it is cut back off once the segment has been sampled, so the output stays the generation area and the next segment inherits no material. A segment cannot do both at once: 'auto crop input ref' plus its own direct-reference side is rejected. Unconnected = 'auto crop input ref' segments, and any segment with a direct-reference side set, are rejected. | |
| audio_bgmopt | AUDIO | OPTIONAL background music for the whole chain - a song, roughly as long as the finished video. Wire it here and set a segment's audio reference mode to 'bgm': that segment's soundtrack is cut out of this audio at its own position on the chain's timeline (the PRECEDING segments' frame counts decide the offset), encoded through the Extend node's audio VAE and FROZEN by the audio noise-mask - the segment's audio IS this music and the model only generates video on top of it (it still hears the music). The music is encoded ONE SEGMENT AT A TIME (only the span that segment needs reaches the audio VAE), so peak VRAM tracks a single segment instead of the whole track. Segments that do not use 'bgm' keep their own soundtrack, so the mode can be switched per segment. When the BGM ends before the finished video, the rest is generated freely (model continues the music). The Extend node still errors out before sampling when 'bgm' is used without an audio VAE. Unconnected = 'bgm' segments are rejected. | |
| fun_control_videoopt | VIDEO | OPTIONAL fun-control video (MiniMax H3 Fun ControlNet) for the whole chain - a ComfyUI VIDEO (a file, not a decoded frame tensor), the same socket type the reference-video input and the video Load nodes speak. By keeping it a file, the Extend node only DECODES the frames each segment actually needs (no huge frame tensor ever materializes in memory). Set a segment's fun-control mode to 'auto crop input control': that segment's control slice is the part of this video covering its ABSOLUTE span on the chain's timeline, extended backwards by its carried tail - so abutting slices reassemble the control video continuously. 'whole control video' instead always starts at the video's first frame (the native node's behavior; right for a still image). This node does NOT decode, resize or encode anything here - the raw VIDEO object travels to the Extend node, which slices/encodes per segment. Unconnected = segments whose mode is not 'off' are rejected. | |
| fun_control_maskopt | MASK | OPTIONAL inpaint mask for the fun-control pass - the native Apply node's 'mask' input (1 = regenerate this region). One mask frame per chain frame, aligned to the chain's timeline EXACTLY like the control video: each controlled segment takes the frames covering its own span (its carried tail included), and a mask with fewer frames than the chain freezes its LAST frame from there on - a single frame therefore means the same static mask for the whole chain, exactly like the native node. Only read on segments whose fun-control mode is not 'off', and only together with 'fun_control_source_video' is the masked-out content fed back as the inpaint source. | |
| fun_control_source_videoopt | VIDEO | OPTIONAL source video behind the 'fun_control_mask' (what gets preserved where the mask is 0) - the native Apply node's 'source_video'. A ComfyUI VIDEO (a file, decoded per segment just like the control video, on the SAME window). Only read when a mask is connected: without one nothing is masked out, so there is nothing to source. Unconnected with a mask connected = the masked-out region is inpainted from scratch. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| temporal_tile_config | DICT | Complete per-segment configuration for MMH3 Temporal Extend Video. |
| segments_info | DICT | Inspectable summary: session, storage, segment count and per-segment parameters. |
| ref_image_slots | MMH3_REF_IMAGES | The connected reference sockets, one record per socket (name, slot, batch size, image tensor at its own resolution) in slot order - connect to 'MMH3 Temporal Extend Video' (its 'ref_image_slots' input). Images are NOT resized or merged here: the Extend node sizes each one per segment ('match' / 'max'), exactly like the picked files. Empty when nothing is wired. |
| control_image_slots | MMH3_CONTROL_SLOTS | The fun-control assets wired into this node ('fun_control_video' + optional 'fun_control_mask' / 'fun_control_source_video') bundled for 'MMH3 Temporal Extend Video' (its 'control_image_slots' input). Nothing is decoded, resized or encoded here: the Extend node slices each controlled segment's window out of the video and encodes it as that segment's control hint. The bundle also carries an 'absent' payload when only the mask is wired. Left unconnected = controlled segments are rejected with a clear error. |