Spatial DesktopMaterial Guide · WIP
PhilosophyReferenceOpen desktop

Spatial Desktop design system · work in progress

Material follows interaction.

Opaque ABS gives pointer-driven controls a physical body and uses discrete LED lamps for state. Edge-lit acrylic carries temporary, ambient and system information through illuminated engraving. Neither material is decoration: each one explains how an element behaves before it is used.

Philosophy

A small set of rules should explain the whole interface.

01
Tactile, not ornamental

Depth must communicate pressability, insertion or stacking. Flat information stays flat.

Input-device honesty

Desktop controls echo mouse and keyboard switches. Touch controls belong to the continuous phone-glass surface.

One depth step

A surface can be raised, level or recessed. Avoid nesting multiple embossed frames around content.

Solid working content

The main content of every app window is always opaque and readable. Glass never sits behind long-form content.

Light carries meaning

App colour marks focus, selection, progress and an active toggle—not every border and icon.

Fast mechanical motion

Buttons move down in 8 ms and release in 16 ms. Toggle buttons click equally fast, then remain physically held.

Two materials, two jobs

Mix them only at a deliberate boundary.

02
ABS plasticDurable · physical · opaque

ABS is the body of applications and controls manipulated with a pointer. It should feel like the shell and buttons of a well-made mouse.

  • Movable application windows
  • Push and toggle buttons on ABS
  • Toolbars, tabs and window chrome
  • Solid application content surfaces
Never make primary reading or working content transparent.
Edge-lit acrylic glassAcrylight · ambient · contextual

“Glass” is one continuous acrylic sheet, not a pile of translucent capsules. Neutral parallel reflections reveal its cut thickness; hidden edge emitters feed light into engraved or frosted marks only where state must be communicated.

  • Docked Apps, Project and System Areas
  • Context menus, popovers and toasts
  • Overview and search surfaces
  • Small displays inserted into ABS
Keep the clear face quiet. Colour belongs to injection points and scattering marks—not the whole perimeter.

Light behaves differently

The same colour can communicate state through two different physical models.

03
ABS plastic

ABS uses a restrained state light

Match the real Dolphin controls in the desktop demo: a flat two-pixel application-colour trace with one short halo. It sits flush in the ABS surface, with no contrasting bezel, white centre or extra luminous body.

Emitter
Local indicator integrated flush with the control
Light form
Flat two-pixel line or three-pixel vertical slit
App colour
Application primary colour without whitening
Bloom
One restrained six-pixel shadow at 56%
Inactive
A faint neutral state rail only where required
Edge-lit acrylic

Acrylight reveals a path, not a glowing panel

Hidden LEDs inject light at short sections of the cut edge. Total internal reflection keeps the face transparent; only an engraving, frosted groove or locally exposed edge scatters the light toward the user.

Emitter
Short concealed injection points along the outer edge
Thickness
Neutral parallel reflections reveal the cut panel
Light path
Travels invisibly inside the clear sheet
App colour
Appears only at injection points and scattering marks
Bloom
One sharp core with a four-pixel local scatter
Inactive
The etched groove remains faintly visible but unlit
Shared meaning, different construction: coloured light means active state, selection, focus or progress. ABS exposes a local state indicator. Acrylic transports light through one sheet and releases it only from an engraving, frost or exposed injection edge. Neither material should glow as an undifferentiated surface.

State light is a language

The coloured line is not decoration. Its shape, duration and intensity describe the control state.

04
1 · Material lightNeutral highlights reveal plastic volume or a glass edge. They are always present and never use the app colour.neutral · continuous
2 · Interaction previewHover and keyboard focus briefly increase contrast or add a low-opacity tint. They disappear when attention leaves.8–14% tint · temporary
3 · Committed stateA precise app-coloured line marks something that remains active: toggle on, selected tab or completed slider distance.1–2 px core · persistent
StateLight formABS + LEDEdge-lit acrylicTiming
Idle push buttonNoneTop reflection and contact shadow onlyNeutral edge and faint internal reflection onlyContinuous
HoverLow contrast liftTop highlight becomes slightly clearerEdge becomes slightly clearer; no coloured railWhile hovered
Pointer downNo new state lightMoves 2 px; shadow collapsesStays in the sheet; its inner reflection compresses by 1 px8 ms down
Toggle onPersistent state markThe neutral rail switches to the two-pixel app-colour traceEdge-fed light scatters from an engraved lineAppears immediately; remains until off
Selected tabPersistent state markPressed key plus the same two-pixel trace used in DolphinSelected segment brightens an engraving in the shared sheetFollows selection
Slider progressPath from minimum to thumbThe completed distance uses the same state traceOnly the completed part of a frosted groove scatters edge lightTracks pointer directly; no lagging animation
Keyboard focusTemporary state markThe LED line runs at reduced outputExisting etched boundary brightens locallyOnly while focused
DisabledNoneLower contrast, no indicator lightLower edge contrast, no glowUntil enabled

