GPU LayerStyles SliceImageBatch
Trim, reverse and ping-pong a video batch with one string
- image
- image
A batch of images in ComfyUI is just a stack, and until you have a node that slices a stack you end up doing absurd things - decoding all 81 frames, then discovering you wanted frames 1 to 80. GPULayerStyles_SliceImageBatch gives you Python's slice syntax in a text box: one index, or START:END[:STRIDE].
What it does
Type :15 and you get the first fifteen frames. Type -15: and you get the last fifteen, in forward order. Type ::-1 and you get the whole batch reversed. Type 0:-1 and you drop the final frame. That last one is the specific move this pack documents elsewhere: after interpolating a loop you trim the redundant endpoint with 0:-1, and this is the node that does it.
The implementation really is Python slicing semantics - the source builds a range(length)[slice(...)] and calls it through torch.index_select. So negative indices count from the end, END is exclusive, a negative stride reverses the selection order, and the selection is always a copy: the output is a fresh, independent, contiguous tensor with the same dtype, device and pixel values, even when you selected a single image.
Two useful exceptions to Python behaviour:
:and::are passthrough. They return the input tensor itself, no copy at all. So the default value of theslicewidget costs nothing. Don't leave it as a free "duplicate the batch" node, because it isn't one.- Out-of-range and empty selections raise. Python would quietly hand you an empty list; this node refuses.
0:0, orSTARTbeyond the batch, is an error with a message telling you the allowed range for a batch of that length. That's the right call in a graph - a silently empty batch propagates and fails somewhere confusing later.
The two inputs
image is the batch, and slice is the string (single-line, default :). For a batch of N images, index and START must be between -N and N-1, END between -N and N, and STRIDE cannot be zero. Omit END to run through index 0, which is what makes ::-1 and -15: work.
There are no execution controls on this node - no output_device, no batch_size - because there's no arithmetic to accelerate or chunk. It's pure indexing, and that's a fair simplification: the cost is the copy.
One output, image. Wire it into a Video Combine, another batch node, or the next slice.
Why a batch node needs this at all
Because so much of the interesting video work happens at the seams. Last-frame-to-first-frame chaining - generate a clip, take its last frame as the first frame of the next - is the standard way to get past a model's frame ceiling, and once you've chained three clips you're constantly pulling single frames or ending frames out of batches. Ping-pong loops are the same trick twice: take a batch, reverse it and concatenate, and you have a boomerang. That's three nodes in most workflows; here it's two, because reversing is a string.
It also matters for batch discipline. A lot of the nodes people use to fix a batch - interpolators, upscalers, loop assemblers - need to know exactly how many frames they're getting. Slicing first is how you make that deterministic, and this node's hard errors are what tell you when you guessed wrong.
Install
ComfyUI Manager → search GPU LayerStyles and restart. Or:
cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/lany42/gpu-layerstyles
# restart ComfyUI
No dependencies to install (the runtime dependency list is empty), no models, no API key. The pack wants Python 3.13+ and a ComfyUI recent enough for comfy_api / the V3 node schema - meaning define_schema() rather than NODE_CLASS_MAPPINGS, which is why you won't find the usual mapping dict if you go looking. AGPL-3.0-only.
Getting burned
The copy is the trap on long batches. Selecting even one frame from a 1200-frame 1080p batch allocates a new tensor and holds the input alive, and because there's no batch_size here you can't chunk your way around it. Slice late, after the frames you don't want have already gone out of scope - or better, don't build the surplus batch in the first place.
Second: START:END is half-open and -1 as an END means "all but the last frame", not "through the last frame". If your trimmed clip is one frame short, that's why.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| slice | STRING | : | One index or START:END[:STRIDE]. : and :: pass the input through unchanged; :15 selects the first 15; -15: selects the last 15 in forward order; ::-1 reverses the batch. For N images, index/START must be between -N and N-1, and END between -N and N. Omit END to reverse through index 0. STRIDE cannot be zero. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |