Skip to content

Cue Script Reference ​

A cue script is the text in a cue's script box — the box with the ⚡ Wizard button under a Timeline cue's action, or a Playlist item's Action On Enter / Action On Leave, with the action type Custom. It runs when the cue fires. Each line is one action: a command to Exaplay itself, or a message to another device. You rarely have to type it — ⚡ Wizard builds the lines for you — but this page is the exact syntax the engine reads.

Rules for every line ​

  • One action per line, run top to bottom.
  • A line starts at the first character: no leading spaces, and no space between the prefix and > (OSC>, not OSC >).
  • Fields are separated by commas. Spaces around the address and the OSC path are ignored; everything else is taken literally.
  • $Name or ${Name} in an address (and in an OSC path) is replaced by a variable. A name that does not resolve stops the send and shows an ERROR row in the Monitor.
  • REM at the start of a line makes it a comment.

Commands to Exaplay ​

Any line without a protocol prefix is a dotted command — the same syntax as the TCP Command API:

comp1.play
comp1.cue.go=Act 1
comp2.stop
comp1.media3.set:image.alpha=50
comp1.set:audio.volume=80
system.showmode=on
system.pjlink=192.168.1.50,POWR,1
screen1.calibration.blend=off
comp1.media3.webcapture.reload
comp1.media3.webcapture.click=0.5,0.5

A web page clip takes webcapture.reload / .back / .forward / .stop / .click[=x,y] / .js=… — see TCP › Webcapture verbs.

screen1.calibration=on|off|toggle, screen1.calibration.blend=… and screen1.calibration.black=… switch a screen's calibration, its edge blending and its black level (the same switches as the calibration's Edit… dialog — see TCP › Screen verbs). In a multi-client rig a cue runs on every machine, and the switch is the master's: the master's line switches every PC at the same moment, a client's line changes nothing.

In a cue script, system.pjlink= reaches any projector address you write; the same line sent from outside over TCP/UDP only reaches a projector configured under Control → TCP Devices (see TCP › System verbs). set:time= on a Playlist is the time within the current item.

A bare verb acts on the cue's own composition: play, pause, stop, restart (play from start; media3.restart for one Playlist item), cue.go=3, set:time=10. In the ⚡ Wizard, Browse picks the target from the project tree and Set a value… lists the values an operator drives.

Messages to other devices ​

OSC ​

OSC>host:port,/address[,i:<integer>][,f:<float>][,s:<text>]
OSC>10.0.0.20:8000,/eos/cue/5/fire
OSC>$Console,/cue/5/go,i:1
OSC>$Console,/fader/1,f:0.75,s:main
  • Argument types are i, f and s; any other type is dropped.
  • Put a field that contains commas in double quotes. A : inside an s: value ends the value.
  • Sent as a plain OSC message (not a bundle).

TCP and UDP ​

TCP>host:port,payload
UDP>host:port,payload
TCP>192.168.1.30:9500,PLAY 3\r
UDP>$Projector,%1POWR 1\r
  • The payload is everything after the first comma, sent byte for byte — it may contain commas, and a space after the comma is sent too.
  • Escapes in the payload: \r (CR), \n (LF), \t, \b, \", \\, \xHH (any byte in hex). Any other letter gives a control byte counted from a — \c is 0x02 (STX), \d is 0x03 (ETX) — so write a literal backslash as \\.
  • A field that is exactly $Name is replaced by that variable's value when it exists; any other text starting with $ (such as $1POWR) is your device's text and is sent as it is. Only an unresolved ${Name} makes the line refuse.
  • TCP opens a connection, sends and closes.

HTTP ​

Calls a device's REST API or a webhook — a smart plug, a projector or camera with a web API, Node-RED, Home Assistant.

