Superside Prompt Variants
Ten poses in one node, not ten copies of your prompt
- text
- label
- index
- count
The problem it actually solves
You're generating try-on shots - same person, same product, same lighting rules, ten poses. One long instruction prompt does the heavy lifting; only a three-line paragraph about where the body is pointing changes per run. So you copy the prompt into ten text boxes, every typo fix becomes ten edits, and when you look at an output you have no idea which pose produced it.
Superside Prompt Variants is that pool of fragments in a single node. It holds them, picks one, and - the part that matters - tells you which one it picked.
One thing up front: this is one of the few nodes in the pack that touches no network. The rest of comfyui-superside-nodes is fal.ai wrappers that need a key and bill per call (external-api-nodes); this one is plain Python string work. No api_key, no cost, instant.
How the picking works
The pool is one multiline text field. Blocks are separated by a line containing only ---, and a block may open with a # label line - that line names the block and is not emitted as prompt text. Block without a label gets called variant 1, variant 2 and so on. Blank blocks are dropped, so a trailing --- is harmless.
Then one of three modes decides which block comes out:
- random -
random.Random(seed).randrange(count). Seeded, so seed 42 always gives you the same block. That's the whole point: reproducible randomness instead of a shuffle you can't re-run. - cycle - block number
seed % count. Walk the pool in order by setting the seed widget to increment. - fixed - the block at
index, for sitting on one variant while you judge it.
Every mode is a pure function of the inputs. There is no counter hiding inside the node, so re-running a workflow reproduces the same prompt it produced before.
Inputs you'll actually touch
variants is the pool - where 95% of your time goes. mode is the three-way switch above. seed drives random and cycle; index is only read in fixed mode. The defaults are a two-block example pool (frontal and three-quarter headshots) so you can see the --- convention without reading a manual.
Two things about seed and index. First, index is 1-based and out-of-range values are clamped, not rejected - ask for block 7 in a two-block pool and you silently get block 2. Second, if you walk the pool with control_after_generate: increment, mind the classic trap: that control fires after the run, so the number left in the box is the seed for the next run, not the one that just ran (comfyui-node-plumbing § control_after_generate).
Outputs, and where they go
text is the block itself - wire it into whatever takes a prompt, most usefully slot_1 on Superside Prompt Slots, or straight into the generator node's prompt input.
label and index are the receipts. Wire label into SaveImage's filename_prefix and the pose name ends up in the filename, which is the actual answer to "which pose made this image?" - just keep labels free of slashes and colons if you're naming files with them. index is the 1-based block number, and count is how many blocks were found, which is handy to check when you add a pose and forget a separator.
One caveat: this node is not in the repo's on-node text display list, so nothing renders on it after a run. To read the text without spending a generation, wire text into a Superside Text Preview node - that one is on the list.
Install
ComfyUI Manager: search "Superside" and install comfyui-superside-nodes. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/Superside/comfyui-superside-nodes.git
cd comfyui-superside-nodes
pip install -r requirements.txt
Then restart ComfyUI - new nodes only register on restart - and look under the Superside category. On Windows portable, run pip with the embedded interpreter: ..\..\python_embeded\python.exe -m pip install -r requirements.txt. The requirements (fal-client>=1.0.0, pillow, numpy, torch, requests) are for the fal-backed majority of the pack; you install all of it to get one string node.
Gotchas worth knowing before you debug
The separator has to be alone on its line. ---- won't split, and neither will --- more text. Also, because a leading # line is treated as a label and stripped, don't start a fragment with a markdown heading or a #-prefixed comment you meant to keep.
This node isn't an output node, so it only executes if something downstream needs it. Leave text unwired and you get nothing - which reads as "broken" more often than it should.
And if an old saved workflow refuses to run with "an input value has the wrong type", that's the pack's old text-display serialisation bug, not you: set the offending widget back to default once and re-save.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| variants | STRING | # 01 frontal, loose smile Front-facing studio headshot, weight shifted subtly onto one side so the shoulders sit at a natural loose diagonal, head straight to camera, soft subtle smile, arms down at the sides out of frame. No hands visible. --- # 02 three-quarter, temple detail Body and shoulders rotated to a 3/4 angle away from the head, head counter-rotated back toward the camera to reveal the temple detail of the glasses, soft subtle smile, arms down at the sides out of frame. No hands visible. | Blocks separated by a line containing only ---. A leading '# label' line names the block and is not emitted. |
| mode | COMBO | random | random and cycle both read the seed; fixed reads index. |
| seed | INT | 00–18446744073709550000 | Drives random and cycle. Set the widget to 'increment' to walk the pool one block per run. |
| index | INT | 11–999 | 1-based block to emit in fixed mode. Out of range is clamped. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| text | STRING | — |
| label | STRING | — |
| index | INT | — |
| count | INT | — |