docs(phase-s): spec three-view editor redesign (S-VIEW) — Sample/Browse/Zone

This commit is contained in:
2026-07-27 12:46:43 -04:00
parent c22a78bcba
commit 13b23801a0
3 changed files with 530 additions and 147 deletions
+127 -120
View File
@@ -16,8 +16,7 @@ it here and appends it to `COMPLETED.md`.
## Milestone 9 — slots (MPC-style)
> **Explicitly deferred (Daniel, 2026-07-26) — not silently dropped. Can be picked
> up later if wanted.** An extra, not scheduled work.
> **Abandoned (Daniel, 2026-07-27) — will not be built.**
**Goal:** "Capture to slot N" / "insert slot N", MIDI-bindable. CONTEXT.md
Build order 9.
@@ -177,6 +176,99 @@ is **ReaSampler 9000**. Framing + propagation surfaces:
*cut* (choke) on note-off or on a same-group re-trigger (hi-hat open/closed). Deliberately
out of S15 scope (Trigger ignores note-off entirely there); a Tier-3 choke-group direction.
## Phase S — editor view-model redesign (three views: Sample / Browse / Zone)
> **Additive Phase S sub-phase (S-VIEW; Daniel, 2026-07-27, r9).** Re-partitions the ReaSampler
> 9000 editor from a two-view toggle into a **three-view model where the loaded sample is the
> home** — Sample (default face), Browse (modal picker over Sample), Zone (dedicated keymap
> surface). Adds two performance parameters (key-tracking, preview velocity) and two visual
> components (envelope overlay, real piano-key pattern), and frames two engineering prerequisites
> (drop-to-FX bug, default window size). An **editor** redesign — the S3 voice engine, keymap
> resolution, and read-only-over-bank contract are **unchanged**; component state extends
> additively for key-tracking; VST3 class UID unchanged. Authoritative spec: **CONTEXT.md §Phase
> S — editor view-model redesign (S-VIEW)**. Product framing: `docs/product/midi-playback.md`
> §Addendum r9. When a point lands, doc-keeper moves it to `COMPLETED.md`.
>
> **Depends on Phase S being on dev** (this redesigns Phase S editor shells —
> `reasampler_editor.cpp` + the pure `src/vst/` geometry modules). The Phase L L3 restyle and
> this S-VIEW redesign both touch the editor; sequence so they do not collide (S-VIEW is a
> layout/param change, L3 is a palette/kit change — best landed as one editor pass or S-VIEW then
> L3-restyle-the-new-layout).
**Goal:** A three-view editor that makes "pick a capture, tune it, play it" fast, easy, and fun —
Sample is home, Browse is an easy-to-summon modal picker, Zone is the deliberate keymap surface.
**Verify (in DAW):** open on a 1080p screen → full Sample face (hero waveform + envelope overlay +
fenced root + preview-trigger + control strip) with no scroll; Browse opens as a modal over
Sample, select+confirm loads a new capture; Zone opens on its own button, key-tracking + the
piano-key pattern work; drop-a-capture-onto-FX instantiates a playing instance.
- [ ] **S-VIEW-1 — three-view navigation model.** Retire the flat Browser|Zones toggle; introduce
Sample (home/default), Browse (modal overlay over Sample, select+confirm), Zone (dedicated
surface, own button). Empty state surfaces Browse as the dominant call-to-action. Fresh instance
stays silent (S10 reversal). See CONTEXT.md §S-VIEW navigation contract.
- [ ] **S-VIEW-2 — Sample view (the new main face).** Compose the home face: enlarged **hero
waveform** with the S11 markers (moved from Browse), a **fenced root affordance**, the
**Mono/Stereo toggle** (moved from Browse), and the **"Modes-and-down" control strip** (Mode /
Pitch engine / AHDSR|Trigger / AD pitch env — moved from Zone's param panel, single-capture
one-zone storage per S15-F2). Reference grammar: Simpler / Phase Plant (labelled value-strip
under a hero waveform).
- [ ] **S-VIEW-3 — envelope overlay on the hero waveform (new visual).** Draw the amp envelope
(AHDSR for Gate, fade/%-length for Trigger) as a curve over the Sample waveform at accurate
wall-clock time. New pure `envelope_overlay` module (params + frame-length → polyline; unit-
tested); shell traces it in an accent hue. Informative + decorative — sliders stay the edit
surface (node-drag deferred, fork S-VIEW-F2).
- [ ] **S-VIEW-4 — preview-trigger + velocity knob (new, Sample view).** A button firing the
sampler at the loaded capture's root note through the live voice engine (off the audio-thread
commit path — no MIDI controller needed) + an adjacent velocity knob. Preview velocity leans
**transient editor state** (fork S-VIEW-F1). RT discipline: no `process`-thread work.
- [ ] **S-VIEW-5 — Browse reduced to *choosing* (modal over Sample).** Keep search + bank tabs +
captures grid + scroll + selection; add **confirm/cancel** (double-click loads). **Remove** the
large waveform preview, Mono/Stereo toggle, root keyboard-strip (all moved to Sample), and the
loop-point labels + track-root message (cut). Render as a full-window modal overlay (fork
S-VIEW-F3).
- [ ] **S-VIEW-6 — key-tracking parameter (Zone + Sample, 0%200%, default 100%).** A per-
`PerformanceZone` scalar on keyboard pitch tracking around the root (100% = 12-tone-ET, 0% = no
tracking, 200% = double). Additive/version-bumped, defaults 100% (bit-identical). **Key-track
math lives in the pure sampler core** (unit-tested note/root/keyTrack → ratio), applied in both
Varispeed and Preserve repitch. Surfaces as a control on the Zone param panel + Sample control
strip.
- [ ] **S-VIEW-7 — real piano-key pattern on the keyboard strip (new visual).** Overlay the actual
alternating white/black (bright/dark per palette) key pattern over the pastel spectral fill so
the strip reads as a keyboard. Pure `keyboard_strip` gains a natural/accidental predicate (12-
tone, unit-tested); shell draws the two-tone overlay. Shared by the Zone strip + Sample root
affordance.
- [ ] **S-VIEW-8 — Zone view retained + wired.** Keep +Add Zone / Delete, the per-zone keyboard
strip (now with the piano pattern), the Low/High/Root numeric-entry legend, and the per-zone
param panel; add the key-tracking control. Nothing from today's Zones view dropped.
### Phase S editor prerequisites — routed to staff-engineer (bug + default; NOT design forks)
> Framed in CONTEXT.md §S-VIEW; both are functional prerequisites with the SDK swept and no
> platform ceiling — a diagnosis and a one-line default, not product decisions.
- [ ] **S-VIEW-BUG-1 — drop-to-FX diagnosis (staff-engineer).** Dropping a capture onto a track's
FX chain does not instantiate + init ReaSampler 9000 (drops as audio to arrange instead). The
S17 machinery is **SDK-correct and present** (`TrackFX_AddByName` + `vst_chunk` injection, all
verified); this is a **runtime bug**. Investigate in order: (1) FX-name match (`"VST3:" +
vstPluginName()` vs REAPER's scanned name); (2) gesture routing (`decideGesture`
`InstrumentDrop` vs falling to `OsDrag` — the observed symptom); (3) `vst_chunk` write result +
blob-format match with `setState`. **Verify in DAW:** drop → a playing instance on the track,
one Ctrl-Z removes it.
- [ ] **S-VIEW-SIZE-1 — 1080p default window size (staff-engineer).** The editor opens too small
(`ViewRect(0,0,560,400)`). Mechanism **verified** (`getSize`/`setRect`/`checkSizeConstraint`/
`onSize`/`canResize` in `vendor/vst3sdk/public.sdk/source/common/pluginview.h`): set a larger
default `ViewRect` sized for the new three-band Sample face on 1080p (~840×560+ starting point,
tuned to the band heights) + a `checkSizeConstraint` minimum floor. **Verify in DAW:** opens at
the new default showing the full Sample face without scroll; cannot shrink below the floor.
### Phase S editor redesign — forks (Daniel's to call)
- **S-VIEW-F1 — preview velocity persistence:** transient editor state (**lean**) vs. a small
persisted convenience. Lean transient — no compat surface, no version bump.
- **S-VIEW-F2 — envelope-overlay interactivity:** read-only overlay + sliders edit (**lean**, ship
first) vs. draggable envelope nodes (deferred stretch).
- **S-VIEW-F3 — Browse modal presentation:** full-window overlay (**lean**) vs. a centered sheet
over a dimmed Sample. Presentation detail.
---
# Phase L — Look-and-feel (system-wide visual design language)
@@ -194,13 +286,17 @@ is **ReaSampler 9000**. Framing + propagation surfaces:
> directions: `docs/product/visual-design-language.md`. When a point lands, doc-keeper
> moves it to `COMPLETED.md`.
>
> **L1 (shared LICE drawing kit — the foundation), L2 (dock-panel layout redesign), L4
> (dock-panel button layout enhancement), L5 (dock-panel button refinements), L6 (toolbar
> polish), and L7 (capture ordering, card metadata, and selection styling) have landed** —
> **L1 (shared LICE drawing kit — the foundation), L2 (dock-panel layout redesign), L3
> (VST editor + embed-strip restyle), L4 (dock-panel button layout enhancement), L5
> (dock-panel button refinements), L6 (toolbar polish), and L7 (capture ordering, card
> metadata, and selection styling) have all landed** —
> `theme`/palette module, `component_geometry` geometry/hit-test helpers, `draw_kit` shell, GDI
> `DrawText` retirement in `bank_panel` (L1); `action_bar` pure task-grouped layout module, full
> M11-aware button inventory placed by task cluster, `bank_panel` redesigned through the L1 kit
> (L2); three-zone layout (top capture/placement/maintenance toolbar, bottom Design-View toolbar,
> (L2); VST editor (`reasampler_editor.cpp`) + embed strip (`reasampler_embed.cpp`) restyled
> through the L1 kit — REAPER-grey neutrals + three pastel accents, pastel spectral keyboard
> strip + zone bars, hover/pressed/drag states, local `kCol*` forest-green palette retired (L3);
> three-zone layout (top capture/placement/maintenance toolbar, bottom Design-View toolbar,
> footer toggle + Tail button + Prune), `footer_bar` pure module, `ActionCluster::Tagging`/
> `Switching` in `action_bar` (L4); top-bar overflow menu (`overflow_menu` pure module),
> custom LICE-kit hover-delay tooltips (`tooltip` pure module), opposite-mode Item/Track tag
@@ -209,7 +305,7 @@ is **ReaSampler 9000**. Framing + propagation surfaces:
> Cancel RT moved to overflow, top-bar cluster order tidied (L6); per-bank `SlotMap`
> (id→slot) in `bank_book`, sparse-grid rendering, `card_drag` + `card_meta` pure modules,
> `captureTimeSigNum`/`captureTimeSigDenom` on `Sample`, tertiary-border selection (L7). See
> `COMPLETED.md`. **L3 remains** — L3 gated on Phase S landing on dev.
> `COMPLETED.md`. **Phase L is complete.**
>
> **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
@@ -245,84 +341,16 @@ is **ReaSampler 9000**. Framing + propagation surfaces:
> out the full button inventory (including M11's action-button additions) intuitively,
> uncluttered, and useful — then applies the kit. Sequenced after M11 merges.
## 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-and-revised **B + three-accent pastel** look via the L1 kit: kit
cached-font text (§3.1 — the kit's current face, no font change), kit component draws, the
Neon-Console palette with **REAPER-grey neutrals** (`#2b2b2b`/`#333333`/`#3a3a3a`) and the
**three pastel accents** (primary lime / secondary teal / tertiary purple), the **pastel
spectral keyboard strip** as the signature surface (DS-2
revised), 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 + three-accent
pastel language through the L1 kit — kit AA cached-font text, gradient/rounded kit
components, the pastel 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 drawing shells
(`src/vst/reasampler_editor.cpp` + `reasampler_embed.cpp`) 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 editor/embed UX
> (S10S13, S15S18) 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 Phase S UX), the kit is the **one source of drawing**: if the Phase S
> surfaces reach dev before L1, they draw in the current language and L3 restyles them; if
> L1 lands first, they are born in the kit. **Reality check (product-designer, 2026-07-27,
> read-only against the phase-s worktree): the Phase S surfaces did NOT adopt the kit —
> `reasampler_editor.cpp` and `reasampler_embed.cpp` still draw flat `LICE_FillRect` blocks
> + raw GDI `DrawTextA`, off a local pre-L1 forest-green palette (`kColBackground` etc.),
> not `theme`/`draw_kit`.** So L3 lands as a **full restyle**, not a born-in-kit no-op — all
> three plan points below are live and confirmed still-needed. 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.
>
> **Landed-scope note (product-designer, 2026-07-27).** All Phase S drawing is centralized
> in **exactly two shells** — `reasampler_editor.cpp` (the `IPlugView` editor) and
> `reasampler_embed.cpp` (the S6 embed strip). Every other `src/vst/` UI file
> (`editor_geometry`, `keyboard_strip`, `waveform_view`, `capture_browser`, `param_slider`,
> `browser_scroll`, `embed_strip`) is a **pure geometry/hit-test module — zero LICE, zero
> draw** (the house discipline held on the branch). So L3 touches two draw shells, but their
> rendered component set is broader than the original plan named: the editor draws a
> **capture-first browser** (search + tabs + thumbnails, S10), **channel toggles** (S7),
> **waveform + start/loop markers** (S11), the **keyboard strip + zone bars** (S10/S10-Z),
> and **ADSR / pitch sliders + mode toggles** (S12/S15/S16). Every one of these is on the
> restyle surface — enumerated in the points below.
- [ ] Route the VST editor's + embed strip's text through the kit's cached-font `text()`
(the kit's current face — §3.1, no font change); retire their raw GDI `DrawTextA` path
(present in both shells today). (Gated — Phase S surfaces must be on dev.)
- [ ] Retire the shells' **local pre-L1 palette** — the `kColBackground`/`kColCardBg`/
`kColThumb`/… forest-green-on-charcoal constants block in `reasampler_editor.cpp` (and the
mirrored constants in `reasampler_embed.cpp`) — and draw every surface through the L1
`theme` roles instead. **This is the coordination-contract reconcile: today there are two
palettes (the landed `theme` kit + this local constants block); L3 collapses them to the
one kit.** (Gated.)
- [ ] Restyle the editor + embed components through the kit (browser search/tabs/thumbnails,
channel toggles, ADSR + pitch sliders, mode toggles, zone bars, list rows, waveform,
segmented controls) in the B (Neon Console) palette — **REAPER-grey neutrals** (`bg/base`
`#2b2b2b` / `bg/panel` `#333333` / `bg/cell` `#3a3a3a`) with the **three pastel accents**
(primary lime = live layer; secondary teal / tertiary purple = categorical); add
hover/pressed/drag states. (Gated.)
- [ ] Apply **Direction C's pastel spectral treatment to the keyboard strip + zone bars**
(hue-mapped zones as a pastel sweep anchored on the three accents, active zone lifting to
`accent/primary` + a static glow — never a pulse, per the speed constraint) as the
signature surface; also carry the waveform + loop/start markers onto the kit's
`drawWaveform` + `warn`/accent marker roles; VST3 class UID unchanged. (Gated.)
## Phase L — sequencing
```
L1 (shared kit) ──► L2 (dock-panel layout redesign) [LANDED]
├─────────► L3 (VST editor + embed-strip restyle; GATED on Phase S landing on dev)
├─────────► L3 (VST editor + embed-strip restyle) [LANDED]
└─────────► L4 (dock-panel button layout enhancement) [LANDED]
└────► L5 (dock-panel button refinements; ungated, after L4) [LANDED]
└────► L6 (toolbar polish; ungated, after L5) [LANDED]
└────► L7 (capture ordering + card metadata + selection styling; ungated, after L6) [LANDED]
```
L1, L2, L4, L5, L6, and L7 have all landed. L3 waits for Phase S to reach dev. Phase S
feature work runs in parallel, ungated by Phase L.
L1, L2, L3, L4, L5, L6, and L7 have all landed. **Phase L is complete.**
## Phase L — must-verify-before-build
- **LICE design-kit surfaces (L1)** — `LICE_GradRect`, `LICE_RoundRect`, AA
@@ -352,23 +380,6 @@ feature work runs in parallel, ungated by Phase L.
cursors chosen for drop-result cues (Reorder→IDC_SIZEALL, Move→IDC_HAND, Copy→IDC_UPARROW,
Replace→IDC_SIZEWE); existing pool-privilege guard reused as-is for Alt-replace. Gap navigation
in the grid = skip gaps (arrow keys skip empty slots). See `COMPLETED.md` §L7.
- **L3 restyle surface (L3)** — **PRE-CONFIRMED read-only against the phase-s worktree
(product-designer, 2026-07-27); re-confirm against dev once Phase S merges.** (1) Both draw
shells (`reasampler_editor.cpp`, `reasampler_embed.cpp`) still draw flat — `LICE_FillRect` +
raw GDI `DrawTextA`, no `theme`/`draw_kit`/`LICE_CachedFont` include — so all three L3 points
are live (no born-in-kit no-op). (2) There is a **second palette** to reconcile: a local
`kCol*` forest-green-on-charcoal constants block in the editor shell, divergent from the
landed `theme` roles. (3) Draw is centralized in those two shells only; every other
`src/vst/` UI file is pure geometry (kit adoption is a shell-side change, no geometry
rework). (4) The phase-s branch carries an **older L1 kit** (its `action_bar` predates dev's
L4L7 `theme` palette revisions) — after Phase S merges, L3 draws against dev's current
`theme`/`draw_kit`, so re-confirm the palette roles L3 consumes are dev's, not the branch's
stale copy. **The single open question is now RESOLVED (Daniel, 2026-07-27):** the S18 beta
channel title band gets **no distinct visual accent** — L3 restyles the title band in the
standard B pastel palette, and the beta-vs-stable distinction stays **purely textual** (the
channel-derived plugin name, as today), no channel-specific accent color. With that closed,
the settled DS-1/2/3 spec forces the rest.
---
# Phase Q — Quality (structural reorganization; zero-runtime-cost)
@@ -388,29 +399,26 @@ feature work runs in parallel, ungated by Phase L.
>
> **THE GATE (load-bearing — state first; reconciled to reality 2026-07-27).** Phase Q is
> **gated on the tree being otherwise quiescent.** Daniel's plain readiness target: **"when
> Phase S and L3 are finished."** As of 2026-07-27 the outstanding work is precisely: **(1)
> Phase S** merged to dev (the large second-artifact branch, currently on the phase-s worktree —
> the dominant gate item); **(2) Phase L L3** merged to dev (the VST restyle, itself gated on
> Phase S landing on dev). **L1/L2/L4/L5/L6/L7 have already landed** (see `COMPLETED.md`) the
> earlier "L2 + L3" wording was stale and is corrected here to **L3 only**. **D2** is functionally
> complete (D2-W1..W3-B landed; the lone open item, a per-track lane-split panel indicator, is
> *explicitly deferred*, not a blocking residual). **M9** (slots) is *explicitly deferred*
> (Daniel, 2026-07-26), not scheduled work. D2 and M9 are named in the gate only so that
> *reactivating* either re-arms the quiescence condition; neither blocks the gate today. *Why the
> gate:* Phase Q touches **nearly every file in `src/`** (relocate into subdirectories,
> re-namespace every header, split the four largest TUs, plus the §2b renames). Every large
> in-flight branch (Phase S on its worktree, and L3 once it lands) is diffed against the *current
> flat layout*; landing a rename-and-relocate-everything reorg mid-flight forces every open branch
> through the worst conflict class (every hunk moved, every qualified reference changed) — a
> combinatorial re-resolution, not a linear one. Phase Q is *last* precisely because it reshapes
> the ground every other pillar stands on. Landing it early taxes every subsequent phase; landing
> it last taxes nothing. **Do not begin any Q point until the gate is satisfied.**
> Phase S and L3 are finished."** **As of 2026-07-27 both gate conditions are satisfied:**
> Phase S merged to dev (2026-07-27); Phase L L3 (the VST restyle) merged to dev
> (2026-07-27, commit `c53683e`) — **Phase L is complete** (L1/L2/L3/L4/L5/L6/L7 all
> landed, see `COMPLETED.md`). **D2** is functionally complete (D2-W1..W3-B landed; the
> lone open item, a per-track lane-split panel indicator, is *explicitly deferred*, not a
> blocking residual). **M9** (slots) is **abandoned** (Daniel, 2026-07-27) — will not be
> built. D2 is named in the gate only so that *reactivating* its deferred panel indicator
> re-arms the quiescence condition; neither D2 nor M9 blocks the gate today. *Why the gate:* Phase Q
> touches **nearly every file in `src/`** (relocate into subdirectories, re-namespace every
> header, split the four largest TUs, plus the §2b renames). Every large in-flight branch
> (Phase S on its worktree, and L3 once it lands) is diffed against the *current flat
> layout*; landing a rename-and-relocate-everything reorg mid-flight forces every open
> branch through the worst conflict class (every hunk moved, every qualified reference
> changed) — a combinatorial re-resolution, not a linear one. Phase Q is *last* precisely
> because it reshapes the ground every other pillar stands on. Landing it early taxes every
> subsequent phase; landing it last taxes nothing. **The gate is now satisfied — Phase Q
> may begin.**
>
> **M9 disposition (Daniel-decision note).** M9 is recorded "deferred indefinitely," which is not
> the same as "abandoned." Immaterial to the gate (both clear it). It matters only if M9 is ever
> reactivated: *before* Phase Q it lands cheaply on the flat layout; *after*, it is authored
> against the reorganized tree. Surfaced, not silently resolved — no action unless Daniel schedules
> M9. (Full note: `docs/product/code-organization.md` §4.)
> **M9 disposition — resolved (Daniel, 2026-07-27): abandoned.** M9 is out; it will not be
> reactivated. The gate remains satisfied; no re-arm condition applies.
>
> **Settled (Q-1, this-doc):** the phase is **`Q` (Quality)**; point-id family `Q1..Qn`, wave
> prefixes `Q-W1..Q-W6`. **Recommended, Daniel's to call (Q-2..Q-9, see
@@ -612,8 +620,8 @@ droppable point if the phase needs narrowing (Q-6).
## Phase Q — sequencing
```
GATE: Phase S + Phase L L3 merged to dev (D2 complete, M9 deferred) — tree quiescent
("when Phase S and L3 are finished" — L1/L2/L4L7 already landed)
GATE: Phase S + Phase L L3 merged to dev (D2 complete, M9 abandoned) — tree quiescent
("when Phase S and L3 are finished" — L1/L2/L3/L4L7 all landed — GATE SATISFIED)
Q-W1 (safe opener: core/json extract + directory/namespace layout on clean modules)
@@ -646,5 +654,4 @@ is independently landable and CTest-green.
or VST3 class UID is renamed (naming audit §2b.5). A rename that would alter a shipped contract
literal is out of scope, full stop.
- **The GATE** — do not begin any Q point until **Phase S + Phase L L3** are merged to dev and the
tree is quiescent (D2 complete, M9 deferred; a reactivation of either re-arms the gate).
Re-confirm quiescence against dev before W1.
tree is quiescent (D2 complete, M9 abandoned). Re-confirm quiescence against dev before W1.