Skip to content

Repository files navigation

StreamDeckPluginSharp

Cross-platform .NET 8 SDK for Elgato Stream Deck WebSocket plugins.

This repository is not a USB HID driver. Stream Deck Module / direct hardware protocols are out of scope. The SDK talks to the Stream Deck application over the official plugin WebSocket.

Why this SDK

streamdeck-tools 7.0 already covers Windows + macOS drawing via SkiaSharp. StreamDeckPluginSharp focuses on the remaining gaps:

  • Full Stream Deck plugin protocol v2.0 coverage (didReceiveDeepLink, deviceDidChange, secrets, resources, setTriggerDescription, Stream Deck + dials, and more)
  • Async-first handlers that return Task and accept CancellationToken
  • System.Text.Json, no Newtonsoft / NLog / CommandLineParser dependency
  • Shared stateful services through Microsoft.Extensions.DependencyInjection
  • Property Inspector bindings so React forms stay in sync with C# settings without handwritten WebSocket glue
  • Windows + macOS packaging from the first sample (CodePath / CodePathMac, self-contained publish)

Quick start

await StreamDeckPlugin.RunAsync(args);

[StreamDeckAction("dev.example.plugin.counter")]
public sealed class CounterAction : KeyActionBase<CounterSettings>
{
    public override async Task OnKeyDownAsync(ActionPayload payload, CancellationToken cancellationToken)
    {
        await UpdateSettingsAsync(settings => settings.Count++, cancellationToken);
        await SetTitleAsync(Settings.Count.ToString(), cancellationToken: cancellationToken);
    }
}

Share an external connection across every key:

var builder = StreamDeckPlugin.CreateBuilder(args);
builder.Services.AddSingleton<ObsConnectionService>();
await using var plugin = builder.Build();
await plugin.RunAsync();
public sealed class MuteAction(ObsConnectionService obs) : KeyActionBase<MuteSettings>
{
    public override Task OnKeyDownAsync(ActionPayload payload, CancellationToken cancellationToken)
        => obs.ToggleMuteAsync(cancellationToken);
}

Implement IPluginService on that singleton to start and stop the remote socket with the plugin process. Inject IStreamDeckConnection when background code needs to update titles or images.

Property Inspector

Mark contracts with [TypeScriptContract], generate TypeScript, and bind inputs:

const { settings, bind } = useSettings<CounterSettings>();
return <input type="number" {...bind("increment")} />;

StreamDeckProvider owns connectElgatoStreamDeckSocket. See docs/property-inspector.md.

Sample

samples/CounterSample shows:

  • a keypad action and a Stream Deck + dial sharing one CounterStore
  • typed settings synchronized with a React inspector
  • publish.ps1 / publish.sh for win-x64, osx-arm64, and osx-x64
  • ./pack.ps1 (or ./pack.sh) for NuGet packages and a .streamDeckPlugin installer
./samples/CounterSample/publish.ps1 -Install -Pack

Packages

Package Purpose
StreamDeckPluginSharp Plugin host, actions, protocol
StreamDeckPluginSharp.TypeGen (sdps-typegen) C# → TypeScript contracts
@mikanseilaboratory/streamdeck-pi-client React hooks for inspectors (shared with StreamDeckPluginRust)

Documentation

Build

dotnet test StreamDeckPluginSharp.sln
./pack.sh   # or pack.ps1 on Windows

GitHub Actions runs tests on every push/PR and uploads NuGet packages and the sample .streamDeckPlugin. Tag v* to create a GitHub Release and publish to nuget.org via OIDC Trusted Publishing.

Do not store a long-lived NUGET_API_KEY.

One-time nuget.org setup:

  1. nuget.org → account menu → Trusted Publishing → add a policy:
    • Repository owner: MikanseiLaboratory
    • Repository: StreamDeckPluginSharp
    • Workflow file: release.yml (file name only)
  2. In this GitHub repo, add Actions variable NUGET_USER set to your nuget.org profile name (not email).

The Property Inspector client is published from streamdeck-pi-client.

License

Apache License 2.0

About

C# StreamDeck Plugin SDK with Cross platform support and PropertyInspector type generation

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages