mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-08 02:36:10 +00:00
The runtime absorbed a series of authoring mistakes over time and `runtime/init.ts` says so in its own comments, but the skills kept teaching the old rules. Four of them actively cost an agent a failing run: add `crossorigin` (lint rejects it unconditionally), never build a timeline inside `async` (lint calls that the documented contract), never `gsap.set` later-scene clips (two fixHints instruct exactly that), and 12 copyable media snippets with no `id`, which render silent. Corrected in every place each claim appeared, including `hyperframes-animation`, three workflow scripts, the scaffolded project instructions, the CLI `docs` command, and the public docs site: `data-track-index` is a Studio display lane the render never reads, `class="clip"` is a layout convention rather than a visibility requirement, timed elements may nest, the visibility window is half-open, sub-composition host dimensions are backfilled, and the root-fill rule applies only to the layered-composite path. Behaviour changes, each backed by a render rather than by reading code: - `timeline_registry_missing_init` deleted. The runtime creates the registry before any inline script; a composition without the guard line renders and animates correctly. - `video_nested_in_timed_element` kept, message corrected. A rendered repro shows the nested-with-local-start case really does break, so the rule guards a real defect, but nothing is "FROZEN": the extractor ignores the wrapper's offset while visibility uses it, so the clip shows wrong frames and then vanishes. - `mediaRenderIds` now stamps media whose source is a `<source>` child, closing a duplicate-id gap the old `[src]`-only selector left open. - Stale messages fixed on `subcomposition_root_styled_by_class` and `deprecated_data_layer`. `coreSkillContent.test.ts` pinned the literal sentence that made root `data-start` look required, so it is narrowed to structure plus the regression it genuinely catches. Not covered, and flagged in the PR: the media global-vs-local start heuristic in `runtime/init.ts` is the root cause behind the nested-video defect. Removing it changes the meaning of existing compositions and needs its own deprecation.
106 lines
7.4 KiB
Markdown
106 lines
7.4 KiB
Markdown
---
|
|
name: hyperframes-gsap-adapter
|
|
description: GSAP animation API reference for HyperFrames. Use when writing seekable GSAP timelines in HyperFrames compositions, including gsap.to(), from(), fromTo(), set(), timeline position parameters, labels, easing, stagger, finite repeats, and transform performance.
|
|
---
|
|
|
|
# HyperFrames GSAP
|
|
|
|
GSAP usage scoped to HyperFrames' seek-driven render model. This skill is the GSAP reference _as constrained by HyperFrames_ — for the framework's broader composition contract see `hyperframes-core`.
|
|
|
|
## HyperFrames Contract
|
|
|
|
HyperFrames controls GSAP through its `gsap` runtime adapter. Create a paused timeline synchronously, register it on `window.__timelines` with the exact `data-composition-id`, and let HyperFrames seek it.
|
|
|
|
```html
|
|
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
|
<script>
|
|
window.__timelines = window.__timelines || {};
|
|
const tl = gsap.timeline({ paused: true });
|
|
|
|
tl.from(".title", { y: 48, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
|
|
tl.to(".accent", { scaleX: 1, duration: 0.5, ease: "power2.out" }, 0.25);
|
|
|
|
window.__timelines["main"] = tl; // key must equal data-composition-id on the composition root
|
|
</script>
|
|
```
|
|
|
|
- The registry key must match the composition root's `data-composition-id`.
|
|
- Bracket and dot syntax both register: `window.__timelines["main"] = tl` and `window.__timelines.main = tl` are equivalent (the linter recognizes both). Bracket form is required when the id isn't a valid identifier (e.g. contains `-`).
|
|
- Do not call `tl.play()` for render-critical motion.
|
|
- Building inside an async callback such as `document.fonts.ready` is supported and common. What breaks is **registering the key before the build finishes**: an empty timeline registered early is treated as ready and nested empty, so it renders blank (`lint`: `gsap_timeline_registered_before_async_build`, error). Assign `window.__timelines[id] = tl` at the end of the callback. Do not drive render-critical motion from timers or event handlers.
|
|
- Keep loops finite. HyperFrames renders finite video durations.
|
|
- **Render duration comes from `data-duration` on the composition root, not from GSAP timeline length.** Do not pad the timeline with empty tweens like `tl.set({}, {}, 283)` to "extend" it. (Some external docs show this trick; in HyperFrames it conflicts with the seek-driven duration model — set `data-duration` instead.)
|
|
|
|
## Core Tween Methods
|
|
|
|
- **gsap.to(targets, vars)** — animate from current state to `vars`. Most common.
|
|
- **gsap.from(targets, vars)** — animate from `vars` to current state (entrances).
|
|
- **gsap.fromTo(targets, fromVars, toVars)** — explicit start and end.
|
|
- **gsap.set(targets, vars)** — apply immediately (duration 0).
|
|
|
|
Always use **camelCase** property names (e.g. `backgroundColor`, `rotationX`).
|
|
|
|
## Common vars (cheatsheet)
|
|
|
|
- **duration** — seconds (default 0.5).
|
|
- **delay** — seconds before start.
|
|
- **ease** — `"power1.out"` (default), `"power3.inOut"`, `"back.out(1.7)"`, `"elastic.out(1, 0.3)"`, `"none"`. See `./gsap-easing-and-stagger.md`.
|
|
- **stagger** — number or object. See `./gsap-easing-and-stagger.md`.
|
|
- **repeat** — finite number; never `-1` in HyperFrames. Compute repeats from the visible duration.
|
|
- **yoyo** — alternates direction with repeat.
|
|
- **overwrite** — `false` (default), `true`, or `"auto"`.
|
|
- **immediateRender** — default `true` for from()/fromTo(). Set `false` on later tweens targeting the same property+element.
|
|
- **onComplete**, **onStart**, **onUpdate** — callbacks.
|
|
|
|
For transforms, autoAlpha, clearProps, and SVG specifics see `./gsap-transforms-and-perf.md`.
|
|
|
|
## Animated Property Allowlist
|
|
|
|
HyperFrames is stricter than vanilla GSAP. Animate only:
|
|
|
|
- **Compositor-cheap**: `opacity`, `x`, `y`, `scale`, `scaleX`, `scaleY`, `rotation`, `rotationX`, `rotationY`, `skewX`, `skewY`, `transformOrigin`
|
|
- **Visual fills**: `color`, `backgroundColor`, `borderColor`, `borderRadius`
|
|
- **CSS variables**: `"--hue": 180` etc.
|
|
- **Media `volume`** (on `<audio>` / `<video>`): animate for fades/ducking, e.g. `tl.to("#bgm", { volume: 0, duration: 1 }, "outro")`. The runtime probes these keyframes from the timeline and drives them in both preview and render (they match). This sets the _author_ volume; `data-volume` is the static baseline when no tween touches the element.
|
|
- **DOM text `innerText`** (for numeric counters): tween it directly, e.g. `tl.to(el, { innerText: 100, snap: { innerText: 1 } })` — `snap` keeps it integer; the GSAP inspector recognizes it as a counter. Equivalent to the `onUpdate`-proxy form in `../rules/counting-dynamic-scale.md`; prefer that proxy form for locale formatting (`toLocaleString`) or suffix logic, and pair it with a separate transform-scale tween when the number should grow.
|
|
|
|
**Avoid** (use the transform alias instead):
|
|
|
|
- `width` / `height` / `top` / `left` / `right` / `bottom` / `margin*` / `padding*` — trigger layout reflows. Use `scaleX/Y` (with `transformOrigin`) or `x` / `y`.
|
|
|
|
**Forbidden** (breaks the renderer or the clip lifecycle):
|
|
|
|
- `display`, raw `visibility` **on a clip element**: never duration-tween these. HyperFrames owns a clip's visibility and `lint` rejects it. Use `autoAlpha` (opacity plus endpoint visibility) or a zero-duration timeline set at an explicit boundary. Animating a clip element's other visual properties is fine and the shipped catalog does it throughout; what is forbidden is taking over its visibility.
|
|
- Anything driven by `Math.random()`, `Date.now()`, `performance.now()`, or event handlers — animation state must be deterministic from time alone.
|
|
|
|
> **Note**: the list above is a **denylist**, not an allowlist. Properties outside it, including `width`, `height`, `filter`, `clipPath` and `strokeDashoffset`, are legitimate targets; prefer transforms and opacity where you have the choice, for performance rather than correctness. See `hyperframes-core/references/determinism-rules.md` for the full deterministic-render contract.
|
|
|
|
## References
|
|
|
|
- `./gsap-timeline-and-labels.md` — timeline creation, position parameter (`+=`, `<`, `>`), labels, nesting, sub-comp `fromTo` preference, playback control.
|
|
- `./gsap-easing-and-stagger.md` — easing families, stagger objects, function-based values, `gsap.matchMedia()`, `gsap.defaults()`.
|
|
- `./gsap-transforms-and-perf.md` — transform aliases, autoAlpha, `quickTo`, `will-change`, performance rules.
|
|
- `../rules/gsap-effects.md` — drop-in recipes: typewriter (with cursor / backspace / word rotation) + audio visualizer (uses `skills/hyperframes-creative/scripts/extract-audio-data.py`).
|
|
|
|
## Best Practices
|
|
|
|
- Use camelCase property names; prefer transform aliases and autoAlpha.
|
|
- Prefer timelines over chained tweens with delays; use the position parameter.
|
|
- Add labels with `addLabel()` for readable sequencing.
|
|
- Pass defaults into the timeline constructor.
|
|
- Store the tween/timeline return value when controlling playback.
|
|
|
|
## Do Not
|
|
|
|
- Animate layout properties (`width`/`height`/`top`/`left`) when transforms suffice.
|
|
- Use both `svgOrigin` and `transformOrigin` on the same SVG element.
|
|
- Chain animations with `delay` when a timeline can sequence them.
|
|
- Create tweens before the DOM exists.
|
|
- Use infinite `repeat: -1` in HyperFrames compositions — use finite repeat counts computed from the visible duration.
|
|
|
|
## Credits And References
|
|
|
|
- HyperFrames adapter source: `packages/core/src/runtime/adapters/gsap.ts`.
|
|
- GSAP documentation: https://gsap.com/docs/v3/
|
|
- GSAP timeline pause and seek behavior: https://gsap.com/docs/v3/GSAP/Timeline/pause%28%29/
|