Toggle buttons

Pressing and toggling are separate events. Every button performs the same fast 8 ms click. After it resolves, an ABS toggle stays lower and powers its indicator; a glass toggle remains in the shared sheet while its engraved mark stays lit. A push button retains neither.

Sliders

The light represents a value, so it ends exactly at the thumb and follows without easing. ABS reuses the same two-pixel state trace as the active Dolphin tab; the remaining distance is a thin neutral guide. Glass brightens a frosted groove in the acrylic sheet.

Colour ownership

Use the application primary colour for in-app state. System surfaces use their owning Area colour. Warning, error and success colours replace it only when status meaning is more important than app identity.

Where the light may exist

ABS light may appear only as the shared state trace, a small dot, a vertical slit or a backlit symbol—never as glowing plastic. Acrylight may appear only at an outer injection edge or where the shared sheet is engraved, frosted or cut.

Every component in both materials

The behaviour stays consistent. Only the physical response changes.

05
Application primary colour

Push and toggle buttons

Click both versions. Push returns; toggle remains held and shows its material-specific state light.

ABS travels 2 px and switches on its state trace · glass compresses its reflection and lights an engraving in the shared sheet
ABS surface

Opaque keycap · 2 px app-colour trace · no visible housing

Acrylight surface

One acrylic sheet · etched control boundary · 1 px illuminated engraving

Tabs and segmented choices

The active item is lower and darker in ABS, but optically inset in acrylic glass.

The meaning stays consistent; the ABS tab lights its state trace while the acrylic tab releases edge-fed light from a one-pixel etch
ABS surface

Selected key remains physically down · luminous line shows persistent state

Acrylight surface

Etched segments stay in one plane · selected groove scatters light

Text and search fields

Both are recessed because they receive content rather than trigger an action.

ABS uses a physical well and the Dolphin-style live slit · glass uses a darker transparent inset with a focused edge
ABS surface

Opaque well · strong inner shadow · 3 px vertical app-colour slit

Glass surface

Transparent inset · visible edge · restrained focus light

Sliders and continuous values

The active length is meaningful state, so both materials use application colour through different hardware.

ABS uses a round opaque thumb · acrylic lights a frosted groove and uses a rectangular clear thumb
ABS surface
1:553:38

2 px application-colour trace · short 6 px halo · neutral remainder

Acrylight surface
1:553:38

1 px frosted groove · edge-lit progress · transparent acrylic thumb

Menus and popovers

The surrounding surface decides the material, not the menu command itself.

An in-app dropdown may remain ABS · desktop context menus and transient system UI use one continuous glass sheet
ABS app menu

Belongs to the opaque application body

Glass system menu

One square sheet · rows remain flat · only the panel owns a cut edge

Rows and selection

Rows are information, not physical keys. Neither material raises every row.

Selection uses a tint plus one app-colour edge; depth stays flat
ABS surface
FDownloadsSelected location
DDocumentsLocal folder

Opaque tint · embedded selection edge

Glass surface
FDownloadsSelected location
DDocumentsLocal folder

Translucent tint · etched selection edge

Checks and compact choices

A small binary control follows its host surface while preserving the same check state.

The mark carries state colour; the container communicates material
ABS surface
Keep window visible

Small keycap · pressed cavity when checked

Glass surface
Keep window visible

Etched square · illuminated mark when checked

Status and notifications

The message origin decides whether it is embedded in an app or floats at system level.

Application status is ABS and attached · system notification is glass and transient
ABS app status
Project savedStored inside this application

Solid and connected to its parent window

Glass system notice
Project savedTemporary system feedback

Floating, transparent and square

Composition rules

How the pieces combine without becoming busy.

06

Do

  • Keep app content fully opaque.
  • Use one dominant material per surface.
  • Reserve app colour for meaningful state.
  • Let empty space separate groups.
  • Keep borders thin and local.
  • Use real app icons in launch surfaces.

