Beta software, written entirely by AI.Nothing has been reviewed line by line by a human or security-audited. No warranty, no liability: you use it at your own risk.Read more
Skip to content

A real-world plugin: OBS ​

An official C# plugin, shown for reading

The OBS plugin is one of the official C# plugins: it is built and signed by the maintainer, and the server loads a C# plugin only with that signature. Plugins by other authors are JavaScript plugins. This page walks through it because it shows what a full integration looks like.

The OBS plugin (id obs) controls OBS Studio over obs-websocket v5, which is built into OBS 28 and newer. It is the largest plugin in the repository and uses almost everything the SDK offers, so it is the best example to read after the tutorials.

What it provides ​

  • 22 actions in the OBS category: scenes, studio mode, transitions, streaming, recording, replay buffer, virtual camera, audio mute and volume, scene item visibility and text sources.
  • About 45 live variables with the obs. prefix, for example obs.streaming, obs.stream.duration, obs.scene.current, obs.stats.fps, plus obs.input.<slug>.muted and obs.item.<scene>.<source>.visible for things that come and go.
  • A settings page (Enabled, Server, Port, Password) and a status bar item with the connection state.

It requires OBS 28 or newer with the WebSocket server turned on (Tools, WebSocket Server Settings in OBS). The README of the plugin lists every variable and action.

The entry point ​

cs
using MacroGrid.Plugin.Abstractions;

namespace MacroGrid.Plugin.Obs;

/// <summary>Entry point (plugin.json's "entry") — the host finds this type by reflection and instantiates it
/// with a parameterless constructor, then calls <see cref="Initialize"/> once.</summary>
public sealed class ObsPlugin : IPlugin
{
    public void Initialize(IPluginHost host)
    {
        var obs = new ObsConnection(host);
        host.RegisterVariableProvider(obs);
        host.RegisterSettingsPage(new ObsSettingsPage(host, obs));

        host.RegisterAction(new ObsSetSceneAction(obs));
        host.RegisterAction(new ObsSetPreviewSceneAction(obs));
        host.RegisterAction(new ObsStudioTransitionAction(obs));
        host.RegisterAction(new ObsToggleStudioModeAction(obs));
        host.RegisterAction(new ObsSetTransitionAction(obs));
        host.RegisterAction(new ObsSetProfileAction(obs));

        host.RegisterAction(new ObsStartStreamAction(obs));
        host.RegisterAction(new ObsStopStreamAction(obs));
        host.RegisterAction(new ObsToggleStreamAction(obs));
        host.RegisterAction(new ObsStartRecordAction(obs));
        host.RegisterAction(new ObsStopRecordAction(obs));
        host.RegisterAction(new ObsToggleRecordAction(obs));
        host.RegisterAction(new ObsPauseRecordAction(obs));
        host.RegisterAction(new ObsVirtualCamAction(obs));
        host.RegisterAction(new ObsReplayBufferAction(obs));
        host.RegisterAction(new ObsSaveReplayAction(obs));

        host.RegisterAction(new ObsSetMuteAction(obs));
        host.RegisterAction(new ObsToggleMuteAction(obs));
        host.RegisterAction(new ObsSetVolumeAction(obs));
        host.RegisterAction(new ObsAdjustVolumeAction(obs));

        host.RegisterAction(new ObsSetItemVisibilityAction(obs));
        host.RegisterAction(new ObsSetTextAction(obs));
    }
}

One object, ObsConnection, owns the connection. It is registered as the variable provider, handed to the settings page and to every action.

FileRole
ObsPlugin.csIPlugin: creates the connection and registers everything (above).
ObsConnection.cs, ObsConnection.*.csIVariableProvider and IVariableCatalogSource. Runs for the plugin's lifetime: connects, keeps the variables up to date, updates the status item and reconnects with capped exponential backoff. One partial class, split by concern (loop, polling, events, variables, status).
ObsClient.cs, ObsAuth.cs, ObsJson.csA small obs-websocket v5 client: handshake, authentication, requests and events.
ObsState.csA cache of what OBS reported (scenes, inputs, scene items).
Actions/*.csThe actions, grouped by scenes, outputs, audio and sources. They share small base classes (ObsActionBase, ObsOptionsAction, ObsRequestAction, ObsModeAction) and implement IActionHandler, IActionDescriptor and, for dropdowns, IOptionsSource.
ObsSettings.csObsSettings (persisted as settings.json in DataDirectory) and ObsSettingsPage : IPluginSettingsPage.

Patterns worth copying ​

  • A long-running provider. ObsConnection.RunAsync runs until its token is cancelled. It creates its status item with host.CreateStatusItem("connection"), publishes variables through the IVariableStore it is given, and never lets a failed connection end the method: it retries with a capped exponential backoff, and a settings change wakes it up early.
  • Dynamic variables are removed. When an OBS input or scene item is deleted or renamed, the plugin removes its variable with store.Remove(name), so it stops showing up in the picker.
  • Dropdowns from a cache. Actions implement IOptionsSource; the scene, input and item lists come from the cache of what OBS reported, so they do not wait for a live round trip.
  • Clear failures. An action that targets something that no longer exists (a scene that was deleted in OBS) fails with a clear message. The server shows it on the phone and in the editor's status bar, so a stale button is never silent.
  • Settings apply immediately. The settings page's Save writes settings.json and signals the connection, so a corrected host, port or password reconnects within moments.
  • Tests without OBS. WebSocketBridgeForOBS/tests drives the plugin against a fake obs-websocket server (FakeObsServer.cs). Run dotnet test on WebSocketBridgeForOBS/tests/MacroGrid.Plugin.Obs.Tests.

The plugin's user-visible strings (action names, form labels, status text) are written in English and translated to Turkish through WebSocketBridgeForOBS/locales/tr.json; the code, comments and docs are in English, which is the rule for every plugin in the repository.

Using it in a layout ​

  1. Install the plugin (Plugin basics), open its settings from the gear button and turn Enabled on (the plugin starts disabled).
  2. Add a button with the text {obs.scene.current} and bind the set-scene action to it.
  3. Add a label Live {obs.stream.duration} and bind the stream actions to a toggle.

Macro Grid sites: PC · Phone · Plugins
Released under the MIT License. Beta software, written entirely by an AI assistant, provided as is without warranty.