$npx -y skills add heygen-com/hyperframes --skill hyperframes-keyframesUse when a HyperFrames composition needs seek-safe 2D/3D keyframes, GSAP timelines, CSS keyframes, Anime.js, WAAPI, FLIP, paths, masks, SVG morph/draw, text trails, 3D depth, or hyperframes keyframes diagnostics. Don't use for broad scene strategy, brand design, media sourcing,
| 1 | # HyperFrames Keyframes |
| 2 | |
| 3 | Keyframes are a pose contract: visible states, continuous subject identity, seek-safe runtime, verified pixels. |
| 4 | |
| 5 | Use `hyperframes-animation` for broad scene recipes. Use `hyperframes-cli` for full command docs. Use `references/keyframe-patterns.md` only when choosing implementation mechanisms, not visual style. |
| 6 | |
| 7 | ## Procedure |
| 8 | |
| 9 | 1. Identify the animated subject, visible states, final state, and runtime. |
| 10 | 2. Choose the smallest mechanism that proves the prompt. Read `references/keyframe-patterns.md` only if the mechanism is unclear. |
| 11 | 3. Author seek-safe keyframes in the declared runtime. Build synchronously and register the runtime instance. |
| 12 | 4. Verify with `hyperframes lint`, `hyperframes check`, `hyperframes keyframes`, one focused `--shot`, and snapshots at proof times. |
| 13 | 5. If proof fails, fix the source keyframes and rerun the smallest failing diagnostic before rendering. |
| 14 | |
| 15 | ## Contract |
| 16 | |
| 17 | - Name the moving subject. |
| 18 | - Name the poses needed to prove the intended motion, including the final state. |
| 19 | - Keyframe visible channels, not hidden helper state. |
| 20 | - Preserve object identity when continuity matters. |
| 21 | - Crossfade only when the intended motion is replacement or dissolve. |
| 22 | - Hold readable or semantic states long enough to see. |
| 23 | - Final frame is part of the animation, not cleanup. |
| 24 | - Do not reset to rest unless requested. |
| 25 | - Do not end on black unless requested. |
| 26 | - If editing a starter scene, preserve layout, copy, assets, colors, and final state unless asked to redesign. |
| 27 | |
| 28 | ## Runtime Rules |
| 29 | |
| 30 | GSAP: |
| 31 | |
| 32 | - build synchronously at page load |
| 33 | - use `gsap.timeline({ paused: true })` |
| 34 | - register as `window.__timelines[compositionId]` |
| 35 | - registry key must match `data-composition-id` |
| 36 | - do not call `tl.play()` for render-critical motion |
| 37 | - keep repeats finite |
| 38 | |
| 39 | CSS keyframes: |
| 40 | |
| 41 | - finite duration and iteration count |
| 42 | - deterministic delay |
| 43 | - `animation-fill-mode: both` |
| 44 | - use `data-start` when timing belongs to a clip |
| 45 | |
| 46 | Anime.js: |
| 47 | |
| 48 | - create synchronously |
| 49 | - `autoplay: false` |
| 50 | - finite duration and loops |
| 51 | - push every instance to `window.__hfAnime` |
| 52 | |
| 53 | WAAPI: |
| 54 | |
| 55 | - finite `duration` |
| 56 | - `fill: "both"` |
| 57 | - deterministic construction |
| 58 | - the text surface does not list WAAPI; verify with `--shot` (it seeks WAAPI) and snapshots |
| 59 | |
| 60 | Never use for render-critical motion: |
| 61 | |
| 62 | - `Date.now()` |
| 63 | - `performance.now()` |
| 64 | - unseeded `Math.random()` |
| 65 | - hover/scroll triggers |
| 66 | - timers |
| 67 | - async-created timelines |
| 68 | - unregistered `requestAnimationFrame` |
| 69 | - infinite loops |
| 70 | |
| 71 | ## GSAP Skeleton |
| 72 | |
| 73 | ```js |
| 74 | const root = document.querySelector("[data-composition-id]"); |
| 75 | const compositionId = root.dataset.compositionId; |
| 76 | const tl = gsap.timeline({ paused: true }); |
| 77 | |
| 78 | tl.addLabel("state-a", 0); |
| 79 | tl.to(".subject", { |
| 80 | keyframes: [ |
| 81 | { x: 0, opacity: 1, duration: 0.2 }, |
| 82 | { x: 120, opacity: 1, duration: 0.4, ease: "power2.out" }, |
| 83 | { x: 100, opacity: 1, duration: 0.2, ease: "power2.inOut" }, |
| 84 | ], |
| 85 | ease: "none", |
| 86 | }); |
| 87 | |
| 88 | window.__timelines = window.__timelines || {}; |
| 89 | window.__timelines[compositionId] = tl; |
| 90 | ``` |
| 91 | |
| 92 | Use labels for semantic states. Use position parameters instead of chained delays. Use `immediateRender: false` for later `from()`/`fromTo()` tweens touching the same property. |
| 93 | |
| 94 | ## Keyframe Forms |
| 95 | |
| 96 | - Array keyframes: pose ladder with per-step duration/ease. |
| 97 | - Percentage keyframes: exact timing inside one tween. |
| 98 | - Property arrays: compact multi-stop changes. |
| 99 | - `ease: "none"` on the parent when each stop carries its own easing. |
| 100 | - `easeEach` when every segment should share the same feel. |
| 101 | |
| 102 | Do not copy numeric distances or timing from examples. Derive them from the actual composition geometry and duration. |
| 103 | |
| 104 | For one subject moving between two boxes, prefer one continuous transform tween or FLIP. Split `x/y/scale` into multiple eased keyframes only when the viewer should feel distinct beats; every segment changes velocity and can read as a hitch. |
| 105 | |
| 106 | ## Channels |
| 107 | |
| 108 | Prefer compositor/visual channels: `x/y/z`, `xPercent/yPercent`, `scale`, `rotationX/Y/Z`, `skew`, `transformOrigin`, `svgOrigin`, `opacity`, `autoAlpha`, `clip-path`, masks, CSS vars, SVG path/dash values, camera transforms, shader uniforms. |
| 109 | |
| 110 | Avoid layout/lifecycle channels: `top/left/right/bottom`, `width/height`, `margin/padding`, `display`, `visibility`, late DOM creation, helper overlays doing subject motion. |
| 111 | |
| 112 | For visibility changes, use `autoAlpha` on the registered seekable GSAP timeline, or a zero-duration `tl.set()` at an explicit boundary. Target only a non-clip element or a wrapper inside the clip; never target `.clip` itself. Never duration-tween raw `visibility`, and never tween `display`. |
| 113 | |
| 114 | ## Mechanism Choice |
| 115 | |
| 116 | Choose the smallest mechanism that proves t |