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.
|
||||
|
||||
@@ -290,3 +290,181 @@ build:** the `IReaperUIEmbedInterface` contract + embed message/lifecycle agains
|
||||
`video_processor.h` / `reaper_plugin_functions.h`.
|
||||
- **`IReaperUIEmbedInterface`** — embed contract + message/lifecycle, against
|
||||
`reaper_plugin_fx_embed.h` (needed only at S6).
|
||||
|
||||
---
|
||||
|
||||
# Phase L — Look-and-feel (system-wide visual design language)
|
||||
|
||||
> **New pillar, own lettered namespace, 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, so ReaSampler and ReaSampler 9000 shed the flat "temple os" drawing for a
|
||||
> modern, sleek 2026 dark synth look. It answers Daniel's post-DAW-test verdict on the
|
||||
> instrument ("this looks like temple os… the VST is dogshit… scope it for the whole
|
||||
> system… does Cockos have a toolkit?"). Namespaced **`L` (Look-and-feel)** so it is
|
||||
> orthogonal to and ungated by the M/D/B/R/V/S pillars — a parallel team owns it while
|
||||
> Phase S feature work proceeds independently. Authoritative spec: **CONTEXT.md §Phase L
|
||||
> — visual design language (design-system spec)**. Product framing, the settled decision
|
||||
> record (DS-1/DS-2/DS-3 all SETTLED 2026-07-26), palette, and the three visual
|
||||
> directions: `docs/product/visual-design-language.md`. When a point lands, doc-keeper
|
||||
> moves it to `COMPLETED.md`.
|
||||
>
|
||||
> **This section is self-contained for a team without Phase S context.** Where a point
|
||||
> touches a Phase S surface (the VST editor, the embed strip, the keyboard strip), the
|
||||
> gate is stated explicitly so the team does not chase files that are not on dev yet.
|
||||
>
|
||||
> **Settled decisions (Daniel, 2026-07-26 — see `docs/product/visual-design-language.md`
|
||||
> §6):**
|
||||
> - **DS-1 — toolkit: LICE + WDL free game, no external frameworks.** Draw the modern
|
||||
> look with LICE directly; reuse any useful WDL/vwnd piece (skin/image helpers, draw
|
||||
> idioms, a control like the scroll listbox) where it beats re-deriving — "don't
|
||||
> reinvent the wheel." Reject iPlug2 / JUCE / VSTGUI (external frameworks re-opening the
|
||||
> settled bare-SDK+LICE build shape). Keep hit-test geometry in pure CTest-covered
|
||||
> modules — do not import vwnd's retained-mode object model wholesale.
|
||||
> - **DS-2 — visual direction: Direction B ("Neon Console") + Direction C's spectral
|
||||
> keyboard strip.** Near-black + one vivid accent everywhere; a hue-mapped spectral
|
||||
> keyboard strip as the signature surface. The kit palette is abstract (roles, 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 inventory (including M11's action-button additions) intuitively,
|
||||
> uncluttered, and useful — then applies the kit. Sequenced after M11 merges.
|
||||
|
||||
## L1 — shared LICE drawing kit (the foundation)
|
||||
**Goal:** One shared **LICE-based design kit** — a role-based palette + a type scale + a
|
||||
component-draw layer — that every surface (the bank panel now, the VST editor + embed
|
||||
strip later) draws through, replacing flat `LICE_FillRect` blocks and raw-GDI `DrawTextA`
|
||||
with a modern dark look: gradient surfaces (`LICE_GradRect`), anti-aliased rounded controls
|
||||
(`LICE_RoundRect`/`LICE_Line`), cached anti-aliased text (`LICE_CachedFont`), and a full
|
||||
interaction-state model (rest/hover/active/pressed/dragging/focus/disabled) the current
|
||||
drawing lacks entirely. The B+spectral palette constants (DS-2) live in one constants block.
|
||||
No new dependency — LICE is the toolkit; WDL/vwnd reuse is assessed at build time per DS-1
|
||||
("don't reinvent the wheel"). CONTEXT.md §Phase L (design-system spec). Product framing +
|
||||
palette + directions + forks: `docs/product/visual-design-language.md`. **Verify LICE
|
||||
gradient/AA/font surfaces and the `LICE_CachedFont`↔`HFONT` lifecycle against
|
||||
`vendor/WDL/WDL/lice/lice.h` + `lice_text.h` before use.**
|
||||
**Verify:** CTest green on the pure layer (the theme/palette contrast-floor tests + the
|
||||
component geometry/hit-test helpers); in-DAW, the kit renders a modern dark button/row/
|
||||
surface with AA cached-font text and working hover/pressed states, drawn double-buffered
|
||||
with no flicker.
|
||||
**Depends on:** the existing `bank_panel` LICE surface (the first consumer). Nothing in
|
||||
Phase S — L1 stands alone on the extension side.
|
||||
|
||||
- [ ] Pure `theme`/palette layer: role→color mapping (`bg/base`, `bg/panel`, `bg/cell`,
|
||||
`text/primary`, `text/dim`, `accent`, `accent/hot`, `warn`) selected via **one direction
|
||||
constants block** carrying the settled **B (Neon Console) + C spectral** values (DS-2),
|
||||
so the direction is a single-file change. Unit-test that each text-on-surface pair clears
|
||||
its WCAG floor (AA 4.5:1 body / 3:1 large + state indicators) — the "punch to the floor,
|
||||
not past it" rule made testable. No LICE/host types.
|
||||
- [ ] Pure component **geometry/hit-test** helpers where not already owned: button rect,
|
||||
slider track/handle geometry, list-row rect + hover hit-test (mirror of
|
||||
`mode_switch`/`bank_grid`/`editor_geometry` — no LICE, no host types, CTest-covered).
|
||||
- [ ] Shell **draw kit** (LICE): `fillSurface` (micro-gradient + 1px inner highlight/shadow
|
||||
— the vwnd trick that kills the flat look), `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).
|
||||
Double-buffered draw preserved (draw to `LICE_SysBitmap`, single `BitBlt`) — the
|
||||
"zero-jank" half of "speed is the selling point." **DS-1: assess WDL/vwnd reuse here at
|
||||
build time** — reuse a vwnd piece (e.g. its scroll listbox) where genuinely cheaper than
|
||||
LICE, else draw on LICE; keep hit-test geometry in the pure layer either way.
|
||||
- [ ] Retire the raw GDI `DrawText` path in `bank_panel` in favor of the kit's cached-font
|
||||
`text()` — the single biggest "temple os → modern" lever. (The VST-editor/embed-strip GDI
|
||||
retirement is L3, gated on Phase S — see below.)
|
||||
|
||||
## L2 — dock-panel layout redesign (extension-side; DS-3: thorough, not a re-skin)
|
||||
**Goal:** Redesign the docked `bank_panel` **layout** to house the *full* button/affordance
|
||||
inventory — including the buttons **M11 adds** — intuitively, uncluttered, and useful, then
|
||||
draw it all through the L1 kit. This is **not** a light re-skin (DS-3 settled): M11's
|
||||
action-trigger buttons + keybinding-help labels, on top of the existing capture/organize/
|
||||
prune/view affordances, are a real button inventory that a straight skin-pass would leave
|
||||
crowded. L2 groups the inventory by *task* (capture, organize, reclaim, view), gives every
|
||||
button a home that does not squeeze the grid, and only then applies the kit's draws. All
|
||||
new layout math goes in a **pure geometry module** (mirror of `mode_switch`/`bank_grid`);
|
||||
`bank_grid`/`tab_strip`/`mode_switch` stay the pure source of truth for what they own.
|
||||
CONTEXT.md §Phase L (dock-panel layout contract — the full M11-aware inventory).
|
||||
**Verify (in DAW):** the full button inventory (existing + M11) is laid out cleanly — the
|
||||
grid stays the centerpiece, frequent capture actions are one reach away with their keybinding
|
||||
labels legible, destructive prune is set apart and `warn`-marked, hover lights every
|
||||
interactive element; nothing is crammed or cut off at panel resize; the panel's GDI text is
|
||||
gone (kit cached-font throughout); all hit-testing is CTest-green pure geometry.
|
||||
**Depends on:** L1 (the kit). **Sequence AFTER M11 merges to dev** — L2 must inventory M11's
|
||||
*actual landed* buttons, not a forecast; starting before M11 designs against a moving target.
|
||||
|
||||
- [ ] **Layout design + pure geometry:** design the panel layout that groups the inventory
|
||||
by task — a compact action bar/toolbar for the frequent capture actions (icon+label,
|
||||
keybinding as a `micro` sub-label), an overflow/menu for rare ones, header space for the
|
||||
Design View mode switch + active-bank indicator, the bank tab strip + move/copy/remove
|
||||
organize cluster, and prune set apart and `warn`-colored. Add a new **pure** action-bar
|
||||
layout module (mirror of `mode_switch`/`bank_grid`); keep all hit-test math pure/CTest.
|
||||
- [ ] **Inventory the full M11-aware button set and place every one** (see CONTEXT.md
|
||||
§Phase L for the enumerated inventory): existing — bank grid, mode switch + membership
|
||||
count, named-banks tab strip (overflow/scroll), active-bank indicator, pool/banks
|
||||
full-height toggles, create/rename/delete/activate bank, move/copy/remove sample, prune
|
||||
(R-E); M11 — action-trigger buttons (capture item/track, re-capture, resample-and-mute,
|
||||
batch capture, conform-on-insert, insert-at-cursor, drag-out, null-test verify) and
|
||||
per-action keybinding-help labels. Density is a design decision: 8px grid, elevation
|
||||
layers over hairlines, `warn` for destructive verbs.
|
||||
- [ ] **Apply the L1 kit** to draw the redesigned panel: cached-font text (retire GDI),
|
||||
kit `drawButton`/segment/tab draws, palette roles, micro-gradient surfaces, hover on
|
||||
every interactive element. Structure of the vertical-split / grid / tab bones is
|
||||
preserved; the *layout of the inventory around them* is the design work (DS-3).
|
||||
|
||||
## L3 — VST editor + embed-strip restyle (GATED on Phase S landing on dev)
|
||||
**Goal:** Bring the ReaSampler 9000 VST editor (`IPlugView` LICE surface) and the S6 embed
|
||||
strip up to the settled B+spectral look via the L1 kit: cached-font text, kit component
|
||||
draws, the Neon-Console palette, the **spectral keyboard strip** as the signature surface
|
||||
(DS-2), and hover/pressed/drag states throughout. CONTEXT.md §Phase L (VST restyle + the
|
||||
Phase S coordination contract). Product framing: `docs/product/visual-design-language.md` §5.3.
|
||||
**Verify (in DAW):** the VST editor + embed strip render in the settled B+spectral language
|
||||
through the L1 kit — AA cached-font text, gradient/rounded kit components, the spectral
|
||||
keyboard strip, working hover/pressed/drag; the VST3 class UID is unchanged (a visual
|
||||
refresh is not a compat event).
|
||||
**Depends on:** L1 (the kit) **AND — GATE — Phase S landing on dev.** The VST editor, embed
|
||||
strip, and 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 with Phase S (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, and L3 is the point that completes the VST/embed
|
||||
> adoption and applies the settled B+spectral treatment.
|
||||
|
||||
- [ ] Route the VST editor's + embed strip's text through the kit's cached-font `text()`;
|
||||
retire their raw GDI `DrawTextA` path. (Gated — Phase S surfaces must be on dev.)
|
||||
- [ ] Restyle the editor + embed components through the kit (buttons, sliders/ADSR, list
|
||||
rows, waveform, segmented controls) in the B (Neon Console) palette; add hover/pressed/
|
||||
drag states. (Gated.)
|
||||
- [ ] Apply **Direction C's spectral treatment to the keyboard strip** (hue-mapped zones,
|
||||
glow-on-active as a static drawn state — never a pulse, per the speed constraint) as the
|
||||
signature surface; VST3 class UID unchanged. (Gated.)
|
||||
|
||||
## Phase L — sequencing
|
||||
```
|
||||
L1 (shared kit) ──► L2 (dock-panel layout redesign; AFTER M11 merges to dev)
|
||||
└─────────► L3 (VST editor + embed-strip restyle; GATED on Phase S landing on dev)
|
||||
|
||||
Phase S (separate team, ungated): S-work builds with current drawing, adopts L1 when it lands.
|
||||
```
|
||||
L1 is the foundation both L2 and L3 consume. L2 is extension-side, lands after M11. L3 waits
|
||||
for Phase S to reach dev. Phase S feature work runs in parallel, ungated by Phase L.
|
||||
|
||||
## Phase L — must-verify-before-build
|
||||
- **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`
|
||||
(design-language doc §1.1); **confirm exact signatures + the `LICE_CachedFont`↔`HFONT`
|
||||
lifecycle at build.**
|
||||
- **WDL/vwnd reuse assessment (DS-1)** — at build time, evaluate whether a vwnd piece beats
|
||||
re-deriving it: `virtwnd-slider.cpp` / `vwnd_slider_drawknobstack` as the slider/knob
|
||||
drawing reference, `virtwnd-listbox.cpp` as a candidate scroll listbox, `virtwnd-controls.h`
|
||||
for `WDL_STYLE_*` gradient hooks, `virtwnd-skin.h` for image-skin helpers. Reuse where
|
||||
useful; keep hit-test geometry pure regardless.
|
||||
- **M11 button inventory (L2)** — L2's layout depends on the *actual* set of buttons M11
|
||||
lands (action-trigger buttons + keybinding-help labels). Re-inventory against dev after
|
||||
M11 merges before finalizing the layout.
|
||||
|
||||
@@ -0,0 +1,545 @@
|
||||
# Visual design language — ReaSampler + ReaSampler 9000 (Phase L)
|
||||
|
||||
System-wide look-and-feel framing. This is the **why** and the visual spec for the
|
||||
whole-system look-and-feel effort, now carried as its own **Phase L** (Look-and-feel):
|
||||
the shared LICE drawing kit (**L1**), the extension's docked bank-panel layout redesign
|
||||
(**L2**), and the ReaSampler 9000 VST editor + embed-strip restyle (**L3**). It was
|
||||
written after Daniel DAW-tested the S1–S6 instrument:
|
||||
|
||||
> "this shit looks like temple os. it's 2026, we need something more modern and sleek.
|
||||
> speed is the selling point. […] If we are going to enhance look and feel, we need to
|
||||
> think big and full. Scope it out for the whole system. […] the VST is dogshit. Does
|
||||
> Cockos have a toolkit for this type of visual design?"
|
||||
|
||||
**Status:** framed by product-designer (2026-07-26); the DS-1/DS-2/DS-3 forks are
|
||||
**SETTLED (Daniel, 2026-07-26)** — recorded in §6 with the reasoning preserved. The
|
||||
build points it feeds live in **PLAN.md §Phase L** (**L1** the shared LICE drawing kit,
|
||||
**L2** the dock-panel layout redesign, **L3** the VST editor + embed-strip restyle) and
|
||||
**CONTEXT.md §Phase L** (the design-system spec). Toolkit facts below are **verified
|
||||
against the vendored `vendor/WDL` tree**, not lore.
|
||||
|
||||
> **Phase-boundary note (2026-07-26).** This look-and-feel effort was originally drafted
|
||||
> as Phase S points **S0-DS** (the shared kit) and **S14** (the panel refresh). It was
|
||||
> **lifted out of Phase S into its own Phase L** so a parallel team can take it up
|
||||
> without Phase S context and so Phase S feature work (S7–S13) proceeds ungated. The old
|
||||
> `S0-DS` content is now **L1**; the old `S14` content is now **L2** (expanded from a
|
||||
> light re-skin into a thorough layout redesign — see DS-3 below); the VST editor +
|
||||
> embed-strip restyle, which S10–S13 originally folded in, is now the explicit **L3**
|
||||
> point, **gated on Phase S landing on dev**. Phase S's S10–S13 build their interaction
|
||||
> UX with the current drawing and **adopt the L1 kit when it lands** — they are not
|
||||
> gated on Phase L.
|
||||
|
||||
---
|
||||
|
||||
## 0. TL;DR
|
||||
|
||||
- **Cockos ships exactly the toolkit Daniel asked about**, and it's already vendored.
|
||||
Two layers: **LICE** (the immediate-mode 2D rasterizer — gradients, anti-aliased
|
||||
lines/circles/round-rects/beziers, alpha blending, and a real font engine with
|
||||
shadow/outline/glow effects) and **WDL VirtualWnd / vwnd** (a retained-mode LICE-drawn
|
||||
*widget* layer — buttons, sliders, knobs, listboxes, skins — the thing REAPER and SWS
|
||||
themselves are built on). **The current VST editor uses almost none of it** — it draws
|
||||
flat `LICE_FillRect` blocks and pipes text through raw GDI `DrawTextA`. *That* is the
|
||||
"temple os" look: no gradients, no anti-aliasing, no rounded corners, no hover, aliased
|
||||
system text. The ceiling is not the problem; we're drawing at the floor.
|
||||
- **DS-1 SETTLED (2026-07-26): LICE, and anything useful in WDL is free game.** "Don't
|
||||
reinvent the wheel" — if vwnd (or any WDL machinery: skin/image helpers, draw idioms)
|
||||
offers a usable piece, use it; otherwise build on LICE. **No external frameworks**
|
||||
(not JUCE, not iPlug2, not VSTGUI). LICE can deliver a 2026-modern dark synth UI —
|
||||
REAPER's own themed UI and SWS prove the ceiling. This is fully consistent with the
|
||||
settled **D-A** decision (bare SDK + LICE, no framework); the fork is recorded in §6.
|
||||
- **The real work is L1 — a shared drawing kit** — one small LICE-based
|
||||
component/palette/type layer that the VST editor, the embed strip, and the bank panel
|
||||
all draw through. It is the one source of drawing for the whole system.
|
||||
- **DS-2 SETTLED (2026-07-26): Direction B ("Neon Console") + Direction C's spectral
|
||||
keyboard strip** as the signature surface. Three visual directions are in §4; B+spectral
|
||||
is the settled target. "Speed is the selling point" is a **design constraint**, not a
|
||||
tagline: the UI must *feel* instant (§3.5).
|
||||
- **DS-3 SETTLED (2026-07-26): the dock-panel work is a real, thorough layout design, not
|
||||
a light reskin.** L2 lays out the *full button inventory* (including M11's additions)
|
||||
intuitively, uncluttered, and useful — §5.2.
|
||||
|
||||
---
|
||||
|
||||
## 1. The toolkit question, answered from the vendored source
|
||||
|
||||
Daniel: *"Does Cockos have a toolkit for this type of visual design?"* Yes — two layers,
|
||||
both already in `vendor/WDL`. Verified by reading the headers, not from memory.
|
||||
|
||||
### 1.1 LICE — the rasterizer (this is the load-bearing answer)
|
||||
|
||||
`vendor/WDL/WDL/lice/` is Cockos's own 2D graphics library — the same one REAPER's UI,
|
||||
the theme engine, and SWS draw with. The current `bank_panel` and VST editor already link
|
||||
it. What it actually offers, beyond the flat `LICE_FillRect` the editor currently limits
|
||||
itself to (all verified in `lice/lice.h` / `lice/lice_text.h`):
|
||||
|
||||
| Capability | Function (verified) | We use it today? |
|
||||
|---|---|---|
|
||||
| **Gradient fills** | `LICE_GradRect` (per-axis R/G/B/A ramps) | **No** — this alone kills the flat look |
|
||||
| **Anti-aliased lines** | `LICE_Line`/`LICE_FLine`/`LICE_ThickFLine` (`aa=true` default) | No |
|
||||
| **Rounded rectangles** | `LICE_RoundRect` (corner radius, AA) | No |
|
||||
| **AA circles / knobs** | `LICE_Circle`/`LICE_FillCircle` | No |
|
||||
| **Bezier curves** | `LICE_DrawCBezier` (AA envelope/curve draw) | No |
|
||||
| **Triangles / polygons** | `LICE_FillTriangle`/`FillConvexPolygon`/`FillTrapezoid` | No |
|
||||
| **Alpha compositing** | every primitive takes `alpha` + blend `mode` | Barely (opaque only) |
|
||||
| **Real font engine** | `LICE_CachedFont` / `LICE_IFont`: `SetFromHFont`, AA glyph cache, `SetTextColor`, `DrawText` | **No — we use raw GDI `DrawTextA`** |
|
||||
| **Text effects** | shadow / outline / glow / blur (`LICE_FONT_FLAG_FX_SHADOW`/`_OUTLINE`/`_BLUR`) | No |
|
||||
|
||||
**The single biggest visual lever is text.** The editor's `drawText` does
|
||||
`GetDC` → `SetTextColor` → `DrawTextA` — native, un-anti-aliased-in-the-bitmap GDI text
|
||||
that reads as "1998." Switching to a `LICE_CachedFont` (created once from a chosen
|
||||
`HFONT`, cached, AA glyphs, optional soft shadow) is the difference between "temple os"
|
||||
and "modern synth." Small, mechanical change, outsized payoff, and it belongs in L1 (§5)
|
||||
so every surface gets it at once. `bank_panel` already routes some text through GDI too;
|
||||
the kit fixes both.
|
||||
|
||||
**Conclusion:** LICE is a genuine, sufficient 2D toolkit for a modern dark synth UI. The
|
||||
gap between the current editor and a sleek one is entirely in *which LICE calls we make*,
|
||||
not in LICE's ceiling. **No new dependency is required to get the look Daniel wants.**
|
||||
|
||||
### 1.2 WDL VirtualWnd (vwnd) — the retained-mode widget layer, and DS-1's "free game" rule
|
||||
|
||||
`vendor/WDL/WDL/wingui/virtwnd*.{h,cpp}` is the layer above LICE: `WDL_VWnd` (a virtual
|
||||
window / control that draws itself into a shared LICE bitmap), with concrete controls —
|
||||
`virtwnd-iconbutton.cpp` (buttons), `virtwnd-slider.cpp` (sliders +
|
||||
`vwnd_slider_drawknobstack` knob rendering), `virtwnd-listbox.cpp` (scrolling lists),
|
||||
`virtwnd-skin.h` (image-based skins), plus `WDL_STYLE_*` hooks for background gradients
|
||||
and slider/knob bitmaps (`virtwnd-controls.h`). **This is the toolkit REAPER and SWS
|
||||
themselves use for custom UI.**
|
||||
|
||||
**DS-1's settled rule: WDL is free game — don't reinvent the wheel.** Where a WDL piece
|
||||
(a skin/image helper, a draw idiom, a specific control's rendering) is genuinely usable
|
||||
and cheaper than re-deriving it, **use it**; otherwise build on LICE directly. The one
|
||||
standing caution — not a prohibition — is the **retained-mode object model**: vwnd's
|
||||
controls own their hit-test/drag/value internally, whereas the house discipline keeps
|
||||
layout/hit-test in **pure geometry modules** (`mode_switch`, `embed_strip`,
|
||||
`editor_geometry`, the planned `keyboard_strip`) so hit-test math stays CTest-covered
|
||||
outside the DAW. So the default is to **borrow vwnd's drawing craft** (read
|
||||
`virtwnd-slider.cpp` / `vwnd_slider_drawknobstack` as the reference for a good LICE
|
||||
slider/knob and reproduce the look procedurally over pure geometry we own) and to reach
|
||||
for a vwnd *object* only where it carries no bespoke-geometry requirement and re-deriving
|
||||
it is genuinely wasteful. The plain **scrolling listbox** (`virtwnd-listbox.cpp`) for a
|
||||
long sample list is the archetypal "just use it" case — no bespoke drawing, tedious to
|
||||
re-derive; adopt it if it fits at build time. The **keyboard strip and waveform** are
|
||||
bespoke surfaces vwnd has no widget for — custom-drawn regardless. The rule is a
|
||||
build-time judgment call per piece, made under one principle: **reuse what WDL gives us,
|
||||
keep hit-test geometry testable.**
|
||||
|
||||
### 1.3 The frameworks we are NOT taking (and why — DS-1 settled: no external frameworks)
|
||||
|
||||
- **IPlug (WDL's own `IPlug/`)** — the VST2-era plugin framework in WDL. **Dated and
|
||||
irrelevant.** VST2 is deprecated; it predates VST3; it's not a UI toolkit anyway. Ignore.
|
||||
- **iPlug2** (the modern community fork — NanoVG/Skia GPU renderers, web-UI option) — a
|
||||
genuinely capable modern framework, but it is a **whole new plugin-framework dependency**
|
||||
that would **replace** the bare-SDK + LICE architecture **D-A** settled on 2026-07-26. It
|
||||
brings its own graphics stack (NanoVG/Skia), its own build integration, and its own
|
||||
editor/parameter model — none of which we need, because LICE already clears the bar.
|
||||
**Rejected** (DS-1 settled: no external frameworks).
|
||||
- **VSTGUI** (bundled with the Steinberg SDK) — the noted D-A fallback rung *if the
|
||||
IPlugView↔LICE bridge had proven gnarly*. On the phase-s worktree it didn't — S1 landed
|
||||
the bridge, the editor draws in LICE today. VSTGUI is moot; we're past the point it hedged.
|
||||
|
||||
**Net:** the toolkit question resolves cleanly. Use **LICE** (already in hand, already the
|
||||
draw surface) as the toolkit, **reuse WDL/vwnd pieces where useful** (DS-1's "don't
|
||||
reinvent the wheel"), and **take no external framework.** Fully consistent with D-A.
|
||||
|
||||
---
|
||||
|
||||
## 2. Palette — dark, modern, punchy
|
||||
|
||||
Daniel's standing taste: **visual punch over conservative contrast** — push vibrancy to
|
||||
the WCAG floor for each element class, not to the past-safe gray. The current palette
|
||||
(shared between `bank_panel.cpp` and the VST editor) is a muted forest-green-on-charcoal:
|
||||
background `RGB(28,28,30)`, waveform/accent `RGB(120,200,160)`, cell `RGB(44,44,48)`. It's
|
||||
*coherent* but *timid* — one desaturated accent, flat fills, hairline borders.
|
||||
|
||||
### 2.1 Structural roles (direction-independent)
|
||||
|
||||
A modern dark UI is built from **elevation layers**, not borders. Define the palette by
|
||||
role, then let the direction set the accent:
|
||||
|
||||
| Role | Purpose | Current | Direction |
|
||||
|---|---|---|---|
|
||||
| `bg/base` | window canvas | `28,28,30` | deepen slightly + a **subtle top-down `LICE_GradRect`** (base look, not flat) |
|
||||
| `bg/panel` | a raised region (list, waveform pane) | — (implicit) | one step lighter than base; elevation reads without a border |
|
||||
| `bg/cell` | a control/row surface | `44,44,48` | as now, but with a 1px inner top highlight (the vwnd trick) |
|
||||
| `line/hairline` | separators | `60,60,66` | keep, use sparingly — elevation should carry most separation |
|
||||
| `text/primary` | labels, values | `210,230,220` | near-white, **must clear WCAG AA (4.5:1) on `bg/panel`** |
|
||||
| `text/dim` | secondary / units | — | a dimmer step, still **AA-large (3:1) minimum** — the WCAG floor, not below it |
|
||||
| `accent` | selection, active, focus | `120,200,160` | **Direction B: one vivid hue** (§4) — this is where the punch lives |
|
||||
| `accent/hot` | hover / live / drag feedback | — (absent) | a brighter accent tint; **today there is no hover color at all** |
|
||||
| `warn` | clip / destructive (prune, delete) | — | a red/amber reserved *only* for byte-deleting or clip states |
|
||||
|
||||
**WCAG-floor discipline (the "punch" rule, concretely):** for each text-on-surface pair,
|
||||
pick the *most* saturated/vibrant accent that still clears its contrast floor — AA 4.5:1
|
||||
for body text, 3:1 for large text and for UI-state indicators (selection borders, active
|
||||
fills). Do not retreat to safe grays "to be sure." The floor is the target, approached
|
||||
from the vibrant side.
|
||||
|
||||
### 2.2 Motion of color, not just color
|
||||
|
||||
The flat look isn't only the hue — it's that every fill is a **single opaque rectangle**.
|
||||
A 2026 dark UI reads as dimensional because surfaces have a **micro-gradient** (a few
|
||||
percent lighter at the top, `LICE_GradRect`) and controls have a **1px top inner-highlight
|
||||
+ 1px bottom inner-shadow**. This is the single cheapest "modern" upgrade after AA text,
|
||||
and it's exactly what `virtwnd`'s button/slider drawing does. Bake it into the kit's
|
||||
`fillSurface()` primitive so every button, row, and cell gets it for free.
|
||||
|
||||
---
|
||||
|
||||
## 3. Typography, spacing, interaction, motion
|
||||
|
||||
### 3.1 Typography within LICE's reality
|
||||
|
||||
- **Use `LICE_CachedFont`, retire raw GDI `DrawTextA`.** Create a small set of cached
|
||||
fonts once (below), owned by the kit, reused across VST + embed + panel. AA glyphs in
|
||||
the bitmap are the "temple os → modern" switch.
|
||||
- **Two or three weights/sizes, no more.** A tool UI wants a **type scale**, not
|
||||
typographic variety: `title` (~15px semibold), `label` (~12px regular), `value`/`mono`
|
||||
(~12px, tabular for note numbers / ms / dB so digits don't jitter during a drag),
|
||||
`micro` (~10px, dim, for units/counts). Four cached fonts total.
|
||||
- **Font choice:** a clean UI sans is available on every Windows target (Segoe UI is the
|
||||
safe system default; the kit takes an `HFONT`, so the exact face is a one-line change).
|
||||
For the numeric `value` role, a tabular/mono face (Consolas is universally present)
|
||||
keeps dragged numbers from reflowing. Windows-only (D5) means no cross-platform
|
||||
font-fallback worry.
|
||||
- **Soft shadow on title/accent text only** (`LICE_FONT_FLAG_FX_SHADOW`) — subtle depth,
|
||||
used sparingly; body text stays crisp and flat for legibility.
|
||||
|
||||
### 3.2 Spacing & grid
|
||||
|
||||
- **An 8px base unit** (4px for tight internal padding). Row heights, gaps, and pane
|
||||
insets are multiples of it — this is what makes a UI read as "designed" not "placed."
|
||||
- **Generous row height** for list/zone rows (~28–32px). In the editor, S10 deletes the
|
||||
seven mini-buttons per row so rows can breathe.
|
||||
- **Consistent 8px pane inset** everywhere (panel edges, between panes). The current
|
||||
editor pins controls flush to edges — a big part of the cheap feel.
|
||||
|
||||
### 3.3 Interaction states (the editor currently has NONE)
|
||||
|
||||
A control looks identical whether the mouse is over it, on it, or nowhere near. **This is
|
||||
half of why it feels dead.** Define a state model every kit component honors:
|
||||
|
||||
| State | Visual | Cost |
|
||||
|---|---|---|
|
||||
| **rest** | `bg/cell` + inner highlight | — |
|
||||
| **hover** | lighten fill toward `accent/hot`, ~8–12% | requires `WM_MOUSEMOVE` tracking (§3.5) |
|
||||
| **active/selected** | `accent` fill + `accent` border | already partly present |
|
||||
| **pressed** | darken + 1px inset (the surface "pushes in") | on `WM_LBUTTONDOWN` |
|
||||
| **dragging** | live element follows cursor; ghost/marker at target; rest dims slightly | S10 drag machine |
|
||||
| **focus (keyboard)** | 1px `text/primary` ring (distinct from selection) | already present in panel (`kColFocusBorder`) |
|
||||
| **disabled** | desaturate + 40% alpha | rare (stale zone, no bank) |
|
||||
|
||||
Hover is the highest-value addition — it's what makes a UI feel *alive* and responsive,
|
||||
and the visible proof of "speed is the selling point" (§3.5). It requires
|
||||
`WM_MOUSEMOVE` (and `TrackMouseEvent` for `WM_MOUSELEAVE`). The panel's `wndProc` already
|
||||
runs a timer; adding hover tracking is cheap. In the editor, the S10 drag-state machine
|
||||
already introduces the move tracking, so hover rides in on that work at near-zero cost.
|
||||
|
||||
### 3.4 Component patterns (reused across VST + embed + panel)
|
||||
|
||||
The kit defines a **small, shared vocabulary** of drawn components, each: (a) drawn by a
|
||||
kit function taking a `Rect` + state, (b) hit-tested by a **pure geometry** helper (the
|
||||
house discipline). The set:
|
||||
|
||||
- **Button** — rounded (`LICE_RoundRect`), gradient fill, inner highlight, hover/pressed
|
||||
states, centered `LICE_CachedFont` label. Replaces the flat `LICE_FillRect` +
|
||||
`DrawRect` + GDI-text buttons in both artifacts (the whole M11 action-button
|
||||
inventory, panel toggles, prune button, Add Zone, etc.).
|
||||
- **List row** — selectable, hover, focus, optional leading thumbnail (the panel's
|
||||
waveform cell is a specialization). Shared by the sample list (VST + panel) and zone
|
||||
list.
|
||||
- **Slider / knob** — for ADSR (S12) and any level control; drawn in the
|
||||
`virtwnd-slider` idiom (track + filled portion + handle with highlight), hit-test pure.
|
||||
- **Marker / handle** — the draggable grip primitive: keyboard-strip zone edges (S10),
|
||||
waveform loop markers (S11). A consistent grip look (a bright vertical bar + a small
|
||||
triangular tab) so "this is draggable" reads instantly.
|
||||
- **Segmented switch** — the panel already has this (`mode_switch`); restyle it through
|
||||
the kit (gradient segments, lit-active, hover).
|
||||
- **Tab (named-banks strip)** — a specialization of the segmented/button idiom with the
|
||||
overflow/scroll affordance already specced in Phase B; drawn through the kit.
|
||||
- **Waveform** — peaks envelope (`peaks` module) drawn as a filled AA shape
|
||||
(`LICE_FillTriangle`/trapezoids or a bezier top), midline, over `bg/panel`. Shared
|
||||
between the panel thumbnail and the S11 editor waveform.
|
||||
- **Keyboard strip** — the bespoke S10 surface: white/black key lanes, zone bars as
|
||||
translucent colored overlays, root markers. No prior art in the kit; it *defines* new
|
||||
kit primitives (key-lane fill, zone overlay). **Direction C's spectral treatment
|
||||
(§4, DS-2 settled) lives here** — the hue-mapped keyboard is the signature surface.
|
||||
|
||||
### 3.5 Motion policy — "speed is the selling point," read as a constraint
|
||||
|
||||
Daniel named speed as *the* selling point. The design reading: **the UI must feel
|
||||
instant, and no decoration may cost that.** Concretely —
|
||||
|
||||
- **Sub-frame response.** Hover/press/drag feedback repaints immediately on the input
|
||||
message (no timer latency). This is why hover tracking is a *feature*, not overhead —
|
||||
instant visual acknowledgment is the *perception* of speed.
|
||||
- **Zero-jank drawing.** Keep the existing **double-buffer** discipline (draw to a
|
||||
`LICE_SysBitmap`, single `BitBlt`) the editor and panel already use. Every kit
|
||||
component draws into the offscreen bitmap; nothing draws direct-to-DC.
|
||||
- **Repaint only what changed where cheap.** Full-panel repaint is fine at these sizes,
|
||||
but during a drag, invalidate the affected region (`InvalidateRect` with a rect, not
|
||||
`nullptr`). Build-time residual, flagged not mandated.
|
||||
- **NO decorative animation.** No easing tweens, no fades, no animated meters beyond a
|
||||
direct level follow. Animation that costs a frame of latency **violates** the speed
|
||||
promise. The one permitted case: a level/meter readout that follows the audio directly
|
||||
(already how the embed strip's level band works). Motion = immediate feedback, never
|
||||
ornament. **Direction C's glow/bloom is a drawn *state*, never a pulse** — it must stay
|
||||
static.
|
||||
- **The "fast" feeling is mostly typography + hover + no-jank**, not motion. A crisp AA
|
||||
label that lights on hover and commits a drag with zero flicker *reads* faster than any
|
||||
animation.
|
||||
|
||||
---
|
||||
|
||||
## 4. Three visual directions (DS-2 SETTLED: B + C's spectral keyboard strip)
|
||||
|
||||
Each is a complete palette + treatment, not a shade of the same thing. All three are
|
||||
LICE-drawable today (no new dependency); all three honor the WCAG-floor "punch" rule.
|
||||
Ordered safe → bold. **Daniel settled (2026-07-26) on Direction B as the target, with
|
||||
Direction C's spectral keyboard strip as the signature surface.**
|
||||
|
||||
### Direction A — "Studio Rack" (evolutionary; not selected)
|
||||
|
||||
The current forest-green-on-charcoal, but *executed properly*: gradient surfaces, AA
|
||||
text, rounded controls, a hover state, inner highlights. Same hue family — accent stays
|
||||
green (brightened to `~140,220,170`), background gains a subtle vertical gradient,
|
||||
controls get the vwnd inner-highlight/shadow treatment.
|
||||
|
||||
- **Feel:** a well-made piece of pro audio hardware. Restrained, "REAPER-native."
|
||||
- **Why not selected:** it's the *conservative* answer — fixes "temple os" but doesn't
|
||||
make anyone say "sleek." Retained as the fallback if B/C ever feel too loud for a
|
||||
pro-audio context, but Daniel's taste points away from it.
|
||||
|
||||
### Direction B — "Neon Console" (contemporary synth; SETTLED default)
|
||||
|
||||
A modern soft-synth / plugin look: near-black background (`~18,18,22`) with a **single
|
||||
vivid accent** (electric cyan `~60,200,235` leads; hot magenta `~235,70,170` is the
|
||||
bolder sub-option), used with intent for the *live/active/selected* layer only. Everything
|
||||
else is a calm neutral gray scale; the accent does all the punch. Waveforms and the
|
||||
keyboard strip's active zone glow in the accent; inactive elements are quiet gray. This is
|
||||
the "Serum / Vital / modern Arturia" idiom — vivid-accent-on-near-black.
|
||||
|
||||
- **Feel:** a 2026 instrument. Sleek, focused, the accent guides the eye to what's live.
|
||||
- **Accent:** one vivid hue (cyan leads). Clears WCAG-large comfortably at full saturation
|
||||
on near-black — "push to the floor from the vibrant side." A second dimmer tint for
|
||||
hover. **This is the settled target** — the strong-but-safe center; the single-accent
|
||||
discipline is easy to keep coherent across VST + embed + panel.
|
||||
- **Watch:** a single vivid accent can feel "gamer" if over-applied — discipline required
|
||||
(accent = live only, never chrome). One hue is a commitment; changing it later is a
|
||||
palette sweep (cheap in the shared kit — one constants block — but a sweep).
|
||||
|
||||
### Direction C — "Spectral" (bold; SETTLED for the keyboard strip)
|
||||
|
||||
Lean *all the way* into vibrancy and depth. Near-black base, but the accent is a
|
||||
**two-color gradient** — zones and the waveform aren't a flat accent, they're a
|
||||
**hue-mapped gradient** (e.g. low notes cool-blue → high notes hot-magenta across the
|
||||
keyboard strip; the waveform filled with a vertical accent gradient). Selection glows; the
|
||||
active zone has a soft outer bloom (`LICE_GradRect` halo). Multi-zone keymaps become
|
||||
genuinely *beautiful* — each zone a band of the spectrum — which is exactly the
|
||||
"multi-zone-in-one-instance" capability that RS5K structurally lacks (the sharpest
|
||||
"better than RS5K" claim, made *visual*).
|
||||
|
||||
- **Feel:** premium, almost visualizer-grade. The keyboard strip becomes a signature — a
|
||||
spectrum you play across.
|
||||
- **Settled scope:** **C's spectral treatment lands on the keyboard strip** (the signature
|
||||
surface), over Direction B's Neon-Console chrome everywhere else. This is the
|
||||
"modern-sleek center with one bold, identity-defining surface" Daniel chose — dial the
|
||||
spectrum up (full C across more surfaces) or down (pure B) after seeing it on the DAW.
|
||||
- **Watch:** gradients/bloom are easy to overdo into "toy"; the glow must stay a static
|
||||
drawn state, never a pulse (§3.5); risks reading as *flashy* over *fast* if the speed
|
||||
discipline slips.
|
||||
|
||||
**Settled recommendation, now spec:** build the **kit palette abstractly** (roles, not
|
||||
hardcoded colors — §2.1) so the direction is *one file of constants*; **default to
|
||||
Direction B (Neon Console)** with **Direction C's spectral keyboard strip** as the
|
||||
signature surface. Because the palette is abstract, a later re-pick is one file.
|
||||
|
||||
---
|
||||
|
||||
## 5. The build shape (feeds PLAN.md / CONTEXT.md §Phase L)
|
||||
|
||||
Three points and their sequencing.
|
||||
|
||||
### 5.1 `L1` — shared LICE drawing kit (the foundation)
|
||||
|
||||
A small shared module — the palette + type + component-draw layer that the VST editor,
|
||||
the embed strip, and the bank panel all draw through. Honoring the house pure/shell split:
|
||||
|
||||
- **Pure layer (CTest-covered):** the *geometry* of components — a `theme`/palette module
|
||||
(role → color, direction-selectable via one constants block; pure, trivially testable
|
||||
that contrast pairs clear their floor with the B+spectral constants) and per-component
|
||||
**layout/hit-test** helpers where they don't already exist (button rect, slider
|
||||
track/handle geometry, list-row rect + hover hit-test). These mirror
|
||||
`mode_switch`/`embed_strip`/`editor_geometry` — no LICE, no host types, unit-tested.
|
||||
- **Shell layer (DAW-verified):** the **draw kit** — LICE functions that render each
|
||||
component (`drawButton`, `drawSlider`, `drawListRow`, `drawWaveform`, `fillSurface` with
|
||||
the micro-gradient + inner highlight, `text()` via a shared `LICE_CachedFont` set). Owns
|
||||
the cached-font lifecycle. **WDL/vwnd reuse is assessed here, at build time, per DS-1** —
|
||||
reuse a vwnd piece where it's genuinely cheaper (the scroll listbox is the archetype),
|
||||
else draw on LICE. This is the layer that *replaces* the flat `LICE_FillRect` +
|
||||
`DrawTextA` calls in every surface.
|
||||
- **Cross-artifact reuse (load-bearing):** the kit is the **one source** all surfaces
|
||||
draw through — the same instinct as the one-source-multiple-views rule. A button looks
|
||||
identical in the panel, the embed strip, and the VST because it's the same `drawButton`.
|
||||
This is what makes "scope it for the whole system" real rather than divergent restyles.
|
||||
- **Coordination with Phase S:** L1 is not S10's dependency — S10–S13 build their
|
||||
interaction UX with the *current* drawing and **adopt the kit when L1 lands** (whichever
|
||||
order happens). The kit is the one source of drawing; when both exist, all surfaces
|
||||
consume it.
|
||||
|
||||
### 5.2 `L2` — dock-panel layout redesign (extension-side; DS-3 SETTLED: thorough, not a re-skin)
|
||||
|
||||
**DS-3 settled (2026-07-26): this is a real, thorough layout design, not a light reskin.**
|
||||
The panel already has good bones (thumbnails, selection, focus ring, a LICE grid, the
|
||||
multi-bank vertical split, the Design View mode switch). But **M11 (about to merge to
|
||||
dev)** adds a substantial button inventory — the panel must lay out the *full* inventory
|
||||
intuitively, uncluttered, and useful. L2 designs that layout, then applies the L1 kit to
|
||||
draw it.
|
||||
|
||||
**The full button/affordance inventory L2 must place (dev, M11-aware):**
|
||||
|
||||
*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.
|
||||
|
||||
*M11 adds (dev PLAN.md M11 — merging now):*
|
||||
- **Action trigger buttons** — clickable buttons that fire 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 real cluster of buttons.
|
||||
- **Keybinding help labels** — each capture/provenance action surfaces its current key
|
||||
binding (e.g. "Capture Item → F5") or an "unbound" marker.
|
||||
|
||||
**L2 design mandate (the thorough part):**
|
||||
- **Group by function, not by phase.** The user thinks in *tasks* — capture, organize,
|
||||
reclaim, view — not in M/B/R/D phases. Cluster the capture-action buttons together
|
||||
(with their keybinding labels), the bank-organization affordances together (tabs +
|
||||
move/copy/remove + create/rename/delete), the view/mode switch in the header, and the
|
||||
destructive prune apart and `warn`-marked. First-principles: what does a capture-heavy
|
||||
workflow reach for most, and how few clicks/pixels away is it?
|
||||
- **A place for every button that doesn't crowd the grid.** The grid is the centerpiece;
|
||||
the button inventory must not squeeze it. Consider a **compact action bar/toolbar** for
|
||||
the frequent capture actions (icon+label buttons drawn through the kit, keybinding as a
|
||||
`micro` sub-label), an **overflow/menu** for the rare ones, and reserved header space
|
||||
for view/mode. The keybinding labels are `micro`/`text-dim` so they inform without
|
||||
shouting.
|
||||
- **Density is a design decision, not an accident.** Use the 8px grid (§3.2), elevation
|
||||
layers (§2.1) to separate the action bar from the grid from the bank strip without a
|
||||
forest of hairlines, and the kit's `warn` role to make prune (and any destructive verb)
|
||||
unmistakable. Hover on every interactive element (§3.3).
|
||||
- **Then apply the L1 kit** to draw it all: cached-font text (retire the panel's GDI
|
||||
text), kit `drawButton`/segment/tab draws, palette roles, micro-gradient surfaces.
|
||||
- **Hit-test geometry stays pure.** The layout redesign may add new pure geometry modules
|
||||
(an action-bar layout module, mirror of `mode_switch`/`bank_grid`) but keeps all
|
||||
hit-test math in the pure, CTest-covered layer. `bank_grid`/`tab_strip`/`mode_switch`
|
||||
stay the source of truth for what they own; new layout gets its own pure module.
|
||||
|
||||
**Sequence L2 AFTER M11 merges to dev** — L2 must inventory M11's *actual* landed buttons,
|
||||
not a forecast of them. If L2 starts before M11 lands, it designs against a moving target.
|
||||
|
||||
### 5.3 `L3` — VST editor + embed-strip restyle (GATED on Phase S landing on dev)
|
||||
|
||||
The ReaSampler 9000 VST editor (`IPlugView` LICE surface) and the S6 embed strip get the
|
||||
full kit treatment: cached-font text, kit component draws, the B+spectral palette, the
|
||||
spectral keyboard strip as the signature surface, hover/pressed/drag states everywhere.
|
||||
|
||||
**L3 is explicitly GATED: these surfaces do not exist on dev yet.** The VST editor, the
|
||||
embed strip, and the keyboard strip live in Phase S, which has landed on the phase-s
|
||||
worktree but **not on dev**. L3 cannot be built on dev until Phase S (at least the editor
|
||||
+ embed surfaces, S1/S6/S10) lands on dev. **The Phase L team must not chase these files
|
||||
on dev** — the gate is stated so they don't. Until Phase S merges to dev, L3 is a planned,
|
||||
blocked point; L1 and L2 are the live Phase L work.
|
||||
|
||||
**Coordination contract (stated once, 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 (L1 kit or S10–S13 UX), the kit is
|
||||
the **one source of drawing**; when both exist, the Phase S surfaces draw through it, and
|
||||
L3 is the point that completes that adoption + applies the settled B+spectral look. If
|
||||
S10–S13 land on dev before L1, they draw in the current language and L3 restyles them; if
|
||||
L1 lands first, S10–S13 are born in the kit. Either way there is one kit, one look.
|
||||
|
||||
### 5.4 Sequencing summary
|
||||
|
||||
```
|
||||
L1 (shared kit) ──► L2 (dock-panel layout redesign, extension-side; AFTER M11 merges)
|
||||
└─────────► L3 (VST editor + embed-strip restyle; GATED on Phase S landing on dev)
|
||||
|
||||
Phase S (separate team, ungated): S7…S13 build with current drawing, adopt L1 kit when it lands.
|
||||
```
|
||||
|
||||
L1 is the foundation both L2 and L3 consume. L2 is extension-side and lands after M11. L3
|
||||
is gated on Phase S reaching dev. Phase S feature work proceeds in parallel, ungated.
|
||||
|
||||
---
|
||||
|
||||
## 6. Forks — all SETTLED (Daniel, 2026-07-26)
|
||||
|
||||
**Fork DS-1 — the toolkit. SETTLED: LICE + WDL free game, no external frameworks.**
|
||||
|
||||
- **Settled:** draw the modern look with **LICE** directly (gradients, AA, rounded, cached
|
||||
fonts). **Anything useful in WDL/vwnd is free game** — "don't reinvent the wheel": reuse
|
||||
a vwnd piece (skin/image helper, draw idiom, a specific control like the scroll listbox)
|
||||
where it's genuinely usable and cheaper than re-deriving; otherwise build on LICE. The
|
||||
one standing caution (not a ban): keep hit-test **geometry** in pure CTest-covered
|
||||
modules rather than importing vwnd's retained-mode object model wholesale, so the
|
||||
pure/shell split and its test coverage hold.
|
||||
- **Rejected:** any **external framework** — iPlug2, JUCE, VSTGUI. They re-open settled
|
||||
D-A to solve a look problem that is *not* a toolkit-ceiling problem (REAPER's own themed
|
||||
UI is LICE). WDL's own VST2-era `IPlug` is dated and irrelevant.
|
||||
- **Reasoning preserved:** LICE is a sufficient modern-dark-UI toolkit; the current
|
||||
"temple os" look is drawing at LICE's floor, not hitting its ceiling. No new dependency,
|
||||
fully consistent with D-A.
|
||||
|
||||
**Fork DS-2 — visual direction. SETTLED: Direction B (Neon Console) + Direction C's
|
||||
spectral keyboard strip.**
|
||||
|
||||
- **Settled:** **B** (near-black + one vivid accent, modern soft-synth idiom) as the
|
||||
system-wide target, with **C's spectral, hue-mapped keyboard strip** as the signature
|
||||
surface — the multi-zone-in-one-instance advantage made visual.
|
||||
- **Not selected:** **A Studio Rack** (evolutionary green — retained only as a fallback if
|
||||
B/C read too loud for pro-audio).
|
||||
- **Reasoning preserved:** modern-sleek center + one bold identity surface; Daniel reacts
|
||||
better to bold than to conservative. The kit palette is abstract (roles, one constants
|
||||
block), so this is **reversible for ~one file** — a starting direction, not a permanent
|
||||
lock.
|
||||
|
||||
**Fork DS-3 — panel refresh scope. SETTLED: thorough layout redesign (not a light
|
||||
re-skin).**
|
||||
|
||||
- **Settled:** L2 is a **real, thorough layout design** that lays out the full button
|
||||
inventory (including M11's action buttons + keybinding labels) intuitively, uncluttered,
|
||||
and useful — then applies the L1 kit to draw it. Sequenced **after M11 merges** so it
|
||||
designs against the actual button set.
|
||||
- **Superseded:** the earlier "(a) light — apply the kit, keep the structure" lean. M11's
|
||||
button additions make a *layout* pass necessary, not just a skin pass — a forest of new
|
||||
buttons crammed into the current structure would be exactly the clutter the redesign
|
||||
exists to prevent.
|
||||
- **Reasoning preserved:** the panel's grid/vertical-split bones are sound and stay; the
|
||||
*layout of the button inventory around them* is the design work. Structural rework
|
||||
destabilizing landed Phase-B panel work is still avoided — L2 groups and places, it does
|
||||
not tear down the vertical-split / grid / tab structure.
|
||||
|
||||
---
|
||||
|
||||
## 7. What this does NOT change (guardrails)
|
||||
|
||||
- **D-A stays settled** — bare Steinberg SDK + LICE, no framework. This doc *reinforces*
|
||||
it (LICE is sufficient), it does not re-open it. (D-A lives on the phase-s worktree; on
|
||||
dev it is the settled Phase S build-shape decision.)
|
||||
- **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. No
|
||||
hit-test math moves into untestable code, even where a WDL piece is reused (DS-1).
|
||||
- **RT discipline untouched** — the kit is draw-thread only; nothing here touches
|
||||
`process` or the off-thread reload handoff (Phase S concern).
|
||||
- **Read-only-over-bank untouched** — this is look-and-feel; no data-ownership change.
|
||||
- **The instrument keeps the same VST3 class UID / component-state contract** — a visual
|
||||
refresh is not a compat event (Phase S concern; noted for when L3 runs).
|
||||
- **Windows-only (D5)** — the font/GDI/HFONT choices assume Windows; no cross-platform
|
||||
font fallback concern.
|
||||
- **Phase S is not gated on Phase L** — S7–S13 proceed in parallel; they adopt the kit
|
||||
when it lands. Phase L (L1/L2) is the live work on dev; L3 waits for Phase S to reach dev.
|
||||
Reference in New Issue
Block a user