Docs menu
Extend

Engine plugins

Control Unreal Engine, Unity and Godot projects from Tangle with triggers, properties and game events.

Tangle can drive real-time engines in installations, kiosks, virtual production and interactive shows: fire named triggers, set and watch named properties, and react to game events. Unity and Godot need a small Tangle plugin in the game. Unreal needs no Tangle plugin: it uses Epic's built-in Remote Control API.

EngineTangle moduleWhat goes in the gamePort
Unreal Engine 5 (and 4.26+)epic.unreal.engineEpic's Remote Control API pluginHTTP 30010, WebSocket 30020
Unity 2021.3+unity.unity.engineTangle Unity package (dev.tangle.engine)TCP 9420
Godot 4.1+misc.godot.engineTangle Godot addonTCP 9420

The Unity package and the Godot addon are MIT licensed and live in the Tangle source tree under tangle-connect/plugins/unity and tangle-connect/plugins/godot.

What you get in Tangle

All three modules work the same way from the show's side:

  • Triggers (in Unreal: exposed Blueprint functions) become buttons. The buttons are one scenes widget whose options are the game's list, so they follow what the game exposes without editing the dashboard.
  • Properties can be set and watched. Numeric properties get sliders, with the range set in the game. Four slider slots are available; the sliders setting picks which properties go on them (default: the first numeric properties).
  • Game events become device events named game.<name>, with their data, so automations can react to them.
  • Layouts: compact (status, last event, trigger buttons), operator (adds the 4 sliders) and full (adds the game or preset name, slider property names and a reload button).

Statuses:

SituationStatus
Game or editor not running (port closed)offline, reconnects on its own (1 s, 2 s... 30 s)
Running but not answering (a long load, stuck, paused in the debugger, a firewall dropping packets)timeout
Wrong token (Unity, Godot) or passphrase (Unreal)error, not retried until you change the device
Unreal preset not found (its level is not loaded)degraded, retried at every poll

Each module has a setup step (configurator) with the install instructions and a final check that the game answers.

Unity

Install the package

  1. In Unity: Window > Package Manager > + > Add package from disk..., and pick tangle-connect/plugins/unity/package.json. Or use Add package from git URL... with the repository URL and ?path=/tangle-connect/plugins/unity.
  2. Create an empty GameObject in your first scene, name it Tangle, and add Tangle > Tangle Server. It keeps itself across scene loads.
  3. Press Play. The console shows [Tangle] Listening on 0.0.0.0:9420.
  4. In Tangle, add a device with the module Unity (unity.unity.engine), host = this computer's IP address. Run the device's Install the Tangle Unity package check: it should pass.

Windows asks to allow the game (or the Unity editor) through the firewall the first time. Allow it on private networks, or Tangle cannot reach it.

The package works on any platform with TCP sockets (Windows, macOS, Linux, Android, iOS), but not WebGL: browsers cannot listen on a port.

Triggers

Add Tangle > Tangle Trigger to any GameObject, set Trigger Name (for example intro), and wire On Trigger to what should happen: play a Timeline, start an Animator state, call your method. On Trigger With Argument gets the first argument Tangle sends, as text. Several components with the same name all run.

From code:

GetComponent<Tangle.TangleTrigger>().Triggered += args => Debug.Log($"intro with {args.Count} args");
Tangle.TangleServer.TriggerReceived += (name, args) => Debug.Log($"Tangle fired {name}");

Properties

Add Tangle > Tangle Property and set Property Name (speed), then either:

  • set Target to a component and Member to one of its fields or properties (intensity on a Light, speed on your script). Types: float, double, int, long, bool, string, enum (as text);
  • or leave Target empty: the component's own Value (float) is the property. Wire On Value Changed to whatever should follow it.

Tick Use Range and set Min and Max to clamp numbers and give Tangle's sliders their range (the default is 0 to 1). Untick Writable for values Tangle should only watch, such as a score. Changes made by the game are pushed to Tangle about 10 times per second.

IL2CPP builds with managed code stripping may remove engine properties nothing else uses. If a property works in the editor but not in a build, add a link.xml that preserves that type.

Game events

Call Tangle.TangleServer.SendEvent("door-opened", 2); from code, or add Tangle > Tangle Event and call its Send() from any UnityEvent (a UI button, an animation event, a Timeline signal). Tangle receives the device event game.door-opened.

Server settings

