⚡ Images Shuffler
Shuffle your frames, but never land on the same one twice
- image
- IMAGE
⚡ Images Shuffler is the sibling of Images Seeker in ComfyUI-Pronodes' "Reactivity" corner, and it solves a different problem. Seeker scrubs through a video to the good parts; Shuffler takes your frames and reorders them randomly - but with one guardrail that keeps the result watchable instead of a stutter: no frame is ever placed right next to the same frame twice in a row. It's a reshuffle for rapid-fire, beat-synced edits where an adjacent repeat would read as a glitch.
Think of it as the "shuffle but don't repeat" button for a slideshow, a glitchy-cut music video, or a collage sequence. If you've got a batch of frames and a beat map, this makes the frame swaps land on the beats rather than wherever a plain random.shuffle feels like putting them.
Inputs and the beat map
Same beat-map language as its sibling - points_string is a multiline list of frame:(value) pairs, and the default is the pack's standard 0:(0.0), 7:(1.0), 15:(0.0). Here, 1.0 marks the moments where the image should change - each 1.0 point advances to the next shuffled frame. Between beats (0.0), the current image just holds. That's the reactivity: the visual swap is locked to your timeline's key moments.
The other inputs:
image(IMAGE) - your frame batch, as a tensor.fps(INT, default 12) - your source frame rate. Mostly for keeping the timing coherent with the rest of the pipeline.points_string(STRING) - the beat map.
One IMAGE output: the reordered batch, ready for a video combine node.
How the shuffle actually works
Reading the source, the mechanism is clearer than the name suggests:
- The frame indices are cycled (repeated) until they match the number of points in your map - so the edit can be longer than the source clip.
- The indices are shuffled with a "no consecutive duplicates" constraint: the algorithm refuses to pick a frame that equals the one it just placed, retrying up to a hundred times if it paints itself into a corner. (The author's docstring frames this as "no element appears consecutively with its original neighbors" - the code's actual check is simpler: it only bans the same frame value twice in a row, which matters because the frame list is cycled to match your beat count.)
- Each
1.0point in your timeline advances the pointer by one, so the image that's on screen changes exactly at your beats.
The result is a deliberately jarring but structured edit - random order, but with the structure (the beats) and the guardrail (no immediate repeats) doing the work of keeping it from feeling like a broken video player.
The honest caveats
- These reactivity nodes are the least-polished part of the pack. Both Shuffler and Seeker have essentially no community presence - the pack is a tiny MIT project explicitly marked "still in development." Expect zero tutorials and rough edges.
- It's a random node. You'll get a different order every run. If you need a deterministic output, note that there's no seed input here - that's not a bug, it's the genre. (Loop the whole workflow with a fixed seed elsewhere if you must reproduce a take.)
- "No consecutive" only means identical neighbors. The guardrail bans the same frame value landing twice in a row - it does not detect two different frames that happen to look alike (a talking head, a static background), because the constraint is positional and value-based, not perceptual.
- The
points_stringparser is strict:frame:(value)comma-separated, one per line. Malformed input just fails the run.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/yuvraj108c/ComfyUI-Pronodes
or search "ComfyUI-Pronodes" in ComfyUI Manager and restart. Shared pack dependencies are light (yt_dlp, imageio[ffmpeg]), no models download at runtime. If you're building beat-reactive edits and the "shuffle but don't stutter" idea clicks, this node does one specific thing and does it in ~40 lines. If you want polished, well-documented video tooling, look at VideoHelperSuite instead - this is the experimental corner of an author's side project, and it's happy being that.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| fps | INT | 121–255 | — |
| points_string | STRING | 0:(0.0), 7:(1.0), 15:(0.0) | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |