# Getting started This walkthrough builds a plugin that draws a clock on the desktop, then adds a settings page and a tray command. Ten minutes, no LiveWall source needed. ## 1. Create the project ```bash mkdir MyClock && cd MyClock dotnet new classlib -n MyClock -f net8.0-windows ``` Edit `MyClock.csproj`: ```xml net8.0-windows true enable enable latest false runtime ``` If you only have the shipped binaries, reference the DLL instead: ```xml C:\path\to\LiveWall\LiveWall.Sdk.dll false ``` > **Never ship `LiveWall.Sdk.dll` in your plugin folder.** LiveWall loads the contract itself; a second > copy would give you a *different* `ILiveWallPlugin` type and the plugin would be rejected. ## 2. Write the plugin `ClockPlugin.cs`: ```csharp using System.Windows; using System.Windows.Controls; using System.Windows.Media; using LiveWall.Sdk; public sealed class ClockPlugin : ILiveWallPlugin { private TextBlock? _clock; public void Initialize(IPluginContext context) { context.Log.Info("Clock plugin starting"); context.Extensions.AddOverlay(new ClockOverlay(this)); context.Extensions.AddCommand(new PluginCommand("clock.say", "Clock: say hello", cmd => cmd.Host.ShowNotification("Clock", "Hello!")) { Category = "Clock" }); context.Extensions.AddSettingsPage(new ClockSettingsPage(context)); } public void Shutdown() => _clock = null; private sealed class ClockOverlay : IWallpaperOverlay { private readonly ClockPlugin _plugin; public ClockOverlay(ClockPlugin plugin) => _plugin = plugin; public string Name => "Clock"; public FrameworkElement CreateView(OverlayContext context) { _plugin._clock = new TextBlock { Text = "12:00", FontFamily = new FontFamily("Segoe UI Light"), FontSize = 44, Foreground = Brushes.White, HorizontalAlignment = HorizontalAlignment.Right, Margin = new Thickness(0, 24, 32, 0) }; return _plugin._clock; } public void Update(OverlayState state) { /* wallpaper changed - optional */ } } private sealed class ClockSettingsPage : IPluginSettingsPage { private readonly IPluginContext _context; public ClockSettingsPage(IPluginContext context) => _context = context; public string Title => "Clock"; public string Description => "Colour of the desktop clock."; public FrameworkElement CreateView() { var box = new TextBox { Text = _context.Storage.Get("colour", "#FFFFFF"), Width = 140 }; box.TextChanged += (_, _) => _context.Storage.Set("colour", box.Text); return box; } } } ``` `plugin.json` (copy it next to the assembly, and add `` to the csproj): ```json { "id": "com.example.clock", "name": "Desktop Clock", "version": "1.0.0", "author": "Your name", "description": "Draws a clock on top of the wallpaper.", "apiVersion": "1.0", "entry": "MyClock.dll", "type": "ClockPlugin", "minHostVersion": "1.8.0", "permissions": ["DesktopOverlay", "SettingsUi", "Commands"] } ``` ## 3. Build and install ```bash dotnet build -c Release mkdir "%APPDATA%\LiveWall\plugins\com.example.clock" copy bin\Release\net8.0-windows\MyClock.dll "%APPDATA%\LiveWall\plugins\com.example.clock\" copy bin\Release\net8.0-windows\plugin.json "%APPDATA%\LiveWall\plugins\com.example.clock\" ``` Then in LiveWall: 1. **Plugins** tab → tick **Enable the plugin system** → read the warning → accept. 2. Press **Rescan plugins**. *Desktop Clock* appears with an **unverified** badge. 3. Press **Enable** → the per-plugin warning appears, listing the hash and the three permissions → accept. The clock appears on your desktop. The folder can be opened from the app: **Plugins ▸ Open plugin folder**. ## 4. Debugging * Everything you log goes to `%APPDATA%\LiveWall\logs\livewall-YYYYMMDD.log`, prefixed with your plugin id: `[com.example.clock] Clock plugin starting`. * `Plugins ▸ Plugin log` shows the same summary in the app, and **Advanced ▸ Diagnostics** includes a `— Plugins —` section with each plugin's state, hash and permissions. * Attach a debugger with **Debug ▸ Attach to Process ▸ LiveWall.exe**. Your plugin's exceptions are visible in the Visual Studio exception window; `Initialize` is called on the UI thread. * Edit → **Rescan** reloads your assembly without restarting LiveWall (the collectible load context really does unload — see [troubleshooting.md](troubleshooting.md#unloading)). * After changing code, rebuild, overwrite the DLL, and press **Disable** then **Enable** (or Rescan). ## 5. Next steps * [extension-points.md](extension-points.md) — every extension point, with the airspace and threading caveats you will hit as soon as you do something real. * [api-reference.md](api-reference.md) — the complete surface. * [examples.md](examples.md) — recipes: custom renderer, source resolver, playlist provider.