From ae9019465e1c284c30ddfbd947fe6df70658d83b Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Sat, 1 Aug 2026 10:36:22 -0400 Subject: [PATCH] =?UTF-8?q?docs:=20close=20out=20=CE=98-W6=20and=20Phase?= =?UTF-8?q?=20=CE=98,=20and=20file=20two=20legibility-pass=20deferrals?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/COMPLETED.md | 61 ++++++++++++++++++++++++++++++++++++ docs/PLAN.md | 80 ++++++++++++++++------------------------------- docs/TODO.md | 57 +++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 53 deletions(-) diff --git a/docs/COMPLETED.md b/docs/COMPLETED.md index b6c4e35..706ec23 100644 --- a/docs/COMPLETED.md +++ b/docs/COMPLETED.md @@ -552,3 +552,64 @@ cell widths are unchanged. `enforceGateUnavailableWhileDrawn` (`core/instrument/engine/play_params.h`), now the single home of that rule, called by both `resolvePlay` and the editor's `applyControl`. + +### Θ-W6-T1 — legibility-and-antialiasing + +Made the editor legible, then audited every drawn surface for high-DPI clean rendering +— sequenced sizing first, audit second, since the audit's disposition list needed a +surface that had stopped moving. + +- **Sizing.** Knobs grew 28→40 px (inner curve dial 14→20), the deck cell 48×58→60×74, + and the label band 12→16 px, now drawn in `Font::Label` rather than `Font::Micro`. + Group captions and toggle segments deliberately stay `Font::Micro` — bumping them + would grow the per-group `captionWidth` reserves, and row 1 has only 14 px of + headroom at the floor width. +- **Editor default/minimum size 840×620 → 980×680**, because the deck cannot pack + three rows at the old floor with the wider cells. An existing saved instance's + window grows on open. The floor is validated by a derived test rather than + literals. +- **All 14 time-constant labels now read in ms**; internal representation untouched + (`formatEnvTimeMs` is display-only). `holdFraction` knobs and `Len %` stay `%` — + they are fractions, not times. The bank panel's clip-length readout is a duration, + not a parameter time constant, and stayed out of scope. +- **Double-click reset, per ring.** Outer ring resets the value, inner dial resets + the exponent to 1.0, independently. The window class gained `CS_DBLCLKS`; + `WM_RBUTTONDBLCLK` was added as its peer so the spline right-click delete survives, + and both DBLCLK handlers fall through to the ordinary down handler. The chrome's + preview-velocity knob answers reset too, resolving against the drawn circle via a + shared `inKnobFace` rule now used by both the deck and the chrome. +- **Antialiasing pass.** Fixed: knob track/value arcs (widened to 3 px stacked-radius + AA arcs), knob needle (`LICE_ThickFLine`), inner dial arc and needle, staged + envelope slopes, spline contour, velocity-popup trace, waveform outline, preview + triangle. Already clean: node handles, curve knots, knob discs, buttons, piano + keys, loop markers, borders, gradients, text. The full disposition table is a + standing artifact in `docs/product/visual-design-language.md` §8. +- Three LICE facts the audit established: `LICE_Line` takes integer endpoints so + `aa=true` still quantizes; `LICE_FillTriangle` has no `aa` parameter at all; LICE + has no thick-arc call, so a wider ring is stacked 1 px arcs. +- **Measured cost:** the new AA waveform stroke adds ~0.41 ms per full-grid panel + repaint (0.070 → 0.48 ms over a 24-card × 2-band × 136-column grid), ~2.5% of a + 60 Hz frame. Recorded in the §8 table and annotated as a one-off scratchpad + measurement, not a standing regression guard. +- **The piano-key open question is answered: not aliasing.** Every key is an + axis-aligned integer-width `LICE_FillRect`, so there was no sloped edge for + aliasing to act on; the defect was integer-division residue in the tiling, and + W2-T3's fix (remainder moved into symmetric end margins) is arithmetic. Above + client-pixel scaling it is unverified — nothing implements + `IPlugViewContentScaleSupport`. + +**Two structural changes forced by review.** The waveform column's vertical +arithmetic moved into a pure, unit-tested `waveformColumnSpan` in +`core/ui/component_geometry` — the first pass had silently broken symmetry about +the midline in the shared `draw_kit` primitive that also feeds the docked bank +panel and browse thumbnails. And `PlaySeconds` plus its `AdsrSeconds`/ +`AhdSeconds`/`PitchEnvSeconds`/`FilterSeconds` companions hoisted out of +`sample_map.h` into a header-only `play_seconds` INTERFACE target, so the new +`core/instrument/ui/deck_values` module stops transitively linking the bank model +and WAV codec. `deck_values` itself is an extraction of `controlValue`/ +`applyControl`/`resetDeckParam`/the ms formatter out of the editor shell, making +reset semantics unit-testable; `editor_controls.cpp` dropped 469→293 lines. + +All visual outcomes remain **pending Daniel's by-eye sign-off on `dev`** — sizes, +arc weight, and whether the waveform stroke improves or thickens the docked panel. +Not recorded as accepted. diff --git a/docs/PLAN.md b/docs/PLAN.md index 8e5c982..3aab970 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -115,6 +115,9 @@ drag/drop defects that block getting captures into it. **Consolidates items** 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16. +**All six waves have landed — Phase Θ is complete.** W1 through W6 each carry their own +landed note above; see `docs/COMPLETED.md` for every track's full narrative. + **The organizing constraint.** Three surfaces in the instrument are single-writer by nature and dictate the wave shape: @@ -253,60 +256,30 @@ as the boundary. **One track.** Both items repaint essentially every surface in the editor; concurrent tracks would collide everywhere. -#### Θ-W6-T1 — `legibility-and-antialiasing` +**Θ-W6-T1 has landed** — `legibility-and-antialiasing` — see `docs/COMPLETED.md` for the +full narrative. It shipped both halves together: knobs grew 28→40 px (inner curve dial +14→20), the deck cell 48×58→60×74, and the label band 12→16 px, now drawn in +`Font::Label` rather than `Font::Micro` — group captions and toggle segments deliberately +stayed `Font::Micro`, since bumping them would outgrow row 1's headroom at the floor +width. The editor's default/minimum size grew 840×620→980×680 to fit the wider deck at +floor width; an existing saved instance's window grows on open, and the floor is +validated by a derived test rather than literals. All fourteen time-constant labels now +read in ms (display-only; internal representation untouched) — `holdFraction` knobs, +`Len %`, and the bank panel's duration readout stayed out of scope. Double-click resets +each ring independently — outer ring resets the value, inner dial resets the exponent to +1.0 — reaching the chrome's preview-velocity knob too via a shared `inKnobFace` rule. -**Goal.** Make the editor legible — bigger knobs and labels, time constants in ms, -double-click reset per ring — then audit every drawn surface for high-DPI clean rendering. +The antialiasing audit fixed knob arcs and needle, the inner dial arc and needle, staged +and spline envelope slopes, the spline contour, the velocity-popup trace, the waveform +outline, and the preview triangle; node handles, curve knots, knob discs, buttons, piano +keys, loop markers, borders, gradients, and text were already clean. The disposition +table is a standing artifact in `docs/product/visual-design-language.md` §8. The +piano-key open question is answered: not aliasing — every key is an axis-aligned +`LICE_FillRect`, so the earlier width defect was integer-division residue in the tiling, +not a sloped edge. High-DPI host scaling itself is unverified (deferred, see +`docs/TODO.md`). -**Consolidates items 10, 13.** Sequence internally: sizing first, audit second. - -**Surface boundary — owns:** `core/instrument/ui/knob_deck` (sizing geometry), -`shell/panel/draw_kit` (the shared LICE draw shell — arcs, lines, slopes), and all three -Sample-face bands for repaint-level changes. **Note the blast radius:** `draw_kit` is -shared with the docked bank panel, so an antialiasing change there lands on the extension -UI too. That is desirable, but it puts the panel in this track's verification scope. - -**Behavior — sizing and ergonomics (item 10).** -- **Radial knobs and their text labels grow** — both are currently too small. No target - size was given; this is a visual-judgment change accepted by eye. -- **Time-constant labels display in ms, not seconds.** A display-unit change; this makes - no claim about internal representation. -- **Double-click on any radial knob resets it to its default value.** -- **On dual-ring knobs, each ring is its own reset target**: double-click the outer ring - resets the time/level value; double-click the inner curve dial resets the exponent to - **1.0** (the settled linear neutral) — each independently, without touching the other. - -**Behavior — antialiasing audit (item 13).** -- **A review pass, not a point fix.** Audit each class of drawn surface and confirm it - renders with antialiasing (or an equivalent) suitable for high-DPI, high-resolution - displays. Where one renders visibly aliased, bring it to the smooth standard. -- Daniel named the visibly pixely surfaces: **radial arcs, waveform lines, envelope - segment slopes.** By the time this runs, those include the inner dials (W3), the stereo - lanes (W2-T2), the staged *and* spline segment slopes (W3, W5), the loop markers - (W4-T1), and the piano key edges (W2-T3). -- The outcome is observable, not procedural. - -**Acceptance criteria.** -- Knobs and labels are legibly larger; **Daniel signs off on the result by eye.** -- **Every** time-constant label reads in ms. -- Double-click resets any radial knob to its default; on dual-ring knobs, double-clicking - the inner dial resets **only** the exponent (to 1.0) and double-clicking the outer ring - resets **only** the value. -- Radial arcs (including the inner dials), waveform lines (including the stereo lanes), - and envelope segment slopes (staged **and** spline) render smooth — **no visible jaggies - at 100% scale or on a high-DPI display.** -- **The audit produces a short disposition list**: surfaces checked, which needed work, - which were already clean. A required deliverable, not a side effect — it is what makes - the audit re-runnable. -- Daniel signs off by eye on the named surfaces. -- The docked bank panel is re-verified for regression, since `draw_kit` is shared. - -**Open questions.** -- **Target sizes [verify by eye].** No numeric target was given; item 10's own note is - that sizing is judged by eye. Bring a build, not a spec. -- **Whether the piano-key width defect was aliasing [verify].** W2-T3 fixes uniform width - regardless of cause; this audit confirms whether aliasing was the cause and whether the - fix survives DPI scaling. +All visual outcomes remain pending Daniel's by-eye sign-off on `dev`. --- @@ -327,7 +300,8 @@ independent of the editor chain — which is what makes Ξ-W1 concurrency-safe w bakes — "filtering, pitching, amp all set up nice" is the instrument items 1, 2, 3, and 14 build — and its settled reset scope enumerates the filter parameters, the spline contours, and the loop points by name. Baking a processing chain that does not exist yet is not a -schedule preference; the feature is not expressible. +schedule preference; the feature is not expressible. Phase Θ landed as of Θ-W6-T1 (see +`docs/COMPLETED.md`); this gate is satisfied. --- diff --git a/docs/TODO.md b/docs/TODO.md index 8ee2295..f071894 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -252,3 +252,60 @@ controls stacked internally (e.g. the filter's static control knobs above its en knobs) per Daniel's design notes once they land. The VELOCITY↔VOICE adjacency criterion is re-evaluated (or explicitly retired) against the new layout rather than the old per-row one. + +## The AA waveform stroke's cost on the docked bank panel's card thumbnails + +**Context (what shipped — Θ-W6-T1, legibility-and-antialiasing).** The antialiasing +audit fixed the min/max waveform column plot by adding an AA `LICE_FLine` stroke across +each column's extremes, on top of the existing fill (`draw_kit.cpp` `drawWaveform`). +`drawWaveform` is shared by the editor's hero waveform lanes, the docked bank panel's +card thumbnails, and the browse cards — the stroke lands on all three. + +**The wart.** Measured cost (Release, MSVC 14.44, real LICE, 24 stereo cards × +136 columns = 6528 columns): fill alone 0.070 ms per full-grid repaint, fill+stroke +0.48 ms — the stroke adds ~0.41 ms, about 2.5% of a 60 Hz frame. At card-thumbnail +scale the added smoothness is far less visible than on the editor's hero lanes, so the +cost is paid on every repaint of every card for a benefit concentrated in one consumer. + +**Intended fix.** The identified cheap lever: skip the stroke below a card-sized box +and keep it only on the editor's hero lanes. + +**The constraint the fix MUST handle.** Not done, because it is a product call about +where the comb artifact — the min/max column plot's jagged outline — actually reads +badly enough to matter, not a performance-forced decision (2.5% of a frame on +hover/scroll/drag repaint, not a continuous cost, is not itself disqualifying). + +**Priority / risk.** Low. The measurement is a one-off scratchpad number +(`docs/product/visual-design-language.md` §8), not a standing regression guard — +re-measure before relying on it again. + +**Done looks like.** A size threshold (or explicit per-consumer flag) below which +`drawWaveform` skips the AA stroke, with the panel/browse cards confirmed still +readable and the editor's hero lanes unchanged. + +## High-DPI host scaling is unverified (distinct from the antialiasing audit) + +**Context (what shipped — Θ-W6-T1, legibility-and-antialiasing).** The antialiasing +audit (item 13) confirmed every drawn surface renders smooth at 100% scale — the +disposition table in `docs/product/visual-design-language.md` §8 is the record. That +audit is about rasterization quality at the pixel level the plugin already draws at; +it says nothing about what happens when a host scales the plugin window itself. + +**The wart.** Nothing in the instrument implements `IPlugViewContentScaleSupport`. A +host that applies DPI scaling to the plugin window resamples the already-rasterized +output rather than asking the plugin to redraw at the target resolution — every AA +guarantee the audit just confirmed (and the piano-key uniform-width guarantee, §8.1) +holds only at the client-pixel level the plugin itself draws, not above it. + +**Intended fix.** Not proposed. Implementing `IPlugViewContentScaleSupport` (or +confirming the host compositor's resampling is acceptable without it) is the shape of +a fix, not yet scoped. + +**The constraint the fix MUST handle.** Not yet known — no design work has started. + +**Priority / risk.** Not stated. Recorded as a gap, not a defect: no host behavior has +been observed to be wrong, only unverified. + +**Done looks like.** Either `IPlugViewContentScaleSupport` is implemented and the +AA/uniform-width guarantees are re-verified at a scaled client size, or a decision is +recorded that host-side resampling of the rasterized output is an accepted tradeoff.