Files
hyperframes/docs/guides/gsap-animation.mdx
JamesandClaude Opus 4.6 915fe2f47a docs: improve quality based on Remotion/Stripe/Tailwind patterns
Major improvements across all 18 pages:

- Use Mintlify components: <Steps> for tutorials, <Tabs> for alternatives,
  <CodeGroup> for multi-platform commands, <Tree> for directory structures,
  <AccordionGroup> for FAQ/scannable content, <Mermaid> for diagrams
- Add filename annotations to all code blocks (e.g., ```html index.html)
- Add numbered comments inside multi-step code examples
- Show expected terminal output after CLI commands
- Add "When to use" / "When NOT to use" sections to all package pages
- Add "Next Steps" CardGroup to every page (no dead-end pages)
- Cross-link between pages at point of curiosity (not just "see also" dumps)
- Expand thin pages (engine, studio) with architecture details and examples
- Add decision guides (rendering modes, template selection)
- Use <Warning> and <Note> sparingly (max 2-3 per page)

Also adds DOCS_GUIDELINES.md at repo root with writing standards.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 23:57:01 +00:00

135 lines
5.7 KiB
Plaintext

---
title: GSAP Animation
description: "Add animations to your Hyperframes compositions with GSAP."
---
Hyperframes uses [GSAP](https://gsap.com/) for animation. Timelines are paused and controlled by the runtime — you define the animations, the framework handles playback. For background on how animation runtimes plug into Hyperframes, see [Frame Adapters](/concepts/frame-adapters).
## Setup
Include GSAP and create a paused timeline:
```html index.html
<script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js"></script>
<script>
// 1. Create a paused timeline — the framework controls playback
const tl = gsap.timeline({ paused: true });
// 2. Add animations using the position parameter (3rd arg) for absolute timing
tl.to("#title", { opacity: 1, duration: 0.5 }, 0);
// 3. Initialize the global timelines registry (if not already present)
window.__timelines = window.__timelines || {};
// 4. Register the timeline using the data-composition-id as the key
window.__timelines["root"] = tl;
</script>
```
<Note>
The key you use in `window.__timelines` must match the `data-composition-id` attribute on your composition's root element. See [Compositions](/concepts/compositions) for how the root element is structured.
</Note>
## Key Rules
1. **Always create timelines with `{ paused: true }`** — the framework controls playback via [deterministic seeking](/concepts/determinism)
2. **Register timelines on `window.__timelines`** with the [`data-composition-id`](/concepts/data-attributes#composition-attributes) as key
3. **Use the position parameter** (3rd argument) for absolute timing: `tl.to(el, vars, 1.5)`
4. **Only animate visual properties** — never control media playback in scripts
## Supported Methods
| Method | Description |
|--------|-------------|
| `tl.to(target, vars, position)` | Animate to values |
| `tl.from(target, vars, position)` | Animate from values |
| `tl.fromTo(target, fromVars, toVars, position)` | Animate from/to values |
| `tl.set(target, vars, position)` | Set values instantly |
## Supported Properties
`opacity`, `x`, `y`, `scale`, `scaleX`, `scaleY`, `rotation`, `width`, `height`, `visibility`, `color`, `backgroundColor`, and any CSS-animatable property.
## Timeline Duration and Composition Duration
A composition's duration equals its GSAP timeline duration. The two are directly linked:
```javascript compositions/intro-anim.html
// Your last animation ends at 3 seconds...
tl.from("#title", { opacity: 0, y: -50, duration: 1 }, 0);
tl.to("#title", { opacity: 0, duration: 1 }, 2);
// ...so this composition is exactly 3 seconds long.
```
If your composition contains a video clip that is 283 seconds long, but your last GSAP animation ends at 8 seconds, the composition will be only 8 seconds long and the video will be cut short. To extend the timeline to match the video:
```javascript index.html
// All your visual animations
tl.to("#lower-third", { left: -640, duration: 0.6 }, 7.2);
// Extend the timeline to 283 seconds to match the video length.
// This adds a zero-duration tween at 283s without affecting any elements.
tl.set({}, {}, 283);
```
<Warning>
This is one of the most common mistakes in Hyperframes. If your video cuts off early, the timeline is too short. See [Common Mistakes: Composition Duration Shorter Than Video](/guides/common-mistakes) for more details.
</Warning>
## What NOT to Do
These patterns will break your composition or cause sync issues:
```javascript index.html
// WRONG: Playing media in scripts — the framework owns media playback
document.getElementById("el-video").play();
document.getElementById("el-audio").currentTime = 5;
// WRONG: Creating a non-paused timeline
const tl = gsap.timeline(); // missing { paused: true }!
// WRONG: Animating dimensions directly on a <video> element
tl.to("#el-video", { width: 500, height: 280 }, 5);
// WRONG: Manually nesting sub-timelines
const masterTL = window.__timelines["root"];
masterTL.add(window.__timelines["intro-anim"], 0);
```
The framework automatically manages [media playback](/reference/html-schema#framework-managed-behavior), [clip lifecycle](/concepts/compositions#two-layers-primitives-and-scripts), and [sub-composition nesting](#sub-composition-timelines). Scripts that duplicate this behavior will conflict.
## Sub-Composition Timelines
Each [nested composition](/concepts/compositions#nested-compositions) registers its own timeline. The framework automatically nests sub-composition timelines into the parent based on [`data-start`](/concepts/data-attributes#timing-attributes):
```javascript compositions/intro-anim.html
// In compositions/intro-anim.html
const tl = gsap.timeline({ paused: true });
tl.from(".title", { opacity: 0, y: -50, duration: 1 });
window.__timelines["intro-anim"] = tl;
// DO NOT manually add sub-timelines to the master:
// masterTL.add(window.__timelines["intro-anim"], 0); // UNNECESSARY
```
<Warning>
Don't animate `width`, `height`, `top`, or `left` directly on `<video>` elements — this can cause the browser to stop rendering frames. Wrap the video in a `<div>` and animate the wrapper instead. See [Common Mistakes](/guides/common-mistakes) for a detailed explanation.
</Warning>
## Next Steps
<CardGroup cols={2}>
<Card title="Compositions" icon="layer-group" href="/concepts/compositions">
Understand the building blocks that timelines animate
</Card>
<Card title="Frame Adapters" icon="plug" href="/concepts/frame-adapters">
Learn how GSAP plugs into the render pipeline
</Card>
<Card title="Common Mistakes" icon="triangle-exclamation" href="/guides/common-mistakes">
Avoid pitfalls that break animations
</Card>
<Card title="HTML Schema Reference" icon="code" href="/reference/html-schema">
Full reference for composition attributes
</Card>
</CardGroup>