> ## Documentation Index
> Fetch the complete documentation index at: https://hyperframes-feat-thread-message-stack.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Animate with GSAP

> Create a paused timeline that HyperFrames can seek to any frame.

GSAP is the primary animation runtime for HyperFrames compositions. You author the motion; HyperFrames owns the playhead.

## Minimal contract

Give the composition a finite duration, create a paused timeline, and register it under the composition ID:

```html theme={null}
<!doctype html>
<html lang="en">
  <head>
    <script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js"></script>
  </head>
  <body>
    <div
      id="root"
      data-composition-id="intro"
      data-start="0"
      data-duration="3"
      data-width="1920"
      data-height="1080"
    >
      <h1 id="title" class="clip" data-start="0" data-duration="3" data-track-index="0">
        HyperFrames
      </h1>
    </div>

    <script>
      const timeline = gsap.timeline({ paused: true });

      timeline.fromTo(
        "#title",
        { opacity: 0, y: 32 },
        { opacity: 1, y: 0, duration: 0.6, ease: "power3.out" },
        0,
      );

      window.__timelines = window.__timelines || {};
      window.__timelines.intro = timeline;
    </script>
  </body>
</html>
```

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 theme={null}
<div data-composition-id="demo" data-duration="12"></div>
```

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 theme={null}
// 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 theme={null}
<div
  data-composition-id="intro"
  data-composition-src="compositions/intro.html"
  data-start="2"
  data-duration="4"
></div>
```

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 theme={null}
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)
