mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-08 10:46:06 +00:00
* refactor(skills): consolidate 15 skills into 3 for better trigger reliability Merge 9 GSAP skills (core, timeline, scrolltrigger, plugins, utils, react, frameworks, performance, effects) and 6 HyperFrames skills (compose, captions, tts, audio-reactive, marker-highlight, cli) into 3 consolidated skills: - `gsap` — core API + timelines + performance in SKILL.md; scrolltrigger, plugins, utils, react, frameworks, effects in references/ - `hyperframes` — composition authoring rules in SKILL.md; captions, tts, audio-reactive, marker-highlight in references/ - `hyperframes-cli` — CLI commands (init, lint, preview, render, etc.) Why: With 15 separate skills, agents must correctly trigger the right subset for any task. "Create an animated video with captions" needed 6+ skills to fire — each with ~90% trigger accuracy means ~53% chance of getting all of them. With 3 skills, that same task needs just `hyperframes` + `gsap` (~90% both fire). Progressive disclosure still works via references/ files loaded on demand. Also fixes: CLAUDE.md referenced `window.__GSAP_TIMELINE` (incorrect) — corrected to `window.__timelines`. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(cli): add --skip-skills flag to init command Allow skipping the AI coding skills installation prompt during `hyperframes init` with `--skip-skills`. Useful when skills are already installed or when the user wants to scaffold without them. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(skills): address code review feedback on consolidation Restore content lost during over-compression: - captions: fix overflow to `visible` (not hidden — clips glow effects), add container pattern warning, scale headroom formula, and self-lint placement guidance - audio-reactive: restore sampling frequency pattern (per-frame tl.call loop vs single tween) and textShadow-on-container gotcha - effects/typewriter: restore word rotation, appending words, spacing with static text, and multi-line cursor handoff patterns - effects/audio-visualizer: restore spatial mapping conventions, fetch vs inline loading, WebGL/DOM rendering approaches, and canvas layering - hyperframes-cli: restore --strict-all flag in render flags table Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(cli): update build:copy and template for consolidated skill names - build:copy: reference skills/hyperframes, skills/hyperframes-cli, skills/gsap instead of the old 15 skill directory names - _shared/CLAUDE.md template: update skill table to consolidated names Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
148 lines
8.2 KiB
Markdown
148 lines
8.2 KiB
Markdown
# ScrollTrigger
|
|
|
|
## Registering
|
|
|
|
```javascript
|
|
gsap.registerPlugin(ScrollTrigger);
|
|
```
|
|
|
|
## Basic Trigger
|
|
|
|
```javascript
|
|
gsap.to(".box", {
|
|
x: 500,
|
|
scrollTrigger: {
|
|
trigger: ".box",
|
|
start: "top center",
|
|
end: "bottom center",
|
|
toggleActions: "play reverse play reverse",
|
|
},
|
|
});
|
|
```
|
|
|
|
**start/end** format: `"triggerPosition viewportPosition"`. Examples: `"top top"`, `"center center"`, `"bottom 80%"`, numeric px `500`, relative `"+=300"`, `"+=100%"` (scroller height), `"max"`. Wrap in `clamp()` (v3.12+): `"clamp(top bottom)"`. Can be a function returning string/number.
|
|
|
|
## Key Config Options
|
|
|
|
| Property | Type | Description |
|
|
| ----------------------------------------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| **trigger** | String/Element | Element whose position defines start. Required. |
|
|
| **start** | String/Number/Function | When active. Default `"top bottom"` (or `"top top"` if pinned). |
|
|
| **end** | String/Number/Function | When ends. Default `"bottom top"`. |
|
|
| **endTrigger** | String/Element | Different element for end calculation. |
|
|
| **scrub** | Boolean/Number | Link progress to scroll. `true` = direct; number = catch-up seconds. |
|
|
| **toggleActions** | String | Four actions: onEnter, onLeave, onEnterBack, onLeaveBack. Values: play/pause/resume/reset/restart/complete/reverse/none. Default `"play none none none"`. |
|
|
| **pin** | Boolean/String/Element | Pin element while active. `true` = pin trigger. Animate children, not the pinned element. |
|
|
| **pinSpacing** | Boolean/String | Default `true` (adds spacer). `false` or `"margin"`. |
|
|
| **horizontal** | Boolean | For horizontal scrolling. |
|
|
| **scroller** | String/Element | Scroll container (default: viewport). |
|
|
| **markers** | Boolean/Object | Dev markers. Remove in production. |
|
|
| **once** | Boolean | Kill after end reached once. |
|
|
| **snap** | Number/Array/Function/"labels"/Object | Snap to progress values. |
|
|
| **containerAnimation** | Tween/Timeline | For fake horizontal scroll (see below). |
|
|
| **toggleClass** | String/Object | Add/remove class when active. |
|
|
| **onEnter/onLeave/onEnterBack/onLeaveBack** | Function | Callbacks; receive ScrollTrigger instance. |
|
|
| **onUpdate/onToggle/onRefresh/onScrubComplete** | Function | Progress/state callbacks. |
|
|
|
|
**Standalone** (no linked tween): `ScrollTrigger.create({...})` with callbacks.
|
|
|
|
## Scrub
|
|
|
|
```javascript
|
|
scrollTrigger: { trigger: ".box", start: "top center", end: "bottom center", scrub: true }
|
|
```
|
|
|
|
`scrub: true` = direct link; number (e.g. `1`) = smooth lag.
|
|
|
|
## Pinning
|
|
|
|
```javascript
|
|
scrollTrigger: {
|
|
trigger: ".section", start: "top top", end: "+=1000", pin: true, scrub: 1
|
|
}
|
|
```
|
|
|
|
## Timeline + ScrollTrigger
|
|
|
|
```javascript
|
|
const tl = gsap.timeline({
|
|
scrollTrigger: { trigger: ".container", start: "top top", end: "+=2000", scrub: 1, pin: true },
|
|
});
|
|
tl.to(".a", { x: 100 }).to(".b", { y: 50 });
|
|
```
|
|
|
|
## ScrollTrigger.batch()
|
|
|
|
Creates one ScrollTrigger per target, batches callbacks within a short interval. Good for staggered reveal of many elements.
|
|
|
|
```javascript
|
|
ScrollTrigger.batch(".box", {
|
|
onEnter: (elements) => gsap.to(elements, { opacity: 1, y: 0, stagger: 0.15 }),
|
|
start: "top 80%",
|
|
});
|
|
```
|
|
|
|
Options: `interval` (batch window), `batchMax` (max per batch). Callbacks receive `(targets, scrollTriggers)`.
|
|
|
|
## Horizontal Scroll (containerAnimation)
|
|
|
|
Pin a section, animate inner content's `x`/`xPercent` horizontally on vertical scroll:
|
|
|
|
1. Pin the section
|
|
2. Animate inner content with **ease: "none"** (required)
|
|
3. Attach ScrollTrigger with pin + scrub
|
|
4. Use `containerAnimation` on nested triggers
|
|
|
|
```javascript
|
|
const scrollTween = gsap.to(scrollingEl, {
|
|
xPercent: () => Math.max(0, window.innerWidth - scrollingEl.offsetWidth),
|
|
ease: "none",
|
|
scrollTrigger: {
|
|
trigger: scrollingEl,
|
|
pin: scrollingEl.parentNode,
|
|
start: "top top",
|
|
end: "+=1000",
|
|
},
|
|
});
|
|
|
|
gsap.to(".nested", {
|
|
y: 100,
|
|
scrollTrigger: { containerAnimation: scrollTween, trigger: ".wrapper", start: "left center" },
|
|
});
|
|
```
|
|
|
|
Pinning and snapping unavailable on containerAnimation-based ScrollTriggers.
|
|
|
|
## ScrollTrigger.scrollerProxy()
|
|
|
|
Override scroll position reading for third-party smooth-scroll libraries. Call `ScrollTrigger.update` when the scroller updates.
|
|
|
|
```javascript
|
|
ScrollTrigger.scrollerProxy(document.body, {
|
|
scrollTop(value) {
|
|
if (arguments.length) scrollbar.scrollTop = value;
|
|
return scrollbar.scrollTop;
|
|
},
|
|
getBoundingClientRect() {
|
|
return { top: 0, left: 0, width: window.innerWidth, height: window.innerHeight };
|
|
},
|
|
});
|
|
scrollbar.addListener(ScrollTrigger.update);
|
|
```
|
|
|
|
## Refresh and Cleanup
|
|
|
|
- `ScrollTrigger.refresh()` — recalculate after DOM/layout changes. Auto on resize (200ms debounce).
|
|
- Create ScrollTriggers top-to-bottom or set `refreshPriority`.
|
|
- Kill instances when removing elements: `ScrollTrigger.getAll().forEach(t => t.kill())` or `ScrollTrigger.getById("id")?.kill()`.
|
|
|
|
## Do Not
|
|
|
|
- Put ScrollTrigger on child tweens inside a timeline — put on the timeline.
|
|
- Nest ScrollTriggered animations inside a parent timeline.
|
|
- Use scrub and toggleActions together (scrub wins).
|
|
- Use an ease other than "none" on the horizontal animation with containerAnimation.
|
|
- Leave markers in production.
|
|
- Create triggers in random order without refreshPriority.
|
|
- Forget refresh() after layout changes.
|