Nodes/ValiTools/VFileRandom
ComfyUI Node

VFileRandom

Random reference images that draw like a shuffled deck, not dice

By vangel76·Created 2 months ago·Updated 8 days ago· 1
VFileRandom
    • image
    • mask
    • filename
    • remaining_in_cycle
    • filename_noext
    ◄folder►
    ◄seed0►
    ◄include_subfoldersfalse►
    ◄reset_cyclefalse►

    What it is

    VFileRandom loads a random image from a folder - with one twist that makes it genuinely better than the average "random image loader": it draws without repeats. Think of a shuffled deck, not dice. Every image in the folder gets shown exactly once before any image repeats, then the deck reshuffles. If you've ever run a 40-image batch through img2img or IPAdapter only to realize image #7 was a repeat of #2 and you wasted the GPU, you know why that property is the whole point.

    Why you'd reach for it

    It's a reference-image feeder for img2img, ControlNet, IPAdapter, style conditioning - anywhere you want to run a batch that cycles through a folder of source images (faces for character consistency, moods, lighting references, a moodboard) and actually want to see all of them. The no-repeat guarantee matters most for long batches, because a plain random picker drifts toward repeats as the folder shrinks relative to the batch size, and suddenly you've generated your best look at one image twice while another never got its turn.

    The shuffle-bag behavior isn't new (it's the same trick behind "shuffle" modes in music players), but in ComfyUI it's surprisingly scarce - most random loaders are memoryless, which is exactly what you don't want for a fair cycle through a reference set.

    How it works

    The node keeps per-folder state in vfile_random_state.json, stored next to the package itself. Each key is (folder, include_subfolders), so two folders get independent cycles, and the file survives ComfyUI restarts - your half-finished cycle doesn't reset just because you rebooted. On each run it scans the folder, drops files that were deleted, and inserts any new files into the current bag at random positions (they're "due" before the reshuffle). When the remaining bag runs dry, it reshuffles the whole set and starts over.

    The seed widget does something a lot of people find surprising at first: it only triggers a new draw. The no-repeat cycle itself is stateful and ignores the seed for fairness; a fixed seed just means "don't draw again." Keep it on randomize to advance the deck each queue, fix it to freeze the current pick.

    The inputs that matter

    • folder - absolute path to the directory holding your images. This one's on you; there's no browser-picker fallback.
    • seed - as above: randomize to advance, fix to pause. The cycle survives regardless.
    • include_subfolders - scan recursively. Each (folder, subfolders) combination gets its own cycle.
    • reset_cycle - forget what's been drawn and start a fresh shuffled deck on this run. Set it, queue, then turn it back off.

    Outputs: image (as a batch-ready tensor), mask (from the alpha channel), filename (relative to the folder), remaining_in_cycle, and filename_noext. After each run the node also shows the cycle progress on its face, like 45 / 235, so you can watch the deck shrink.

    Supported extensions: .png, .jpg, .jpeg, .webp, .bmp, .gif, .tif, .tiff.

    Installing

    Install via ComfyUI Manager (search "ValiTools" or "comfyui-ValiTools"), or clone it:

    cd ComfyUI/custom_nodes
    git clone https://github.com/vangel76/comfyui-ValiTools
    

    Then restart ComfyUI. No pip deps, no model downloads - it only uses numpy/torch/PIL, which ComfyUI already provides.

    Common issues

    • "no image files found in '<folder>'" means the path is wrong, not relative, or the folder holds unsupported extensions. Use an absolute path and double-check the extension list above.
    • The mask surprises you. It comes from the alpha channel and it's inverted - 1 - alpha - so black is opaque and white is transparent, and a PNG with no alpha gives you an all-zero mask. If you're feeding it to an inpaint node, check the polarity before you trust it.
    • Cycle state is a file. Delete vfile_random_state.json (in the pack's directory) and every cycle resets. Deleting images mid-cycle just drops them; adding images mid-cycle works, but they slot into the current bag, so the count you see can climb between reshuffles. To force a clean start without touching files, use reset_cycle.
    • "Why did it pick the same one again?" - it shouldn't, within one cycle. If you see repeats, you're probably running two VFileRandom nodes with the same folder (independent cycles), or you manually fixed the seed and changed something that re-queued the same draw.
    CategoryValiTools

    Inputs (4)

    NameTypeDefaultDescription
    folderSTRINGAbsolute path to the folder to draw images from.
    seedINT00–18446744073709550000Only triggers a new draw (keep it on 'randomize'); the no-repeat cycle itself is stateful.
    include_subfoldersBOOLEANfalse—
    reset_cycleBOOLEANfalseForget which images were already drawn and start a fresh shuffled cycle on this run.

    Outputs (5)

    NameTypeDescription
    imageIMAGE—
    maskMASK—
    filenameSTRING—
    remaining_in_cycleINT—
    filename_noextSTRING—