Internal · SpaceMusic · Platform Memo
The Factory
A web platform that turns SpaceMusic’s exports into a curated, automated production line — built almost entirely as a surface over infrastructure we already run.
The loop we’re building
Imagine logging in one morning to a feed of five hundred sculptures the machine produced overnight — each a variation on a theme — scrolling them like a photo roll, starring the dozen that stop you, and then, from a favourite, asking for “fifty more like this one but tighter.” That review-and-refine loop is the whole product. Everything else is plumbing in service of it.
Concretely the loop has five moves: an artist authors a parameter sweep on the web; the SpaceMusic engine renders one exported artifact per variation; the artifacts land in a feed; a human curates the winners; and a favourite refines into the next, narrower sweep. Round and round, each pass converging on what you actually like. The pleasant surprise — and the point of this memo — is that we are far closer to having this than it feels, because most of it is a new surface over storage, identity, and a message bus we already operate.
Figure 1 · The author → render → curate loop Open full size · print A3 landscape ↗
The single arrow that makes this a loop rather than a pipeline is the coral one: a curated favourite carries the exact parameters that produced it, so “more like this” is a machine-answerable request, not a vague wish. That return edge is the whole reason the platform is worth building instead of just dumping files in a folder.
SpaceMusic is two products
SpaceMusic runs as one program but serves two jobs. One is a live instrument: an artist drives geometry in real time to audio, on stage or in the studio, and the Pro UI at ui.spacemusic.tv is the control surface for that. The other is an artifact factory: run scenes unattended, vary their parameters, and export the results to be 3D-printed or laser-cut. Nobody watches the factory run — the output is the files.
This memo is about the factory half, and the split matters because it tells us where each piece belongs. Authoring a batch needs data — the scene’s parameter list, its saved values, the current contents of the audio-file folders — and all of that is already web-native: it lives in the cloud library, not locked inside a GPU. Only the rendering needs the machine. So the factory’s control room belongs on the web, next to the library and the feed, with SpaceMusic reduced to a render worker that takes instructions and produces files. The instrument and the factory are different rooms; we should not try to run both from one panel.
The one thing to build
Here is the uncomfortable truth the reconnaissance turned up, and it reshapes everything: SpaceMusic does not record what it makes. Today an export is a bare geometry file plus a thumbnail, synced to cloud storage as anonymous bytes. There is no record, anywhere, of which parameters produced which artifact. The web only “sees” a new result by re-listing a folder. Every hard thing you want — a searchable feed, favourites, “more like this,” even the print pipeline’s need to know an object’s source — is blocked by that one missing fact.
So the platform has exactly one thing at its heart, and everything else is a view over it: a provenance row — one record per exported artifact, holding the artifact’s location, the scene and the exact parameter values that made it, and its outcome. The feed is a query over these rows. Curation is a couple of columns on them. “Refine from this favourite” is reading a row’s parameters back into the authoring tool. And the same row is what the 3D-print pipeline needs to trace an object back to its origin. Build the provenance row well and the platform mostly falls out; skip it and you have rebuilt today’s blindness behind a nicer screen.
“If we fix only one thing, make it this: a record of what each result is and how it was made. Everything else is a view over that record.”
Two planes, one gateway
We are not standing up a new service. The backend is already a single web gateway at api.spacemusic.tv that owns cloud storage, per-user identity, signed upload links, and a real-time message bus — plus a small database pattern we can copy for a results table. The factory adds a few tables and endpoints there, an ingest hook, and a new artist-facing app. That is the entire new footprint.
The cleanest way to reason about how a result travels is to separate two planes — a control plane that carries instructions and status, and a data plane that carries the actual files. Each has exactly one source of truth, and keeping them apart is what makes an unattended factory debuggable.
Figure 2 · The two-plane architecture Open full size · print A3 landscape ↗
Follow the two colours. On the data plane (blue), the worker uploads each artifact to the factory bucket together with a small export.json sidecar; the bucket landing fires a notification that upserts a provenance row; the app’s feed reads those rows. The bucket is the source of truth for what was produced, which means anything that drops a sidecar there — even a manual upload or a future non-SpaceMusic tool — gets indexed for free. On the control plane (grey), the app submits an authored batch, and the worker — a signed-in SpaceMusic Host on a GPU box in the studio — pulls the next queued job, leases it, and heartbeats progress. It reaches outward, so nothing in the studio needs to be exposed to the internet, and a worker that crashes simply drops its lease and the job requeues.
The seam, and staying honest
Two programs written at different times now have to agree on one thing: the batch file. Authoring happens on the web; execution happens in the engine; the .smbatch file is the only coupling between them. This is the seam that fails silently — if the web asks for “audio file = track05” in a spelling the engine does not recognise, the engine renders the whole batch on the wrong input and reports no error. A silent wrong answer is worse than a loud failure.
Two commitments defuse it. First, one generator owns both sides. The same tool that tells the web what parameters exist (the scene’s parameter schema) also defines the batch file’s vocabulary, so the two cannot drift apart — values are spoken as stable parameter paths and library file-paths, never as internal engine keys. Second, the factory reports what it skipped. The worker validates each parameter write at run time, and anything it cannot apply becomes a visible skip on the job record, not a missing row nobody notices. A batch is only “complete” when the results produced plus the steps skipped add up to the number requested, and the feed states it plainly: “480 results · 20 skipped, 18 because a parameter would not apply.” The factory is allowed to fail; it is not allowed to lie by omission.
What we are deliberately not building
A platform is defined as much by its edges as its features. These are out, on purpose:
- Multi-tenant sharing and roles. The factory is an internal production tool for our own studio, not a feature we ship to SpaceMusic customers — it would not even transfer in a sale of SpaceMusic. So for now everyone works under a single shared studio account; no workspaces, no per-user permissions, no team ACL. shared studio account · schema keeps a cheap source/owner column, nothing more
- A generic multi-tool framework. SpaceMusic is the one producer that matters. We design SpaceMusic-first with a clean ingest contract (files plus a sidecar); “another tool could post here” then falls out of that contract for free, without building a plugin system for tools that do not exist yet.
- Live scene transitions. Cross-dissolving between scenes is a separate, larger, in-engine project. Between batch runs it is a plain hard cut — nobody is watching the factory, so it does not matter.
- The live instrument. The Pro UI stays its own surface. The factory is the async half; folding real-time control into it would confuse two very different modes.
A few genuinely open details remain — they shape the build, not the decision: the engine needs a reliable “geometry has settled” signal before it fires each export (the main correctness risk); the results that already exist have no sidecar and need a one-time backfill; and a drag-and-drop upload path for non-SpaceMusic results can wait. None of these block the shape above.
The build, staged
The design is arranged so we get something useful early and defer the hard engine work. Each rung stands on its own; we can pause at any of them and still be better off than today.
Figure 3 · The staged build Open full size · print A3 landscape ↗
P0 is the spine: the new app, single sign-on, and the results/jobs/projects tables in the gateway. P1 is the one to notice — a feed and library viewer over the exports we already have. It is immediately valuable, because we do not currently have any way to browse our own library, and it de-risks the provenance core without touching the engine at all. It also forces one small, healthy change: the desktop starts writing the export.json sidecar, and a one-time backfill indexes what already exists. P2 adds the automation half — authoring, dispatch, and the render worker — feeding new results into the P1 feed. P3 closes the loop with refine-from-favourite and multi-parameter sweeps, and hands selected results to the 3D-print pipeline.
The order is deliberate: the biggest, riskiest piece — the engine’s timing gates and the authoring seam — is deferred to P2, after a useful library viewer already exists. If the automation work slips, we still shipped the thing we most obviously lack today: a place to see what we have made.
Glossary
Terms and proper nouns used in this memo, in plain language.
- provenance row
- The one record per exported artifact that holds its location, the scene and parameter values that produced it, and its outcome. The heart of the platform.
- artifact
- One exported thing — a geometry file (
.3dm), a screenshot, or a scene — plus its thumbnail. - export.json
- A small “sidecar” file written next to each artifact recording what made it. The ingest contract: whatever lands in storage with one of these gets indexed.
- sweep
- Running one scene many times while varying parameters — a slider from A to B in N steps, or a dropdown through all its options — exporting each result.
- .smbatch
- The file that describes an authored sweep. Produced on the web, executed by the engine; the only coupling between the two.
- control plane
- The instructions-and-status side: submitting batches, leasing jobs, reporting progress and skips. Source of truth for what happened.
- data plane
- The files side: uploading artifacts and their sidecars, indexing them as rows. Source of truth for what was produced.
- pull-with-lease
- The worker asks the server for the next job, claims it for a while, and reports in. Avoids exposing the studio machine; recovers automatically if it crashes.
- Render worker
- A signed-in SpaceMusic Host on a GPU machine that runs batches and uploads results. The “machine” in “author on the web, render on the machine.”
- MinIO
- The S3-compatible cloud storage we run; holds the artifacts.
- API gateway
- The single web backend at
api.spacemusic.tvthat already owns storage, identity, signed links, and the message bus; the factory adds tables to it. - SMCodeGen
- Our generator that emits the scene parameter schema; here it also owns the
.smbatchvocabulary so the two cannot drift. - Pro UI
- The live-control web surface at
ui.spacemusic.tv— the instrument, not the factory. - fabricationStatus
- A result’s production state (queued / printing / done), kept separate from “favourite.” Liking a shape is not the same as deciding to make it.
- Inbox
- The default project that catches ad-hoc or manual results so nothing exists without a home.
- Authentik / SSO
- Our single sign-on. One login carries identity across the sibling web apps.
The core bet
Provenance first
One record per result — artifact, the parameters that made it, and its outcome. The feed, curation, refine-loop, and print hand-off are all views over it.
Ship first
P1 — the feed + viewer
A library browser and results feed over today’s exports. Useful on day one, de-risks the provenance core, needs no engine work.
Held back
The automation half
Authoring, dispatch, the render worker, and the honesty guarantee land in P2 — deferred behind a working viewer so a slip costs less.