Work xosc
desktop

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.

Versionv0.1.0 Last updateApr 29, 2026 PrimaryTypeScript
  • TypeScript
  • Electron
  • React
  • React Flow
  • Astro
  • Web MIDI API
  • HTML5 Gamepad API
  • node-osc
  • node-serialport
  • NSIS
  • GitHub Actions
XOSC — Forward any USB input — keyboard, MIDI, gamepad, serial — as OSC, to anything.

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 patchgit 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.

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.

Gallery

The full set.

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.