XOSC
Forward any USB input — keyboard, MIDI, gamepad, serial — as OSC, to anything.
XOSC is a tiny Windows desktop utility that listens for keyboard, MIDI, gamepad, or serial input and forwards it as OSC over UDP — to Resolume Arena, Avolites, QLab, or anything else that speaks OSC. The mapping graph is React Flow in an Electron renderer; the Node main process owns the OSC sender, serial port, and global hotkeys. Built for VJs and live-event operators who want "press the button you want to bind" plumbing without writing a driver.
- TypeScript
- Electron
- React
- React Flow
- Astro
- Web MIDI API
- HTML5 Gamepad API
- node-osc
- node-serialport
- NSIS
- GitHub Actions
XOSC opens a UDP socket and turns whatever the
operating system reports — a key on a USB keypad, MIDI Note 60
on channel 1, button 9 on a generic gamepad, the ASCII line
"BTN1_DOWN\n" coming out of an Arduino at
115 200 baud — into an OSC packet at
127.0.0.1:7000. Designed for Resolume Arena; works
for any OSC receiver. One window, no daemons, no service to
install.
The input matrix
- Keyboard — any key code with modifier capture (Ctrl / Alt / Shift / Meta). Discrete trigger, plus ASCII string payload for receivers that want the raw key name.
- MIDI via Web MIDI — Note On/Off, CC, Pitch Bend, Program Change. Channel and note number forward as OSC args; CC numbers fan out to addressable output nodes.
- Gamepad via the HTML5 Gamepad API, polled at 60 Hz. Buttons fire discrete triggers; axes forward raw floats. Up to four pads addressable independently.
- Serial on any COM port via
node-serialport, line-buffered. Each unique line is its own trigger — wire an Arduino with five push-buttons and you have five named OSC events.
Signal chain
Capture → match → emit. The OS reports an
event; the input bus normalizes it to a stable signature
(midi:noteOn:1:60, kbd:F13,
serial:COM4:BTN1_DOWN); the React Flow mapping
graph routes it to every wired output node; each output node
owns its host:port and emits a UDP packet. Pulse,
Toggle, and Hold arg modes
determine the payload shape. Multiple outputs fire in parallel
— fan out to two Resolume machines, an Avolites desk, and a
QLab cue stack at the same time.
How it's split
The renderer is React + React Flow: the mapping graph, the
listeners that don't need Node (keyboard, Web MIDI, Gamepad
API), and every UI surface. The main process owns the
Node-only pieces: the node-osc UDP sender,
serialport for COM input, Electron's
globalShortcut for system-wide hotkeys, and a
JSON config file at %APPDATA%\XOSC. IPC is a thin
command channel — the renderer asks main to send OSC, register
a shortcut, or open a serial port; main streams events back.
Ten themes, no purple-cyan-glossy
The whole UI is driven by a flat token map applied to
:root — eight dark themes (Solder, Phosphor,
Blueprint, Sodium, Rack, Console, Vapor, Obsidian) and two
light (Bone, Newsprint). Each one repaints both the marketing
site and the in-app graph live with no reload. The defaults
are tuned for FOH operators staring at the screen for hours
— high-contrast monospace, no gloss, no gradients, no glow.
How it ships
Tagging vX.Y.Z kicks GitHub Actions, which builds
on windows-latest, runs NSIS for
the installer, and uploads
XOSC-Setup-X.Y.Z.exe to the GitHub release. The
Astro site at xosc.gamingworld.uk
auto-fetches the latest release for its download button. The
whole pipeline is just release patch →
git push --tags. Currently Windows-only and
unsigned; macOS / Linux builds are scoped for after the
mapping-graph editor lands its v0.2 polish pass.
Why "XOSC"
The X stands for "any" — any input, any output, any receiver. The original brief was a single binding for one Resolume macro from a USB foot-pedal; once the mapping graph existed, every other input class was a half-day of plumbing. The whole project is the FL-Studio "press the button you want to bind" experience, applied to OSC.
Straight from the source
The project's own README.
Rendered in place — every link, image, and code block carried over from the repo. The page below is what a contributor would see opening the project for the first time.
XOSC
Map any input → any OSC. Built for Resolume, works for anything.
XOSC is a tiny Electron app that listens for keyboard, MIDI, gamepad, or serial input and forwards it as OSC to Resolume Arena/Avenue (or any OSC receiver).
It's the FL-Studio-style "press the button you want to bind" experience, applied to OSC plumbing.
- Site & download: https://xosc.gamingworld.uk
- Platform: Windows 11 only (Peak Technologies publisher; unsigned).
Repo layout
xosc/
├── VERSION # single source of truth
├── justfile # `just` for everything
├── package.json # Electron app
├── electron/ # main + preload (Node)
├── src/ # renderer (React)
├── installer/nsis/ # NSIS script
├── scripts/ # bump-version, changelog
├── web/ # Astro site (xosc.gamingworld.uk)
├── docs/ # markdown source — published to web
├── CHANGELOG.md # auto-appended on release
└── .github/workflows/ # build + release + deploy
Building
You need: Node 20+, just, and on Windows: NSIS for the installer.
just # list recipes
just dev # hot-reload Electron
just build # produce dist/xosc-X.Y.Z.exe
just package # + NSIS installer dist/XOSC-Setup-X.Y.Z.exe
just release patch # bump → build → package
Cutting a release: tag vX.Y.Z and push. GitHub Actions builds on windows-latest and uploads the installer to the GitHub release. The website auto-fetches the latest release for its download button.
Architecture in one paragraph
Renderer holds the mapping graph (React Flow), input listeners that don't need Node (keyboard / Web MIDI / Gamepad API), and every UI surface. Main process owns the things only Node can do: node-osc UDP sender, serialport for serial input, globalShortcut for system-wide hotkeys, and a JSON config file in %APPDATA%/XOSC. IPC is a thin command channel — the renderer asks main to send OSC, register a shortcut, or open a serial port; main streams events back.
See docs/ for the user-facing manual.
Build something like this
Want a tool like this for your shop?
We've shipped this kind of thing before. Twenty-minute intro call, no slides.