FieldDefaultNotes
Port9420Must match the device's port in Tangle
Bind Address0.0.0.0127.0.0.1 accepts only Tangle on the same computer
TokenemptyWhen set, the device's token setting must match
Keep Across ScenesonDontDestroyOnLoad
Run In BackgroundonThe game answers while unfocused
Property Checks Per Second10How often values are compared for changes
VerboseoffLogs connections and requests

Requests are handled on the main thread, once per frame, so triggers and properties can use any Unity API. A game at 60 fps answers within about 16 ms.

Actions

ActionParameters
unity.trigger.firename, optional args (array)
unity.property.setname, value (converted to the property's type; the game may clamp it)
unity.property.setSlotslot (1 to 4), value
unity.property.getname
unity.game.refreshRead the trigger and property list again
unity.game.pingThe setup check

State unity.property.values holds every property, for example { "speed": 4, "lights": true }.

Godot

Install the addon

  1. Copy addons/tangle into your project's addons/ folder, keeping the path res://addons/tangle/.
  2. Project > Project Settings > Plugins: enable Tangle. This adds the Tangle autoload and its settings.
  3. Run the project. The output shows [Tangle] Listening on *:9420.
  4. In Tangle, add a device with the module Godot (misc.godot.engine), host = this computer's IP address. Run the device's Install the Tangle Godot addon check: it should pass.

The addon works in desktop and mobile exports, not in the web export.

Triggers

Add a TangleTrigger node anywhere in a scene, set Trigger Name (intro), and connect its triggered(args) signal to what should happen (an AnimationPlayer, a cutscene). Several nodes with the same name all emit. From code, without a node:

func _ready():
    Tangle.add_trigger("intro", "Starts the intro")
    Tangle.trigger_received.connect(_on_tangle_trigger)

func _on_tangle_trigger(trigger_name: String, args: Array):
    if trigger_name == "intro":
        $AnimationPlayer.play("intro")

Properties

Add a TangleProperty node and set Property Name (speed), then either:

  • set Target to a node and Property to one of its properties (speed on your script, light_energy on a light, position:x for a sub-property). Types: float, int, bool, String; other types are shown as text and read-only;
  • or leave Target empty: the node's own Value (float) is the property. Follow it with the value_changed_by_tangle(new_value) signal.

Use Range with Min Value and Max Value clamps numbers and sets the slider range (default 0 to 1). Untick Writable for watch-only values.

Game events

Tangle.send_event("door-opened", {"door": 2})

Settings

In Project Settings > General > Tangle > Server (turn on Advanced Settings to see them):

SettingDefaultNotes
tangle/server/port9420Must match the device's port in Tangle
tangle/server/bind_address*127.0.0.1 accepts only Tangle on the same computer
tangle/server/tokenemptyWhen set, the device's token setting must match
tangle/server/property_checks_per_second10How often values are compared for changes
tangle/server/verbosefalsePrints connections and requests

Exported builds also take overrides on the command line after --:

game.exe -- --tangle-port=9500 --tangle-token=secret --tangle-bind=127.0.0.1

The addon runs on the main thread once per frame and keeps running while the scene tree is paused.

Actions

The Godot module has the same actions as Unity, under godot.: godot.trigger.fire, godot.property.set, godot.property.setSlot, godot.property.get, godot.game.refresh and godot.game.ping. Its state is godot.property.values.

Unreal Engine

The epic.unreal.engine module uses the Remote Control API that ships with Unreal Engine, in the editor or in a packaged game.

Enable the Remote Control API

  1. Edit > Plugins, search "Remote Control", enable Remote Control API (and Remote Control Web Interface if you want Epic's browser control page). Restart the editor.

  2. Project Settings > Plugins > Remote Control: check that the web server starts automatically, and note the HTTP and WebSocket ports. In UE 5.1 and later, look at the passphrase and allowed-clients settings: either allow the Tangle computer, or set a passphrase and put it in the device's passphrase setting.

  3. In the editor, the console command WebControl.StartServer starts the server if it is not running. Test it from the Tangle computer:

    curl http://<unreal-pc>:30010/remote/info
  4. Packaged games (nDisplay, kiosks): keep both plugins enabled for the build, start the game with -RCWebControlEnable -RCWebInterfaceEnable, and allow ports 30010 and 30020 in the Windows firewall.

Expose what the show needs

Recommended: a Remote Control Preset.

  1. Content Browser > Add > Remote Control > Remote Control Preset, and name it (for example Show).
  2. Open it and expose:
    • functions: Blueprint functions of level actors ("Play Intro", "Reset"). Each becomes a button in Tangle, under its display name;
    • properties: numbers, booleans and text (a light's intensity, a speed variable). Numbers become sliders; set their UI min and max so the sliders get the right range.
  3. In Tangle, set the device's preset setting to the preset's name. Keep the preset's level loaded.

With a preset, the module opens the WebSocket and Unreal pushes value changes. If the WebSocket server is off (or websocket is false), values are polled every 5 s.

Without a preset, list objects directly in the device settings:

  • functions: { name, objectPath, function, parameters }
  • properties: { name, objectPath, property, type, min, max }

The object path is what the editor's right-click Copy Reference gives for a level actor, for example /Game/Maps/Main.Main:PersistentLevel.BP_Show_C_1. Both ways can be combined.

Game events from Unreal

The Remote Control WebSocket pushes changes of preset properties. To tell Tangle that something happened:

  1. Add a String variable LastEvent to a level actor and expose it in the preset (display name, for example, "Last Event").
  2. In Blueprints, set it to the event name (intro-finished) when the thing happens. Set it to an empty string first if the same event can happen twice in a row.
  3. Set the device's eventProperty setting to Last Event. Each new value becomes the device event game.<value>.

Settings and actions

SettingDefault
hostrequired
port30010 (HTTP)
wsPort30020 (WebSocket)
websockettrue
passphrasesecret, stored in the OS credential store
preset, eventProperty, functions, properties, sliders
ActionParameters
unreal.function.callname, optional parameters. The return value is in unreal.function.lastResult
unreal.property.setname, value (converted to the property's type and clamped to its range)
unreal.property.setSlotslot, value
unreal.property.getname
unreal.function.callObjectobjectPath, function, parameters (any object, for scripts)
unreal.property.setObjectobjectPath, property, value
unreal.info.refreshRead the preset again
unreal.info.pingThe setup check

The module checks GET /remote/info every 5 s to tell whether Unreal is there.

Tangle engine protocol

The Unity package and Godot addon speak the Tangle engine protocol, version 1. You only need it to write a plugin for another engine or to debug.

  • TCP: the game is the server, Tangle connects to it. Default port 9420. Several clients may connect at once (a main and a backup Tangle).
  • Messages are UTF-8 JSON objects, one per line, ended by \n.
  • Each client message is a request with a numeric id and an op; the game answers each with one reply carrying the same id: {"id": 3, "ok": true, ...} or {"id": 3, "ok": false, "error": "unknown trigger: intro2"}.
  • The game also sends pushes: messages with an event field and no id.
opFieldsReplyPurpose
helloprotocol (1), client, clientVersion, optional tokenprotocol, engine, engineVersion, app, appVersionMust be first. A wrong token answers bad token and closes the connection
listtriggers, propertiesWhat the game exposes now
triggername, optional argsFire a trigger
setname, valuevalue (after clamping and conversion)Set a property
getnamevalueRead a property
pingtime (game clock, seconds)Keep-alive; Tangle sends it every few seconds

Properties in a list reply have name, type (number, integer, boolean or string), value, optional min and max, and writable.

Pushes:

{"event": "property", "name": "speed", "value": 2.5}
{"event": "game", "name": "level-complete", "data": {"level": 3}}
{"event": "list"}

list means triggers or properties appeared or disappeared (a scene was loaded); Tangle reads the list again.

Example session:

> {"id":1,"op":"hello","protocol":1,"client":"tangle","clientVersion":"1.0.0"}
< {"id":1,"ok":true,"protocol":1,"engine":"unity","engineVersion":"2022.3.20f1","app":"Lobby Show","appVersion":"1.2"}
> {"id":2,"op":"list"}
< {"id":2,"ok":true,"triggers":[{"name":"intro"}],"properties":[{"name":"speed","type":"number","value":1,"min":0,"max":10,"writable":true}]}
> {"id":3,"op":"trigger","name":"intro"}
< {"id":3,"ok":true}

Warning: The engine protocol has no encryption. The optional token only prevents accidental control from another Tangle or a stray tool. Use it on a show network only, never expose the port to the internet, and set the bind address to 127.0.0.1 when Tangle runs on the same computer.