VideoFillerGrid Assemble
Stitch generated clips into one video without nuking your VRAM
- clips
- fillers
- path
- video
Video models are great at five seconds and bad at five minutes. The workaround for anything longer is to generate short clips, then little transition clips that bridge every pair, so the cut doesn't look like two unrelated generations slapped together. The hard part was never generating those - it's joining them into one file, and ComfyUI has no clean way to assemble a dynamic-length list. VideoFillerGrid Assemble is that missing join, in one pass, straight to an mp4.
Why plain ComfyUI can't do this
You'd think stitching clips is trivial, but the graph fights you on it. A dynamic-length join needs a list-reduce; the only image one core ships (RebatchImages) caps at 4096 frames, and for audio there's no list-reduce at all. Worse, ComfyUI materialises the whole expanded list at every node, so building the cut as tensors costs memory proportional to duration.
This node sidesteps all of that. Every clip and filler arrives once (INPUT_IS_LIST), gets decoded a single time, and the node walks your order list straight into the encoder. Only the N + N×N distinct sources are ever resident, so memory is flat in duration and nothing intermediate hits disk.
How the grid works
You provide N source clips and the N×N fillers that transition between every ordered pair, arriving in cartesian order: filler k is the s→t transition where k = s×N + t. Your order file is one clipIndex,fillerIndex per line, and each unit emits its source clip then its filler - so 0,1 then 1,3 reads as A → A→B → B → B→A → A.
Two details matter. Frame size comes from the first clip; fillers are rescaled to match with common_upscale (lanczos, centre) when they differ - handy while testing at a lower generation resolution. Frame rate comes from the first filler. Audio is normalised to 48 kHz stereo, silent when a source has no track, and each segment is trimmed or padded to match its frames exactly. That last bit is the real win over container stitching: audio is cut from the running frame index, so the two streams can never drift.
The inputs that matter
Only three inputs really matter:
- clips and fillers - both
VIDEOlists, arriving whole and in workflow order. - order - a
STRING, oneclipIndex,fillerIndexper line. This is your entire editorial control. - seconds - the length of the final cut, default 20. Set it to
0to write every unit whole instead (more on that below).
The optional bits are equally sane: crf (default 18, near-transparent; each +6 roughly halves file size), preset (veryfast to slow - quality is set by CRF, preset only affects size and encode time), and save_sources, which writes the fillers and an order.txt into a _sources folder beside the video. Keep it on and you can re-cut the same material to another length without regenerating. The outputs are path (the file location) and video, which wraps the finished mp4 so the node previews its own result.
Looping cuts - the subtle bit
Set seconds = 0 and every unit is written whole. That's required for a seamless loop: if the closing filler leads back to the first clip, trimming clips it part-way and the join to the start no longer lands. Untrimmed, the cut ends where the closing filler ends, so looping playback is as clean as any internal join.
Install
The easiest path is ComfyUI Manager - search "comfyui_videofillergrid" - or just:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_videofillergrid
then restart. No extra dependencies - it leans on av and torch, which ComfyUI already ships, plus torchaudio only when a filler's audio needs resampling. The bundled "Gen Segments Order List (Looping)" subgraph can emit a random order, but wants a recent ComfyUI (0.32+); the node itself doesn't care - feed it any string.
Traps worth knowing
The README is honest about its failure modes. The big one: N must be right. If len(fillers) != len(clips)², the indices in your order file don't mean what you think. The node doesn't enforce it - a partial grid is legal - but it's almost always stale files. Clip and filler indices are also independent, so pairing clip B with filler A→C (line 1,2) encodes fine - the cut just won't make sense. Out-of-range indices and an empty order list are the hard errors. And if seconds is longer than your material, you get everything - the walk just ends when the order runs out, no padded file. There's no community lore on it yet - treat the README's list as ground truth for now.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| clips | VIDEO | The source clips, in loader order. | |
| fillers | VIDEO | The N*N fillers, in cartesian order. | |
| order | STRING | One 'clipIndex,fillerIndex' per line. | |
| seconds | FLOAT | 20.00–86400 | Length of the final cut; the walk is truncated to exactly this. Set 0 to write every unit whole instead - required for a looping cut, where clipping the closing filler would break the join back to the start. |
| filename_prefix | STRING | video/VideoFillerGrid | Path prefix under the output folder. A counter and .mp4 are appended, so 'video/Foo' becomes output/video/Foo_00001_.mp4. |
| crfopt | INT | 180–51 | H.264 quality. Lower is better and bigger; each +6 roughly halves the file size. 0 is lossless, 18 is near-transparent, 23 is x264's own default, above ~28 gets visibly soft. Only affects the final video. |
| presetopt | COMBO | veryfast | How hard x264 works to hit the CRF quality. Slower presets give the same look in a smaller file, but take longer to encode; quality is set by CRF, not by this. veryfast suits long cuts, slow is for a final master. |
| save_sourcesopt | BOOLEAN | true | Also write the N*N fillers and the order file into a <name>_sources folder beside the video. They are not needed for the cut, only to re-cut it to another length without regenerating. Turn off to write the video alone. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| path | STRING | — |
| video | VIDEO | — |