Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2be091b
Fix stale dial/scene state after Meld reconnect.
zv1n Apr 18, 2026
adfbd69
Preserve dial state across reconnects; bump to 0.6.3.0.
zv1n May 5, 2026
ae277dc
Refactor connection logic to treat each connection idempotently.
zv1n May 13, 2026
d43bf5a
Fix Stream Deck hydration state
zv1n May 13, 2026
de0f0ac
Migrate Stream Deck plugin to official Node.js SDK
zv1n Aug 2, 2026
b658958
Harden the SDK migration: fix all expert-review findings
zv1n Aug 3, 2026
f56af3e
Add a fake Meld WebChannel server and fix bugs it revealed
zv1n Aug 3, 2026
05e6284
Fix session updates never reaching actions, and cover the gap
zv1n Aug 3, 2026
9c92b7d
Fix defects from the action-layer review, and cover them
zv1n Aug 3, 2026
5381941
Cover the property-inspector runtime with a fake-DOM harness
zv1n Aug 3, 2026
d3b4f6c
Fix bugs and vacuous tests found by the clean-sweep review
zv1n Aug 3, 2026
3832888
Fix round-2 review findings: widget icon, scene TTL, harness fidelity
zv1n Aug 3, 2026
6cd2aaf
Close the last two harness gaps from the round-3 review
zv1n Aug 3, 2026
0edf719
Fix round-4 findings, including a wrong-effect regression
zv1n Aug 3, 2026
be52d26
Fix dial desync after a Meld session restore, and round-5 findings
zv1n Aug 3, 2026
36bf2d8
Fix toggle keys undoing themselves inside Meld's autosave window
zv1n Aug 3, 2026
b8709ab
Fix media stale-scene inertness and three tests that proved nothing
zv1n Aug 3, 2026
745eaee
Model Qt's idle gate, signal subscription and key-press sequence
zv1n Aug 3, 2026
0dd29f9
Pin the toggle TTL and the replay unknown-gain guard
zv1n Aug 3, 2026
4f49fb3
Fix the idle-gate flush and cross-key expiry; pin the toggle TTL prop…
zv1n Aug 3, 2026
f003055
Stop the dial transitioning to a stage Meld refused
zv1n Aug 3, 2026
1fe9429
Cover the retarget guards and pin the media TTL
zv1n Aug 3, 2026
a03f6b7
Harden Meld migrations and reconnect lifecycle
zv1n Aug 4, 2026
3a872e9
Add configurable clip durations
zv1n Aug 4, 2026
17b7f7a
Fix clip duration preset synchronization
zv1n Aug 4, 2026
8a08104
Expand functional test coverage
zv1n Aug 4, 2026
8a57532
Prepare Stream Deck plugin 0.6.4.0
zv1n Aug 4, 2026
b1306a6
Fix reversed active/inactive icon states and bump to 0.6.4.1
zv1n Aug 13, 2026
3386392
Add CI workflow to typecheck and run tests
zv1n Aug 13, 2026
26f653d
Fix for readme language.
zv1n Aug 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm

- run: npm ci

- run: npm run typecheck

- run: npm test
12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
.DS_Store
*.streamDeckPlugin
*.streamDeckPlugin

# Node.js
node_modules/

# Stream Deck build output
*.sdPlugin/bin
*.sdPlugin/logs

