π List Batch Images
How you get six renders into one batch when they arrive one at a time
- images
- batch
ComfyUI's IMAGE socket is a batch - a [B, H, W, C] tensor - but most of the interesting 3D work isn't batched. You render the same asset from six camera angles, one at a time, and you want them to arrive at the downstream node as a single batch of six: to save them as a numbered sequence, to feed a multi-view texture pipeline, to upload as one set.
There's a class of node that solves this: an accumulator. This is the pack's, and it's about forty lines of real logic.
The mechanism
It keeps static, class-level buffers: a dictionary keyed by batch_id, holding a list of frames and a count. Every time the graph executes the node:
- If
resetis on, wipe thatbatch_id's buffer and count. - Push whatever arrived on
imagesinto the buffer. A batch of 6 arriving in one go becomes 6 entries; a single image becomes 1. - Print the progress:
[ListBatchImages] ID: mv_batch | Progress: 3/6. - If the count has reached
expected_count, stack the firstexpected_countframes into one tensor, clear the buffer, and return it. - Otherwise return
None- and here's the clever part - aNoneon an IMAGE output means downstream nodes don't execute. ComfyUI treats the branch as unsatisfied and stops. So nothing saves a half-finished sequence.
That's the trick: it turns N separate executions into one batch, and it refuses to fire early.
Inputs and output
images(IMAGE) - whatever your render stage produces. Usually fed from a loop, aSave-less preview chain, or a multi-view generator.batch_id(default"mv_batch") - the buffer's name. "mv" is multi-view, from the author's own pipeline, and you can see the same naming in this pack'sLoad Batch Images (BC/NM/POS), which expects files named<prefix>bc_1.png,<prefix>nm_1.png,<prefix>pos_1.png.expected_count(default 6) - how many frames make a set.6is the multi-view convention; set it to however many angles your generator produces.reset(default off) - clear the buffer this run. Use it as the first node in a fresh chain.
Single output: batch (IMAGE) - the full stack, or nothing.
The traps, and they're real
The buffer is not part of your workflow. It lives on the Python class in memory, shared across every node in the graph using that batch_id and surviving between runs. Consequences:
- Two List Batch Images nodes with the default
batch_idshare one buffer and will interleave each other's frames. Give every accumulator in a graph its own id. - If a run fails halfway, the frames already collected stay in the buffer. Your next run starts at 3/6 and you silently get a batch made of two different runs. Hit
reset- or restart ComfyUI if you've lost track. expected_countsmaller than what actually arrives means the extra frames sit in the buffer and leak into the next execution.
IS_CHANGED returns NaN, so the node always re-executes and is never cached. That's required for the accumulator to work, and it also means it's not a node you can park in a graph and forget about - it will run every queue.
Nothing downstream runs until the batch is complete. If your graph looks like it silently stopped, this node is the first suspect: open the console, read Progress: N/6, and check whether the number is climbing or stuck. A stuck count almost always means the loop feeding it produced fewer frames than expected_count (an angle that failed to render, a generator returning 5 views not 6).
Install
cd ComfyUI/custom_nodes
git clone https://github.com/Antonioilev/ComfyUI_Antonioilev_Lightpack.git
Restart ComfyUI - that's it. This node imports torch and nothing else, so it works even if you haven't installed trimesh and the whole mesh half of the pack is failing to load. ComfyUI Manager users: search Antonioilev Light Pack. The startup banner [Antonioilev_Light_pack] Loaded N nodes (M failed) will list any module that couldn't import; this one shouldn't be in that list.
When not to use it
If your images already arrive as a batch - a single Load Image set, a VHS-style loader, anything that outputs [6, H, W, 3] in one execution - you don't need to accumulate anything, and adding this node just inserts a way to desynchronise. This exists for the genuinely sequential case: multi-view render loops, batch prompts executed one at a time, and any workflow where the frames reach you over several graph executions rather than in one.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | β | |
| batch_id | STRING | mv_batch | β |
| expected_count | INT | 6 | β |
| reset | BOOLEAN | false | β |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| batch | IMAGE | β |