Skip to content

feat(animation): letter_spacing and draw_start become keyframe properties - #404

Merged
LeadcodeDev merged 1 commit into
mainfrom
fix/letter-spacing-and-draw-start
Sep 28, 2026
Merged

LeadcodeDev merged 1 commit into
mainfrom
fix/letter-spacing-and-draw-start

Conversation

@LeadcodeDev

Copy link
Copy Markdown
Owner

Closes #380. Closes #377. Refs #388.

Both halves were blocked on the same thing — a new field on AnimatedProperties, in a file another workstream owned while #363/#380 and #377 were in flight.

One of those agents explicitly refused to work around it, and was right to: adding letter_spacing to KNOWN_MOTION_PROPERTIES alone would have made it validate and stay completely inert, which is the exact defect #363 was fixing. It stopped and reported instead. This PR is the other side of that boundary, now that the file is free.

letter_spacing

{ "property": "letter_spacing",
  "keyframes": [{ "time": 0, "value": 0 }, { "time": 0.8, "value": 18 }],
  "easing": "ease_out" }

The intrinsic measurement keeps the static style.letter-spacing, so animating it does not re-run layout — the policy every layout property follows here. The consequence is real, and the rule file leads with it rather than hiding it: a text whose spacing opens overflows its box. Size the box for the final value, or accept the overflow knowingly.

Two mechanisms now share a name, which is worth knowing before it surprises someone: a timeline changing letter-spacing snaps and the validator warns about it; a keyframes track on letter_spacing interpolates. Different subsystems, deliberately different behaviour.

draw_start

draw_progress advances the head of a stroke; draw_start advances its tail. Together they are a window travelling along the path — a line that runs rather than one that grows. On its own it erases the beginning of a finished stroke.

line and svg both trim through PathMeasure::get_segment — the primitive #403 added — rather than a dash effect. That is what keeps a zero-length dash with a round cap from painting the stray dot #376 had to remove; reusing the dash trick here would have reintroduced it on a different component.

shape keeps its own component-level draw_start from #403, because it carries path_morph too and the two belong together. The rule file says which is which.

Verification

Five tests. Three fail without the wiring:

a keyframed letter_spacing must move the glyphs apart: tight=48px, loose=48px
assertion `left == right` failed: draw_start 0.5 must erase the first half

Two assert equality and pass both ways on purpose — an absent animated value must leave the declared one alone, which is why the field defaults to NaN rather than 0.

One probe deliberately stops six pixels short of the cut, with the reason written into the assertion: a round cap extends half the 8px stroke back past the trim. That is the cap working, not the trim failing — and it was worth writing down rather than quietly widening the tolerance.

cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace (1718) all clean.

Written comment-free, per the codebase-wide rule from #345.

…ties

Both were blocked on the same thing: a new field on `AnimatedProperties`, in a
file another workstream owned while #363/#380 and #377 were in flight. Neither
agent reached across the boundary, and one of them explicitly refused to add
`letter_spacing` to `KNOWN_MOTION_PROPERTIES` on its own — that alone would have
made it validate and stay inert, which is the exact defect #363 was about.

**`letter_spacing`.** The intrinsic measurement keeps the static
`style.letter-spacing`, so animating it does not re-run layout — the same policy
every other layout property follows. The consequence is real and documented
rather than hidden: a text whose spacing opens overflows its box.

Two mechanisms now share a name. A `timeline` changing `letter-spacing` snaps,
and the validator warns; a `keyframes` track on `letter_spacing` interpolates.
Different subsystems, deliberately different behaviour, said plainly in the rule
file.

**`draw_start`.** `draw_progress` advances the head of a stroke; this advances
its tail. Together they are a window travelling along the path — a line that
runs rather than one that grows. On its own it erases the beginning of a
finished stroke.

`line` and `svg` both trim through `PathMeasure::get_segment`, the primitive
#403 added, rather than a dash effect. That is what keeps a zero-length dash
with a round cap from painting the stray dot #376 had to remove.

`shape` keeps its own component-level `draw_start` from #403: it carries
`path_morph` too, and the two belong together.

Five tests. Three fail without the wiring — `tight=48px, loose=48px` for
spacing, and a painted first half for the trim. Two assert equality and pass
both ways on purpose: an absent animated value must leave the declared one
alone, which is why the field defaults to NaN rather than zero.

One probe stops six pixels short of the cut on purpose, with the reason in the
assertion: a round cap extends half the stroke width back past the trim, which
is the cap working, not the trim failing.

Closes #380
Closes #377
@LeadcodeDev LeadcodeDev added the enhancement New feature or request label Sep 28, 2026
@LeadcodeDev LeadcodeDev self-assigned this Sep 28, 2026
@LeadcodeDev
LeadcodeDev merged commit 7c5b659 into main Sep 28, 2026
4 checks passed
@LeadcodeDev
LeadcodeDev deleted the fix/letter-spacing-and-draw-start branch September 29, 2026 18:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

1 participant