Unreal Engine
AllWhat it's for — CueSync drives an Unreal Engine world the way it drives a lighting desk. The free CueSync for Unreal plugin receives the CueSyncBus over OSC, so the level moves with the music — beat, energy, key and phrase arriving as normalized 0→1 values, with anticipation ahead of the drop — and, optionally, follows your cue stack and timecode over a second, reliable link.
There are two connections, and the second one is optional:
| Plane A — the reactive bus | Plane B — authoritative show output | |
|---|---|---|
| Carries | beat, energy, key, phrase, accents | cue channels, accent activations, timecode |
| Transport | one-way OSC over UDP 8001 | reliable WebSocket on 8091 |
| Setup | add the output, press Play | pair once with a token from the plugin |
| Without it | — | the bus still works exactly as described below |
Plane A is what most projects need. Add Plane B when the world has to follow the show — cues that release cleanly, and scrubbing that doesn't leave anything stuck on.
Requirements
- Unreal Engine 5.8, macOS or Windows.
- CueSync for Unreal 1.8 or later for everything on this page. The desktop hides features an older plugin can't do rather than guessing.
- CueSync itself is macOS on Apple Silicon. A Windows Unreal machine is fine — it just needs a Mac running CueSync on the same network to drive it.
Install the plugin
- Copy
CueSyncForUnreal/into your project'sPlugins/folder, or install it from Fab. - Enable CueSync for Unreal in Edit → Plugins. It auto-enables the stock OSC, WebSocket Networking and Niagara plugins.
- Restart the editor.
Connect the bus (Plane A)
In Unreal:
- Drag a CueSync Bus Manager actor into your level — or add a CueSync Bus Receiver component to an actor you already have.
- Leave Bus Collection empty to use the bundled
MPC_CueSyncBus, or point it at your own Material Parameter Collection. - Press Play.
In CueSync:
- Open Settings → Network Outputs and add an Unreal Engine 5 output.
- Set the host to the Unreal machine's IP and the port to 8001.
- Connect it. See Network Outputs for the connection states and what each one means.
That is the whole reactive setup. Read the collection in any material or Niagara system; bind the accent events in Blueprint.
What arrives on the bus
Every value lands at /RemoteControl/CueSyncBus/<Name> and is written into the Material Parameter Collection.
| Parameter | Range | Meaning |
|---|---|---|
BeatPhase | 0→1 | phase within the beat — the world pulse |
BarPhase | 0→1 | phase across four bars — slow drift |
Energy | 0→1 | musical energy — density, bloom |
HueShift | 0→1 | derived from musical key — palette |
Anticipation | 0→1 | how close the next drop is, smoothed against the plugin's own clock |
Bpm | float | live tempo |
EnergyTrend | −1 / 0 / +1 | falling / steady / rising |
PhraseId | int | phrase index |
Anticipation is the one to build against. The bus carries how many beats remain until the next drop, and the plugin turns that into a frame-smooth ramp that peaks exactly on the downbeat and falls away damped. A world driven by Energy alone reacts after the moment; a world driven by Anticipation arrives with it.
Accent events
These fire as Blueprint events on the bus component. Bind your own art to them.
| Function | Event | Arguments |
|---|---|---|
BurstFX | OnBurstFX | intensity (int) |
TriggerDrop | OnTriggerDrop | — |
CutToCamera | OnCutToCamera | index (int) |
PlayCameraMove | OnPlayCameraMove | move name (string) |
SetScreenMedia | OnSetScreenMedia | screen id (int), clip (string) |
PauseSequence / StopSequence | OnPauseSequence / OnStopSequence | sequence name (string) |
GotoFrame | OnGotoFrame | sequence name (string), frame (int) |
Blackout | OnBlackout | on (0/1) |
LoadLevel / UnloadLevel | OnLevelStream | level name (string), load (bool) |
Two of them also act on their own, because a show-safety command must not depend on a project having wired a Blueprint: Blackout fades the player camera and latches until CueSync releases it, and LoadLevel / UnloadLevel perform the matching streaming call. Both can be turned off per actor (bApplyDefaultBlackoutFade, bApplyDefaultLevelStreaming) when the project owns that flow itself.
Drop-on drivers
Add a driver component to any actor and it follows the bus with no Blueprint graph. Each one finds the bus itself and stays inert when there isn't one.
| Driver | What it does |
|---|---|
| Fixture Group | drives a group of lights with a per-fixture phase offset — chase, ping-pong, fan from centre, converge, or a seeded random scatter — so a truss reads as a light show instead of one simultaneous flash |
| Light | one light: energy brightness, per-beat flash, hue-wheel colour, a flare on BurstFX |
| Media | the receiver for SetScreenMedia — opens a clip on an LED wall or projection, and blanks on blackout |
| Niagara | pushes energy, beat phase and hue into a system's user parameters; bursts on accents |
| Material | the same values into named parameters of a mesh's dynamic material |
| Transform | beat-pulse scale, energy bob, bar-phase spin, relative to the actor's start transform |
| Post Process | energy → bloom and exposure, with a per-beat chromatic pulse |
| Camera Shake | shakes on qualifying downbeats, harder on TriggerDrop |
| Sequence Director | plays named Level Sequences; pause, stop, goto-frame; chases timecode |
| Channel | drives world properties from the authoritative cue channels (Plane B), restoring baselines on release |
Fixture groups. Tag your lights CueSyncGroup:<GroupName>. Tagged actors are ordered by actor label, so Truss_01…Truss_12 chase in the order you named them and a re-run cannot reshuffle a look you rehearsed. Leave BaseIntensityOverride at 0 and each lamp keeps its authored intensity as its own base, so a hand-lit stage gains movement instead of being flattened to one number.
Show modes
Place a CueSync Show Mode actor in the persistent level to run one map three ways — Live, Capture and Demo. Each mode applies its own console variables, loads or unloads its streaming levels, and sets the camera director's blend time.
Demo drives itself: the plugin's own clock, an energy swell, a hue drift and a scripted accent timeline, with no desktop, deck or operator attached. It yields the moment a real CueSync stream arrives and hands back if that stream stops, so plugging in mid-demo is a silent handover rather than two shows fighting over one bus.
When the plugin reports its mode, CueSync shows it in the output's configuration panel. It is worth reading before a show: Capture removes the framerate cap that holds a live show at a locked 60, and Demo means the level is driving itself.
Authoritative show output (Plane B)
Pair once, and CueSync mirrors its authoritative cue and timecode state to Unreal over a reliable link: channels are applied as a replace, so releasing a cue releases exactly what it owned and nothing orphans; rewinding the show reverts the world cleanly instead of leaving values stuck on.
- In Unreal, open Window → CueSync Monitor and click Open pairing page (or browse to
http://<unreal-machine-ip>:8090/). The page shows an 8-character pairing token. It survives editor restarts, so you pair once. Optionally click Require PIN in the Monitor to add a PIN. - In CueSync, edit the Unreal Engine 5 output and open Authoritative Show Output (optional).
- Paste the pairing token, and the PIN if you set one. The control port defaults to 8091.
- Connect. A wrong token or PIN reports a clear error rather than failing quietly.
Once paired, the panel also lists the channel names Unreal has bound, so you can see from CueSync what the world is actually listening for.
Timecode genlock
While a show plays, the plugin installs itself as the engine's timecode provider, so Level Sequences chase the show — re-seeking on a jump, scrubbing otherwise, and freewheeling across momentary gaps. It hands the engine's previous provider back when the last desktop client disconnects. See Timecode for the CueSync side.
The tablet remote
The plugin serves a LAN-local control surface on port 8090 — open it on a tablet and drive the world from the floor. It uses the same pairing token as Plane B, and it lists whatever the level has registered: cameras, camera moves, screens and clips.
Ports, and exactly when they are open
| Port | Protocol | Open when |
|---|---|---|
| 8001 | UDP (OSC) | whenever a bus actor is in the level — editor and packaged builds |
| 8090 | TCP (HTTP) | in the editor by default; not in cooked builds |
| 8091 | TCP (WebSocket) | same as 8090 |
A game you ship to end users should not open listening sockets because a plugin is enabled, so the web remote is editor-only unless you opt in. A stage build that needs the tablet or Plane-B control turns it on in the project's Config/DefaultEngine.ini:
[CueSync.WebRemote]
bEnable=True
or with -CueSyncWebRemote=1 on the command line. The OSC bus on 8001 is a separate listener and works in cooked builds either way — a packaged world still reacts to the music with the remote off.
One endpoint, GET /api/snapshot, is deliberately unauthenticated: it is how CueSync checks whether Unreal is alive before pairing, and it returns only mode, tempo, beat age, plugin version and bound channel names. Everything else requires the token.
The plugin makes no outbound connections, collects no telemetry and requires no account. Keep 8090 and 8091 on your show LAN — never expose them on a routable interface.
Emergency blackout
CueSync's blackout reaches Unreal like any other output. The plugin fades the player camera itself — covering every pixel regardless of which drivers you wired — gates every driver, holds the Material Parameter Collection's continuous values at 0, and latches until CueSync sends the release. Bpm and PhraseId keep reporting the truth, because a readout claiming 0 BPM during a blackout is a lie about the music rather than a safety measure.
Troubleshooting
Nothing moves. Check the output shows connected in Network Outputs, then confirm a bus actor or receiver component is actually in the level being played. The plugin logs the addresses it receives — Plane A is one-way UDP, so the Unreal log is the only place the truth exists.
Lights ignore everything. A light placed in Unreal is Static by default, and a static light refuses intensity changes at runtime. Set the ones you want driven to Movable.
The whole rig flashes together. That is the Auto Reactor driving every light identically. Tag the fixtures into a group and use the Fixture Group driver.
The tablet can't reach the page. Confirm you browsed to the machine's LAN address rather than localhost, that the editor is running, and that macOS or Windows firewall is allowing Unreal. In a packaged build, check the bEnable=True opt-in above.
Pairing says denied. Five wrong tokens or PINs from one address pause that address; the pause clears after a quiet minute, so wait and retype rather than restarting the editor. Delete Saved/CueSync/Pairing.ini to rotate the token entirely.
A media clip doesn't appear. Clip ids compare case-sensitively. An unknown id logs a warning naming both it and every registered id.
A level won't stream. The name must be a streaming level of the persistent level. An unknown name logs a warning naming the world rather than failing silently.
See also: Network Outputs · Timecode · Diagnostics · Protocols
Looking for a quick fix?
The Help Center has short task-focused articles and a support team that responds within 24 hours.