Internal · SpaceMusic Architecture

The Host at the Center

How SpaceMusic runs today: one Host process launches the engine, serves the web UI, and translates between them.

A host at the center

For most of SpaceMusic's life, "the software" was the vvvv patch — the engine that renders the visuals. Everything else (the control panel, file loading, sharing a screen) lived inside it or beside it. That has changed. There is now a single program in the middle of everything called the Host, and the engine is just one of the things it looks after.

The Host is a small Windows application. From one launch it starts the rendering engine, opens our new browser-based control panel, shows a front-door screen, and — when you want to — bridges the whole thing out to phones, tablets, and remote viewers over the internet. Think of it less as a feature and more as the switchboard: nothing else has to know about firewalls, logins, or the network, because the Host handles all of that and hands each piece exactly what it needs.

This document explains, in plain terms and one main picture, how those pieces fit together today and how a value travels between the engine and the screen.

The pieces

There are four things worth naming. Everything in the diagram later is one of these, or a connection between them.

  1. The Host. The Windows app at the middle. It launches the other parts, serves the control panel as a small local website, and is the only piece that deals with the network and sign-in. It also supervises a video streamer and a relay for the over-the-internet case.
  2. The Core. Our rendering engine — the exported vvvv/Stride program (SpaceMusic.exe) that actually draws the visuals. It publishes its parameters on a local connection and accepts changes back. It knows nothing about the cloud or who is connected; it just renders.
  3. The Pro UI. Our first web-based user interface — the control surface, built as a web app (Svelte) and shown in a browser. It is the long-term replacement for the older desktop (Avalonia) control panel. It does not contain the controls in its code; it reads a description of them and renders accordingly.
  4. The bridge. The translation layer between the Core and the Pro UI — the "API in between." There is no per-button endpoint; it is one live stream of parameter values out to the browser and one stream of edits back in. It isn't a separate program or a server — it's two matching pieces of code (a C# half inside the engine, a TypeScript half inside the browser) speaking one small protocol, with nothing extra to install or host. The same bridge works on the local network and over the internet.

One more input feeds the Pro UI and isn't a running program: the SpaceMusic DNA — our master list of every parameter, where it sits, its range and options. The DNA is turned into a single file, spec.json, that tells the Pro UI what to draw. More on that in section 04.

The whole picture

The diagram below is the one to keep. The Host sits in the middle. To its left it launches the Core (the engine) and a small video streamer; to its right it serves the Pro UI and the front-door Shell into a browser. The engine and the browser talk through the bridge — the highlighted box in the middle. And the DNA, turned into spec.json, feeds the Pro UI the layout it renders.

Figure 1 · The host-centered setup Open full size · print A3 landscape ↗

ONE MACHINE — e.g. THE STUDIO PC SpaceMusic DNA Google Doc → CSV spec.json the UI layout Remote viewers over the web · phone, laptop THE HOST one Windows app — the hub Launches everything · serves the web UIs Proxies the bridge · streamer · WAN relay THE BRIDGE the API in between channels ⇄ browser snapshot · delta · set The Core vvvv engine · Stride render params ws :8788 textures Spout share The Pro UI browser · Svelte first web-based UI reads spec.json + params Texture streamer Spout → H.264 video The Shell front-door launcher build · SMCodeGen relay + LiveKit launches serves video renders layout values out edits in

Read it left to right. The DNA (top left) is compiled into spec.json, which the Host serves to the Pro UI so the browser knows which controls to draw. The Host (center, highlighted) launches the Core and the streamer and serves the Pro UI and Shell. The highlighted box in the middle is the bridge: live parameter values flow out of the engine through it to the browser, and your edits flow back the other way. The engine's rendered visuals reach the browser as video through the streamer. And one arrow leaves the Host up to the right, to remote viewers over the web — the same setup made reachable over the internet, detailed in section 05.

From DNA to spec.json

The Pro UI is deliberately empty of opinions about what to show. It is a renderer: hand it a description of the controls and it draws them; change the description and the screen changes without touching the app's code. That description is spec.json, and it comes from the SpaceMusic DNA.

The DNA is our parameter model — every slider, dropdown, toggle and button; which page and section it lives on; its range, its options, its channel name. Today it is authored in a Google Doc and exported as CSV files. A build step (our code generator) reads those and produces one flat spec.json that lists every control and the menu/status chrome around it. The Host reads that file once at startup and serves it to the browser at /spec.json.

This is the first of the two "translations" in the system, and it happens before anything runs — it is design-time. It turns the human-friendly DNA into a machine-friendly layout the web app can render. (When a session is shared over the internet, the running engine publishes its own copy of this layout over the relay, so a remote screen always matches the engine it is connected to.) The same DNA also still feeds the older desktop UI — one source, two renderers.

"The UI doesn't know your product; it knows your spec. Change the spreadsheet, regenerate, and the panel rebuilds itself."

The bridge in between

The second translation is the live one — what we mean by "the API in between." There is no REST API with an address per button. Instead, the engine and the browser share one small, two-way protocol, shown in Figure 2.

Figure 2 · How a value travels Open full size · print A3 landscape ↗

spec.json (built from the DNA) defines which controls exist The Core live channels the single source of truth The Pro UI controls on screen a thin renderer over the channels publish · MessagePack full snapshot + small deltas write · JSON “set” { op:set, path, value } values out edits in renders from the same loop runs on the LAN (direct socket) and over the web (relay)

It is a loop. The engine continuously publishes its parameter values — a full snapshot when a screen first connects, then only the small changes after that — encoded compactly (MessagePack). The browser decodes them and updates the matching control. When you move a slider or toggle a setting, the browser sends one tiny edit back (a JSON set message); the engine applies it and the change shows up on every connected screen on the next update. Rendered visuals don't travel this wire — they go separately as video through the streamer — which keeps the parameter channel small and fast.

The same loop runs in two places without changing the browser code. On the same machine or the local network — the direct reach — the browser talks straight to the engine's connection (the Host proxies it for other devices on the LAN). Over the internet — the relay reach — the identical values and edits pass through a cloud relay instead, and video goes through a media server (LiveKit). Which one is used is decided automatically by the web address the page was opened from. That is how the same Pro UI works whether you're at the machine or on a phone across the world.

Where the bridge lives, and what it's built from

Worth being concrete here, because "the bridge" sounds like it might be a server somewhere — it isn't. There is nothing extra to deploy and no machine sitting in the middle. The bridge is two matching pieces of code at the two ends, plus the small protocol they share:

On the same machine or the local network, those two talk directly — there is no server between them. The Host (also C#, on the same PC) only forwards the bytes when another device — a phone or tablet on the network — needs to reach the engine's local-only connection; it never reads or owns the data. The one piece that lives off the PC is the relay used for the over-the-internet case: a small service (Centrifugo) on our Hetzner server. Even then it is just a meeting point that passes messages between the engine and a remote browser — the bridge's real work still happens in that C# half and that TypeScript half, never on the server. In short: C# on the engine side, TypeScript on the browser side, both on the PC with the Core; our server only relays, and only when you go remote.

Adding another UI

Because the layout is just data and the engine speaks one small protocol, adding a new UI is mostly a question of how much you want to reuse. There are three honest levels — from an afternoon to a small project — and none of them is a rebuild.

  1. The same Pro UI, a different spec. The Pro UI renders whatever spec.json it is handed. A simpler control surface — a stripped-down "live" panel, say — is just a smaller spec. Same code, same design, no programming. You get this case for free.
  2. A different web UI that reuses our kernel. Someone builds their own interface — their own look, their own controls — and wires it up for real. It does not render our spec; it brings its own widgets. What it reuses is the bridge client: the small, look-agnostic piece that knows how to talk to the engine. Connect, listen to the handful of channels you care about, draw whatever you like, send edits. Modest effort.
  3. A fully independent UI. Reimplement the protocol from scratch, in any language. It is documented — a WebSocket, parameter values out as MessagePack, edits in as JSON. More work (you decode the wire yourself), but zero dependency on any of our code.

So which parts of the Pro UI are truly special — needed, unique, impossible to abstract away? Honestly, almost none. Strip it down and the only thing a new UI must share is that bridge client: a connection (a WebSocket on the LAN, or the relay client over the internet), the wire codec, and a few conventions any UI has to respect — read and write a control's .Value (not its bare name), send the right type tag on a write, and stay within the Project/Settings parameters the engine accepts. That kernel is tiny and has nothing to do with how anything looks.

Figure 3 · What a new UI reuses Open full size · print A3 landscape ↗

above: each UI's own · below: shared THE SHARED FOUNDATION OPTION 1 · EASIEST Same Pro UI, new spec Reuses — the whole Pro UI You build — a new spec.json Effort — trivial, no code OPTION 2 A different web UI Reuses — the bridge client You build — your own widgets Effort — modest OPTION 3 Fully independent Reuses — none of our code You build — widgets + wire decode Effort — most, still small The Core live channels · source of truth THE BRIDGE CONTRACT WebSocket · MessagePack out · JSON set in channel paths · type tags · .Value Bridge client transport + wire codec · optional helper

Everything else the Pro UI does sits above that line and is either optional or swappable: turning a spec into widgets, the control catalog, the library browser, the lobby, sign-in, the texture tiles. The Pro UI's one genuinely unique job is "render a spec into controls" — and a different UI simply brings its own controls instead. So for a prototype that wants to drive a few real parameters, the recipe is short: open the connection, reuse the wire decoder, send a JSON set when a control changes, respect the .Value and type-tag conventions — an afternoon for a handful of controls, not a rebuild. The cleanest investment we could make is to package that bridge client so "connect to SpaceMusic" becomes a one-line import rather than a copy — after which every future UI, ours or not, starts from the same place.

Where the DNA is heading

One link in this chain is still manual: the DNA itself. Today the master list of parameters (section 04) lives in a Google Doc, is exported to CSV by hand, committed, and only then built. That works, but it is the slowest, most fragile step — the spreadsheet is the source of truth, edits are manual, there is no validation and no record of who changed what, and nothing moves downstream until someone remembers to re-export and commit.

The plan (051) gives the DNA a proper home: a self-hosted database called Directus, running at dna.spacemusic.tv, with the data shown and edited through our own diagram.spacemusic.tv skin — diagrams plus an editable grid — and the Directus admin kept as a power-user back door. The DNA stops being a spreadsheet and becomes a real relational model: parameters and their UI placements as linked tables, with types, ranges and options enforced at the data layer. (A proven spike already round-trips the real DNA through it without losing a row.)

What that streamlines:

Crucially, this changes only where the spec comes from, not how anything consumes it. Everything downstream of the DNA — spec.json, the Pro UI, the bridge — is untouched; the platform just makes the source faster, safer, and shared. Put beside the previous section, the shape is clean end to end: a properly-managed model on one side, a small public contract on the other, and any number of UIs in between.

Why this shape matters

"The engine just renders. The Host handles the world. The browser just draws what it's told. Each piece stays simple because the boundaries are clean."

Putting the Host at the center buys us three things. One launch, one place to be: starting the Host brings up the engine and the control panel together, and gives us a single front door for sign-in and sharing — instead of a tangle of separate tools. A simpler engine: because the Host owns the network, logins, and relays, the Core can stay focused on rendering and never has to know who is watching or where from. And a portable UI: the control panel is now an ordinary web app, so the same screen that runs next to the engine also runs on a laptop, a tablet, or a phone over the internet — no rebuild, just a different reach.

The two translations are what make that portability real. The DNA → spec.json step means the layout is data, not code, so the panel can be regenerated from a spreadsheet. The bridge means the engine and the browser share one small protocol that works the same near and far. Together they turn "the SpaceMusic patch on this PC" into "a control surface anyone we authorize can open" — which is the direction the whole product is heading.

The deeper reference for any of this — file by file — lives in docs/web-ui/; this document is the map, those are the streets.

Glossary

Terms used in this document, in plain language.

Host
The Windows app at the center of the setup. Launches the engine and the web UI, serves them locally, and bridges everything to the network.
Core
The rendering engine — the exported vvvv/Stride program that draws the visuals and publishes its parameters.
Pro UI
SpaceMusic's first web-based control surface (a Svelte browser app), replacing the older desktop control panel.
Shell
The front-door screen the Host shows first — for choosing/starting a session and signing in — before the Pro UI appears.
bridge
The live translation layer between engine and browser: parameter values out, edits in. The "API in between," but a stream, not endpoints — and not a server: a C# half runs inside the Core, a TypeScript half inside the browser, both on the PC with the engine.
bridge client
The small, look-agnostic kernel that speaks the bridge — the connection (transport) plus the wire codec. Today it lives inside the Pro UI's code; packaging it would let any UI "import SpaceMusic" instead of copying files.
DNA
SpaceMusic's master parameter model — every control, its place, range, and options. Authored in a Google Doc, exported to CSV.
Directus
An open-source, self-hostable database with an admin UI and an API. Plan 051 uses it to host the DNA at dna.spacemusic.tv, replacing the Google-Doc-to-CSV relay.
spec.json
The single file, generated from the DNA, that tells the Pro UI which controls to draw. The Host serves it at /spec.json.
channel
One named, live value in the engine (e.g. a slider's position). The UI reads and writes channels; the engine is the source of truth.
reach
Which path the browser uses to talk to the engine: direct on the same machine/LAN, or relay over the internet.
relay
The cloud middle-man (Centrifugo for parameters, LiveKit for video), running on our Hetzner server, that lets a remote browser reach an engine behind a firewall. The only part of the bridge path that lives off the PC.
streamer
A small companion program the Host supervises that turns the engine's rendered output into video for the browser to display.
MessagePack
A compact binary format (like a smaller, faster JSON) used to send parameter snapshots and updates to the browser.
Spout
A Windows mechanism for sharing live video frames between programs on the same machine — how the engine hands frames to the streamer.

Working today

Host-centered & live

One launch brings up the engine and the web Pro UI; the bridge carries values and edits both ways, proven on the LAN and over the internet.

Maturing

Over-the-web sessions

Remote viewing, the lobby/front-door, and the shared content library are in active use and still being hardened.

Direction

The DNA platform

The parameter model is moving from a Google Doc toward a proper relational source, with spec.json generated the same way.

SpaceMusic Web UI Architecture · designed for A3 landscape print ← back to the document

Figure 1 · The host-centered setup

ONE MACHINE — e.g. THE STUDIO PC SpaceMusic DNA Google Doc → CSV spec.json the UI layout Remote viewers over the web · phone, laptop THE HOST one Windows app — the hub Launches everything · serves the web UIs Proxies the bridge · streamer · WAN relay THE BRIDGE the API in between channels ⇄ browser snapshot · delta · set The Core vvvv engine · Stride render params ws :8788 textures Spout share The Pro UI browser · Svelte first web-based UI reads spec.json + params Texture streamer Spout → H.264 video The Shell front-door launcher build · SMCodeGen relay + LiveKit launches serves video renders layout values out edits in
SpaceMusic Web UI Architecture · designed for A3 landscape print ← back to the document

Figure 2 · How a value travels

spec.json (built from the DNA) defines which controls exist The Core live channels the single source of truth The Pro UI controls on screen a thin renderer over the channels publish · MessagePack full snapshot + small deltas write · JSON “set” { op:set, path, value } values out edits in renders from the same loop runs on the LAN (direct socket) and over the web (relay)
SpaceMusic Web UI Architecture · designed for A3 landscape print ← back to the document

Figure 3 · What a new UI reuses

above: each UI's own · below: shared THE SHARED FOUNDATION OPTION 1 · EASIEST Same Pro UI, new spec Reuses — the whole Pro UI You build — a new spec.json Effort — trivial, no code OPTION 2 A different web UI Reuses — the bridge client You build — your own widgets Effort — modest OPTION 3 Fully independent Reuses — none of our code You build — widgets + wire decode Effort — most, still small The Core live channels · source of truth THE BRIDGE CONTRACT WebSocket · MessagePack out · JSON set in channel paths · type tags · .Value Bridge client transport + wire codec · optional helper