# SDK log output when run from the repo root
/logs/
49 changes: 29 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,49 +6,58 @@ To download the current official release, visit our page on the [Elgato marketpl

If you're interested in developing a software intergration with Meld Studio, you can find our API documentation [here](./WebChannelAPI.md). If you have any questions, please join our [discord](https://discord.gg/ZHpeXEw4) and reach out in [`#support`](https://discord.com/channels/1019227275897614337/1019584582913364101).

## Architecture

The plugin is built on Elgato's official [Node.js Stream Deck SDK](https://docs.elgato.com/streamdeck/sdk/introduction/getting-started/) (`@elgato/streamdeck`). It runs as a single long-lived Node process, so there is exactly **one** connection to Meld Studio for the whole plugin, shared by every action and every property inspector.

- `src/plugin.ts` — entry point; registers the 14 actions and starts the Meld connection.
- `src/meld/` — the Meld service layer: a single QWebChannel-over-WebSocket connection (`connection.ts`) with automatic reconnect and a track-observer registry, a typed session model (`session.ts` / `types.ts`), and typed events (`events.ts`).
- `src/actions/` — one file per action, all extending `MeldAction` (`base.ts`), which turns Meld/session/reconnect events into a single declarative `render()` call.
- `src/ui-bridge.ts` — answers property-inspector requests for session data from the one connection; the inspectors under `co.meldstudio.streamdeck.sdPlugin/ui/` never talk to Meld directly.

The build (`rollup`) bundles `src/plugin.ts` into `co.meldstudio.streamdeck.sdPlugin/bin/plugin.js`.

Requires Stream Deck **7.1+** and bundles the **Node 24** runtime (see `manifest.json`).

## Development

We primarily develop on macOS, so these instructions are tailored to macOS. Feel free to submit a PR to update them for Windows if that's your flavor of OS.

1) Check out the repository.
1) Check out the repository and run `npm install`.
2) Run `scripts/install.sh` (optionally, `--fresh` to remove and reinstall).

This will update the plugin in `~/Library/Application\ Support/com.elgato.StreamDeck/Plugins/` if it exists.
This builds the plugin (`npm run build`) and syncs it into
`~/Library/Application\ Support/com.elgato.StreamDeck/Plugins/`.

3) Code away.
4) Run `scripts/install.sh` again to update the install.
3) Code away. Type-check with `npm run typecheck`.
4) Run `scripts/install.sh` again to rebuild and update the install, or use
`npm run watch` to rebuild on save and restart the plugin automatically.

See below for debugging information.

## Debugging:

1. To enable debugging on macOS, run: `defaults write com.elgato.StreamDeck html_remote_debugging_enabled -bool YES` and restart Stream Deck app.
2. Navigation to `http://localhost:23654/` in Chrome.
3. Click on one of the two entries:
The plugin runs in Node, so it is debugged as a Node process, while property inspectors remain web pages.

![](images/screen-list.png)
- **Plugin (Node):** the manifest enables the Node inspector (`"Nodejs": { "Debug": "enabled" }`). Attach a debugger / open `chrome://inspect` in Chrome to connect to the plugin process. Logs are written to `co.meldstudio.streamdeck.sdPlugin/logs/`.
- **Property inspectors (web):** run `defaults write com.elgato.StreamDeck html_remote_debugging_enabled -bool YES` and restart the Stream Deck app, then navigate to `http://localhost:23654/` in Chrome to inspect the inspector pages.

* The blue link shows the Property Inspector page and console log.
* The red link shows the CodePath button press page and console.

Which should yield you:
![](images/screen-list.png)

![](images/debug.png)

From here you can refresh the plugin source from the debug console UI.

For more details: https://streamdecklabs.com/debugging-your-javascript-plugin/

## Packaging

Elgato provides a CLI packaging tool.

