Releases: stoatworks-labs/blackmatrix
Release list
BlackMatrix v0.2.2
Fixes the lock button, which did nothing — and renames it, because "lock" was
promising something it could not do.
Lock ownership is per IP address. That is the Videohub spec's rule, and it is
why two panels on one machine share a lock: an owner routes straight through
its own lock. The browser sits at that address too, so the one client a lock
never stopped was the one that set it.
- A destination is now claimed, not locked. Claim a row and it crosshatches:
its crosspoints stop taking clicks, it cannot be staged into a take, and the
flag on the row is how you release it. That holds against whoever made the
claim, which is the whole point of pressing it. - Panels are unaffected. On the wire a claim is still the protocol's lock,
owned per address, and an owner still routes through its own — the stricter
rule applies only to this app's own API. - The row says "claimed by you" rather than "claimed by 127.0.0.1" when the
claim is yours.
Also in this release, from the same report: the demo offered ten routable
multiview windows for an ATEM Mini. The base Mini has no multiview output at
all, the Mini Pro and Pro ISO have a fixed ten-window layout that takes no
source, and only the Extreme models route their windows. The model list now
offers no multiview destinations for those, or for their SDI twins.
Thanks to the tester who found both.
BlackMatrix v0.2.1
Fixes the Windows desktop app, which could never start the server.
Tauri's resource_dir() is current_exe().canonicalize(), and on Windows that
returns a verbatim \\?\ path. Win32 performs no normalisation inside one, so a
forward slash stops being a separator: the launcher's {resource}/node resolved
to nothing, the .exe fallback's existence check was false for both spellings,
and clicking Start did nothing at all — silently, with no error in the panel.
- Windows paths are de-verbatimed and spelled with backslashes before anything is
spawned or read. - The spawned server no longer pops a console window over the panel.
- The gear button reports the real config directory instead of a hardcoded macOS
path.
macOS and Linux are unaffected by the path fix.
Verified end to end on Windows 11 x64: the panel reaches RUNNING, the embedded
runtime spawns, and the server answers.
Also in this release, and not Windows-specific: the desktop bundle was
missing @av/ascii-matrix, one of the three workspace packages the server
imports, so the embedded server exited at startup on macOS and Linux too. The
bundle now vendors whatever the server actually depends on, and the build fails
if something it imports is not there.
BlackMatrix v0.2.0
Failover for redundant media servers
A redundant media server rig is two machines playing the same show and a router downstream deciding which one reaches the screens. This release makes an ATEM fleet that router, in both of the shapes the industry uses — and, because an ATEM re-syncs its inputs, main and backup do not have to be genlocked to each other for a clean cut, which an SDI router does require.
The media server drives it. disguise's understudy sends matrix routing itself the moment it takes over a failed machine; PIXERA fires a control action at a matrix switcher from its System Lost trigger. Both can already point at the Videohub emulation. Three things in it would have bitten a client written against a real router rather than the 2018 document, and all three are fixed:
END PRELUDEnow closes the opening status dump. It is not in the published v2.3 spec, but real firmware sends it and a client may wait for it.- A bare request for a section this device has none of — monitoring outputs, serial ports, processing units — is answered with an empty block instead of
NAK. A NAK reads as a broken router. - An output whose source cannot be named is left out of the routing block rather than sent as
-1, which is not a thing the protocol can say.
videohub.modelName and videohub.protocolVersion are overridable for a driver that checks them.
The lock trap, which is the one that loses a show. A refused route is answered with ACK and an unchanged status — what the spec requires, and what a media server that fires and forgets never reads. So a locked destination was a failover that silently did not happen. videohub.failoverClients names the addresses whose routes walk through a lock, and says so in the log. Legality is never overridden.
A plain line protocol
New @av/ascii-matrix, on TCP and UDP (ascii.enabled, port 9995), for everything that can send a string but not speak Videohub — disguise's generic Telnet Matrix, PIXERA's TCP module, 7thSense, a show controller.
ROUTE 2 1 route output 2 to input 1
1*2! the same thing, Extron style
SALVO backup fire a salvo by name
3. fire the third salvo (Extron preset recall)
FAILOVER main fire a watch's lost salvo
Extron-shaped requests get Extron-shaped answers, because a driver sending 1*2! is waiting for Out2 In1 All. Numbers are one-based and the greeting says so.
Failover watches
For the rig whose media server cannot drive a matrix at all: watch a TCP port, a URL, or a heartbeat it must be sent, and fire an ordinary salvo when it stops answering. Ordinary is the point — the failover can be rehearsed by pressing Take on it.
It will not fire before it has seen the machine working once (an unbooted rack looks exactly like a dead one), it starts disarmed, it fires once, and it does not switch back unless a restored salvo says what back means. Triggerable by hand from the UI, over REST, or over the line protocol.
Also
- Mock ports are overridable (
BLACKMATRIX_PORT,BLACKMATRIX_VIDEOHUB_BASE_PORT,BLACKMATRIX_ASCII_PORT,BLACKMATRIX_MOCK_ROUTER_PORT), so a second copy can run beside one already up. docs/failover.mdis the survey of how disguise and PIXERA actually do this, and what to type into their fields.
None of the failover support has been driven by a real media server. It is written from disguise's and PIXERA's published documentation and tested against this repo's own clients.
Installing
macOS installers are signed and notarised and open normally. macOS will still ask for local network access on first run — say yes, or no switcher will be found. The Windows installer is unsigned, so SmartScreen warns once. Container: ghcr.io/stoatworks-labs/blackmatrix.
BlackMatrix v0.1.2
Live and Preset, with Take, Clear and Undo
A router gives an operator two ways to work and this only had one. Live is a crosspoint per click, straight to air. Preset stages a set of changes so you can look at them and then make them happen together — a sequence of visible single cuts is not the same event as one take.
Staged crosspoints are drawn outlined; filled still means on air. The row header reads current → staged, and clicking it drops that one from the take.
Undo restores what a change replaced — but only where that change is still what is on air. If a destination has moved since, by another operator or a panel, undo leaves it alone and says which ones. Overwriting someone else's decision because you pressed undo would be worse than not undoing.
A phone layout
Below 800px the grid is replaced rather than shrunk — a destination list, then the sources that destination will accept. A 4 M/E is 56 sources by 104 destinations; that is not a small-screen layout problem, it is a different interface. Preset is the default at phone width, so a mis-tap stages instead of cutting.
A native iOS app
New, in mobile/. It finds the BlackMatrix server on your network so nobody has to type an address, then shows that server's UI. It does not speak the ATEM or Videohub protocols itself — a phone cannot hold those open, and the panel emulation needs a listening socket.
Built and verified in the iOS simulator. Android is scaffolded but has never been built.
Fixed
- The web was using a stale copy of the routing rules. It had a version of the aux-availability reading from before a real switcher corrected it, so the UI offered "Camera 1 Direct" on outputs the server then refused. There is now one implementation, shared. Verified against the switcher's own masks.
- The support footer survives moving between pages instead of being destroyed with the first one it landed on.
Also
The Stoatworks support footer, with its feedback button, on the Devices and Source routing pages.
Installing
macOS installers are unsigned — Gatekeeper will object on first open, and macOS will ask for local network access on first run. Say yes, or no switcher will be found. Container: ghcr.io/stoatworks-labs/blackmatrix.
BlackMatrix v0.1.1
Use this instead of v0.1.0, which cannot see the network when launched from the Finder.
Fixed: the desktop app could not reach anything
Since macOS 15 an app must declare why it uses the local network, and on macOS 26 the enforcement is thorough: without NSLocalNetworkUsageDescription a GUI-launched app is denied LAN traffic silently — no prompt, no error, sockets simply never arrive. Discovery found nothing and a manually added switcher never connected, and both were that one cause.
It could not be seen in development: a process started from a terminal inherits the terminal's permission, so it only fails once the app is double-clicked. macOS will now ask for local network access on first run — say yes, or nothing will be found.
Easier to add a device
The form asked for an id. That exists so salvos and ties have something stable to point at, which is the app's problem and not yours. It now asks for:
- Address — the only required field
- Type — switcher or router
- Model — defaults to auto-detect, because the device reports its own on connecting. Picking one says what you expect, and a mismatch is flagged on the card: a typo'd address reaching a different box looks exactly like that.
- Name — optional, defaults to the model or the address
{"address": "192.168.1.14"} is now enough to add a switcher: it connects, names itself and takes a panel port.
Also
The Stoatworks support footer, with the "report a bug or send feedback" button, on the Devices page.
Installing
macOS installers are unsigned, so Gatekeeper will object on first open. Container: ghcr.io/stoatworks-labs/blackmatrix.
BlackMatrix v0.1.0
Superseded by v0.1.1. The desktop app in this release cannot see the local network when launched from the Finder — it is missing the macOS local-network declaration, so LAN traffic is denied silently. Use v0.1.1.
First release.
A crosspoint router matrix across a fleet of Blackmagic ATEM switchers and Videohubs — one grid, with Videohub protocol emulation so hardware router panels drive the same crosspoints.
What it does
- Every routable bus as a destination: aux outputs, ME program and preview, upstream and downstream keyer fill and key, SuperSource boxes and art, and every multiviewer window. On the ATEM Mini Extreme ISO this is 39 destinations where Blackmagic's own Videohub server on the switcher offers 5.
- Legality read off the switcher, not from a model table — each input's availability bitmasks decide what may be routed where, so an aux output cannot be routed back onto an aux bus.
- Real Videohubs as devices in the same fleet and the same grid, with the router's own locks.
- Salvos across the whole fleet, and ties that make one destination follow another across boxes.
- Videohub emulation per switcher, so panels, Companion and Blackmagic's software can route it.
- Source routing — which connector feeds each input channel, on models that offer a choice.
- Device management and network discovery in the app: no config file editing.
- Captures: read a switcher's real shape to disk and replay it as a device with no hardware present.
Verified
Against a real ATEM Mini Extreme ISO on 2026-08-21: connected, captured, probed, its matrix served over the Videohub emulation as a 29×39 router, and read back to back against Blackmagic's own Videohub server on the switcher — agreeing on all five destinations they share.
Hardware corrected two rules that shipped wrong in development: multiviewer windows 1 and 2 are not fixed to program and preview, and the aux availability bits say which bus rather than merely "an aux".
Not verified
- No real Videohub has ever been a device, and no hardware router panel has driven the emulation.
- Only the ATEM Mini Extreme ISO has been captured. Other models in the simulator carry approximate shapes, marked as such.
- The desktop app's tray window has not been exercised as a native GUI — the bundled server chain has (it serves the UI from inside the .app).
Installing
The desktop app bundles its own Node runtime; nothing else needs installing. Container users: ghcr.io/stoatworks-labs/blackmatrix. Or run the server directly with npm run build && npm start.
macOS installers are unsigned unless Apple signing secrets are configured, so Gatekeeper will object on first open.
AI-assisted project — see the README.