feat(skills): add layout-before-animation approach to hyperframes skill (#233)

Adds structured approach (what, structure, timing, layout, animate) and
layout-before-animation guidance — build end-state CSS first, then add
gsap.from() entrances and gsap.to() exits. Prevents unintentional overlap
by making layout problems visible before adding motion.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-04-09 11:20:32 -07:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 6f04983e20
commit d86e4cb3c3
+71 -1
View File
@@ -5,10 +5,79 @@ description: Create video compositions, animations, title cards, overlays, capti
# HyperFrames
HTML is the source of truth for video. A composition is an HTML file with `data-*` attributes for timing, a GSAP timeline for animation, and CSS for appearance.
HTML is the source of truth for video. A composition is an HTML file with `data-*` attributes for timing, a GSAP timeline for animation, and CSS for appearance. The framework handles clip visibility, media playback, and timeline sync.
## Approach
Before writing HTML, think at a high level:
1. **What** — what should the viewer experience? Identify the narrative arc, key moments, and emotional beats.
2. **Structure** — how many compositions, which are sub-compositions vs inline, what tracks carry what (video, audio, overlays, captions).
3. **Timing** — which clips drive the duration, where do transitions land, what's the pacing.
4. **Layout** — build the end-state first. See "Layout Before Animation" below.
5. **Animate** — then add motion using the rules below.
For small edits (fix a color, adjust timing, add one element), skip straight to the rules.
When no `visual-style.md` or animation direction is provided, follow [house-style.md](./house-style.md) for motion defaults, sizing, and color palettes.
## Layout Before Animation
Position every element where it should be at its **most visible moment** — the frame where it's fully entered, correctly placed, and not yet exiting. Write this as static HTML+CSS first. No GSAP yet.
**Why this matters:** If you position elements at their animated start state (offscreen, scaled to 0, opacity 0) and tween them to where you think they should land, you're guessing the final layout. Overlaps are invisible until the video renders. By building the end state first, you can see and fix layout problems before adding any motion.
### The process
1. **Identify the hero frame** for each scene — the moment when the most elements are simultaneously visible. This is the layout you build.
2. **Write static CSS** for that frame. Every element at its final `top`, `left`, `width`, `height`. Use the browser or `npx hyperframes preview` to visually verify nothing overlaps unintentionally.
3. **Add entrances with `gsap.from()`** — animate FROM offscreen/invisible TO the CSS position. The CSS position is the ground truth; the tween describes the journey to get there.
4. **Add exits with `gsap.to()`** — animate TO offscreen/invisible FROM the CSS position.
### Example
```css
/* Step 1-2: Layout the end state. This is what the viewer sees at peak visibility. */
.title {
position: absolute;
top: 200px;
left: 160px;
opacity: 1;
}
.subtitle {
position: absolute;
top: 320px;
left: 160px;
opacity: 1;
}
.logo {
position: absolute;
bottom: 80px;
right: 80px;
opacity: 1;
}
```
```js
// Step 3: Animate INTO those positions
tl.from(".title", { y: 60, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
tl.from(".subtitle", { y: 40, opacity: 0, duration: 0.5, ease: "power3.out" }, 0.2);
tl.from(".logo", { scale: 0.8, opacity: 0, duration: 0.4, ease: "power2.out" }, 0.3);
// Step 4: Animate OUT from those positions
tl.to(".title", { y: -40, opacity: 0, duration: 0.4, ease: "power2.in" }, 3);
tl.to(".subtitle", { y: -30, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.1);
tl.to(".logo", { scale: 0.9, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.2);
```
### When elements share space across time
If element A exits before element B enters in the same area, both should have correct CSS positions for their respective hero frames. The timeline ordering guarantees they never visually coexist — but if you skip the layout step, you won't catch the case where they accidentally overlap due to a timing error.
### What counts as intentional overlap
Layered effects (glow behind text, shadow elements, background patterns) and z-stacked designs (card stacks, depth layers) are intentional. The layout step is about catching **unintentional** overlap — two headlines landing on top of each other, a stat covering a label, content bleeding off-frame.
## Data Attributes
### All Clips
@@ -89,6 +158,7 @@ Video must be `muted playsinline`. Audio is always a separate `<audio>` element:
- Register every timeline: `window.__timelines["<composition-id>"] = tl`
- Framework auto-nests sub-timelines — do NOT manually add them
- Duration comes from `data-duration`, not from GSAP timeline length
- Never create empty tweens to set duration
## Rules (Non-Negotiable)