From 58f7dc1c724b0ef432f1e92b1eab2c2ae5d3d0e1 Mon Sep 17 00:00:00 2001 From: Vance Ingalls Date: Mon, 29 Jun 2026 09:56:37 -0700 Subject: [PATCH] docs(skills): teach transforms-over-layout-props up front Reframe the gsap "prefer transforms" guidance from a GPU-perf nicety to the real HyperFrames render-correctness reason: the seek-by-frame capture engine integer-snaps layout props, so slow tweens stutter. Add the CSS-rest + x/y offset conversion recipe, the parent-relative %/px note, and the one exception (html-in-canvas elements). Frames the gsap_non_transform_motion lint rule as the backstop, not the teacher, so agents reach for transforms up front instead of relying on lint to reject. Co-Authored-By: Claude Opus 4.8 (1M context) --- skills-manifest.json | 2 +- .../adapters/gsap-transforms-and-perf.md | 20 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/skills-manifest.json b/skills-manifest.json index d8591b9eb..b1371c40c 100644 --- a/skills-manifest.json +++ b/skills-manifest.json @@ -18,7 +18,7 @@ "files": 1 }, "hyperframes-animation": { - "hash": "57458f4308708e21", + "hash": "9f0ccb60ff53e739", "files": 115 }, "hyperframes-cli": { diff --git a/skills/hyperframes-animation/adapters/gsap-transforms-and-perf.md b/skills/hyperframes-animation/adapters/gsap-transforms-and-perf.md index 295589159..2dc673351 100644 --- a/skills/hyperframes-animation/adapters/gsap-transforms-and-perf.md +++ b/skills/hyperframes-animation/adapters/gsap-transforms-and-perf.md @@ -57,9 +57,25 @@ Animate any custom property. Works for color, length, number — anything CSS wi ## Performance Rules -### Prefer transforms and opacity +### Animate transforms, not layout properties -Animating `x`, `y`, `scale`, `rotation`, `opacity` stays on the GPU compositor. Avoid `width`, `height`, `top`, `left`, `margin`, `padding` when transforms achieve the same effect. +Animate `x`, `y`, `scale`, `rotation`, `opacity`. Never animate `left`, `right`, `top`, `bottom`, `width`, `height`, `margin*` — and never `roundProps`. + +This is a **render-correctness** rule in HyperFrames, not just a GPU-performance nicety. The renderer seeks frame-by-frame and screenshots each frame, and the browser compositor snaps layout properties to whole device pixels. On a fast tween the per-frame step is several pixels, so the snap is invisible; on a slow tween or a long ease-out tail the value moves less than a pixel per frame — it holds the same pixel for several frames, then jumps a whole one. The result is motion that looks smooth when fast but visibly stutters when slow. Transforms interpolate sub-pixel and stay smooth at any speed. `roundProps` forces the same integer snap onto a transform — don't use it. + +**Convert a position animation to a transform** by leaving the element at its resting `left`/`top` in CSS and animating the _offset_ with `x`/`y`: + +```javascript +// CSS: #card { left: 1340px; top: 540px } ← resting position stays in CSS +tl.to("#card", { left: 1340, top: 540, duration: 1 }); // ✗ stutters +tl.fromTo("#card", { x: 640, y: 0 }, { x: 0, y: 0, duration: 1 }); // ✓ x/y = delta from CSS rest (640 = startLeft − 1340) +``` + +For a parent-relative `left: "100%"` sweep, use `xPercent: 100` only when the element is the full width of its container; otherwise convert to pixels (`x: containerWidth`). + +**The one exception:** elements drawn through the html-in-canvas API — those under a `` ancestor, e.g. the `liquid-glass-*` blocks. The canvas rasterizes from sub-pixel `getComputedStyle`, so layout props don't snap there and those elements keep `left`/`top`. Everything the browser lays out (plain DOM) follows the rule. + +The `gsap_non_transform_motion` lint rule is the backstop, not the teacher — reach for transforms from the start instead of animating layout props and waiting for lint to reject them. ### will-change (sparingly)