docs: record Θ-W7, the arc-and-spline antialiasing fix, and file the scaled-fallback deferral

This commit is contained in:
2026-08-01 15:18:59 -04:00
parent 806a3037a3
commit 6c982cd617
3 changed files with 129 additions and 5 deletions
+56
View File
@@ -613,3 +613,59 @@ 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.
### Θ-W7-T1 — arc-and-spline-aa
Two defects Daniel found by eye once Θ-W6-T1's antialiasing pass shipped — diagnosing
both corrected the initial reading of each.
- **Arcs never reached opacity.** `LICE_Arc` rasterizes a whole circle clipped per 90°
chunk and splits ink across two pixels by the fractional part of the radius;
`rOuter = radius - 0.5f` is half-integer, so no pixel in the ring was ever opaque —
measured peak alpha 138/255. The three stacked radii also did not tile: spacing
dilates from 1.0 px to 1.41 px at 45°, leaving partial-coverage holes. It read as
fuzz, but it was a stroke that never fully inked.
- **Splines were fully aliased, not gapped.** The apparent dotting was not missing
ink: `LICE_ThickFLine` steps the major axis and structurally cannot gap. The paint
loop passed **integer** `cx`/`cy`, so LICE had no sub-pixel position to interpolate
— every pixel was full or empty with no AA fringe, and integer `cy` quantized the
slope into an alternating 1/2 px staircase that reads as beading at 100%.
- **The cheap fix was rejected.** Float endpoints plus `LICE_ThickFLine` fixes
opacity and the staircase, but `ThickFLine` lays width along the *minor* axis, so
perpendicular weight is `wid·cosθ` — a measured 42% ripple dipping at every 45°
diagonal.
- **What landed:** one pure analytic thick-stroke rasterizer. Coverage is
distance-to-polyline, accumulated with `max()` into a scratch buffer and blended
**once** — the single blend is what structurally prevents the compositing fringe
build-up behind the first defect. An arc is just a polyline, so one code path
replaces the stacked arcs, both spline traces, and the two needles. Pure coverage
math in a new `core/ui/stroke_aa`; the blend loop in a new
`shell/instrument/editor_stroke`. `shell/panel/draw_kit` was deliberately **not**
touched, keeping the docked bank panel and browse cards entirely out of the blast
radius.
- **Measured, before → after:** arc peak alpha 138/255 → 255/255; arc perpendicular
weight 1.623.24 px (67% ripple) → 2.953.11 px (5%); spline weight 1.412.00 px
(29%) → 1.952.01 px (3%). Cost: **+0.09 ms per full editor repaint** (30 arcs
0.113 → 0.169 ms; 500 px contour 0.013 → 0.047 ms), a knowing regression on an
interaction-driven surface, measured in Release against real LICE in an
uncommitted harness.
- **`velocity_curve` gained `subpixelFromPoint`** — sub-pixel y was unavoidable since
integer `cy` was the root cause. The existing integer map now *rounds* the new
float map rather than forking a second formula, so hit-testing is unchanged.
- **Daniel then ruled that every sub-2 px stroker width be enlarged**, because the
stroker can only guarantee an opaque core at width >= 2 px (an opaque pixel needs
`d <= halfWidth 0.5`, and the worst-case pixel-centre-to-centreline distance is
0.5). The knob track arc, the inner-dial needle, and the deck's mini velocity trace
all moved 1.0 → 2.0 px. A test pinning the sub-opaque behaviour at 1 px was kept as
a guard against reintroduction.
- **The audit's method was the root failure, not its output.**
`docs/product/visual-design-language.md` §8 had claimed stacked 1 px `LICE_Arc`
calls "keep every ring antialiased" — false. The Θ-W6 audit verified *which
primitive was called* rather than *what it rasterized*, which is how both surfaces
were signed off clean while never producing an opaque pixel. That sentence is
deleted, the rows are re-dispositioned with measurements, and the methodological
lesson is recorded in §8 as a standing blockquote.
All visual outcomes remain **pending Daniel's by-eye sign-off on `dev`** — nothing was
verified in a live REAPER window; all measurement was against an offscreen bitmap in a
standalone harness. Not recorded as accepted.
+41 -5
View File
@@ -115,8 +115,10 @@ 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.
**All seven waves have landed — Phase Θ is complete.** W1 through W7 each carry their own
landed note above; see `docs/COMPLETED.md` for every track's full narrative. Θ-W7 was
opened after Θ-W6-T1 shipped, to fix two rendering defects Daniel found by eye; it did not
exist in the plan when this phase was originally scoped.
**The organizing constraint.** Three surfaces in the instrument are single-writer by
nature and dictate the wave shape:
@@ -283,6 +285,33 @@ All visual outcomes remain pending Daniel's by-eye sign-off on `dev`.
---
### Θ-W7 — Arc-and-spline antialiasing fix
**Depends on W6 for:** a drawn surface to find a defect on — this wave did not exist in
the plan; it was opened after Daniel found two rendering defects by eye once Θ-W6-T1
shipped, so the audit's own output is what surfaced them.
**One track.**
**Θ-W7-T1 has landed**`arc-and-spline-aa` — see `docs/COMPLETED.md` for the full
narrative. The stacked-`LICE_Arc` knob and dial rings never reached an opaque core (peak
alpha measured 138/255), and the staged/spline envelope and velocity-curve traces were
fully aliased rather than gapped, from integer `cy` quantizing the slope. Both defects,
plus the two needles, now route through one pure analytic thick-stroke rasterizer —
coverage in a new `core/ui/stroke_aa`, the single LICE blend in a new
`shell/instrument/editor_stroke` — replacing `LICE_Arc` and `LICE_ThickFLine` outright.
Measured: arc peak alpha 138/255 → 255/255, arc perpendicular-weight ripple 67% → 5%,
spline weight ripple 29% → 3%, at a cost of +0.09 ms per full editor repaint. Daniel then
ruled every sub-2 px stroker width up to 2 px, since the stroker only guarantees an
opaque core at width ≥ 2 px; the knob track arc, the inner-dial needle, and the deck's
mini velocity trace each moved 1.0 → 2.0 px. `docs/product/visual-design-language.md` §8
is corrected — a false "keeps every ring antialiased" claim is deleted, the rows are
re-dispositioned with measurements, and the audit's methodological lesson (verifying
which primitive was called is not verifying what it rasterized) is recorded as a standing
blockquote. All visual outcomes remain pending Daniel's by-eye sign-off on `dev`.
---
## Phase Ξ — The resample loop
**Ships:** one consolidated, fully robust provenance/usage tracking system, and on top of
@@ -300,7 +329,7 @@ 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. Phase Θ landed as of Θ-W6-T1 (see
schedule preference; the feature is not expressible. Phase Θ landed as of Θ-W7-T1 (see
`docs/COMPLETED.md`); this gate is satisfied.
---
@@ -616,8 +645,13 @@ work that did not come from the source doc has no row, and inventing one would w
proof it exists to give.
- **Θ-W3-T1 — `live-parameter-delivery`** (`pth-w3-t1-live-parameter-delivery`). Arose
from Θ-W2-T1's implementation review, not from `TODO-1.0.md`. It is the only such track
in this plan today; if others appear, they belong on this list rather than in the table.
from Θ-W2-T1's implementation review, not from `TODO-1.0.md`. The first such track in
this plan; see Θ-W7-T1 below for the second.
- **Θ-W7-T1 — `arc-and-spline-aa`** (`pth-w7-t1-arc-and-spline-aa`). Opened after
Θ-W6-T1 shipped, when Daniel found two rendering defects by eye in the editor — not
from `TODO-1.0.md`, and not a track this plan originally scoped. The second such track
in this plan today; if others appear, they belong on this list rather than in the
table.
### Deliberate compressions
@@ -672,6 +706,8 @@ Phase Θ — ReaSampler 9000: one parameter set, filter, shapeable envelopes, le
T1 spline-egs .............................. 3
W6 Editor legibility pass
T1 legibility-and-antialiasing ............. 10, 13
W7 Arc-and-spline antialiasing fix
T1 arc-and-spline-aa ....................... (not one of the seventeen)
Phase Ξ — The resample loop (W1 concurrency-safe with Θ from Θ-W2 onward)
W1 Consolidated tracking, and the programmed-note model
+32
View File
@@ -309,3 +309,35 @@ 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.
## The analytic stroker's scaled fallback path is unexercised
**Context (what shipped — Θ-W7-T1, arc-and-spline-aa).** `blendCanvas`
(`shell/instrument/editor_stroke.cpp`) guards against `LICE_EXT_GET_SCALING` being
active by falling back to a per-pixel `LICE_PutPixel` path, because the primary raw-bits
path derives its geometry from logical width/height while writing through
`getRowSpan()` — under an active scale that would misplace the stroke or write past the
DIB allocation.
**The wart.** Nothing calls `SET_SCALING` today, so the fallback path never runs. Under
an active scale it would rasterize the coverage mask at *logical* resolution with each
logical pixel expanded to a scale-sized block — geometrically correct but blocky rather
than resolution-independent. This connects to the already-filed high-DPI host-scaling
deferral above; cross-referenced here rather than duplicated.
**Intended fix.** Not proposed — same shape as the host-scaling deferral above:
implementing (or verifying) genuine scale-aware rasterization is the shape of a fix, not
yet scoped.
**The constraint the fix MUST handle.** Not yet known — no design work has started, and
none can usefully start before the host-scaling deferral above is resolved, since that
is what would first exercise this path.
**Priority / risk.** Low / deferred. Recorded as a gap, not a defect: the fallback is
guarded, correct-but-blocky rather than wrong, and unreached by anything in the tree
today.
**Done looks like.** Either the fallback path is exercised under a genuinely scaled
bitmap and confirmed to place the stroke correctly, or it is redesigned to rasterize at
physical rather than logical resolution once `IPlugViewContentScaleSupport` (or
equivalent) makes scaling real.