# code-sinth — design system The studio hardware emulation language. Anything we add to the right-pane control surface should follow this. The goal is consistency: a new component should look like it belongs on the same physical rack as everything else. The reference implementation lives in [web/sandbox/studio.html](../web/sandbox/studio.html). ## Vision > Vintage studio rack module. Dark anodised aluminium plates mounted on a > darker frame, lit from above by a softbox. Metal parts catch the light. > Engraved labels on the metal. Amber LEDs and amber readouts where > something is "active". References that pull this together: Moog Voyager, Roland TR-808, Korg MS-20, Universal Audio 1176. Skeuomorphic but **disciplined** — every effect exists to model a physical material under a specific lighting setup, not for decoration. ## Lighting model **One single rule, never broken**: light comes from **above**, slightly in front. Every reflective surface lights its top and shadows its bottom. This applies regardless of where the surface sits within the rack. Practical consequences: - Vertical gradients on metal (lighter top, darker bottom). - Specular bands on the upper portion of any large flat surface. - Bevels: bright on top edge, dark on bottom edge. - Top-edge gloss crescent on circular pieces (knob disc, indicator dot). - Subtle warm rim light at the very bottom — bounce light from the surface the rack sits on (typical of softbox-lit photos of studio gear). When in doubt, ask: "if this were aluminium under a softbox lamp, where would the highlight go?" ## Color tokens All colors live as CSS custom properties on `:root`. Semantic naming, not literal — adding a new theme later means changing the values, not the selectors. ```css /* surfaces (warm-neutral dark, faint warm tint to feel like metal not plastic) */ --bg: #131210; /* page bg, behind the rack */ --hw-bg: #1a1916; /* outer rack base */ --hw-bg-hi: #232220; --hw-bg-lo: #0e0d0b; --hw-edge: #050505; /* sharp dark edges between surfaces */ --hw-screen: #161412; /* code-area glass — slightly darker than the rack */ /* text */ --hw-fg: #a8a39a; /* general body text */ --hw-fg-hi: #d8d0c0; /* numeric values, labels at attention */ --hw-fg-dim: #6c6660; /* secondary status text */ --hw-engrave: #8a847a; /* engraved labels on metal */ /* accent — amber. ONLY for active indicators: arcs, LEDs, running label */ --hw-amber: #e8a050; --hw-amber-hi: #f4c890; --hw-amber-mut: rgba(232, 160, 80, 0.18); --hw-amber-glow: rgba(232, 160, 80, 0.45); --hw-amber-off: #28201a; /* status LEDs */ --hw-led-red: #c84838; /* stop / alert */ --hw-led-green: #6aca8a; /* play / running */ /* code syntax — warm desaturated palette, never bright primary colors */ --hw-syn-com: #5a554f; --hw-syn-kw: #d68868; --hw-syn-num: #d6a268; --hw-syn-fn: #c8a878; --hw-syn-id: #b8b0a0; --hw-syn-op: #6c6660; ``` **The amber accent is precious**. Used for: knob value arcs, fader scale indication, step LEDs when on, the running label, numeric readouts on amber LCDs (we don't currently have those). Never for plain text, plain borders, or decorative accents — overuse kills its meaning. ## The "metal" language (3 reusable layers) Any frame that should read as a brushed-aluminium plate composes three shared CSS variables: ```css /* (1) horizontal specular band on the upper portion */ --metal-specular: linear-gradient(180deg, rgba(255, 248, 230, 0.08) 0%, rgba(255, 248, 230, 0.03) 28%, rgba(255, 248, 230, 0) 45%, rgba(0, 0, 0, 0) 70%, rgba(0, 0, 0, 0.10) 100%); /* (2) very fine repeating horizontal stripes (brushed steel feel) */ --metal-brush: repeating-linear-gradient(0deg, rgba(255, 250, 235, 0.018) 0px, rgba(255, 250, 235, 0.018) 1px, rgba(0, 0, 0, 0.030) 1px, rgba(0, 0, 0, 0.030) 2px); /* (3) 4-edge bevel via inset shadows */ --metal-bevel: inset 0 1px 0 rgba(255, 248, 230, 0.18), /* top edge highlight */ inset 0 -1px 0 rgba(0, 0, 0, 0.70), /* bottom edge shadow */ inset 1px 0 0 rgba(255, 248, 230, 0.06), /* left edge faint highlight */ inset -1px 0 0 rgba(0, 0, 0, 0.45); /* right edge dark */ ``` A frame plugs them in and adds its own base color and drop shadow: ```css .some-panel { background: var(--metal-specular), var(--metal-brush), linear-gradient(180deg, /* base color top → bottom */ ); box-shadow: var(--metal-bevel), /* element-specific drop shadow */; } ``` This is the single most important rule: **every metal surface uses these three layers**. Don't reinvent them per component. ## Surface hierarchy Three depth layers, each visually brighter than the one beneath so they read as plates physically mounted on top of each other: | Layer | Element | Base gradient | Drop shadow | |------------------|-------------------------------|-------------------------------------------|----------------------------------------------| | L0 (deepest) | `.hardware` (outer rack) | `#181513` → `#080604` | `0 8px 32px rgba(0,0,0,0.65)` | | L1 (mid) | `.top-bar`, `.bottom-bar` | `#25211d` → `#16130f` | `0 2px 4px rgba(0,0,0,0.4)` | | L2 (brightest) | `.knobs`, `.faders`, `.seq` | `#2c2823` → `#1a1612` → `#110d09` | `0 2px 4px + 0 6px 14px` (two-layer) | The progressively brighter base + progressively bolder drop shadow makes the L2 plates feel "lifted" off the rack, while the bars feel mounted flush. The code "screen" is **outside** this hierarchy — it's a recess, not a surface (see below). ## Components ### Outer rack frame (`.hardware`) - L0 of the surface hierarchy. Largest border-radius (10px) — the overall unit feels like a single piece. - Has 4 corner screws, **only on the outermost frame** — sub-panels do not carry screws. - Padding 14px. Grid: editor column on the left, fixed-width control column (220px) on the right. ### Top / bottom bars (`.top-bar`, `.bottom-bar`) - L1. Twin styling — they read as a matched pair anchoring the screen. - Height 30px. Border-radius 4px (lower than rack). - Top bar: transport button group + status text. Bottom bar: running label with pulsing amber dot. Same height/style/border, different contents — visual symmetry is the point. ### Code "screen" (`.screen`) - Not a panel — a **recess**. No raised surface, no bevel highlights. - Achieved with deep inset shadows on a slightly darker background: ```css background: var(--hw-screen); box-shadow: inset 0 2px 4px rgba(0,0,0,0.7), inset 0 0 0 1px var(--hw-edge), inset 0 6px 14px rgba(0,0,0,0.5); ``` - Reads as a hole cut into the rack with a glass screen behind it. - Sits between top-bar and bottom-bar to complete the "header / screen / footer" feel of a single rack module. ### Sub-panels (`.knobs`, `.faders`, `.seq`) - L2 of the hierarchy. Border-radius 6px. - Use `.knobs, .seq, .faders` shared selector for the metal language; each adds its own internal layout (grid for knobs, flex row for faders, flex column for seq). ### Knobs The most elaborate component. Eight layers in canvas, in this order: 1. **Drop shadow** — black disc fill at slight Y-offset with `shadowBlur`. Sits the knob "on" the panel. 2. **Amber value arc** — outside the knob's outer edge. Faint full-track stroke + bright glowing active arc (length proportional to value). 3. **Dark rim** — thin (~2.5px) outer ring of the knob body. Vertical gradient `#2a2826 → #0a0908 → #040404`. 4. **Big metallic disc** — fills most of the knob's area. This is the centerpiece. Six sub-layers stacked: - **Base** radial gradient (matte foundation, slightly darker at the edge). - **Concentric brushing** — concentric circles every 0.55px with pseudo-random alpha alternating bright/dark. Imitates lathe-turned aluminium. Deterministic seed so it doesn't shimmer between frames. - **Vertical lighting** overlay (white wash 32% on top, black wash 45% on bottom). - **Horizontal specular band** on the upper third (white-warm 42% peak with soft falloff). - **Bottom rim light** — warm cream wash 14% at the very bottom. - **Bevel** — bright crescent on the top edge (55% white-warm) + dark crescent on the bottom edge (50% black). 5. **Inset shadow** between disc and rim, gives the disc a "sunk-in" feel. 6. **Indicator notch** — small dark triangle on the disc, base near the center, tip toward the rim, rotated to the value angle. Engraved appearance: dark fill + thin bright lower-edge highlight catching light on the inside of the groove. Fixed pixel sizes: `totalR = 26`, `rimW = 2.5`, `discR = 23.5`, notch half-base = 1.5. Canvas is `72×72` — the extra ~10px margin lets the amber arc and drop shadow render without clipping. Indicator angle range: `Math.PI * 0.78` (lower-left) to `Math.PI * 2.22` (lower-right) — a 7:30 → 4:30 sweep, matching how real synth knobs end their throw. ### Faders Vertical sliders, sit in their own sub-panel arranged in a row. - **Track** (`.fd-track`) — 5px wide × 78px tall. Deep slot cut into the panel. Heavy `inset 0 1px 3px rgba(0,0,0,0.85)` shadow + thin warm highlight at the bottom edge for chamfer feel. - **Tick marks** (`.fd-ticks`) — 16px wide pseudo-element on each side of the track. `repeating-linear-gradient` 1px on / 6px off. Engraved scale alongside the slot. - **Cap** (`.fd-cap`) — 26×14px rounded-corners metallic block. Same metal language as the knob disc, condensed for a small element: - Brushed stripes via `repeating-linear-gradient` (4% / 5% alpha). - Vertical light gradient `#b6b0a4 → #807a6e → #3a352e → #1a1612`. - Horizontal grip line — dark band at 46-54% Y for the "thumb groove". - 4-edge inset bevel (top bright, bottom dark, left subtle highlight, right dark). - Drop shadow `0 2px 3px rgba(0,0,0,0.6)`. Interaction: click anywhere on the track jumps the cap there + starts a drag; drag follows pointer; pointerCapture is on the track itself so the cap follows even past the bounds. ### Step LEDs (`.led`) - Off: `linear-gradient(180deg, #100c08 → #28201a)` — looks unlit but not flat black (so the off LEDs have a subtle "physical" feel). - On: `radial-gradient(circle at 50% 25%, #f4c890 → #e8a050 → #a06820)` + `0 0 5px var(--hw-amber-glow)` outer glow. - Hover: brighter dim variant. Click toggles. - 16-cell row. Beat dividers every 4 cells via a pseudo-element on the left edge of cells where `i % 4 === 0`. - Playhead: `outline: 1px solid rgba(232, 160, 80, 0.6)` + 1px offset. ### Buttons (`.hw-btn`) - Vertical gradient `#2c261f → #14110d`. - Border `1px solid var(--hw-edge)`. - Inset highlight on top edge + dark on bottom edge. - Letter-spacing 0.12em, uppercase, font-size 10px. - Hover: text changes to amber. Active: `transform: translateY(1px)` + inset darkening (the "press" feel). - **Button groups** in the top bar (STOP+RUN): adjacent, no gap, share borders. First child has left-rounded corners only, last child has right-rounded only. The middle border merges. Gives the feel of a single rocker switch. ### Screws (`.screw`) - 8px diameter. **Only on the outermost rack** — sub-panels don't carry screws (real rack panels are usually pop-mounted, not bolted). - `radial-gradient(circle at 30% 25%, #8a7d6a → #3a3025 → #100c08)` for the metal head. - `::after` adds a slot mark with a 45° linear-gradient hard-edge. - Inset shadow + small drop shadow for "sunk into the metal". ### Engraved labels The `.label` class on knob/fader cells, the engraved text inside bars. - `font-size: 9-10px`, `letter-spacing: 0.16-0.18em`, `text-transform: uppercase`. - Color `var(--hw-engrave)` — the desaturated warm gray. - Double text-shadow for the engraved feel: ```css text-shadow: 0 1px 0 rgba(0, 0, 0, 0.7), /* deep shadow below */ 0 -1px 0 rgba(255, 220, 180, 0.04); /* faint highlight above */ ``` - The shadow below + highlight above creates the optical illusion of text incised into metal lit from above. ### Numeric value displays - Below knobs and faders. Cream color (`var(--hw-fg-hi)`), tabular nums. - **No frame, no inset background** — flat text on the panel. We experimented with LCD-style amber inset readouts and it felt too busy. The amber is reserved for active indicators; values are passive. - Width matches the knob (~46px min) so the layout doesn't shift when the digit count changes. ## Typography Single font stack: `'JetBrains Mono', 'Cascadia Code', Consolas, monospace`. Everything monospace — keeps the "instrument firmware" feel. Sizes: - Body / labels: 10-11px - Code: 12-13px - Headings (when needed): 12-14px Letter-spacing: `0.06em` for normal text, `0.16-0.18em` for engraved labels and button text. Wider tracking gives the "carved into metal" feel. Tabular numerals (`font-variant-numeric: tabular-nums`) for any value display so they don't wobble when digits change. ## Interaction - **Drag**: knobs and faders use `pointerdown` + `setPointerCapture`. Always change `cursor` to `grabbing` on body during the drag (so the cursor doesn't flicker if the pointer leaves the element bounds). - **Click track to jump**: faders accept a click anywhere on the track to jump the cap there, then a drag continues from that point. - **Double-click to recenter**: knobs reset to their default value. - **Shift-drag for fine adjust**: knobs accept `ev.shiftKey` for ¼-speed adjustment. - **`pointercancel`** is always handled alongside `pointerup` — covers edge cases where the browser cancels a drag mid-gesture. - Always remove all listeners and reset cursors on the up/cancel handler. ## Spacing & proportions - Outer rack padding: 14px. - Outer rack gap (editor ↔ control column): 12px. - Right-stack inner gap (knobs / faders / seq): 8px. - Sub-panel padding: 8-14px depending on density. - Element gap inside sub-panels: 4-12px. The unifying scale is multiples of 2 (2/4/8/12/14). Avoid 5px, 7px, 13px — they look like accidents. ## What is intentionally NOT here To keep the language disciplined, these were considered and rejected: - **Skeuomorphic photo textures** (real wood, real brushed metal photos). Pure CSS gradients keep the file small and stay sharp at any DPI. - **3D rotation / perspective transforms**. The lighting model already conveys depth; transforms add visual noise. - **Animated reflections / moving highlights**. Static metal looks premium; moving highlights look like a screensaver. - **Multiple accent colors**. Amber is the only "active" hue. A second accent would dilute the meaning. - **Decorative dots / flourishes / brand marks**. The rack is minimalist — every visible element is functional. - **Bright primaries in syntax highlighting**. The code area is "behind glass" with warm light passing through; saturated greens and blues break the illusion. ## How to add a new component 1. Decide its surface hierarchy layer (L0 / L1 / L2). Almost everything new is L2 (a sub-panel). 2. Apply the metal language: `var(--metal-specular)`, `var(--metal-brush)`, `var(--metal-bevel)` plus a base color and drop shadow appropriate to the layer. 3. Use `--hw-engrave` for any label text, with the double-text-shadow formula. 4. Use `--hw-amber` only if the new component has an "active" indicator to show. 5. Drag interactions: pointerdown + setPointerCapture, body cursor = `grabbing`, listen for pointermove/up/cancel, clean up on up/cancel. 6. Numbers: tabular-nums, `--hw-fg-hi` color, no inset frame. 7. If it's reflective (metal disc, cap, sphere), light it from above. No exceptions.