mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-13 07:40:06 +00:00
feat(lint): add gsap_non_transform_motion rule, migrate registry comps to transforms
Animating layout properties (left/right/top/bottom/margin*) or using
roundProps snaps motion to integer device pixels. Under the seek-by-frame
capture engine this is invisible at high per-frame deltas (fast tweens) but
visibly stutters at low deltas (slow tweens / ease-out tails): sub-pixel
movement rounds to the same pixel for several frames, then jumps a whole
pixel. Transforms (x/y/scale) interpolate sub-pixel and stay smooth.
New rule gsap_non_transform_motion (error):
- Sources timeline tweens from the acorn parser's full animation list, so
label- and relative-positioned tweens (tl.to(..., "label") / "+=1") are
covered and real AST keys avoid phantom-prop / nested-brace misreads.
- Exempts html-in-canvas elements (a <canvas layoutsubtree> ancestor): they
are rasterized from sub-pixel getComputedStyle and do not integer-snap.
Per-element resolution, so a grouped glass+text tween still flags the
plain-DOM half. roundProps is never exempt (it rounds before the style).
- Uses Object.hasOwn for the layout-prop lookup, skips set(), and merges
standalone gsap.* calls.
Migrated 9 registry compositions off layout-prop animation onto transforms,
each render-verified visually identical:
- liquid-glass-{notification,widgets,media-controls,context-menu}: plain-DOM
text overlays -> transforms; glass panels stay on left/top (canvas-exempt).
- vignelli: curtain wipes left:% -> xPercent.
- lt-mask-reveal: sweep left:% -> x px.
- flowchart, flowchart-vertical, decision-tree: cursor paths left/top -> x/y.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
c811a2750a
commit
619a603eab
+8
-2
@@ -48,6 +48,7 @@
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 8px;
|
||||
background: #ffd23f;
|
||||
}
|
||||
@@ -92,12 +93,17 @@
|
||||
var role = document.getElementById("lt-role");
|
||||
|
||||
// An accent sweep crosses left→right; the name is revealed by a clip-path wipe behind it; role fades up.
|
||||
// Sweep travel: left:"100%" was parent-relative (offsetParent = .lt-namewrap). Since the sweep is
|
||||
// only 8px wide, xPercent would travel just 8px, so translate by the container width in pixels instead.
|
||||
// The .lt-namewrap shrink-wraps the name "Dr. Maya Chen" to 536px (no horizontal padding/border, so
|
||||
// clientWidth == content width), which is exactly what left:"100%" resolved to.
|
||||
var SWEEP_TRAVEL = 536;
|
||||
gsap.set(nameEl, { clipPath: "inset(0 100% 0 0)" });
|
||||
gsap.set(sweep, { left: "0%", opacity: 0 });
|
||||
gsap.set(sweep, { x: 0, opacity: 0 });
|
||||
gsap.set(role, { y: 14, opacity: 0 });
|
||||
|
||||
tl.to(sweep, { opacity: 1, duration: 0.12, ease: "none" }, 0.1);
|
||||
tl.to(sweep, { left: "100%", duration: 0.55, ease: "power2.inOut" }, 0.12);
|
||||
tl.to(sweep, { x: SWEEP_TRAVEL, duration: 0.55, ease: "power2.inOut" }, 0.12);
|
||||
tl.to(nameEl, { clipPath: "inset(0 0% 0 0)", duration: 0.5, ease: "power2.inOut" }, 0.16);
|
||||
tl.to(sweep, { opacity: 0, duration: 0.15, ease: "none" }, 0.6);
|
||||
tl.to(role, { y: 0, opacity: 1, duration: 0.5, ease: "power3.out" }, 0.55);
|
||||
|
||||
Reference in New Issue
Block a user