feat(engine): dynamic-video foundations — transform origins, glass kit, spring presets#96
Merged
Merged
Conversation
Both properties were parsed but the paint pivot was hardcoded to the box center. resolve_origin (pure) maps px/percent/keyword components to absolute pivots (absent = center, byte-identical non-regression); apply_transform gains three paths: unchanged 2D, single-pivot 3D, and dual-pivot 3D wrapping the perspective matrix in its own translate pair when perspective-origin differs. Keywords left/center/right/ top/bottom added additively to the length parser. Unlocks hinge/edge rotations (3D doors, side-pivoting cards); skill 3D rule documents the configurable pivot.
- gradient-border wired for real: css field (reusing the schema type)
painted as a DRRect ring filled with a linear gradient shader,
radius-aware (inner radii floored), replacing the standard border
when both are set; the never-called components helper is deleted;
angle follows the existing background-gradient convention
- FilterFn::Noise{intensity, seed}: Skia fractal_noise -> luminance
color-matrix scaled by intensity -> Overlay blend over the chain,
usable in filter AND backdrop-filter — per-element frosted grain;
determinism proven (same seed = byte-identical frames)
- zombie resolution with a discovery: the legacy LayerStyle is
entirely dead (zero consumers) so backdrop-blur/inner-shadow were
hard-rejected by CssStyle deny_unknown_fields rather than silently
ignored; they are now accepted compat fields with validator
warnings pointing to backdrop-filter / box-shadow inset, and
removed from the dead LayerStyle; skill docs corrected (they
oversold all three fields)
AnimationTiming gains spring: Option<SpringConfig> (serde-additive).
A single generic post-pass (apply_spring_to_motion) remaps a preset's
motion keyframes to the spring solver — builders stay oblivious:
- motion allowlist only (translate/scale/rotation axes); opacity
keeps its ease (alpha overshoot flashes), blur/draw_progress
excluded (out-of-range overshoot)
- 2-keyframe motions get spring easing directly; manual-overshoot
entrances (scale_in 0->1.08->1) collapse to endpoints so the
spring supplies the overshoot instead of doubling it; same-endpoint
oscillators (pulse/shake/float) are untouched (a spring to the same
value freezes the effect)
- bounce_in/elastic_in hardcoded springs become their defaults,
overridden by user config; duration stays the keyframe window
(solver already runs in real seconds and clamps at window end)
- HTML DSL: spring:true coerces to {} (SpringConfig::default 15/100/1
as the single source of truth — accepted deviation), spring:false
absent, anything else a clear error pointing at the JSON form
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #86. Closes #87. Closes #88. First PR of the dynamic-videos wave (#95) — three workstreams grouped on one branch (shared files, single merge to arbitrate).
#86 — real transform-origin / perspective-origin: both were parsed with a hardcoded center pivot. Pure
resolve_origin(px/%/keywords), threeapply_transformpaths (unchanged 2D, single-pivot 3D, dual-pivot 3D wrapping the perspective in its own translate pair). Absent = center, byte-identical (non-regression test). Unlocks hinge/edge 3D rotations. 7 pixel tests.#87 — glassmorphism kit complete:
gradient-borderpainted for real (DRRect ring + linear gradient shader, radius-aware, replaces the standard border; dead helper deleted);FilterFn::Noise{intensity, seed}via Skia fractal noise (luminance matrix × intensity, Overlay blend) infilterANDbackdrop-filter— per-element frosted grain, determinism proven byte-identical. Discovery: the legacyLayerStyleis entirely dead, sobackdrop-blur/inner-shadowwere hard-rejected, not ignored — now accepted CssStyle compat fields with validator warnings pointing to the real syntax; skill docs corrected (they oversold all three). 10 tests.#88 — spring easing on any preset:
spring: {damping, stiffness, mass}onAnimationTiming; one generic post-pass remaps motion keyframes to the solver (opacity keeps its ease; manual overshoots collapse so the spring supplies them; oscillators untouched; bounce/elastic hardcodes become overridable defaults). HTML DSLspring:true→SpringConfig::default()(single source of truth — accepted deviation from the briefed 12/100). 10 property-level tests (position overshoots, alpha monotone, convergence at window end).Verify:
cargo test --workspace→ 430 passed ✓ ·cargo fmt --check✓ · clippy gated ≤1 ✓ · 3 example scenarios validate unchanged ✓