text() — Text Display Cue
Display text content with six simple modes: pick, cycle, shuffle, scroll, ticker, and reveal.
Modes
pick — Random Selection
Display ONE random item from an array. Each trigger picks a new random item.
text(pick:["Hello","World","Goodbye"], dur:3)
cycle — Sequential Playthrough
Display items one after another in order, with crossfade transitions.
text(cycle:"poem.txt", dur:2)
text(cycle:["Line 1","Line 2","Line 3"], dur:2, loop:0)
shuffle — Randomized Playthrough
Display all items in random order, reshuffling each pass.
text(shuffle:"poem.txt", dur:2, loop:0)
scroll — Teleprompter
Smooth scrolling text display, like a teleprompter.
text(scroll:"speech.txt", speed:60)
ticker — News Crawl
Horizontal scrolling text, like a news ticker or stock crawl.
text(ticker:"Breaking news • Headlines here • More info", speed:100)
Content Sources
Array
text(pick:["Option A","Option B","Option C"])
File
Load from .txt file. Files are resolved in order:
- Project texts directory:
scores/<project>/texts/<filename>(what new projects get) - Older project text directory:
scores/<project>/text/<filename> - Shared text directory:
shared/text/<filename>
text(cycle:"poem.txt", dur:2)
Inline String
Separate lines with newlines or semicolons.
text(cycle:"Hello;World;Goodbye", dur:2)
Unit Splitting
For files and inline strings, control how content is split:
| Unit | Description |
|---|---|
unit:line |
Each line is a separate item (default) |
unit:stanza |
Blank lines separate groups |
unit:word |
Split by words |
unit:char |
Split by characters |
text(shuffle:"hello world", unit:char, dur:0.3)
text(pick:"poem.txt", unit:stanza)
Per-Item Duration
Prefix any item with duration: to override the default:
text(cycle:"1:fast;5:slow;2:medium", dur:3)
Works with words too:
text(cycle:"2:hello 4:world 1:goodbye", unit:word)
And in arrays:
text(pick:["1:Quick","5:Slow","Normal"], dur:3)
In text files:
2:First line shows for 2 seconds
5:This line has: colons and shows for 5 seconds
This line uses the default duration
Items without a duration prefix use the default dur: value.
Grouping Lines (Stanzas)
Use unit:stanza to group lines separated by blank lines:
text(cycle:"poem.txt", unit:stanza, dur:3)
File format:
3:First stanza line 1
First stanza line 2
First stanza line 3
5:Second stanza
shows for 5 seconds
Third stanza uses default duration
with multiple lines
Each group displays as a unit. Duration prefix on the first line applies to the whole group.
Parameters
| Param | Description | Default |
|---|---|---|
pick: |
Array/string/file — show ONE random item | — |
cycle: |
Array/string/file — show all items sequentially | — |
shuffle: |
Array/string/file — show all items in random order | — |
scroll: |
String/file — teleprompter mode | — |
ticker: |
String/file — horizontal news crawl mode | — |
reveal: |
Array/string/file — lines fade in one by one and stay; after linger: the block fades out |
— |
linger: |
Reveal: seconds the complete block stays up | 8 |
fadeout: |
Reveal: seconds for the final fade-out | 3 |
width: |
Reveal at an element: block width in the element's own units | 300 |
next: |
Cue to run when the text has finished: a quoted cue, e.g. next:"zoom(to:star, scale:6, dur:4)", or an element id |
— |
unit: |
line, stanza, word, or char |
line |
dur: |
Seconds per item (pick/cycle/shuffle) | 2 |
speed: |
Scroll/ticker speed in px/sec | 60 |
dir: |
Ticker direction: left or right |
left |
hold: |
Keep final content visible + show preview | false |
fade: |
Fade duration in ms | 300 |
loop: |
Number of passes, or 0 for infinite |
1 |
target: |
center, self, or element ID |
center |
hide: |
1 hides the cue/target element while its text shows (it stays visible, and editable in the DSL inspector, by default) |
0 |
bg: |
Background of the target:self teleprompter box, e.g. transparent |
dark panel |
offsetX: |
Horizontal offset in px | 0 |
offsetY: |
Vertical offset in px | 0 |
pad: |
Padding in px for target:self scroll mode |
16 |
style: |
CSS styling | — |
uid: |
Unique identifier | auto |
trig: |
playhead, click, toggle, or extent |
playhead |
sync: |
Sync random choices across network clients | false |
Examples
Random greeting from array
text(pick:["Hello","Hi","Hey","Greetings"], dur:2)
Random line from file
text(pick:"quotes.txt", dur:3)
Random stanza from file
text(pick:"poems.txt", unit:stanza, dur:5)
Cycle through poem lines
text(cycle:"haiku.txt", dur:3)
Cycle through stanzas
text(cycle:"poem.txt", unit:stanza, dur:4)
Infinite shuffle with styling
text(shuffle:"words.txt", dur:1.5, loop:0, style:"color:yellow;font-size:6em")
Character scramble effect
text(shuffle:"HELLO", unit:char, dur:0.2, loop:5)
Per-item durations
text(cycle:"2:Quick;5:Slow;3:Medium")
Teleprompter for speech
text(scroll:"speech.txt", speed:40, style:"font-size:1.5em")
Teleprompter constrained to element bounds
text(scroll:"speech.txt", speed:60, target:self, pad:8)
The teleprompter will be sized to match the SVG element's bounding box, with optional padding.
Reveal a poem line by line
text(reveal:"poem.txt", dur:3, fade:1500, linger:10, fadeout:4, target:self)
Each line fades in over fade ms, the next follows after dur seconds, all stay visible;
linger seconds after the last line the whole block fades out over fadeout seconds.
At an element (target:self or an id) the block is drawn inside the score, in the element's
own group, starting at its left edge just below it — so it stays locked to it through zoom, pan,
scrolling and any animation of that group. Sizes are then in that group's units: width: (default
300), offsetX/Y, and the font-size in style. Without a target it is a centred page overlay.
News ticker
text(ticker:"Breaking news • Headlines scroll here • Click to dismiss", speed:120)
Ticker constrained to element
text(ticker:"Item 1 • Item 2 • Item 3", speed:80, target:self, loop:0)
Right-to-left ticker
text(ticker:"Scrolling right", speed:100, dir:right)
Hold final content visible
text(cycle:["Step 1","Step 2","Step 3"], dur:2, trig:click, target:self, hold:true)
Shows preview of first item at element before trigger, keeps final item visible after completion.
Ticker with preview and hold
text(ticker:"Click to scroll this message", speed:80, trig:click, target:self, hold:true)
Text is visible statically at element before clicking, then scrolls, then holds at final position.
Positioned at cue element (replaces element)
text(pick:["Yes","No","Maybe"], dur:2, target:self)
When target:self is used, the text appears centered on the cue element and the element is hidden during display. The element fades back in when the text completes.
Positioned at another element by ID
text(pick:["Yes","No","Maybe"], dur:2, target:display-area, trig:click)
When target: is set to another element's ID, the text appears centered on that element and the target element is hidden during display. This is useful for separating the trigger element from the display area.
Click-triggered button
text(cycle:"1;2;3;4;5", dur:1, trig:click)
Synced random across clients
text(pick:["🎲 One","🎲 Two","🎲 Three"], dur:2, trig:click, sync:true)
Synced infinite shuffle
text(shuffle:"words.txt", dur:1, loop:0, trig:click, sync:true)
Trigger Modes
playhead (default)
Text cue triggers when playhead crosses the element:
text(pick:["A","B","C"], dur:2)
text(cycle:"poem.txt", trig:playhead)
click
Text cue triggers when user clicks the element. The element remains clickable at any time:
text(pick:["Click me!","Clicked!"], dur:2, trig:click)
text(cycle:"1;2;3;4;5", dur:1, trig:click)
Click-triggered cues are always active and don't depend on playhead position.
toggle
Click to start, click again to stop. Useful for continuous random text that runs until manually stopped:
text(shuffle:"word1;word2;word3", dur:0.5, loop:0, trig:toggle)
text(shuffle:["A","B","C"], dur:1, loop:0, trig:toggle, target:self)
The first click starts the infinite loop, the second click stops it.
extent
Text runs while the playhead is within the element's horizontal bounds. Automatically starts when playhead enters and stops when it exits:
text(shuffle:"alpha;beta;gamma", dur:0.8, loop:0, trig:extent)
text(shuffle:["X","Y","Z"], dur:0.5, loop:0, trig:extent, target:self)
This is useful for sections where text should cycle continuously while the playhead traverses a wide element.
Hold Mode
Use hold:true to show a preview before the cue triggers and keep the final content visible after completion.
text(pick:["Yes","No","Maybe"], dur:2, trig:click, target:self, hold:true)
Behavior:
- Preview: First item displays statically at the target location before triggering
- Preview scrolls: When using
target:self, the preview tracks the element position as the score scrolls - Hold: After completion, final content stays visible until the cue is triggered again
- Works with all modes: pick, cycle, shuffle, scroll, and ticker
Best practice: Always use target:self with hold:true to keep the preview positioned at the element rather than screen center.
text(cycle:["Step 1","Step 2","Done"], dur:1.5, trig:click, target:self, hold:true)
text(ticker:"Click to scroll", speed:60, trig:click, target:self, loop:0, hold:true)
Network Sync
By default, each client independently makes random choices for pick and shuffle modes.
Use sync:true to synchronize:
pick with sync
The triggering client's random choice propagates to all clients:
text(pick:["Alpha","Beta","Gamma"], dur:3, sync:true)
shuffle with sync
The triggering client generates a shuffled sequence that all clients follow:
text(shuffle:"words.txt", dur:1, loop:0, sync:true)
For long-running shuffles, a pre-generated sequence (~100 passes) ensures clients stay synchronized without visible repetition.
Interaction
Regular text overlays (pick/cycle/shuffle)
Click any text overlay to dismiss it immediately.
Teleprompter (scroll mode)
- Single click: Pause/resume scrolling
- Double-click: Show confirmation dialog to dismiss
Ticker (news crawl)
- Click: Dismiss immediately
Stopping All Text
stopAllCueTexts()
Removes all active text overlays.
Scroll speed from a signal
speed: takes a follow(), so a ticker can run at a rate something else decides:
text(uid:crawl, ticker:"…", speed: follow(fader.t))
It is sampled when the cue fires, not followed: a scroll is one animation
whose duration is worked out from distance ÷ speed at the moment it starts, so
a later value has nothing left to change. With no range of its own a follow()
here spans 10–400 px/s.
Before this, a
follow()onspeed:parsed, ran, and was ignored — it fell throughNumber(...)asNaNand quietly became the 60 px/s default.
Demo
See demo-text — text cues, timing and placement.
http://localhost:8001/?project=demo-text
Tip: use ← → or ↑ ↓ to navigate the docs