Fluxta

Messaging

A live JSON channel between editor and plugin.

Settings are persisted and slow-moving. Sometimes an editor needs something else: the list of scenes that exist right now, whether the connection is up, a "test this" button that reports back.

Messaging covers that — arbitrary JSON, in both directions, stored nowhere.

The four calls

WhereSendReceive
EditorsendToPluginonReceiveFromPlugin
Background processsendToEditoronReceiveFromEditor

sendToEditor goes to every open editor of the plugin, not one in particular. Usually there is at most one, but that is not guaranteed.

Define your own protocol

The SDK imposes no message format. Since both ends are yours, almost anything works, but a tagged object is worth adopting from the start — a plugin ends up with more message kinds than expected:

type ToPlugin = { event: "getScenes" } | { event: "testConnection" };

type ToEditor =
  | { event: "scenes"; scenes: string[] }
  | { event: "status"; connected: boolean };

Ask on mount

The pattern that covers most editors is: subscribe first, then ask.

the editor
useEffect(() => {
  const off = editor.onReceiveFromPlugin<ToEditor>((data) => {
    if (data.event === "scenes") setScenes(data.scenes);
    if (data.event === "status") setConnected(data.connected);
  });

  void editor.sendToPlugin({ event: "getScenes" });
  return off;
}, []);
the background process
plugin.onReceiveFromEditor<ToPlugin>((data) => {
  if (data.event === "getScenes") {
    plugin.sendToEditor({ event: "scenes", scenes: obs.scenes });
  }
});

Subscribe before asking. A reply arriving before the listener is attached is lost; there is no queue.

Then push updates as they happen, without being asked:

obs.on("connected", () => {
  plugin.sendToEditor({ event: "status", connected: true });
});

The editor gets the current state on mount and stays current afterwards, without polling.

Messages can go nowhere

There is no delivery guarantee and no error, in either direction:

  • An editor sending to a background process that is not running: dropped.
  • A background process sending to an editor nobody has open: dropped.

Neither call reports it. Two consequences:

  • Never make a message the only way to get something. An editor that can only render after a reply shows an empty box forever when the plugin is down. Render from saved settings first, then enrich when live data arrives.
  • Do not treat a send as a write. If something must survive, put it in settings. Messages are for what is true right now.

Show the offline state rather than hiding it. A dropdown that silently has no options looks broken; one that says the plugin is not connected is an explanation.

Do not send credentials over this channel

It is a channel between two halves of one plugin, but there is still no reason to move a token through it. The editor can read plugin settings directly.

When not to use messaging

A dropdown on an If/Else condition or an Event filter needs none of this. Declare an Options Source and Fluxta asks the plugin for the list itself, then renders the dropdown.

Messaging is for an editor's own UI — a form field, a status line, a test button. Reach for Options Sources first when the thing being filled in is a condition operand.

On this page