Built for one show and paused when that show no longer needed it. Almost every interactive piece a studio ships needs something outside the engine pulling triggers. This is the general version.

The setup
An XR stage, with the Unreal scenes driven by Switchboard. Something outside the engine has to say which scene is live and poke the interactive elements inside it, and OSC is the path of least resistance: every control surface in the building already speaks it.
The first version was Blueprint. It worked and it did not scale: every new scene meant re-wiring the same dispatch by hand, and the control surface had to know what was in the level it was talking to.
What the plugin does
A fixed vocabulary, and one place that speaks it:
/ue/level/load <MapName>/ue/level/transition <MapName> <Time>/ue/actor/show <Tag>/ue/actor/hide <Tag>/ue/actor/toggle <Tag>/ue/actor/trigger <Tag>/ue/timeline/play <Tag>/ue/timeline/resume <Tag>/ue/timeline/pause <Tag>/ue/timeline/stop <Tag>/ue/cue/next/ue/cue/prev/ue/cue/goto <Index>/ue/cue/reset/ue/fx/activate <Tag>/ue/fx/deactivate <Tag>/ue/fx/reset <Tag>
Actors and sequences are addressed by tag, so the control surface never learns an actor name. Tag something in the editor and it is reachable.
Two decisions carry the rest of it.
The receiver outlives the scenes. It is a UGameInstanceSubsystem, so
Unreal makes exactly one and it survives level transitions, which matters when
half the vocabulary is change the level. A receiver that dies with the map
cannot be the thing that loads the next one.
A receiver is one node. Anything that wants a value drops a receiver component and binds one event. A phone's orientation arriving as a Float4 and driving a transform is a two-node graph. That is the part the rewrite actually bought, and it replaced about twenty nodes of server setup, binding, address parsing and type unpacking that every listener used to repeat.

Argument types are inferred rather than declared: no args is an event, one float is a float, three floats are a vector. The sending side never has to agree a schema in advance. In Blueprint that lands as a switch on the type and a read of the one field that is valid.
The problem that went away
The Blueprint version's hardest part was knowing which level was live. It solved that centrally: one director carrying a Level Index and a Switch on Int, with a branch per level naming the actors in that level. It worked, and it meant one graph had to know every scene in the show.

The plugin has no director and no switch, and it did not replace that routing
with better routing. A receiver registers with the dispatcher on BeginPlay
and unregisters on EndPlay, so the set of live receivers is the current
level. Nothing has to be told which scene is up, because only that scene's
receivers exist. A level defines what it listens for by containing the things
that listen.
A HandleCommand interface survives from the old model, reached by exactly one
address. Nothing else in the vocabulary consults a director.
What that says
I went in thinking the wiring was the problem. It was the cheap half: seventeen verbs, a tag convention, a server owning its own lifecycle, an afternoon of design and a weekend of C++, and it is the part that feels like real work because it is the part with architecture in it.
The expensive half was never in the engine. It is the surface an operator actually wants: a cue stack they trust under pressure, feedback that a command landed, a state readout, a way back when a level fails to load. That was the TouchDesigner module, and it is the one I did not finish.
It is not hard the way the plugin is hard, just specific, and specific gets designed by watching someone run a show. The next installation that needs a trigger will specify it.