LUNADASH / PLUGINS

Plugins that run in the compositor.

Native effect plugins change how LunaDash animates, places and lays out windows. Create one with the generator, build it with the CMake SDK and enable it through the control API.

What a plugin is

A plugin is an effect: a shared library loaded into the compositor. For its target feature LunaDash sends a JSON request with the built-in result, and the plugin answers with a complete replacement (replace) or an adjusted result (augment). Each target accepts one enabled plugin. The shell's look is changed in the shell itself, not through plugins.

Plugins are trusted native code. Metadata and ABI checks are compatibility checks, not signing or a sandbox; a crash or hang takes down the compositor. Plugins stay disabled until you enable them.

Create, build and install

GENERATOR
lunadash-create-plugin --list
lunadash-create-plugin --target window-layout --id org.example.layout --output my-layout

Ids match ^[A-Za-z0-9][A-Za-z0-9._-]+$; the generator needs a new output directory.

CMAKELISTS.TXT
cmake_minimum_required(VERSION 3.21)
project(MyLunaDashPlugin LANGUAGES C CXX)
find_package(LunaDashPlugin 2 CONFIG REQUIRED)
lunadash_add_plugin(my_plugin
  METADATA "metadata.json"
  SOURCES Effect.cpp
)
ONE-USER INSTALL
cmake -S . -B build -G Ninja -DCMAKE_INSTALL_PREFIX="$HOME/.local"
cmake --build build
cmake --install build

metadata.json

TERMINAL
{
 "schemaVersion":2,
 "sdk":{"name":"LunaDash","apiVersion":2},
 "id":"org.example.layout","name":"Example layout","version":"1.0.0",
 "author":{"name":"Your name"},
 "type":"effect","target":"window-layout","mode":"replace","entry":"libmy_plugin.so",
 "enabledByDefault":false,
 "settings":{"gap":{"type":"integer","default":12,"control":"slider","minimum":0,"maximum":64}}
}

A package can declare up to 16 implementations in targets, sharing one .so. "windowTemplate":"stacking" on a window-layout replacement selects the overlapping, freely movable window policy.

Targets

TargetResponseValidation
window-animationduration, enterOffset, focusOpacity, exitScale, easingA complete animation profile; turning animations off in Settings still wins.
shell-animation{ duration }One duration from 0 to 600 ms for shell transitions.
window-rules{ workspace, maximized }The rule for a new ordinary window; the workspace must exist.
window-layout{ windows:[{id,x,y,width,height},...] }Every non-minimized id once, positive sizes, inside the work area; overlap only when the template allows it.

The contract

The SDK generates the exported ludash_plugin_entry_v2; you implement ludash_plugin_process(request, response, capacity) and return the UTF-8 JSON length (without the NUL) or a negative value. Hooks run on the compositor thread: never block, keep host pointers or start work that outlives the call.

WINDOW-LAYOUT REQUEST
{
 "target":"window-layout","mode":"replace",
 "context":{"workspace":0,"area":{"x":0,"y":40,"width":1920,"height":1040},"newWindows":[23],"windowTemplate":"tiling","allowOverlap":false},
 "builtin":{"windows":[...]},"current":{},"settings":{"gap":12}
}

builtin is always present; augment also receives the previous valid result in current. Return a complete object. Invalid output keeps the previous valid result and quarantines the plugin.

Plugin settings

Settings use toggle (boolean), select (enum), number and slider (bounded) controls; every field needs a type and a default.

TERMINAL
"settings":{
 "glow":{"type":"boolean","default":true,"control":"toggle"},
 "quality":{"type":"string","default":"medium","control":"select","enum":["low","medium","high"]},
 "strength":{"type":"number","default":0.5,"control":"slider","minimum":0,"maximum":1}
}

Install and enable

An SDK-built package is found under lunadash/plugins/<id> in the XDG data directories, normally ~/.local/share/lunadash/plugins/<id>; the SDK's .lunadash-sdk.json receipt must match the metadata. Enable it in ~/.config/LuDash/extensions.json through the control API:

TERMINAL
lunadashctl extension-save '{"schemaVersion":1,"builtins":{},"plugins":{"org.example.layout":{"enabled":true,"mode":"replace","settings":{"gap":16}}}}'

Disable a plugin before replacing its library, install the new build, then enable it again.

Debug checklist

  1. Check the target with lunadash-create-plugin --list.
  2. Rebuild with LunaDashPlugin 2 after editing the metadata.
  3. Read lunadashctl status → extensions.installed for the status, error and settings.
  4. After fixing, clear the error with an empty extension-error request.