Indexed 2x2 Grid from Batch
Four frames in one image, each one labeled
- images
- grids
- grid_count
- index_groups_debug
There's a classic ComfyUI subgraph for "show me what's happening in this video at a glance": select four frames, label each with its frame number, composite them into a 2×2 grid. It's a handful of nodes, and it's fiddly to keep the labels aligned with the right cells. Indexed 2x2 Grid from Batch collapses all of that into one node: feed it an IMAGE batch and it returns a batch of 2×2 grid images where every cell has its original frame index stamped on it.
The build-it-yourself route also did one thing badly: every model you feed a montage to has to figure out which frame is which, or you cross your fingers. Here each cell is labeled ("frame 3" if you set label_prefix to "frame "), so both a human eyeballing the contact sheet and a vision model reasoning over it know exactly what they're looking at. That last part is the real reason this node exists in this pack - it pairs with ClaudeCliVisionText's send_all_frames: one API call per grid, four labeled frames in a single view, and the model can compare across all four at once instead of four separate calls with no spatial context.
How it works
The node walks the batch with stride-based windows. Default stride is 3, so for 8 frames you get three grids - (0,1,2,3), (3,4,5,6), (4,5,6,7) - with the final grid backfilled from the end so that whenever N ≥ 4 every grid contains four real frames. When you have fewer than four frames total, you get a single grid and the missing cells are filled with black. Worth noting explicitly: real frames are never repeated to fill a gap - the black cells exist precisely to avoid duplicating content.
Each cell gets a black label bar prepended on top (height from label_bar_height, default 24, white centered text at label_font_size, default 16) via Pillow. If you leave label_prefix empty, the bar is still drawn so all four cells stay geometrically identical - just with bare numbers.
Inputs and outputs
images- the IMAGE batch.stride- INT, 1 to 4, default 3. How many frames to advance between grids. Below 4, grids overlap and share frames (deliberate).label_prefix- string prepended to each index, e.g."frame ".label_font_size(default 16) andlabel_bar_height(default 24) - label cosmetics.
Outputs: grids (the IMAGE batch of grid montages), grid_count (INT), and index_groups_debug - a STRING like "0,1,2,3 | 3,4,5,6 | 4,5,6,7" that shows exactly which frames landed in which grid. That debug string is genuinely useful for checking coverage before you spend API calls.
Installing it
Same pack, same boringly clean install - no Claude Code required for this node; it's pure torch + Pillow. Search ComfyUI Manager for "Claude CLI (Vision+Text)" or:
cd <ComfyUI>/custom_nodes
git clone https://github.com/RandyHaylor/comfyui-claude-cli-vision-text-node.git
Restart ComfyUI and hard-refresh the browser tab (Ctrl+Shift+R). No pip install - only numpy, torch, and Pillow, all already present.
The traps
- Default
stride3 means adjacent grids share a frame: grid 1 ends on 3, grid 2 starts on 3. That's intentional (montage continuity), but if you're counting frames per dollar of API spend, overlapping grids means some frames get analyzed more than once. Crank stride to 4 for a clean partition. - With N < 4 the black-filled cells are real behavior, not a bug - no frame is ever duplicated to fake a full grid.
- The
stridewidget is capped at 4 because a grid is four cells wide; there's no reason to jump further than one grid per step.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| stride | INT | 31–4 | — |
| label_prefix | STRING | — | |
| label_font_size | INT | 166–128 | — |
| label_bar_height | INT | 240–256 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| grids | IMAGE | — |
| grid_count | INT | — |
| index_groups_debug | STRING | — |