Skip to content

fix(transition): stop the feather leaking, give the pill its corners, add clip-path blob - #448

Merged
LeadcodeDev merged 3 commits into
mainfrom
ws-e-transitions
Sep 29, 2026
Merged

LeadcodeDev merged 3 commits into
mainfrom
ws-e-transitions

Conversation

@LeadcodeDev

Copy link
Copy Markdown
Owner

Closes #432. Part of #438.

The feather leaked onto three fixed edges. A feathered wipe built its mask
from the exact reveal rect, whose three non-moving edges sit on the frame
boundary, and MaskFilter::blur softens a shape's own edge wherever it is. The
feathered path now extends those three sides by feather * 6 + 16, comfortably
past the Gaussian's reach at sigma = feather / 3, and leaves the moving edge
exactly where it was. The hard-clip fast path for an unfeathered wipe is
untouched. Reverting it paints [255, 140, 198] — the band colour — onto pixel
(640, 3), which is the issue's own report.

The pill was a rounded rectangle. IRIS_PILL_CORNER_FRACTION was 0.2. At
1.0 the corner radius equals the smaller half-dimension, which is a true
stadium — and a circle at aspect: 1.0, which iris-transition.md already
documented. The doc was right and the constant was wrong.

clip-path gains blob. It reuses the generator the blob transition
already has rather than growing a second one: blob_local_path and
scaled_mask_path become pub(crate) and nothing else moves. The documented
boundary holds — mask_transition and blob_transition still do not depend on
ClipPath, because a transition has no layout box to resolve a percentage
against.

A transition that ignores a field now says so. The applicability table is
written from apply_transition's own match arms, and a field is reported only
when it differs from its default — so an unset field is never flagged, only an
explicit override that does nothing.

The fifth item, which the workstream's briefing left out

A mask with no silhouette, or one that does not resolve to a path, falls back
to a plain fade and says so on stderr under a zero exit code — which reads as
the transition having been ignored rather than refused. validate names both
cases now, reusing mask_shape_to_local_path so the check and the render agree by
construction rather than by a second opinion.

origin on mask, blob, iris and zoom_blur is in frame pixels. Writing
{ "x": 0.5, "y": 0.5 } for the centre is the natural mistake, and it places the
origin half a pixel from the top-left corner with no complaint. A warning now says
which unit the field takes and what the centre of the frame would be.

That item was missing from the brief I wrote, not from the work: the other four
each carried a reproduction and a file pointer and this one carried neither.

Tests

Nine, each reverted and watched go red. Beyond the two quoted above:

a_pill_with_aspect_one_degenerates_into_a_true_circle_not_a_barely_rounded_square
clip_path_blob_reuses_the_wobbling_lobe_generator_instead_of_drawing_a_plain_circle
a_fade_transition_names_every_field_it_ignores_in_one_warning
a_mask_with_no_silhouette_is_named_rather_than_falling_back_to_a_fade_at_render
a_fractional_origin_is_flagged_because_the_field_is_in_frame_pixels

cargo test -p rustmotion-core --lib engine::transition 22 passed · engine::paint_pass 101 · -p rustmotion-core --tests all green · -p rustmotion --lib cli::commands::validate_schema 56 passed.

… add clip-path blob

Four items from #432.

A feathered wipe built its mask from the exact reveal rect, whose three
non-moving edges sit on the frame boundary. MaskFilter::blur softens a
shape's own edge wherever it is, so all three bled feather and band tint
instead of only the edge that moves. The feathered path now extends
those three sides by feather * 6 + 16, comfortably past the Gaussian's
reach at sigma = feather / 3, and leaves the moving edge exactly where
it was. The hard-clip fast path for an unfeathered wipe is untouched.

IRIS_PILL_CORNER_FRACTION was 0.2, so a pill was a barely rounded
rectangle. At 1.0 the corner radius equals the smaller half-dimension,
which is a true stadium -- and a circle at aspect 1.0, which
iris-transition.md already documented. The doc was right and the
constant was wrong.

clip-path gains a blob kind. It reuses the generator the blob transition
already has rather than growing a second one: blob_local_path and
scaled_mask_path become pub(crate) and nothing else moves. The documented
boundary holds -- mask_transition and blob_transition still do not depend
on ClipPath, because a transition has no layout box to resolve a
percentage against.

A transition that ignores a field now says so. The applicability table
is written from apply_transition's own match arms, and a field is
reported only when it differs from its default, so an unset field is
never flagged -- only an explicit override that does nothing.

Refs #432
A mask transition with no silhouette, or one that does not resolve to a
path, falls back to a plain fade and says so on stderr under a zero exit
code -- which reads as the transition having been ignored rather than
refused. validate now names both cases before anything renders, reusing
mask_shape_to_local_path so the check and the render agree by
construction instead of by a second opinion.

origin on mask, blob, iris and zoom_blur is in frame pixels. Writing
{ "x": 0.5, "y": 0.5 } for the centre is the natural mistake, and it
places the origin half a pixel from the top-left corner with no
complaint. A warning now says which unit the field takes and what the
centre of the frame would be.

This is the fifth item of #432, which the workstream's briefing left out.

Closes #432
The generator existed and only the transition could reach it. Both
documents now say clip-path has seven shapes, and that blob is the same
silhouette scaled by radius around origin rather than by a transition's
progress.
@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 e4387cf into main Sep 29, 2026
4 checks passed
@LeadcodeDev
LeadcodeDev deleted the ws-e-transitions branch September 29, 2026 14:24
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

Development

Successfully merging this pull request may close these issues.

Transitions: feathered wipes leak at fixed edges, clip-path blob, iris pill, warnings for ignored fields

1 participant