[https://docs.elgato.com/sdk/plugins/packaging]

```
$ npm -g install @elgato/cli
$ streamdeck validate co.meldstudio.streamdeck.sdPlugin
$ streamdeck pack co.meldstudio.streamdeck.sdPlugin
$ npm install
$ npm run build
$ npx streamdeck validate co.meldstudio.streamdeck.sdPlugin
$ npx streamdeck pack co.meldstudio.streamdeck.sdPlugin
```

This outputs a file `co.meldstudio.streamdeck.streamDeckPlugin` which can be installed directly.
Or simply `npm run pack`, which builds and packs in one step.

23 changes: 21 additions & 2 deletions WebChannelAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ _Side Effects_: Once streaming starts, the `channel`'s `isStreaming` property wi
meld.toggleStream();
```

#### **`registerTrackObserver(trackId: string, context: string)`**
#### **`registerTrackObserver(context: string, trackId: string)`**

Registers an observer for changes to a specific track.

Expand All @@ -519,7 +519,7 @@ const trackId = /* desired track id */;
meld.registerTrackObserver("documentation-context", trackId);
```

#### **`unregisterTrackObserver(trackId: string, context: string)`**
#### **`unregisterTrackObserver(context: string, trackId: string)`**

Unregisters an observer for a specific track.

Expand Down Expand Up @@ -616,6 +616,25 @@ meld.sendCommand("meld.screenshot");
| `meld.replay.show` | Show replay layer for last clip. |
| `meld.replay.dismiss` | Dismiss all active replay layers. |

#### **`sendCommandWithArgs(commandName: string, args: any[])`**

Triggers a custom command with positional arguments.

**Parameters**:

| property | type | description |
| -------- | ---------- | ----------------------------------- |
| commandName | `string` | Command to trigger in Meld. |
| args | `any[]` | Positional arguments for the command. |

```js
meld.sendCommandWithArgs("meld.recordClip", [30]);
```

`meld.recordClip` accepts at most one argument: a finite, non-negative clip
duration in seconds. Its advertised range is 0–90 seconds; omitting the
argument, or passing `0`, records the maximum available duration.

#### **`sendStreamEvent(type: string, data?: any)`**

Dispatches a widget-specific event to Meld Studio (e.g., stopwatch, countdown, confetti, subathon timer, wheel spin).
Expand Down
28 changes: 21 additions & 7 deletions co.meldstudio.streamdeck.sdPlugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ And we're not done yet! We are continually working to bring you even more capabi

## What's New

Version 0.6.2.1
- Added Widget control actions for controlling the counter widget in Meld Studio.
- Added Mute and Cue controls to the Replay Clip action.
Version 0.6.4.1
- Added configurable durations to the Record Clip action. Choose a 10, 15, 30, 60, or 90 second preset, or enter a custom duration from 0 to 90 seconds.
- Improved action state synchronization and recovery after Meld Studio reconnects and session restores.
- Fixed reversed active/inactive icon states on the Cue, Layer Visibility, Effect Visibility, Record, Go Live, and Change Scene actions so thirdparty icon packs indicate correctly with Meld Studio actions.

## Helpful Links

https://meldstudio.co/

## Information

Stream Deck 6.0 and later, macOS 12.3 and later.
Stream Deck 7.1 and later, macOS 12.3 and later.
Languages: English, German

## Support Links
Expand All @@ -34,6 +35,22 @@ hi@meldstudio.co
# Change History:
------------

## 2026-08-12 (v0.6.4.1)
### Changes:
-----------
- Refactored the plugin onto Elgato's official Node.js Stream Deck SDK.
- Optimized Meld Studio interactions for all actions.
- Added configurable durations to the Record Clip action. Choose a 10, 15, 30, 60, or 90 second preset, or enter a custom duration from 0 to 90 seconds.
- Improved action state synchronization and recovery after Meld Studio reconnects and session restores.
- Fixed reversed active/inactive icon states on the Cue, Layer Visibility, Effect Visibility, Record, Go Live, and Change Scene actions so thirdparty icon packs indicate correctly with Meld Studio actions.


## 2026-05-13 (v0.6.3.2)
### Changes:
-----------
- Fixed a bug in how dials and scene change actions store state.


## 2026-01-22 (v0.6.2.1)
### Changes:
-----------
Expand Down Expand Up @@ -91,6 +108,3 @@ hi@meldstudio.co
### Changes:
-----------
- Initial implementation of 6 core features (Scene Selection, Layer Visibility, Effect Visibility, Mute Audio, Stream, and Record).



29 changes: 0 additions & 29 deletions co.meldstudio.streamdeck.sdPlugin/actions/clip/inspector.html

This file was deleted.

15 changes: 0 additions & 15 deletions co.meldstudio.streamdeck.sdPlugin/actions/clip/plugin.js

This file was deleted.

70 changes: 0 additions & 70 deletions co.meldstudio.streamdeck.sdPlugin/actions/media/inspector.html

This file was deleted.

Loading
Loading