Skip to content

Getting Started

RadiatorTwo edited this page May 31, 2026 · 8 revisions

Getting Started

This walkthrough builds a minimal LoupixDeck plugin that contributes a single command — clicking the assigned button writes a line to the host log.

Prerequisites

  • .NET 9 SDK
  • An IDE that supports .NET 9 (Rider, Visual Studio 2022 17.12+, or VS Code with the C# Dev Kit)
  • LoupixDeck installed locally so you can drop the built plugin into its plugin folder and watch it load
  • A local copy of the LoupixDeck.PluginSdk NuGet package (build the SDK repository once — it writes the .nupkg to ./nupkg/)

1. Create the project

dotnet new classlib -n MyPlugin -f net9.0
cd MyPlugin

2. Reference the SDK

The SDK is consumed as a NuGet package from a local feed. Add a nuget.config next to the .csproj:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="LoupixDeck.PluginSdk" value="..\..\LoupixDeck.PluginSdk\nupkg" />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
  </packageSources>
</configuration>

Then reference the package:

dotnet add package LoupixDeck.PluginSdk --version 1.2.*

Important: Do not copy the SDK DLL into your plugin's output folder. The host provides the SDK assembly — bundling it causes load conflicts. The default NuGet behavior is correct; do not set <Private>true</Private>.

3. Write the plugin

Replace the generated Class1.cs with MyPlugin.cs:

using LoupixDeck.PluginSdk;

namespace MyPlugin;

public sealed class HelloPlugin : LoupixPlugin
{
    private IPluginHost _host = null!;

    public override PluginMetadata Metadata { get; } = new()
    {
        Id = "hello",
        Name = "Hello Plugin",
        Version = new Version(1, 0, 0),
        SdkVersion = SdkInfo.Version,
        Author = "you",
        Description = "Minimal example plugin."
    };

    public override void Initialize(IPluginHost host)
    {
        _host = host;
        _host.Logger.Info("Hello plugin loaded.");
    }

    public override IEnumerable<IPluginCommand> GetCommands()
    {
        yield return new SayHelloCommand(() => _host);
    }
}

internal sealed class SayHelloCommand(Func<IPluginHost> hostAccessor) : IPluginCommand
{
    public CommandDescriptor Descriptor { get; } = new()
    {
        CommandName = "Hello.SayHello",
        DisplayName = "Say hello",
        Group = "Hello"
    };

    public ButtonTargets SupportedTargets => ButtonTargets.All;

    public Task Execute(CommandContext ctx)
    {
        hostAccessor().Logger.Info($"Hello from {ctx.Target}!");
        return Task.CompletedTask;
    }
}

A few rules baked into this sample:

  • Exactly one concrete LoupixPlugin subclass per assembly. The host picks it by reflection and ignores everything else.
  • Metadata.SdkVersion is always SdkInfo.Version. The host refuses to load a plugin whose SdkVersion.Major doesn't match its own.
  • CommandDescriptor.CommandName is the stable identifier persisted into user button configurations. Treat it as a public API — renaming it later breaks every config that referenced it.

4. Add the plugin manifest

Next to the .csproj, create a plugin.json. The host reads this file before loading the assembly to determine the plugin's identity, SDK compatibility and which DLL to load:

{
  "id": "hello",
  "name": "Hello Plugin",
  "version": "1.0.0",
  "sdkVersion": "1.6",
  "entryAssembly": "MyPlugin.dll",
  "platform": "Windows"
}
Field Purpose
id Stable plugin identifier. Must match the folder name under the host's plugin root and the Metadata.Id in your LoupixPlugin subclass.
name Display name shown in the host UI.
version Your plugin's version. Keep in sync with PluginMetadata.Version.
sdkVersion SDK contract version you compiled against. The host enforces a major-version match (a host on SDK 2.x refuses a plugin built against 1.x).
entryAssembly File name of the DLL containing your LoupixPlugin subclass.
platform Target OS: Windows, Linux, or All for cross-platform plugins. Plugins for an OS the current host is not running on are skipped silently.

Make sure the manifest is copied to the build output by adding the following to your .csproj:

<ItemGroup>
  <None Update="plugin.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

5. Build

dotnet build -c Release

The output lands in bin/Release/net9.0/ and contains both MyPlugin.dll and plugin.json.

6. Install into LoupixDeck

Create a folder named after Metadata.Id inside the host's plugins\ directory (located next to the LoupixDeck executable — see Debugging for details) and copy your DLL and plugin.json into it:

<LoupixDeck install dir>\plugins\hello\
├── MyPlugin.dll
└── plugin.json

Start LoupixDeck. Open the command-selection menu on any button — the Hello → Say hello entry should appear. Assign it, press the button, and the host log shows the line.

Next steps

  • For text that updates on a button (clock, sensor value, scene name) → see IDisplayCommand.
  • For settings UI (API keys, endpoints) → see Settings Page.
  • For dynamic menus listing remote state (OBS scenes, sensors) → see Dynamic Menus.
  • To attach a debugger and iterate quickly → see Debugging.

Clone this wiki locally