HTTP>METHOD url
HTTP>METHOD url,body
HTTP>GET http://10.0.0.30/relay/0?turn=on
HTTP>POST http://homeassistant.local:8123/api/webhook/show-start,{"scene":"act2"}
HTTP>PUT http://${Camera}/api/preset,recall 3
HTTP>$LobbyLightsOff
  • METHOD is GET, POST, PUT, PATCH or DELETE (upper or lower case). A line without one is a GET.
  • The body is everything after the first comma that follows the address, with spaces at both ends removed. A GET sends no body: write a comma that belongs to the address as %2C (?ids=1%2C2), and a space as %20.
  • A body that starts with { or [ is sent as application/json, anything else as text/plain; charset=utf-8. The body is sent exactly as written: there are no \r / \xHH escapes here (unlike TCP/UDP), so \n inside a JSON string reaches the device as JSON's own \n.
  • http:// and https:// both work. An https:// device needs a trusted certificate; a self-signed one is refused, so use http:// for devices on the local network.
  • ${Name} anywhere in the address or the body, or an address that is exactly $Name, is a variable. An unresolved one stops the send.
  • A user name or password in the address (http://admin:pw@…) is refused: anyone on the network can read a project's scripts back. A device that needs a key usually takes it in the query or the body — that is just as readable, so give such a device a key that can do only what the show needs.
  • In a multi-client show only the master sends the request, so a cue that plays on every machine still calls the device once. A client logs not sent here.
  • The request runs in the background and never holds up playback. A device that does not connect within about 3 seconds, or does not answer within 10, is given up. At most 16 requests wait for an answer at once.
  • The Monitor shows one row per request, after the answer: OUT with the status code and the first characters of the answer for a 2xx, ERROR with the status (or why there was no answer) for anything else. A redirect from https to http is not followed.

Art-Net DMX ​

ARTNET>ip,universe,channel,value
ARTNET>10.0.0.50,0,12,255
  • Port 6454 is fixed; a variable must hold the IP only.
  • The value is clamped to 0–255. Channels you do not name keep the value they had (the same universe can also be driven by a Data Track).

MQTT ​

Publishes one message to an MQTT broker — Home Assistant (its Mosquitto add-on), Node-RED, Mosquitto or an IoT gateway: switch a light, start an automation, tell the building a scene began.

MQTT>broker,topic,payload
MQTT>Home Assistant,exaplay/scene,act2
MQTT>192.168.1.20,zigbee2mqtt/lobby_light/set,{"state":"ON","brightness":120}
MQTT>$Broker,show/state,${ShowState}
MQTT>mosquitto.local:1884,show/blank,
  • broker is the name (or the channel name) of an MQTT device in Inputs: its address, port, user name and password are used, so a password never has to be typed into a cue. Anything else is read as host or host:port (port 1883 if none) and connects without a login.
  • topic is one topic, without + or # (those only subscribe).
  • payload is everything after the second comma, sent byte for byte — a JSON payload keeps its commas, a space after the comma is sent too, and there are no \r / \xHH escapes (unlike TCP/UDP). It may be empty.
  • In a multi-client show only the master publishes, so a cue that plays on every machine still sends one message. A client logs not sent here.
  • The message goes out with QoS 1, not retained: Exaplay waits for the broker to confirm it, then disconnects. Each line opens its own short connection in the background and never holds up playback; a broker that does not accept the connection within 2 seconds, does not acknowledge it within 5, or does not confirm the message within 3, is given up.
  • The broker must be on the local network (10.x, 172.16–31.x, 192.168.x, or this PC). This version speaks plain MQTT over TCP, without TLS (port 8883 is not supported), so a login crosses the network in clear.
  • $Name / ${Name} in the broker and the topic, and ${Name} in the payload, are variables. An unresolved one stops the send.
  • The Monitor shows one row per line (protocol MQTT): OUT with the topic and the start of the payload once the broker confirmed it, ERROR with the reason otherwise (The broker refused the user name or password., no MQTT broker answers at …, the broker did not confirm the message …).

DALI lighting ​

DALI>gateway,target,action[,value[,fade]]
DALI>House,all,off
DALI>House,G2,level,40
DALI>Foyer,G17,scene,2.5,3
  • gateway is a DALI gateway configured in Control → TCP Devices (a Lunatone DALI-2 IoT or a Helvar router), by name or id — never an address.
  • target: all, G<group>, A<short address> (Lunatone) or @cluster.router.subnet.device (Helvar).
  • action: level (value 0–100), on, off, scene (value: scene number; on a Helvar router also block.scene).
  • fade: seconds, Helvar only. A Lunatone gateway uses the ballasts' own DALI fade time.
  • The line is queued and returns at once; the engine sends it in the background. A command the gateway cannot do (a fade on a Lunatone, all on a Helvar router) is refused with the reason in the Monitor and the log. Sent by the master only. See DALI Lighting.

Flow and system ​

LineEffect
WAIT>millisecondsPause before the next line (0–600000, i.e. up to 10 minutes). A script with a WAIT> runs in the background, so the engine never blocks. Loading a project, or deleting the cue's composition, cancels the rest of a running script
TRACKING>group:<name>=on / =off / =toggleSwitch a group of Inputs mappings
TRACKING>solo=<name>Only that group on
TRACKING>all=on / =offAll groups
BATCH>command lineRun a command line (cmd.exe /c), e.g. a .bat file
SHUTDOWN>Force-shut down this machine
RESTART>Force-restart this machine
REM textComment

Example ​

REM Act 2: lights, sound, picture
OSC>$Console,/cue/20/go
TCP>$AudioServer,GO 2\r
WAIT>500
comp_act2.cue.go=Opening
system.pjlink=192.168.1.50,AVMT,30

Where else these lines work ​

  • Over TCP/UDP from outside: only the dotted commands. Protocol lines (OSC>, TCP>, HTTP>, TRACKING>, …) are cue-only there; a remote line containing > is refused.
  • Over HTTP: the TRACKING> text without its prefix can be sent as POST /tracking with {"command": "solo=scene2"}.
  • Failover "On Promotion Send" (multi-client backup): OSC>, TCP> and UDP> lines, plus # comments — see Multi-Client.

See Also ​

Exaplay 3 User Documentation