Internal · SpaceMusic Design
The Mobile Control Surface
520 controls, eight pages, four levels of hierarchy — and one thumb. One number sets every height on the screen.
The shape of the problem
SpaceMusic is a real-time visual engine with a control surface to match: eight pages, 520 controls, 1 395 channels. On a desktop that is a sidebar and a wide window. On a phone it is 390 by 844 points, and most of them are already spoken for.
Subtract the two bars and 746 px of body is left. A preview and two navigation strips take it to about eight rows of list. Every page has to resolve into that, and the pages are not evenly shaped: Time carries three controls, Mapping carries 222 across four levels of nesting.
One number defines the screen
Every height on the screen comes out of a single figure: the row unit is the UI width divided by --div. At the default of 8 on a 390 pt phone that is 48.75 px, and because the divisor also sets the column count the grid is square and eight columns wide.
The top bar, the bottom bar, every strip, every section header and every control row are exactly one unit tall. A half unit — the subgrid — carries the gap above a section, the label inside a strip, and the segmented controls in the settings panel.
Figure 1 · One number, every height Open full size · print A3 landscape ↗
The divisor is a live property on every artboard, not a number baked into the boards. If 48.75 turns out wrong on an iPad, change 8 to 7 or 9 and the whole screen re-flows; nothing else has to be touched, because nothing carries a hard-coded height.
The overlay is a switch in the same place. It draws the grid over the design so an alignment error is visible rather than argued about.
Six levels of type
Six hierarchy levels, the way HTML numbers them. Each level owns a family, a size, a weight and a case, and nothing in the interface picks type for itself — a section header is H4 because it is a section header, not because 11 px looked right there.
- H1 — page title. sans 22 / 500
- H2 — tile and instance names. sans 15 / 500
- H3 — control name. sans 14 / 400
- H4 — section header. mono 11 / 500 · caps
- H5 — strip tab, breadcrumb. mono 9 / 500 · caps
- H6 — group label. mono 8 / 400 · caps
Two more sit outside the ramp because they are not headings. VALUE is mono 16 with tabular figures, so the digits do not jitter as you drag a slider. STATE is the On / Off word on a toggle, mono 9 caps.
Every control treated the same
Slider, dropdown, toggle and button share a height, a type size, a padding and a tap target. Only what happens inside the row differs, and one rule governs that: the fill is the value, wherever there is a value to fill.
A slider fills to its position in range. A toggle that is on fills completely. A dropdown has no quantity to show, so it carries no fill at all and the minus / plus cells at the right edge do the work. A button has nothing to fill either, so its row stays empty and only its edge cell is live — which is also what stops a stray drag from firing it.
Centered and not centered
A range that starts at its minimum — Gain from 0 to 1 — fills from the left edge, because that is where the value actually starts. A range built around zero — X Translate from −10 to 10 — fills out of the zero tick, left or right. A value of exactly zero draws no fill at all, just the cursor sitting on the tick.
Colour, and the merge test
The bars invert against the page: black on a light ground, light on a dark one. That is the starting point, and every value behind it is a token, so it can be tuned without touching a board.
One rule constrains the tuning: no element may fall together visually with another. The case that forces it is a slider scrolled up under the bottom bar. In dark mode the bars sit lighter than any fill; in light mode they sit darker than any fill. The bar is always one step further out than the most extreme thing the list can draw, so the two can never dissolve into each other in either theme.
The two bars
Six cells, and every one of them now does something.
- Top left — the logo. It cycles the preview: closed, partial, full.
- Top centre — the wordmark. SPACE over MUSIC on two lines set to the same width, which is how the mark is drawn everywhere else.
- Top right — styling. Deliberately not inside the app’s own Settings page: these govern how the UI looks, not what it does.
- Bottom left — home. Back to the current page’s starting state.
- Bottom centre — the breadcrumb. Page name, then the path below it.
- Bottom right — the menu.
In full screen both bars go and only the logo stays, in the same cell it occupies in the top bar so it does not jump when you arrive. Tap it again to come back.
The page home
Every page’s starting state is an overview: the level under the page as four tiles filling the list, each with an icon. It is what the bottom-left button always returns to, so there is one reliable way back no matter how deep you are.
Where a page has instances the strip stays — you still pick a layer here — and the tiles fill the rest. For that to hold on Mapping, its eight sections regroup into four: Material folds into Object, and Position, Rotation, Scale and Pivot fold into Transform. That is a change in the DNA, not a trick in the UI.
Two strips, both labelled
A page can nest four levels deep, and the tempting move is a strip per level. Two strips already cost two units; three would cost three, and the list has none to spare.
- At most two strips. One for the zone, one for which instance. Nothing deeper ever becomes a strip.
- Everything below that is a collapsible divider in the scroll. Strips are for levels you switch between constantly; dividers are for levels you open, work in, and close.
- A strip exists only when its level has two or more items. The ladder shrinks to fit the page.
- Every switcher carries a label. ZONES, LAYERS, PLUGINS — in the label band that takes the top 30% of the strip’s single unit, so the strip is still exactly one row on the grid.
Top-down or bottom-up
Top-down is what every board above shows: page in the bottom bar, then the strips at the top of the list. Bottom-up moves the strips below the list and reverses them, so reading upward from the bottom bar you get page, then layer, then section — each level sitting directly above the one it belongs to, and all of it within thumb reach.
It is a setting, not a second design. Nothing else about the page changes.
What a hold opens
The list stays quiet. Precision arrives only when you ask for it, and it arrives as a sheet that rises over the page rather than a screen you navigate to. The strips and the preview stay exactly where they were, dimmed, and the bottom bar sits above the scrim so the breadcrumb stays readable.
Styling settings
The grid divisor, the overlay, the theme, whether the bars invert, the hierarchy direction, whether labels show, the type scale. All of it lives one tap from anywhere, behind the gear at the top right.
Keeping it out of the app’s own Settings page is deliberate. Settings is content — what the engine does. This is chrome — how the surface presents it. They change on different timescales and by different people.
Why this shape holds
Six rules, and they compose rather than compete: one unit sets every height, at most two strips, one full-bleed row per control, the fill is the value, the bars invert and always sit beyond the fill, and everything carries a label. A page is then fully described by which zone it has, whether it has instances, and what its dividers are called.
That matters because the pages are not authored here — they are generated from the DNA, and they change. A surface built out of six rules absorbs a new section or a renamed group without a redesign. A surface built out of per-page layouts does not.
Three things this design does not yet settle, stated plainly. At a divisor of 8 the buttons inside a labelled strip are about 34 px tall, under Apple’s 44 pt guidance — a divisor of 6 or 7 fixes it, which is exactly the reason the divisor is a setting. Render Mode still carries 43 flat controls with no level to split on. And the render parameter names in these mockups are invented, because the real ones arrive with whichever render mode is loaded at runtime.
Settled
- Row unit = width ÷ divisor, default 8
- Grid overlay as a switch
- Six type levels plus value and state
- Bars invert, and never merge with a fill
- Every control one unit tall
- Every switcher labelled
- Logo cycles the preview; home returns to the page overview
Next
- Pick the divisor on a real phone and a real iPad
- Regroup Mapping’s eight sections into four in the DNA
- Safe-area inset on the top bar
- Icons for every page’s home tiles
Later
- Split Render Mode in the DNA
- Swipe to step a dropdown
- Per-level font pickers in the styling panel
Glossary
- DNA
- The authoring platform at dna.spacemusic.tv that owns the parameter tree. Pages, sections, groups and controls are exported from it — not hand-written in the UI.
- Pro UI
- The full desktop control surface. The mobile surface is a second view of the same channels, not a cut-down copy of it.
- unit
- The row height, and the width of one grid column. UI width divided by the divisor; 48.75 px at the default of 8 on a 390 pt phone.
- divisor
- The number the UI width is divided by to get the unit. A setting, not a constant.
- subgrid
- Half a unit. Used for the gap above a section and for the label band inside a strip.
- zone
- The first level under a page. Becomes the top strip. Input’s zones are IO, 1D, 2D, 3D.
- instance
- A dynamic, numbered item inside a zone — plugin 2, stage 1, layer 3. Becomes the second strip, as number chips.
- divider
- A collapsible section header in the scrolling list. Every level below the instance is one of these.
- strip
- A labelled full-width row of tabs or chips. A page has at most two.
- channel
- The engine-side value a control is bound to. The UI never holds state of its own; it reads and writes channels.
- centered
- A slider whose range is built around zero, so its fill grows out of the middle. The opposite starts at its minimum and fills from the left.
- sheet
- An overlay that rises from the bottom edge over a dimmed page. Used for slider precision, long option lists and the menu.
- home
- A page’s starting state: the level under the page shown as four tiles. The bottom-left button always returns here.
- render mode
- The engine plug-in that draws a mapping layer. It supplies its own parameter names at runtime, which is why the ones drawn here are placeholders.