DMX lights and physical signalling

Everything above assumes the kiosk uses screens. However, premium installations often put light into the room. A DMX strip in the enclosure or washing the wall behind it, driven by the avatar’s existing state, achieves three things a screen cannot: it reads from across the room, it tells the visitor when to speak without instructions, and it makes the installation part of the architecture rather than a wheeled-in monitor.

This page is about light going out, driven from Unreal. For hardware going the other way — a button, a key-switch, a relay or a PLC driving the kiosk instead of reflecting it — see Physical buttons and other hardware. This operates over the control channel and needs no Unreal change at all.

Build the turn-taking cue first. Not knowing whose turn it is is the most confusing aspect of talking to an avatar. A green strip solves this without text, in any language, even for visitors who never look at the tablet.

EPromethistState carries the turn, and On State Changed is where you read it. The one that matters is Listening. It is set the instant the avatar’s audio finishes draining, meaning the floor is the visitor’s:

State What the room is being told Effect that works

no session

idle, come and interact

slow breathing fade — this is the one that draws people over

ConnectingConnected

the conversation is starting

fill up from the bottom

Ready

session established; the avatar is about to greet them

finish the fill — see the note below, this fires once

Listening

the visitor’s turn — speak

hold solid green

PrebufferingSpeaking

the avatar is talking

blue, or drive brightness from the speech envelope so the wall breathes with the voice

BargeIn

it stopped to listen to you

snap back to the Listening look — the visual apology for interrupting

Disconnected

the conversation is over

drain back down — empty the tank the way it filled, and land back on the idle breathing

blackout

out of service

red, or dark; pairs with whatever the big screen shows

The fill and drain are worth doing as a pair. Filling upon connect and emptying on disconnect instantly conveys starting and finished without text. This gives the end of a conversation shape; otherwise, the light simply snaps back to idle, and the visitor is never told they are done.

Two things about this table are easy to get wrong, both costing a rebuild if discovered late:

  • Ready is not "your turn". It is set exactly once per session when the backend answers #ready, and never again. The per-turn cycle is ListeningPrebufferingSpeakingListening. Use Ready to end your connecting animation, not to invite speech.

  • Listening covers both "waiting for you to start" and "processing what you just said". When the avatar stops talking, the state becomes Listening. It stays Listening while the visitor speaks and while the backend works out its answer, with nothing separating the two phases.

    *`Prebuffering` is the closest thing to a "thinking" state*, and it is real. It begins when the
    reply starts arriving and ends when the avatar starts speaking. Today, it is usually too short to
    light; our backend answers quickly, causing a flicker. It becomes useful when downstream processes
    delay playback enough to show. For instance, a lip-sync pass requiring a few seconds on incoming
    audio gates both the audio and the `Speaking` state. Here, `Prebuffering` provides the exact
    window where the avatar is visibly working on an answer.
    So: build the turn-taking cue on `Listening` versus `Speaking`, and add `Prebuffering` as a
    thinking colour only if you have measured it as visible. To split `Listening` itself, you need
    your own signal, like an arriving transcript or custom voice detection.

Drive this however suits you. Unreal ships DMX support if you want it in-engine off On State Changed. Alternatively, an external service can sit on the tablet’s WebSocket and talk to your preferred hardware.

If you take the external route, note that the state keys published to the tablet (sessionActive, paused, blackout, …) are session-level, not turn-level. Nothing published says "the visitor may speak now". Publish your own key for this, Set Tablet State String("phase", "listening"), and read that.

The same channel drives anything else physical: a bell, a door release, a turnstile, a scent dispenser, a fan. It works in both directions — see the note on physical buttons in What the thing is.