Skip to content

fix(paint): dither the inflated ramp, face the surface, wire the halo lerp - #445

Merged
LeadcodeDev merged 1 commit into
mainfrom
ws-c-materials-3d-backgrounds
Sep 29, 2026
Merged

LeadcodeDev merged 1 commit into
mainfrom
ws-c-materials-3d-backgrounds

Conversation

@LeadcodeDev

Copy link
Copy Markdown
Owner

Closes #434. Part of #438.

Inflated banding. The shading alpha is truncated to u8 with a raw cast. PR
#399 already fought this for small bevels by measuring a shallow slope over a
longer baseline; past bevel 24 the ramp gets shallow enough that the per-pixel
delta falls near 1 LSB, and truncation then holds identical alpha across several
consecutive pixels. A 4×4 Bayer ordered dither on the quantization fixes it. The
alternative — reworking the reach/relief contrast so peak amplitude holds across
bevel — was rejected: the defect is in how the ramp is displayed, not in the
shading maths, and three passing tests pin that material's calibration.

dot_map arcs. paint_content discarded its AnimatedProperties entirely,
so draw_progress keyframes on the node validated and did nothing while
arc.draw_in stayed a static field. An arc's reveal is now
draw_in × draw_progress, not draw_progress overriding it — an override would
make draw_in silently dead the instant anything animated the node, a worse trap
than the bug.

layout-surface orientation. Cells were translated onto the curve and given
the whole-surface tilt, but never rotated to face the tangent at their own
position, so a projected grid stayed a set of flat cards. Each cell now rotates
about its own centre by the same angles that placed it, leaving the centre cell
untouched as documented. The issue expected an edge column near 120 px: it
measured 144, now 120. The rejected alternative was per-vertex projection
— geometrically truer, but it replaces one 4×4 matrix per cell with a per-corner
derivation, and the rules file already states one transform per cell as the
accepted model.

Halo interpolation. interpolate_animated_bg and lerp_zones had no
production call site at all
— reachable only from their own tests — while
SKILL.md and rules/halo-shapes.md both describe background properties
interpolating across a transition. render_frame_v2_scaled cross-faded two fully
rendered frame buffers instead, so two static copies ghosted past each other. It
now pairs the layers and draws one interpolated result, falling back to the old
cross-fade only for surplus layers when two scenes declare different counts. No
doc change: the code now satisfies what both documents already claimed.

box-shadow under a transparent box. The outset branch drew its rrect with
nothing excluding the box's own footprint. An opaque background hid it; a
transparent one let the shadow's solid core through — probing a box's centre
returned the shadow colour. Clipping with ClipOp::Difference against the border
box is what CSS specifies and what the inset branch already did for its own hole.

What the banding test does not prove

a_wide_inflated_bevel_does_not_posterize_its_ramp_into_solid_flat_plateaus
counts adjacent same-luminance pixel pairs in the ramp: 33 before, 26 after, out
of 71 sampled. It does not prove the residual is imperceptible, and it does not
cover the other half of the reported symptom — an aliased line on pills.
Investigation found a separate ~1–2 luma jitter near the light/shade
zero-crossing, most likely 8-bit quantization in the input silhouette field
feeding the slope calculation. Dithering the output alpha does not address it,
and raising that field's precision is a different, riskier change to a function
three tests already pin. Stated rather than left to be found.

Every other item was reverted individually and watched go red, including the halo
one through a real two-scene scenario sampled at t=0.5.

cargo test -p rustmotion --lib engine::render 78 passed · -p rustmotion-core --lib engine::paint_pass 99 passed · -p rustmotion-components --lib dot_map 13 passed. Clippy and the full suite run once the wave is integrated.

… lerp

Five items from #434.

The inflated material stair-steps at wide bevels because the shading
alpha is truncated to u8 with a raw cast. PR #399 already fought this
for small bevels by measuring a shallow slope over a longer baseline;
past bevel 24 the ramp gets shallow enough that the per-pixel delta
falls near 1 LSB and truncation holds identical alpha across several
pixels. The fix is a 4x4 Bayer ordered dither on the quantization
rather than reworking the shading formula, because the defect is in the
display of the ramp and not in its maths -- three passing tests pin that
material's calibration.

dot_map discarded its AnimatedProperties entirely, so draw_progress
keyframes on the node validated and did nothing while arc.draw_in stayed
a static field. An arc's reveal is now draw_in * draw_progress rather
than draw_progress overriding it: an override would make draw_in
silently dead the instant anything animated the node, which is a worse
trap than the bug.

layout-surface translated each cell onto the curve and applied the
whole-surface tilt, but never rotated a cell to face the tangent at its
own position, so a projected grid stayed a set of flat cards. Each cell
now rotates about its own centre by the same angles that placed it,
which leaves the centre cell untouched as documented. The issue's own
repro expected an edge column near 120px; it measured 144 and now
measures 120.

interpolate_animated_bg and lerp_zones had no production call site at
all -- reachable only from their own tests -- while SKILL.md and
halo-shapes.md both describe background properties interpolating across
a transition. render_frame_v2_scaled cross-faded two fully rendered
frame buffers instead, so two static copies ghosted past each other. It
now pairs the layers and draws one interpolated result, falling back to
the old cross-fade only for surplus layers when the two scenes declare
different counts.

An outset box-shadow drew its rrect with nothing excluding the box's own
footprint. An opaque background hid it; a transparent one let the
shadow's solid core through, so probing a box's centre returned the
shadow colour. Clipping with Difference against the border box is what
CSS specifies and what the inset branch already did for its own hole.

Closes #434
@LeadcodeDev LeadcodeDev added the bug Something isn't working label Sep 29, 2026
@LeadcodeDev LeadcodeDev self-assigned this Sep 29, 2026
@LeadcodeDev
LeadcodeDev merged commit 9139eac into main Sep 29, 2026
4 checks passed
@LeadcodeDev
LeadcodeDev deleted the ws-c-materials-3d-backgrounds branch September 29, 2026 13:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

1 participant