Marketplace

Plugins

A plugin is a single script file that extends DMXexpress: paint a new effect layer, add your own window of controls, or restyle the whole console. Download one below, drop it on the app's Plugins window, and it is live — no restart, no compiler.

1

Download

Grab a .rhai file from the registry below — or from any GitHub link someone shares on the forum.

2

Drop it in

In DMXexpress, open Plugins from the toolbar and drag the file onto the window — or press Open folder and copy it there, then Reload all.

3

Enable it

Tick the plugin in the list. Layers start mixing immediately, windows appear under its Window toggle, and looks restyle the console. Untick or Remove any time.

Plugins are sandboxed, but read them anyway

Scripts run inside the app's sandbox: no file, network, or system access, and a runaway loop is stopped by an operation budget. Still, a plugin does drive your rig's DMX output — skim any script before running it in front of an audience.

Registry

Browse plugins.

Community plugins are reviewed before they appear here. The three starters ship inside DMXexpress — download them here anyway if you deleted yours.

Share yours

Submit a plugin.

Host the .rhai file anywhere public — a GitHub repository or release works perfectly — then submit the direct link. Submissions are held for review before they appear in the registry.

For developers

Write a plugin in an afternoon.

Plugins are Rhai scripts — one file, four optional functions, headers at the top. If you can write a for-loop, you can write a light show.

The shape of a plugin

wave_floor.rhai
//! name: Wave Floor
//! version: 1.0
//! author: you
//! description: A sine wave across every dimmer.
//! blend: highest      // mix | highest | add

fn controls() {
    [
        #{ kind: "slider", id: "rate", label: "Rate", min: 0.1, max: 4.0, value: 1.0 },
        #{ kind: "button", id: "kick", label: "KICK" },
    ]
}

// Called ~40x a second while enabled. Return [address, value] pairs.
fn frame(t, rig, state) {
    let out = [];
    for f in rig {
        if f.dimmer > 0 {
            let v = (1.0 + sin(t * state.rate + f.x)) / 2.0;
            out.push([f.dimmer, (v * 255.0).to_int()]);
        }
    }
    out
}

// A window button was pressed. Stash anything you like in state.
fn button(id, t, state) {
    if id == "kick" { state.kicked_at = t; }
    state
}

The four hooks

FunctionWhat it does
controls()Declares the plugin's window: sliders, checkboxes, buttons, labels. Values arrive in state.
frame(t, rig, state)Called every tick. Returns [address, value] pairs painted onto the plugin's own mixer layer.
button(id, t, state)Runs when a window button is pressed; return the new state map.
theme()Returns #RRGGBB strings for accent, surface, text — a console re-tint while enabled.

Each rig entry

FieldMeaning
i, nameFixture index and display name
addr, channels1-based base address and channel count
dimmer red green blue whiteAbsolute address of that channel, 0 if the fixture has none
x y zStage position in metres — fan effects across space

Rules of the sandbox

  • No file, network, or process access — scripts only compute values
  • An operation budget stops infinite loops with an error, not a hang
  • Errors park the hook and show in the Plugins window; fix and press Reload
  • print("...") goes to the app's Log window
  • hsv(h, s, v) is built in and returns [r, g, b]