String Control ππ ‘π £π
Animate your text in a real-time ComfyUI graph
- STRING
You've got a live ComfyUI workflow running once per frame - think ComfyStream or a StreamDiffusion-style pipeline - and you want the prompt to drift while it runs, not just the seed. That's the entire job of String Control ππ ‘π £π . It's a stateful node that outputs a string, and every time the graph executes it quietly advances an internal clock and hands you a different line from the list you gave it. Wire the output into a CLIP Text Encode and your positive prompt starts to cycle on its own. No API, no key, no Python. Just text that changes over time.
It's one node in ryanontheinside's real-time pack - the same author behind the ComfyStream-adjacent "everything reactivity" suite - and it exists because in real-time land, nobody is clicking "Queue Prompt" a hundred times a minute. The graph itself is the clock.
How it works
Under the hood it's a phase accumulator. Each execution bumps an internal phase by 1 / steps_per_cycle, then runs your chosen movement pattern over that phase and uses the result to pick an index into your list of strings. So your list is a track and the pattern is how it's traversed:
- sine (the default) sweeps up through your strings, then back down. Smooth, looping, easy on the eyes.
- sawtooth sweeps forward and hard-resets to the start.
- square snaps between the first and last line - good for a coarse two-state toggle.
- bounce, exponential, random_walk, smooth_noise and friends are the same idea with different temperaments.
static pins the first line, which sounds useless until you realize it's a handy way to temporarily freeze a node mid-tweak. One important thing: the output is always a whole string. Sine doesn't interpolate characters, it just decides which entry in your list you're currently closest to. If you want smooth blending, put your interpolation downstream.
The inputs that matter
- strings - one string per line. This is your content. The default is
first string / second string / third string, so don't be confused when it starts cycling gibberish; replace it with real prompts. - steps_per_cycle (default 30) - how many executions one full cycle takes. On a 30 fps runner, 30 is about a second per cycle. This is your speed knob.
- movement_type - the pattern above.
- always_execute (default on) - leave it on. When it's on the node re-evaluates every execution; that's what makes the clock tick. If you turn it off, the output freezes the moment nothing upstream changes, and it's very easy to mistake that for a broken workflow.
Output: a single STRING. That's it. Into CLIP Text Encode positive, or negative if you want the anti-prompt to change too.
Installing it
Same as any node in this pack. Easiest via ComfyUI Manager - search "Control Nodes" or just "Realtime" and install. Manual route:
cd ComfyUI/custom_nodes
git clone https://github.com/ryanontheinside/ComfyUI_RealtimeNodes
cd ComfyUI_RealtimeNodes
pip install -r requirements.txt
Then restart ComfyUI. Watch the casing - the repo is RealtimeNodes, and the README's own clone command typo's it to RealTimeNodes. GitHub is case-sensitive, so a copy-paste from the wrong source fails silently-ish with a 404. Note the requirements include mediapipe, which this particular node never touches - it's for the pack's vision half. You can ignore it; the whole pack installs together.
Where people get burned
The classic one is expecting String Control to animate inside a normal ComfyUI session. It won't. A regular single-run graph executes once and the node's clock never moves until you queue another run. It's built for once-per-frame runners, not for batch mode - that's the "real-time" in the pack's name. Also, if your list has one line, all patterns output that one line forever; the node won't complain. For live performance where you want prompts swapping on a beat, this is the one you'll reach for before you graduate to audio-reactive stuff.
The ππ ‘π £π suffix on every node is the pack's brand - Ryan's real-time series. You'll see it in every menu in this pack, and it's how you tell the RealtimeNodes family from lookalikes at a glance.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| always_execute | BOOLEAN | true | When enabled, the node updates every execution |
| strings | STRING | first string second string third string | List of strings to cycle through (one per line) |
| steps_per_cycle | INT | 301β1000 | Number of steps to complete one full cycle |
| movement_type | COMBO | sine | Pattern of value changes over time |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| STRING | STRING | β |