Explicit deferral note on the PLAN M9 section; CLAUDE.md repo-state phrase aligned. An extra for when wanted, not scheduled work.
31 KiB
PLAN.md — ReaSampler milestone roadmap
Living milestone roadmap for ReaSampler. Derived from CONTEXT.md's 11-step build
order; CONTEXT.md remains the authoritative spec — this file is the tickable
checklist, not a re-statement of the spec. When a point lands, doc-keeper removes
it here and appends it to COMPLETED.md.
Conventions
- One checkbox
- [ ]= one discrete, independently-landable point. - Each milestone opens with a Goal (one line) and a Verify criterion (the acceptance gate; precision invariants pulled in where one applies).
- Verify-in-DAW points require a manual REAPER run; pure points are gated by CTest.
- "See CONTEXT.md §…" points at the authoritative detail — do not duplicate it here.
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.
Goal: "Capture to slot N" / "insert slot N", MIDI-bindable. CONTEXT.md Build order 9. Verify (in DAW): Slot capture and slot insert fire from MIDI bindings; slot state persists via the index.
- Slot model + slot↔sample assignment.
- "Capture to slot N" / "insert slot N" actions, MIDI-bindable.
Open questions to resolve during build
Carried from CONTEXT.md §Open questions — keep visible until each is closed by a landed milestone.
parseIntnarrowing hardening:src/bank_model.cppparseIntcastsint64_t → intviastatic_castwithout a range check; integers that fit in int64 but exceedINT_MAXare implementation-defined. Hardening candidate — add bounds check before the cast when integer-field validation is in scope.- Capture send/routing isolation (TODO): The FX-scope capture neutralizes out-of-scope FX, gain, and pan — but NOT aux sends. So a downstream coloring send (e.g. a folder → reverb-track send) still routes and blends the reverb into an item/track capture, past the intended isolation point. A true item-level capture should be taken at the isolated graph point — the target scope's output before out-of-scope track FX/gain/pan and before out-of-scope aux/parallel sends. The hard part: distinguish source routing that must be preserved (e.g. a MIDI send T1→T2 where T2's synth is where a MIDI item's audio is actually produced — the "item level" for that MIDI item is T2's synth output) from coloring sends that must be excluded (folder→reverb). Repro: folder F1; T1 (MIDI) sends MIDI to T2 (synth); T1+T2 → F1; F1 sends to reverb T3; capturing the MIDI item on T1 currently includes the reverb, should be isolated to T2's synth output pre-F1 with the MIDI send preserved and the reverb send excluded. Likely approach: snapshot + mute out-of-scope tracks' aux sends during the render while preserving the main/source signal path — needs a rule for which sends are load-bearing.
Phase D2 — Two-canvas (item-level mode projection; additive to D1)
Design View sub-phase. Extends D1's track-level mode projection to item level via REAPER 7 fixed lanes: on a track present in both stances, each mode owns a fixed lane — the active mode's lane shows and plays, the inactive mode's is hidden and silenced — so a Design take and an Arrange take can share the same track and time position without colliding on the view. Nothing in D1 changes. Runtime floor rises to REAPER 7 for this sub-phase (no version-gate branch; below v7 it is simply unavailable). Authoritative spec: CONTEXT.md §Two-canvas sub-phase (Phase D2 / Phase E) and the surrounding §Design View — additive phase spec. Product framing:
docs/product/design-view.md§Two-canvas direction. When a point lands, doc-keeper moves it toCOMPLETED.md.D2-W1 (pure lane extension), D2-W2 (shell: lane application + new-content detection), D2-W3-A (lane minting + item→lane assignment + persist round-trip), and D2-W3-B (item-level mode actions + W3-A polish) have all landed — see
COMPLETED.md. Phase D2 is functionally complete.Deferred: panel UI indicator for per-track lane/mode state (a per-track lane-split marker). The mode switch already shows the active mode; no natural cheap home for a per-track indicator was found in the bank panel. Explicitly deferred — not silently dropped. Can be picked up later if wanted.
Phase S — MIDI-playback instrument (native VST3 sampler; a second build artifact)
New pillar, own lettered namespace, and — uniquely — a second build artifact. Every prior phase ships inside the one
reaper_reasamplerextension binary; Phase S does not. A REAPER extension cannot be a MIDI-triggered instrument (it is not a node in any track's signal chain), so the instrument is a separate native VST3 plugin the user instantiates on an instrument track, reading ReaSampler's banks and playing them MIDI-triggered. NamespacedS(Sampler) rather than "D" (Daniel's call — "D" collides with Design View). Authoritative spec: CONTEXT.md §MIDI-playback instrument — additive phase spec (Phase S). Product framing + the settled decision record (D1/D5/D6 locked, D-A..D-D settled 2026-07-26):docs/product/midi-playback.md. When a point lands, doc-keeper moves it toCOMPLETED.md.Locked (see
docs/product/midi-playback.md§4): D1 native VST3 (not JSFX); D5 Windows-only / VST3-only / REAPER-only; D6 two products, tightly integrated via the VST-host bridge (live"reasampler"ext-state, project-aware). Settled forks (2026-07-26): D-A bare Steinberg VST3 SDK + LICE editor (no JUCE); D-B split seam with root-note + loop-points added toSamplenow; D-C Tier 0–1 committed (Tier 2 held, Tier 3 optional-forever); D-D embedded TCP/MCP UI scheduled as a later in-phase point (after the main editor exists).Second build artifact (load-bearing, flagged up front): Phase S produces a separate VST3 binary alongside
reaper_reasampler. The Steinberg VST3 SDK is a new vendored dependency (vendor at the spike — an implementation-time prerequisite, not done here), and CMake grows a second target with Windows VST3 module-export/bundle wiring. Both are established by S1 so nothing downstream leans on an unbuilt target.
S1 — opening spike: VST3 skeleton + IPlugView↔LICE bridge (proof + second target)
Goal: Stand up the second build artifact and prove the two least-trodden
unknowns before the engine build leans on them: (1) a silent-but-loading VST3
SingleComponentEffect skeleton that REAPER hosts, and (2) an IPlugView that hosts
a LICE-drawn surface. Converts §1a's experienced-estimates (Windows module-export
names, factory-macro spellings, exact bridge marshalling) into verified fact.
CONTEXT.md §Phase S (build shape, module architecture, API surface).
Prerequisite (implementation-time): vendor the Steinberg VST3 SDK (a new
submodule/dependency alongside reaper-sdk / WDL); confirm whether VSTGUI is
bundled (moot for D-A but resolves the noted fallback rung).
Verify (in DAW): the VST3 skeleton loads in REAPER on an instrument track,
enumerates via GetPluginFactory, sets up an event-in + audio-out bus, and runs an
empty process without error; an IPlugView opens and draws a LICE surface with a
working hit-test; the VST-host bridge resolves GetProjExtState by name and reads a
known "reasampler" value. Nothing plays yet — this is the loading/drawing/bridge
proof.
- CMake second target: a separate VST3 module artifact built alongside
reaper_reasampler(Windows VST3 export/bundle wiring;GetPluginFactory+InitDll/ExitDll— verify exact export names against the vendored SDK). SingleComponentEffectskeleton: factory + class registration,initializedeclaring an event-input bus + an audio-output bus (no audio input),setupProcessing,setActive, emptyprocess. Loads silently in REAPER.IPlugView↔LICE bridge spike: open a plugin editor window hosting a LICE-drawn surface (window creation/sizing, host→draw/hit-test event routing), reusing thebank_panelLICE/SWELL competence. The decision's one real unknown — prove it here. (VSTGUI is the noted fallback only if this proves gnarlier than the panel work suggests.)- Bridge read spike: resolve
GetProjExtState/EnumProjExtStateby name over the host callback (hostcbopcode0xdeadf00d), fetch host project context (0xdeadf00e), and read a known"reasampler"ext-state value. Verify opcodes + marshalling againstreaper_plugin.h/video_processor.h/reaper_plugin_functions.h.
S2 — Sample intrinsic fields (root note + loop points; in the extension)
Goal: Add the two bank-intrinsic seam fields to Sample — root note (MIDI
note the sample was recorded at; distinct from the existing optional musical key)
and loop points (sustain-loop start/end, sample-accurate, zero-crossing-aware) —
as an additive field extension with JSON round-trip, populated at/after capture. This
touches the extension codebase, is independently shippable, and lands early to
close the backfill cliff before the instrument consumes the fields. CONTEXT.md
§Phase S (seam fields, D-B). Same additive shape as provenance (M1).
Verify: CTest green. Round-trip lossless across the new fields; pre-existing
samples (no root note / loop points) deserialize with clean defaults (no loss, no
migration break); capture populates root note where derivable and loop points where
set; relative-paths-only unaffected; BankIndex behavior unchanged (purely
additive).
Depends on: nothing in Phase S (extension-only; can land before or in parallel
with S1).
- Add
rootNote(optional MIDI note) +loopStart/loopEnd(optional sample-accurate loop points) toSample; JSON serialize/deserialize with clean defaults for samples lacking them (additive, backward-compatible — mirror of howprovenancewas added). - Populate the fields on capture where derivable (root note) / settable (loop
points); leave them cleanly empty otherwise. No existing
Samplefield changes. - Tests: full round-trip lossless including the new fields; a legacy
SampleJSON (no new fields) parses with defaults and re-serializes without loss; additive invariant (no change to existing fields, dedup, tier, orBankIndexbehavior).
S3 — pure sampler core (voice engine / envelope / keymap / repitch)
Goal: The REAPER-free and VST3-free sampler core — voice allocation/polyphony,
amplitude envelope (ADSR), key→sample and velocity→sample mapping (the keymap),
repitch/interpolation from root note, keymap resolution — unit-tested in CTest against
known signals. The heart of the phase (D3); the mirror of
bank_model/peaks/view_mode_model/bank_book; test it hard. The core is
invariant under the build-shape choice — no VST3 or REAPER type at its boundary.
CONTEXT.md §Phase S (pure core, module architecture).
Verify: CTest green. Voice allocation is correct under polyphony (note-on/off,
voice stealing where bounded); ADSR shape asserted against a known signal (mirror of
peaks); repitch from root note produces the expected pitch ratio; keymap resolution
maps a (note, velocity) to the correct sample/zone; the core takes and returns only
plain data (no VST3/REAPER types) — enforced by the test target linking neither SDK.
Depends on: S2 (consumes rootNote / loop points as core inputs).
- Voice engine: polyphonic voice allocation (note-on/off, bounded voice stealing), per-voice state, mono-and-basic-polyphony sufficient for Tier 0.
- Amplitude envelope (ADSR) math — asserted against a known signal.
- Repitch/interpolation from root note (chromatic pitch ratio across the keyboard); loop-point-aware sustain for held notes.
- Keymap model + resolution: key ranges/zones (Tier-1 shape) and the (note, velocity) → sample/zone query; Tier-0 chromatic-from-single-root as the degenerate case.
- Tests: voice allocation under polyphony + stealing; ADSR envelope shape; repitch pitch-ratio correctness; keymap resolution (single-root chromatic + zoned); core boundary is plain-data-only (no VST3/REAPER types).
S4 — Tier 0: "the bank plays" (single sample, chromatic)
Goal: The honest MVP — one bank sample mapped chromatically across the keyboard
from its root note, basic polyphony, a simple amp envelope, velocity→volume. Wire the
S3 core into the S1 VST3 shell over the live-state seam (bridge-read bank + audio via
the M4 project-relative path machinery). Editor deferrable behind a parameters-only
default view. CONTEXT.md §Phase S (Tier 0, seams). Delivers the core promise.
Verify (in DAW): on an instrument track, the VST3 plays a chosen bank sample
MIDI-triggered, repitched chromatically from its root note, with basic polyphony,
an amp envelope, and velocity→volume; it reads the live "reasampler" bank via the
bridge and resolves the WAV audio the same project-relative way persist does;
following the active project works; it never captures and never inserts into the
arrange (read-only over the bank).
Depends on: S1, S2, S3.
- VST3
processmarshalling: read MIDI note-on/off/velocity off the event bus, drive the S3 core, write per-voice audio to the output bus. - Live-state seam: read the bank index + selected sample's root note from
"reasampler"ext-state via the bridge; resolve the WAV audio path the M4 project-relative way (shared convention withpersist, not re-implemented). - Sample selection UI (minimal, in the
IPlugViewLICE editor or a parameters-only default view): choose which bank sample this instance plays. - Tier-0 playback: chromatic-from-root, basic polyphony, amp envelope, velocity→volume — plays in REAPER's routing/record/render path like any VSTi.
S5 — Tier 1: "a keymap" (zoned multisamples, per-sample root notes)
Goal: Multiple bank samples zoned across the keyboard (key ranges), each with its own root note — a captured kit (one-shots) or a multisampled instrument (same instrument sampled at several pitches) plays correctly. One sample per key-region. CONTEXT.md §Phase S (Tier 1). Where the root-note + key-range seam fields earn their place. Verify (in DAW): a keymap of several bank samples plays correctly zoned across the keyboard, each repitched from its own root note within its range; a captured kit and a multisampled instrument both play as expected; the keymap is authored in the instrument (performance map) while root notes come from the bank intrinsics (S2); editing the keymap does not touch the bank. Depends on: S4.
- Keymap editor in the
IPlugViewLICE editor: assign bank samples to key ranges (low/high note per sample), each with its own root note (from S2 intrinsics, overridable in the performance map). - Tier-1 playback: zoned resolution — a note picks its zone's sample and repitches from that sample's root note; one sample per key-region.
- Performance-map persistence: the keymap (zones, per-sample assignment) is the
instrument's own state — held in the instrument (read/written over the live
"reasampler"seam per D-B's data-ownership split), never written back as a bank intrinsic.
S6 — embedded TCP/MCP UI (D-D — scheduled in-phase, after the editor)
Goal: Render a compact keymap/level strip inline in the track/mixer control
panel via reaper_plugin_fx_embed.h (IReaperUIEmbedInterface) — the same
Cockos surface REAPER's own embedded FX use — so the instrument draws inline, not only
in its own window. Composes with the S1/S5 LICE editor path (same LICE-class drawing).
Scheduled, not deferred (D-D settled 2026-07-26): a real later point, sequenced
last because it is polish over a Tier-0 need — but on the roadmap. CONTEXT.md §Phase S
(embedded UI, D-D).
Verify (in DAW): the instrument draws a compact inline strip in the TCP/MCP (not
only its own editor window); the inline surface reflects and (where offered) edits the
keymap/levels; the embed lifecycle is clean (open/close/resize); the same LICE drawing
as the main editor is reused.
Depends on: S5 (composes over the existing LICE editor). Must-verify before
build: the IReaperUIEmbedInterface contract + embed message/lifecycle against
vendor/reaper-sdk/sdk/reaper_plugin_fx_embed.h.
- Implement
IReaperUIEmbedInterfaceon the VST3; draw a compact keymap/level strip inline in the TCP/MCP using the same LICE surface as the editor. - Embed lifecycle (open/close/resize/hit-test inline) handled cleanly; reflects the live keymap/levels.
Phase S — held and optional-forever (noted, not specified)
- Tier 2 — "expressive" (HELD). Velocity layers, round-robin (anti-machine-gun), full ADSR, per-sample tuning/gain trim, sustain loops. The next depth increment once Tier 0–1 proves the instrument belongs — its points are not drawn up here.
- Tier 3 — "instrument polish" (optional-forever). Filters, filter/pitch envelopes, LFOs, per-voice pan, choke groups, a modest FX slot. A direction to leave room for, never a commitment.
Phase S — must-verify-before-build (carried from CONTEXT.md §Phase S)
- Steinberg VST3 SDK surface — interface members, base-class overrides,
factory-macro spellings, Windows module-export symbol names
(
InitDll/ExitDll/GetPluginFactory), and whether VSTGUI is bundled. Several are §1a experienced-estimates until S1 confirms them against the vendored SDK. - VST-host bridge — opcodes
0xdeadf00d(resolve-by-name) /0xdeadf00e(host context) and the exact call marshalling, againstreaper_plugin.h/video_processor.h/reaper_plugin_functions.h. IReaperUIEmbedInterface— embed contract + message/lifecycle, againstreaper_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 toCOMPLETED.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 sharedtext()over a cachedLICE_CachedFontset (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 toLICE_SysBitmap, singleBitBlt) — 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
DrawTextpath inbank_panelin favor of the kit's cached-fonttext()— 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
microsub-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 andwarn-colored. Add a new pure action-bar layout module (mirror ofmode_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,
warnfor 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 GDIDrawTextApath. (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, AALICE_Line/LICE_FLine/LICE_ThickFLine/LICE_Circle/LICE_FillCircle/LICE_DrawCBezier,LICE_FillTriangle/FillTrapezoid/FillConvexPolygon, and theLICE_CachedFont/LICE_IFontfont engine (SetFromHFont, AADrawText, shadow/outline/ glow FX flags). Verified present invendor/WDL/WDL/lice/lice.h+lice_text.h(design-language doc §1.1); confirm exact signatures + theLICE_CachedFont↔HFONTlifecycle 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_drawknobstackas the slider/knob drawing reference,virtwnd-listbox.cppas a candidate scroll listbox,virtwnd-controls.hforWDL_STYLE_*gradient hooks,virtwnd-skin.hfor 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.