Getting started
A Mixlar plugin is a folder of Python that plugs into Mixlar Control, the desktop app that drives the Mixlar One (the USB mixer: ESP32-S3, 480×320 touchscreen, 4 faders, 6 macro buttons, a rotary encoder). Plugins subclass MixlarPlugin to add macro actions, a slider mode, and optionally a device widget — a small panel that renders live on the mixer’s screen.
You write against the Mixlar SDK: typed, importable classes that are a faithful port of the same code the app itself uses. Off-app, from mixlar import MixlarPlugin gives you a standalone implementation with autocomplete and type checking. Inside the running app, that same import transparently becomes the app’s own live class — so a plugin authored against the SDK loads completely unmodified. No app install or hardware is required to write, lint, or preview a plugin.
Prerequisites
Section titled “Prerequisites”- Python 3.9 or later
pip- Mixlar Control, if you want to test on a real (or hot-reloaded) install — optional for everything up through emulation
Install the SDK
Section titled “Install the SDK”pip install mixlar-sdkThis installs the mixlar-sdk console script (and the mixlar / mixlar_cli Python packages). You can also run it in place with python -m mixlar_cli, which is handy in CI or before an editable install.
A couple of optional extras add capabilities as you need them:
| Extra | Adds | Needed for |
|---|---|---|
[render] |
Pillow | mixlar-sdk emulate --render (widget PNG previews) |
[publish] |
requests | mixlar-sdk publish (nicer HTTP errors; a stdlib fallback works without it) |
[all] |
everything above | “just give me all of it” |
pip install "mixlar-sdk[all]"Scaffold a plugin
Section titled “Scaffold a plugin”Run create with no arguments for a guided wizard — it asks for the name, id, author, description, and template, then writes the folder and prints next steps:
mixlar-sdk create┌ Create a Mixlar plugin│◇ Plugin name shown on the plugin card│ Wave Toggle│◇ Plugin ID lowercase id + folder name│ wave_toggle│◇ Check if 'wave_toggle' is available on pypi.org? (Y/n)│ ⠹ Searching…│ ✓ 'wave_toggle' looks available│◇ Template│ ● 1 full macros + slider + device widget + settings│ ○ 2 macro just macro actions│ …└ Wave Toggle created 🎉Prefer to skip the prompts, or script it for CI? Pass a name (and --yes to accept every default) and it scaffolds straight from flags:
mixlar-sdk create "My Plugin" --template fullcreate derives the folder name from the plugin id, not the display name — "My Plugin" scaffolds into ./my_plugin/. Useful flags:
| Flag | Does |
|---|---|
--template |
one of macro, slider, widget, full (see below) |
--id |
control the id/slug directly instead of deriving it from the name |
--dir |
scaffold somewhere other than the current directory |
--author |
fill in plugin.json |
--force |
overwrite an existing folder of the same name |
Four templates ship in the SDK:
| Template | Gives you |
|---|---|
macro |
a minimal plugin with one macro action |
slider |
a plugin with a slider mode (SliderMode mixin) |
widget |
a plugin paired with a bundled device widget, no macros |
full |
macros + a slider mode + a bundled widget — the showcase, and the default |
A complete plugin, in a few lines
Section titled “A complete plugin, in a few lines”Here’s roughly what create --template full scaffolds — a macro action, a settings-backed HTTP call, and a device widget pairing:
from mixlar import MixlarPluginfrom mixlar.macros import MacroActions, actionfrom mixlar.colors import ACCENT
class MyPlugin(MacroActions, MixlarPlugin): plugin_id = "my_plugin" plugin_name = "My Plugin" plugin_icon_color = ACCENT
#: Pairs this plugin with widgets/my_widget/widget.json. widget_id = "my_widget"
@action("ping", "Ping", icon="fa5s.satellite-dish") def _ping(self, step): self.push_widget_data("status", "pong!") # → WDATA,my_widget.status,pong!
def on_widget_shown(self, widget_id): self.push_widget_data("status", "idle")
def on_widget_event(self, widget_id, element_id, action): if element_id == "ping_btn" and action == "press": self._ping({})MacroActions derives get_macro_actions(), get_macro_action_groups(), get_macro_action_icons(), and execute_macro_step() from the @action decorators, so there’s no boilerplate quartet of empty methods to override. The full hook reference — lifecycle, macros, slider modes, widgets, settings — lives in Plugin API.
The author loop
Section titled “The author loop”Once you have a folder, the day-to-day cycle is edit → validate → emulate → (eventually) pack:
-
Lint the package.
Terminal window cd my_pluginmixlar-sdk validateChecks
plugin.jsonand every bundledwidgets/<id>/widget.jsonfor shape and reference errors. -
Preview the widget, no hardware required.
Terminal window mixlar-sdk emulate --render preview.pngRenders the widget exactly as the device would, to a PNG (needs the
[render]extra). -
Drive it interactively.
Terminal window mixlar-sdk emulate --interactivePress buttons, toggle switches, and slide sliders from a REPL against a headless mock device, and inspect the resulting state.
-
Link it into the app.
Terminal window mixlar-sdk linkCopies (or symlinks) the package into the app’s plugins directory (
%APPDATA%\Mixlar\config\plugins\, overridable with--plugins-dir) so Mixlar Control can load it.
Edit, re-validate, re-emulate, repeat. Once the shape is right, mixlar-sdk link — or the longer-running mixlar-sdk dev, which folds validate + link into a watch loop and re-syncs on every save — puts the package where the app actually loads plugins from.
The app reads plugins from %APPDATA%\Mixlar\config\plugins\<folder>\, each folder being a package with plugin.json at its root. link/dev are just fast ways to keep a copy there in sync with the folder you’re actually editing.
When a plugin is ready to distribute, sign and zip it into a .mixplugin — see Signing and Pack, sign, publish.
Next steps
Section titled “Next steps”- How it works — how the SDK’s classes map onto the live app
- Plugin API — every hook
MixlarPluginexposes - Widget spec — building a device widget for your plugin
- Validate & emulate — everything
mixlar-sdk emulatecan do - CLI introduction — every command, in detail