docs(product): split look-and-feel into Phase L (L1 kit / L2 panel / L3 VST-restyle)
Port visual-design-language.md to dev with DS-1/2/3 settled (B + spectral strip; LICE + WDL free game; thorough M11-aware panel layout). L1 shared kit; L2 panel redesign after M11 merges; L3 VST restyle gated on Phase S landing. Phase S adopts the kit when it lands — not gated.
This commit is contained in:
+194
@@ -1333,3 +1333,197 @@ and embed message/lifecycle against `vendor/reaper-sdk/sdk/reaper_plugin_fx_embe
|
||||
- **Verify Steinberg SDK, bridge, embed, and LICE-view surfaces** against the vendored
|
||||
headers before use — several §1a claims are experienced estimates until the spike
|
||||
confirms them.
|
||||
|
||||
---
|
||||
|
||||
# Look-and-feel — visual design language (Phase L)
|
||||
|
||||
> **New pillar, own lettered phase, taken up by a parallel team.** Phase L is the
|
||||
> whole-system look-and-feel effort — a shared LICE drawing kit and the surfaces that
|
||||
> adopt it — that replaces the flat "temple os" drawing (opaque `LICE_FillRect` blocks +
|
||||
> raw GDI `DrawTextA`) with a modern, sleek 2026 dark synth look across ReaSampler
|
||||
> (the extension's docked bank panel) and ReaSampler 9000 (the Phase S VST editor + embed
|
||||
> strip). Namespaced **`L` (Look-and-feel)**, orthogonal to and ungated by the
|
||||
> M/D/B/R/V/S pillars. Product framing, the settled decision record (DS-1/DS-2/DS-3 all
|
||||
> SETTLED 2026-07-26), palette, the three visual directions, and the toolkit assessment:
|
||||
> `docs/product/visual-design-language.md`. Same standing discipline: **verify every LICE/
|
||||
> WDL/SWELL API name/signature against `vendor/WDL` before use.** When a point lands,
|
||||
> doc-keeper moves it to `COMPLETED.md`.
|
||||
|
||||
## What it is
|
||||
|
||||
A **shared LICE-based drawing kit** (palette + type scale + component-draw layer) and the
|
||||
surfaces that consume it. The kit is the **one source of drawing** for the whole system —
|
||||
a button, row, slider, or waveform looks identical in the bank panel, the embed strip, and
|
||||
the VST editor because it is the same kit function (the one-source-multiple-views instinct,
|
||||
applied to drawing). The current "temple os" look is the system drawing at the **floor** of
|
||||
LICE (flat fills, GDI text, no gradients/AA/rounded/hover); the kit lifts every surface to
|
||||
LICE's actual ceiling — which REAPER's own themed UI and SWS prove is a modern dark UI.
|
||||
|
||||
## Settled decisions (Daniel, 2026-07-26 — reasoning in `docs/product/visual-design-language.md` §6)
|
||||
|
||||
- **DS-1 — toolkit: LICE + WDL free game, no external frameworks.** Draw with **LICE**
|
||||
directly (gradients via `LICE_GradRect`, AA rounded via `LICE_RoundRect`/`LICE_Line`,
|
||||
cached AA text via `LICE_CachedFont`). **Reuse any useful WDL/vwnd piece** — skin/image
|
||||
helpers, draw idioms, a specific control (e.g. `virtwnd-listbox` for a long scroll list)
|
||||
— where it beats re-deriving; "don't reinvent the wheel." **Reject external frameworks**
|
||||
(iPlug2 / JUCE / VSTGUI — they re-open the settled bare-SDK+LICE build shape to solve a
|
||||
look problem that is not a toolkit-ceiling problem). **Caution, not a ban:** keep
|
||||
hit-test **geometry** in pure CTest-covered modules — do not import vwnd's retained-mode
|
||||
object model wholesale (its controls own their hit-test internally, which would move
|
||||
geometry into untestable shell code and undercut the pure/shell split).
|
||||
- **DS-2 — visual direction: Direction B ("Neon Console") + Direction C's spectral
|
||||
keyboard strip.** Near-black base (`~18,18,22`) with a single vivid accent (electric cyan
|
||||
leads) for the live/active/selected layer only; everything else calm neutral gray. The
|
||||
**spectral (hue-mapped) keyboard strip** — low notes cool → high notes hot, glow-on-active
|
||||
as a static drawn state — is the signature surface (it turns the multi-zone-in-one-instance
|
||||
advantage into a visual identity). The kit palette is **abstract** (role→color, one
|
||||
constants block), so the direction is a single-file change.
|
||||
- **DS-3 — dock-panel scope: a thorough layout redesign, not a light re-skin.** L2 lays out
|
||||
the *full* button/affordance inventory — including M11's action-trigger buttons +
|
||||
keybinding-help labels — intuitively, uncluttered, and useful, then applies the kit.
|
||||
Sequenced after M11 merges so it designs against the actual landed button set.
|
||||
|
||||
## Palette + the "punch" rule (Daniel's standing taste)
|
||||
|
||||
Dark, modern, **visual punch over conservative contrast.** The palette is defined by
|
||||
**role**, not hardcoded hue: `bg/base`, `bg/panel`, `bg/cell`, `line/hairline`,
|
||||
`text/primary`, `text/dim`, `accent`, `accent/hot`, `warn`. A modern dark UI is built from
|
||||
**elevation layers**, not borders — surfaces gain a **micro-gradient** (`LICE_GradRect`,
|
||||
a few percent lighter at the top) + a 1px inner top-highlight / bottom-shadow (the vwnd
|
||||
trick) instead of flat fills. **WCAG-floor discipline:** for each text-on-surface pair,
|
||||
take the *most* vibrant accent that still clears its floor (AA 4.5:1 body / 3:1 large +
|
||||
state indicators) — the floor approached from the vibrant side, never a retreat to safe
|
||||
gray. The `warn` role (red/amber) is reserved *only* for byte-deleting or clip states
|
||||
(prune, delete). Because the palette is role-based in one constants block, the settled
|
||||
B+spectral direction (DS-2) is one file.
|
||||
|
||||
## "Speed is the selling point" — a design constraint, not a tagline
|
||||
|
||||
The UI must **feel instant, and no decoration may cost that.** Sub-frame hover/press/drag
|
||||
feedback repainted immediately on the input message (instant acknowledgment *is* the
|
||||
perception of speed); zero-jank via the preserved double-buffer discipline (draw to
|
||||
`LICE_SysBitmap`, single `BitBlt`); region-scoped `InvalidateRect` during a drag
|
||||
(build-time residual). **No decorative animation** — no tweens/fades/pulses; the only
|
||||
permitted motion is a level/meter readout following the audio directly (as the embed strip
|
||||
already does). Direction C's glow/bloom is a **static drawn state, never a pulse.** The
|
||||
"fast" feeling is typography + hover + no-jank, not motion.
|
||||
|
||||
## Kit architecture (the pure/shell split)
|
||||
|
||||
Pure (no LICE, no REAPER types, unit-tested — the mirror of `mode_switch`/`bank_grid`):
|
||||
- **`theme`/palette module** — role→color mapping, direction-selectable via one constants
|
||||
block (the B+spectral values). Pure; unit-tested that each text-on-surface pair clears
|
||||
its WCAG floor (the "punch" rule made testable).
|
||||
- **Component geometry/hit-test helpers** — button rect, slider track/handle geometry,
|
||||
list-row rect + hover hit-test, and any new layout module L2 needs (an action-bar layout
|
||||
module). No LICE, no host types; CTest-covered. Existing pure modules
|
||||
(`bank_grid`/`tab_strip`/`mode_switch`) stay the source of truth for what they own.
|
||||
|
||||
Shell (LICE-facing, DAW-verified — thin draw layer):
|
||||
- **Draw kit** — `fillSurface` (micro-gradient + inner highlight/shadow),
|
||||
`drawButton`/`drawSlider`/`drawListRow`/`drawWaveform`/segmented-switch/tab draw, and a
|
||||
shared `text()` over a cached `LICE_CachedFont` set (title/label/value-mono/micro). Owns
|
||||
the cached-font lifecycle. Honors the interaction state model (rest/hover/active/pressed/
|
||||
dragging/focus/disabled). **DS-1: WDL/vwnd reuse is assessed here at build time** — reuse
|
||||
a vwnd piece where genuinely cheaper, else draw on LICE; hit-test geometry stays pure
|
||||
regardless.
|
||||
|
||||
## L2 dock-panel layout contract (the M11-aware inventory)
|
||||
|
||||
DS-3 makes L2 a **layout design**, not a skin pass, because M11 adds a real button
|
||||
inventory. L2 must place **every** affordance below without crowding the grid (the
|
||||
centerpiece), grouping by *task*:
|
||||
|
||||
**Existing (landed / specced):**
|
||||
- Bank **grid** — thumbnails, multi-select, keyboard nav, audition, focus ring.
|
||||
- Design View **segmented mode switch** (`[ Arrange | Design ]`) + per-mode membership count.
|
||||
- Multi-bank: **named-banks tab strip** (LICE-drawn, overflow/scroll), **active-bank
|
||||
indicator**, **pool/banks full-height toggles**, create/rename/delete/activate-bank
|
||||
affordances, per-selection **move / copy / remove** sample menu.
|
||||
- **Prune** button (R-E) — the byte-deleting action; `warn`-colored, set apart.
|
||||
|
||||
**M11 adds (dev PLAN.md §M11 — merging to dev now):**
|
||||
- **Action-trigger buttons** — clickable buttons firing the capture + provenance action
|
||||
family directly (capture item / capture track scopes, re-capture from source,
|
||||
resample-and-mute-source, batch capture, conform-on-insert, insert-at-cursor, drag-out,
|
||||
null-test verify). A cluster.
|
||||
- **Keybinding-help labels** — each capture/provenance action surfaces its current key
|
||||
binding (e.g. "Capture Item → F5") or an "unbound"/"—" marker.
|
||||
|
||||
**Layout mandate:** group by task (capture / organize / reclaim / view), not by phase; a
|
||||
compact action bar/toolbar for the frequent capture actions (icon+label, keybinding as a
|
||||
`micro` sub-label), an overflow/menu for the rare ones, header space for the mode switch +
|
||||
active-bank indicator, the bank tab strip + move/copy/remove organize cluster together,
|
||||
prune set apart and `warn`-marked. Density is a design decision — 8px grid, elevation
|
||||
layers over hairlines, hover on every interactive element. Then apply the L1 kit to draw
|
||||
it. New layout math goes in a pure geometry module; `bank_grid`/`tab_strip`/`mode_switch`
|
||||
stay the pure source of truth for their own hit-testing. **L2 sequences after M11 merges**
|
||||
so it inventories the actual landed buttons.
|
||||
|
||||
## The L3 gate + Phase S coordination contract
|
||||
|
||||
**L3 (VST editor + embed-strip restyle) is GATED on Phase S landing on dev.** The VST
|
||||
editor (`IPlugView` LICE surface), the S6 embed strip, and the keyboard strip live in
|
||||
Phase S, which is **not on dev yet** (it exists on the phase-s worktree). L3 cannot be
|
||||
built on dev until Phase S's editor/embed surfaces (≈ S1 / S6 / S10) merge to dev — **the
|
||||
Phase L team must not chase these files on dev; they are not there.** Until then L3 is a
|
||||
planned, blocked point; L1 and L2 are the live Phase L work.
|
||||
|
||||
**Coordination contract (load-bearing):** Phase S's S10–S13 build their interaction UX with
|
||||
the **current** drawing and **adopt the L1 kit when it is available — they are NOT gated on
|
||||
Phase L.** Whichever lands first (the L1 kit or the S10–S13 UX), the kit is the **one source
|
||||
of drawing**: if S10–S13 reach dev before L1, they draw in the current language and L3
|
||||
restyles them; if L1 lands first, they are born in the kit. Either way there is one kit and
|
||||
one look; L3 completes the VST/embed adoption and applies the settled B+spectral treatment
|
||||
(with C's spectral keyboard strip as the signature surface). The VST3 class UID is
|
||||
unchanged — a visual refresh is not a compat event.
|
||||
|
||||
## Precision / invariant implications (what Phase L does NOT change)
|
||||
|
||||
- **The pure/shell split holds.** All layout/hit-test stays in pure CTest-covered geometry
|
||||
modules; the kit's *draw* half is shell, its *geometry* half is pure — even where a WDL
|
||||
piece is reused (DS-1). No hit-test math moves into untestable code.
|
||||
- **RT discipline untouched.** The kit is draw-thread only; nothing here touches `process`
|
||||
or any off-thread reload handoff (a Phase S concern surfaced at L3).
|
||||
- **Read-only-over-bank untouched.** This is look-and-feel; no data-ownership change.
|
||||
- **The capture/placement load-bearing principle is untouched.** Phase L draws; it does not
|
||||
capture, place, or mutate the bank.
|
||||
- **VST3 class UID / component-state contract unchanged** (Phase S concern; noted for L3).
|
||||
- **Windows-only (D5).** Font/GDI/HFONT choices assume Windows; no cross-platform font
|
||||
fallback concern.
|
||||
|
||||
## LICE / WDL API surface (verify all signatures)
|
||||
|
||||
- **LICE design-kit surfaces (L1).** `LICE_GradRect`, `LICE_RoundRect`, AA
|
||||
`LICE_Line`/`LICE_FLine`/`LICE_ThickFLine`/`LICE_Circle`/`LICE_FillCircle`/
|
||||
`LICE_DrawCBezier`, `LICE_FillTriangle`/`FillTrapezoid`/`FillConvexPolygon`, and the
|
||||
`LICE_CachedFont`/`LICE_IFont` font engine (`SetFromHFont`, AA `DrawText`, shadow/outline/
|
||||
glow FX flags). Verified *present* in `vendor/WDL/WDL/lice/lice.h` + `lice_text.h`;
|
||||
**confirm exact signatures + the `LICE_CachedFont`↔`HFONT` lifecycle at build.**
|
||||
- **WDL/vwnd reuse (DS-1, build-time assessment).** `virtwnd-slider.cpp` /
|
||||
`vwnd_slider_drawknobstack` (slider/knob drawing reference), `virtwnd-listbox.cpp`
|
||||
(candidate scroll listbox), `virtwnd-controls.h` (`WDL_STYLE_*` gradient hooks),
|
||||
`virtwnd-skin.h` (image-skin helpers) — all in `vendor/WDL/WDL/wingui/`. Reuse where a
|
||||
piece beats re-deriving; keep hit-test geometry pure regardless.
|
||||
- **Panel drawing/hit-test (L2).** Reuses the `bank_panel` LICE surface + the existing pure
|
||||
`bank_grid`/`tab_strip`/`mode_switch` hit-test modules; the new action-bar layout is a new
|
||||
pure module. `WM_MOUSEMOVE`/`TrackMouseEvent` (`WM_MOUSELEAVE`) for hover on the panel's
|
||||
existing timer-driven `wndProc`. Verify against the SWELL headers as `bank_panel` already
|
||||
does.
|
||||
|
||||
## Non-goals / guardrails
|
||||
|
||||
- **No external UI framework.** iPlug2 / JUCE / VSTGUI are rejected (DS-1). LICE + reused
|
||||
WDL pieces are the toolkit; reject any path that pulls in a new framework.
|
||||
- **No hit-test geometry in untestable shell code.** Even when reusing a WDL piece, layout/
|
||||
hit-test math stays in pure CTest-covered modules (DS-1 caution). Reject a control whose
|
||||
adoption would move geometry into the shell without a pure test seam.
|
||||
- **L2 does not restructure the panel bones.** The vertical-split / grid / tab structure is
|
||||
sound and stays; L2 designs the *layout of the button inventory around it* (DS-3). A
|
||||
ground-up structural rework of landed Phase-B panel structure is out of scope.
|
||||
- **L3 does not build on dev until Phase S lands there.** The gate is explicit; do not chase
|
||||
Phase S files on dev.
|
||||
- **A visual refresh is not a compat event.** VST3 class UID, command-id strings, ext-state
|
||||
namespaces, and component-state contracts are unchanged by Phase L.
|
||||
- **Verify LICE/WDL/SWELL surfaces** against `vendor/WDL` before use.
|
||||
|
||||
Reference in New Issue
Block a user