--- title: "Animate with GSAP" sidebarTitle: "GSAP animation" description: "Create a paused timeline that HyperFrames can seek to any frame." --- import { DocsVideo } from "/snippets/docs-video.jsx"; GSAP is the primary animation runtime for HyperFrames compositions. You author the motion; HyperFrames owns the playhead. The code in that clip is the real thing — a `gsap.to()` with a `keyframes` array, and the same motion being reshaped by dragging the ease curve in Studio rather than guessing numbers. ## Minimal contract Give the composition a finite duration, create a paused timeline, and register it under the composition ID: ```html

HyperFrames

``` The registry key must match `data-composition-id`. ## Rules that matter 1. Create the timeline with `{ paused: true }`. 2. Register it on `window.__timelines`. 3. Give important tweens an explicit position. 4. Prefer `fromTo()` when both endpoints matter; it remains reliable after backward or random seeks. 5. Animate transforms and opacity for movement. Avoid repeatedly animating layout properties such as `top`, `left`, `width`, or `height`. 6. Let HyperFrames control clip visibility and media playback. The normal timeline methods are `to()`, `from()`, `fromTo()`, and `set()`. GSAP supports many CSS properties, but the [HyperFrames animation skill](https://github.com/heygen-com/hyperframes/tree/main/skills/hyperframes-animation) contains the render-safe patterns used by agents. ## Duration An explicit root `data-duration` is the composition's render length: ```html
``` This is the clearest choice for a complete composition. If the root omits `data-duration`, HyperFrames can infer length from registered timelines and supported media after the page initializes. Do not assume a long source video automatically extends a shorter explicit root duration. The authored duration is the output window. ## Media belongs to the runtime Do not play or seek media from the GSAP timeline: ```js // Do not do this. document.querySelector("video").play(); document.querySelector("audio").currentTime = 5; ``` Use media timing attributes instead. If a video needs to move or resize, animate a wrapper around it rather than the video element itself. ## Nested compositions Each nested composition owns and registers its own timeline. The parent decides when the nested scene appears through its host element: ```html
``` Do not manually add the child timeline to the parent's GSAP timeline. HyperFrames maps the parent playhead into the nested scene. ## Verify the motion ```bash npx hyperframes lint npx hyperframes check npx hyperframes snapshot --at 0,0.6,2.9 ``` Check the first frame, the moving state, and the end state. A timeline that looks correct only during continuous browser playback may still fail when the renderer seeks directly to a frame. ## Related topics - [Edit animation and keyframes in Studio](/studio/animation) - [Understand deterministic rendering](/concepts/determinism) - [Use the HTML composition schema](/reference/html-schema)