Do not

  • Put ABS buttons on a glass sheet.
  • Wrap every item in a raised card.
  • Give push buttons persistent light.
  • Blur text-heavy content over wallpaper.
  • Stack border inside border inside border.
  • Use glow merely to decorate an edge.

Reference tokens

Recommended defaults. Scale spatial values, not interaction timing.

07
TokenDefaultPurpose
--press8 msMouse-switch downstroke
--release16 msOne-frame release
--state-line-size2 pxShared horizontal ABS state trace
--abs-live-slit3 × 23 pxVertical identity or live-state marker
--abs-led-bloom6 px / 56%Single restrained halo used by the real desktop controls
--abs-inactive-guide28%Thin neutral continuation of an unfilled slider
--glass-groove1 px neutralVisible but unlit engraving in the shared acrylic sheet
--acrylic-injection-edgeLocal segments onlyShows where concealed LEDs feed light into the sheet
--acrylic-edge-stack1 px + 2 px + 3 px insetNeutral parallel reflections that reveal panel thickness
--acrylic-etch-bloom1 px core + 4 px / 34%Sharp engraving with short local optical scatter
--acrylic-clean-emission0%Unmarked clear sheet does not visibly emit colour
--hover-tint3–7%Temporary interaction preview, never committed state
--slider-follow0 msProgress light must stay attached to the thumb
--window-radius22 pxMovable app squircle
--area-radius0 pxEvery glass surface and control
--inner-radius8–14 pxABS controls and inset wells; glass uses 0 px
--edge1 pxNeutral material boundary
--glass-blur20–24 pxTransient and desktop acrylic only

Implementation templates

Minimal patterns developers can adapt without changing the semantics.

08
Matching ABS and glass buttons
<div class="surface abs">
  <button class="button abs-button">Push action</button>
</div>

<div class="surface glass">
  <button class="button glass-button">Push action</button>
</div>

<button class="abs-button toggle-button" aria-pressed="true">
  Toggle action
</button>

.abs-button { border-radius: 10px; corner-shape: squircle; }
.glass-button { border-radius: 0; corner-shape: square; }

/* Same ON state; two physically different emitters. */
.abs-button[aria-pressed="true"] .light-bar {
  height: 2px;
  border-radius: 2px;
  background: var(--app-primary);
  box-shadow: var(--abs-led-bloom);
}
.glass-button[aria-pressed="true"] .engraving {
  height: 1px;
  background: color-mix(in srgb, var(--app-primary) 82%, white 18%);
  box-shadow: var(--acrylic-etch-bloom);
}
.glass-button:not([aria-pressed="true"]) .engraving {
  background: var(--glass-groove);     /* visible etch, no emitted colour */
  box-shadow: none;
}
Matching ABS and glass sliders
<!-- Same value and semantics; different physical rendering. -->
<input class="range abs-range" type="range" min="0" max="100" value="42">
<input class="range glass-range" type="range" min="0" max="100" value="42">

.abs-range .track {
  height: 2px;
  background: color-mix(in srgb, var(--text) 28%, transparent);
}
.abs-range .filled-part {
  height: 2px;
  border-radius: 2px;
  background: var(--app-primary);
  box-shadow: var(--abs-led-bloom);
}
.glass-range .filled-part {
  height: 1px;
  background: color-mix(in srgb, var(--app-primary) 82%, white 18%);
  box-shadow: var(--acrylic-etch-bloom);
}
.glass-range .thumb {
  border: 1px solid var(--glass-edge);
  border-radius: 0;
  corner-shape: square;
  background: transparent;
  box-shadow: var(--acrylic-edge-stack);
}
Glass context menu
<menu class="glass context-menu">
  <button class="menu-row">Move to Project</button>
  <button class="menu-row">Keep visible</button>
</menu>

.context-menu {
  border-radius: 0;                 /* desktop structure */
  background: var(--glass-surface);
  border: 1px solid var(--glass-edge);
  box-shadow: var(--acrylic-edge-stack);
  backdrop-filter: blur(24px) saturate(1.08);
}
.menu-row {
  background: transparent;         /* rows are not separate glass buttons */
  border: 0;
  box-shadow: none;
}
Solid app with a glass insert
<article class="app-window abs">
  <header class="app-titlebar">Dolphin</header>
  <div class="glass recessed-field">Downloads</div>
  <main class="app-content solid">...files...</main>
</article>

/* The content is always opaque—even when the toolbar contains glass. */
.app-content { background: var(--app-content); opacity: 1; }