mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-05 05:37:09 +00:00
refactor: remove infographics and transitions skills, add asset-management
Removed skills that don't add value beyond model knowledge: - infographics: model already produces equivalent output without it - transitions: patterns are derivable from compose-video constraints Added: - asset-management: organize user-uploaded files into assets/ and fonts/ - Typography section in compose-video: min font sizes, font loading (Google Fonts + local @font-face), weight pairing, font-display:block - Assets section in compose-video: project structure with assets/ and fonts/ directories, path rules, CORS, "check before creating" rule Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
Vance Ingalls
co-authored by
Claude Opus 4.6
parent
e2764a2d0c
commit
36a5c23827
@@ -14,7 +14,7 @@
|
||||
"build": "bun run build:studio && tsup && bun run build:runtime && bun run build:copy",
|
||||
"build:studio": "cd ../studio && bun run build",
|
||||
"build:runtime": "tsx scripts/build-runtime.ts",
|
||||
"build:copy": "mkdir -p dist/studio dist/docs dist/templates dist/skills && cp -r ../studio/dist/* dist/studio/ && cp -r src/templates/warm-grain src/templates/play-mode src/templates/swiss-grid src/templates/vignelli dist/templates/ && (cp src/docs/*.md dist/docs/ 2>/dev/null || true) && (cp -r ../../skills/compose-video ../../skills/captions ../../skills/transitions ../../skills/media ../../skills/social-media ../../skills/infographics dist/skills/ 2>/dev/null || true)",
|
||||
"build:copy": "mkdir -p dist/studio dist/docs dist/templates dist/skills && cp -r ../studio/dist/* dist/studio/ && cp -r src/templates/warm-grain src/templates/play-mode src/templates/swiss-grid src/templates/vignelli dist/templates/ && (cp src/docs/*.md dist/docs/ 2>/dev/null || true) && (cp -r ../../skills/compose-video ../../skills/captions ../../skills/media ../../skills/social-media ../../skills/asset-management dist/skills/ 2>/dev/null || true)",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,466 +0,0 @@
|
||||
---
|
||||
name: infographics
|
||||
description: Design and animate professional infographic compositions in HyperFrames. Use when a composition needs stats, comparisons, processes, timelines, or any data visualization with clean design and contextual animation.
|
||||
---
|
||||
|
||||
# Infographics
|
||||
|
||||
Design and animate professional infographic compositions with clean typography, intentional layout, and animations that reinforce the data story.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Composition mentions stats, percentages, numbers, or comparisons
|
||||
- Content describes a process, timeline, hierarchy, or flow
|
||||
- User asks for "infographic", "data visualization", or "stats overlay"
|
||||
- The narrative has quantitative claims that benefit from visual reinforcement
|
||||
|
||||
## Design Principles
|
||||
|
||||
### Typography Hierarchy
|
||||
|
||||
Every infographic has exactly three levels:
|
||||
|
||||
1. **Hero number/stat** — the largest element, the thing you see first. 120-280px. Bold weight.
|
||||
2. **Label/title** — what the number means. 24-48px. Medium weight. Muted color.
|
||||
3. **Supporting context** — comparison, source, timeframe. 16-24px. Light weight or dimmed.
|
||||
|
||||
```css
|
||||
.stat-hero {
|
||||
font-size: 200px;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.04em;
|
||||
line-height: 1;
|
||||
}
|
||||
.stat-label {
|
||||
font-size: 36px;
|
||||
font-weight: 500;
|
||||
opacity: 0.7;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.stat-context {
|
||||
font-size: 20px;
|
||||
font-weight: 400;
|
||||
opacity: 0.5;
|
||||
}
|
||||
```
|
||||
|
||||
### Layout Rules
|
||||
|
||||
- **One idea per frame.** Don't combine unrelated stats. Each infographic composition shows one concept.
|
||||
- **Grid-aligned.** Use an invisible grid (margins: 80px, gutters: 40px). Elements snap to grid lines.
|
||||
- **Generous whitespace.** At least 30% of the frame should be empty. Cramped layouts look amateur.
|
||||
- **Left-aligned or centered.** Never right-aligned unless the layout demands it (RTL, split-screen right panel).
|
||||
- **Consistent margins.** 80px from all edges minimum. Content never touches the frame edge.
|
||||
|
||||
### Color
|
||||
|
||||
- **Two colors maximum** per infographic — one for the hero element, one for everything else.
|
||||
- **Accent color for the stat.** The number/bar/chart gets the accent. Labels and context stay neutral.
|
||||
- **Dark backgrounds for video overlays.** Use `rgba(0,0,0,0.85)` or solid `#111` — never pure black.
|
||||
- **No gradients, no shadows, no glows.** Flat, clean, confident.
|
||||
|
||||
### What NOT to Do
|
||||
|
||||
- No clip art, icons-for-decoration, or stock imagery
|
||||
- No rounded-everything — use sharp corners or very subtle radius (4-8px max)
|
||||
- No borders around stats — the typography IS the design
|
||||
- No more than 3 colors in a single frame
|
||||
- No center-of-screen placement for everything — use intentional asymmetry
|
||||
- No decorative animation — every movement communicates something
|
||||
|
||||
## Infographic Types
|
||||
|
||||
### Single Stat
|
||||
|
||||
The most common. One number, one label, optional context.
|
||||
|
||||
```html
|
||||
<div
|
||||
class="stat-frame"
|
||||
style="
|
||||
position:absolute; inset:0;
|
||||
display:flex; flex-direction:column;
|
||||
align-items:flex-start; justify-content:center;
|
||||
padding: 0 160px;
|
||||
"
|
||||
>
|
||||
<span
|
||||
class="stat-hero"
|
||||
id="stat-num"
|
||||
style="
|
||||
font-family:'Inter',sans-serif; font-size:200px; font-weight:800;
|
||||
color:#ffffff; letter-spacing:-0.04em; line-height:1;
|
||||
"
|
||||
>0%</span
|
||||
>
|
||||
<span
|
||||
class="stat-label"
|
||||
style="
|
||||
font-family:'Inter',sans-serif; font-size:36px; font-weight:500;
|
||||
color:rgba(255,255,255,0.6); margin-top:16px; letter-spacing:0.02em;
|
||||
"
|
||||
>increase in engagement</span
|
||||
>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Comparison (Side-by-Side)
|
||||
|
||||
Two stats contrasted. Use a vertical divider or spatial separation.
|
||||
|
||||
```html
|
||||
<div style="position:absolute;inset:0;display:flex;">
|
||||
<!-- Left stat -->
|
||||
<div style="flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;">
|
||||
<span id="stat-before" style="font-size:160px;font-weight:800;color:rgba(255,255,255,0.4);"
|
||||
>12%</span
|
||||
>
|
||||
<span style="font-size:28px;color:rgba(255,255,255,0.4);margin-top:12px;">Before</span>
|
||||
</div>
|
||||
<!-- Divider -->
|
||||
<div style="width:2px;background:rgba(255,255,255,0.1);margin:120px 0;"></div>
|
||||
<!-- Right stat -->
|
||||
<div style="flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;">
|
||||
<span id="stat-after" style="font-size:160px;font-weight:800;color:#ffffff;">47%</span>
|
||||
<span style="font-size:28px;color:rgba(255,255,255,0.6);margin-top:12px;">After</span>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Bar Chart
|
||||
|
||||
Horizontal bars. The bar width IS the data.
|
||||
|
||||
```html
|
||||
<div style="position:absolute;top:50%;left:160px;right:160px;transform:translateY(-50%);">
|
||||
<div class="bar-row" style="margin-bottom:32px;">
|
||||
<span style="font-size:20px;color:rgba(255,255,255,0.6);display:block;margin-bottom:8px;"
|
||||
>Desktop</span
|
||||
>
|
||||
<div style="display:flex;align-items:center;gap:16px;">
|
||||
<div id="bar-1" style="height:48px;width:0%;background:#ffffff;border-radius:4px;"></div>
|
||||
<span id="bar-1-label" style="font-size:32px;font-weight:700;color:#ffffff;opacity:0;"
|
||||
>72%</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bar-row">
|
||||
<span style="font-size:20px;color:rgba(255,255,255,0.6);display:block;margin-bottom:8px;"
|
||||
>Mobile</span
|
||||
>
|
||||
<div style="display:flex;align-items:center;gap:16px;">
|
||||
<div
|
||||
id="bar-2"
|
||||
style="height:48px;width:0%;background:rgba(255,255,255,0.3);border-radius:4px;"
|
||||
></div>
|
||||
<span
|
||||
id="bar-2-label"
|
||||
style="font-size:32px;font-weight:700;color:rgba(255,255,255,0.6);opacity:0;"
|
||||
>34%</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Progress / Meter
|
||||
|
||||
A single horizontal line that fills. Good for "X out of Y" or percentage completion.
|
||||
|
||||
```html
|
||||
<div style="position:absolute;bottom:200px;left:160px;right:160px;">
|
||||
<div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:16px;">
|
||||
<span style="font-size:24px;color:rgba(255,255,255,0.5);">Progress</span>
|
||||
<span id="progress-label" style="font-size:48px;font-weight:800;color:#ffffff;">0%</span>
|
||||
</div>
|
||||
<div
|
||||
style="width:100%;height:8px;background:rgba(255,255,255,0.1);border-radius:4px;overflow:hidden;"
|
||||
>
|
||||
<div
|
||||
id="progress-fill"
|
||||
style="width:0%;height:100%;background:#ffffff;border-radius:4px;"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Process / Steps
|
||||
|
||||
Numbered steps with a connecting line. Show one step at a time or reveal sequentially.
|
||||
|
||||
```html
|
||||
<div style="position:absolute;top:50%;left:160px;right:160px;transform:translateY(-50%);">
|
||||
<div
|
||||
class="step"
|
||||
id="step-1"
|
||||
style="display:flex;align-items:flex-start;gap:24px;margin-bottom:48px;opacity:0;"
|
||||
>
|
||||
<span style="font-size:64px;font-weight:800;color:rgba(255,255,255,0.15);line-height:1;"
|
||||
>01</span
|
||||
>
|
||||
<div>
|
||||
<span style="font-size:32px;font-weight:700;color:#ffffff;display:block;">Capture</span>
|
||||
<span style="font-size:20px;color:rgba(255,255,255,0.5);display:block;margin-top:4px;"
|
||||
>Record your content</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="step"
|
||||
id="step-2"
|
||||
style="display:flex;align-items:flex-start;gap:24px;margin-bottom:48px;opacity:0;"
|
||||
>
|
||||
<span style="font-size:64px;font-weight:800;color:rgba(255,255,255,0.15);line-height:1;"
|
||||
>02</span
|
||||
>
|
||||
<div>
|
||||
<span style="font-size:32px;font-weight:700;color:#ffffff;display:block;">Edit</span>
|
||||
<span style="font-size:20px;color:rgba(255,255,255,0.5);display:block;margin-top:4px;"
|
||||
>Compose in HyperFrames</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step" id="step-3" style="display:flex;align-items:flex-start;gap:24px;opacity:0;">
|
||||
<span style="font-size:64px;font-weight:800;color:rgba(255,255,255,0.15);line-height:1;"
|
||||
>03</span
|
||||
>
|
||||
<div>
|
||||
<span style="font-size:32px;font-weight:700;color:#ffffff;display:block;">Publish</span>
|
||||
<span style="font-size:20px;color:rgba(255,255,255,0.5);display:block;margin-top:4px;"
|
||||
>Render and share</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Animation Patterns
|
||||
|
||||
Every animation serves one of three purposes: **reveal**, **emphasize**, or **connect**. If an animation doesn't do one of these, remove it.
|
||||
|
||||
### Count-Up (for numbers)
|
||||
|
||||
The number counts from 0 to its final value. This IS the reveal — don't also fade in.
|
||||
|
||||
```js
|
||||
// Count from 0 to 47
|
||||
const target = { val: 0 };
|
||||
tl.to(
|
||||
target,
|
||||
{
|
||||
val: 47,
|
||||
duration: 1.2,
|
||||
ease: "power2.out",
|
||||
onUpdate: () => {
|
||||
document.getElementById("stat-num").textContent = Math.round(target.val) + "%";
|
||||
},
|
||||
},
|
||||
startTime,
|
||||
);
|
||||
```
|
||||
|
||||
- **Duration:** 0.8-1.5s depending on the magnitude of the number
|
||||
- **Ease:** `power2.out` — fast start, gentle land. The number "arrives" at its value.
|
||||
- **Never linear.** Linear count-up feels mechanical.
|
||||
|
||||
### Bar Growth (for bar charts)
|
||||
|
||||
Bars grow from 0% to their target width. Stagger each bar.
|
||||
|
||||
```js
|
||||
tl.to("#bar-1", { width: "72%", duration: 0.8, ease: "power3.out" }, startTime);
|
||||
tl.to("#bar-1-label", { opacity: 1, duration: 0.3 }, startTime + 0.6);
|
||||
|
||||
tl.to("#bar-2", { width: "34%", duration: 0.8, ease: "power3.out" }, startTime + 0.2);
|
||||
tl.to("#bar-2-label", { opacity: 1, duration: 0.3 }, startTime + 0.8);
|
||||
```
|
||||
|
||||
- **Stagger:** 0.15-0.25s between bars
|
||||
- **Label appears** near the end of the bar's growth, not simultaneously
|
||||
- **Ease:** `power3.out` — bars decelerate as they reach their target
|
||||
|
||||
### Progress Fill
|
||||
|
||||
The fill bar and the label count up in sync.
|
||||
|
||||
```js
|
||||
const progress = { val: 0 };
|
||||
tl.to(
|
||||
progress,
|
||||
{
|
||||
val: 78,
|
||||
duration: 1.5,
|
||||
ease: "power2.inOut",
|
||||
onUpdate: () => {
|
||||
document.getElementById("progress-fill").style.width = progress.val + "%";
|
||||
document.getElementById("progress-label").textContent = Math.round(progress.val) + "%";
|
||||
},
|
||||
},
|
||||
startTime,
|
||||
);
|
||||
```
|
||||
|
||||
### Entrance Choreography
|
||||
|
||||
Elements enter in reading order: top-to-bottom, primary-to-secondary. The hero element enters first, supporting elements follow.
|
||||
|
||||
```js
|
||||
// 1. Hero stat enters (the thing you see first)
|
||||
tl.fromTo(
|
||||
"#stat-num",
|
||||
{ opacity: 0, y: 30 },
|
||||
{ opacity: 1, y: 0, duration: 0.5, ease: "power3.out" },
|
||||
startTime,
|
||||
);
|
||||
|
||||
// 2. Label follows (explains what the number means)
|
||||
tl.fromTo(
|
||||
".stat-label",
|
||||
{ opacity: 0, y: 20 },
|
||||
{ opacity: 1, y: 0, duration: 0.4, ease: "power3.out" },
|
||||
startTime + 0.15,
|
||||
);
|
||||
|
||||
// 3. Context last (supporting detail)
|
||||
tl.fromTo(
|
||||
".stat-context",
|
||||
{ opacity: 0 },
|
||||
{ opacity: 1, duration: 0.3, ease: "power2.out" },
|
||||
startTime + 0.3,
|
||||
);
|
||||
```
|
||||
|
||||
- **Stagger:** 0.1-0.2s between hierarchy levels
|
||||
- **Direction:** `y: 20-30` (subtle upward movement). Never from the sides for stats.
|
||||
- **Duration:** decreases with hierarchy — hero 0.5s, label 0.4s, context 0.3s
|
||||
- **Ease:** `power3.out` for primary, `power2.out` for secondary
|
||||
|
||||
### Exit
|
||||
|
||||
Clean, fast, uniform. All elements exit together — don't reverse the entrance choreography.
|
||||
|
||||
```js
|
||||
tl.to(".stat-frame", { opacity: 0, duration: 0.3, ease: "power2.in" }, exitTime);
|
||||
```
|
||||
|
||||
- **Duration:** 0.2-0.4s. Exits are faster than entrances.
|
||||
- **No y movement on exit.** Just fade. The next frame takes over.
|
||||
|
||||
### Sequential Steps
|
||||
|
||||
Each step enters one at a time, synchronized to narration.
|
||||
|
||||
```js
|
||||
steps.forEach((step, i) => {
|
||||
// Step number gets accent color when active
|
||||
tl.to(step.el, { opacity: 1, duration: 0.4, ease: "power2.out" }, step.startTime);
|
||||
tl.to(step.numberEl, { color: accentColor, duration: 0.3 }, step.startTime);
|
||||
|
||||
// Previous step dims
|
||||
if (i > 0) {
|
||||
tl.to(steps[i - 1].el, { opacity: 0.3, duration: 0.3 }, step.startTime);
|
||||
tl.to(steps[i - 1].numberEl, { color: dimColor, duration: 0.3 }, step.startTime);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Comparison Reveal
|
||||
|
||||
Show both sides, but reveal the "after" with emphasis.
|
||||
|
||||
```js
|
||||
// "Before" appears first, muted
|
||||
tl.fromTo("#stat-before", { opacity: 0 }, { opacity: 1, duration: 0.4 }, startTime);
|
||||
|
||||
// Pause for the viewer to register "before"
|
||||
// "After" enters with more energy
|
||||
tl.fromTo(
|
||||
"#stat-after",
|
||||
{ opacity: 0, scale: 0.8 },
|
||||
{ opacity: 1, scale: 1, duration: 0.5, ease: "back.out(1.4)" },
|
||||
startTime + 0.6,
|
||||
);
|
||||
```
|
||||
|
||||
## Timing to Narration
|
||||
|
||||
Infographics must sync to the spoken content. The stat appears when the narrator says the number.
|
||||
|
||||
```js
|
||||
// Transcript: "...engagement increased by forty-seven percent..."
|
||||
// "forty-seven" starts at 3.2s, "percent" ends at 3.9s
|
||||
// Start count-up at 3.2s, land at 3.9s
|
||||
const STAT_START = 3.2;
|
||||
const STAT_LAND = 3.9;
|
||||
|
||||
tl.to(
|
||||
target,
|
||||
{
|
||||
val: 47,
|
||||
duration: STAT_LAND - STAT_START,
|
||||
ease: "power2.out",
|
||||
onUpdate: () => {
|
||||
el.textContent = Math.round(target.val) + "%";
|
||||
},
|
||||
},
|
||||
STAT_START,
|
||||
);
|
||||
```
|
||||
|
||||
- **Stat appears** when the narrator starts saying the number
|
||||
- **Stat lands** (finishes counting) when the narrator finishes saying it
|
||||
- **Label appears** immediately after the stat lands
|
||||
- **Exit** when the narrator moves to the next topic (or 1-2s after if there's a pause)
|
||||
|
||||
## Composition Structure
|
||||
|
||||
Each infographic is its own composition file:
|
||||
|
||||
```html
|
||||
<template id="stat-47-template">
|
||||
<div data-composition-id="stat-47" data-width="1920" data-height="1080">
|
||||
<!-- Layout HTML here -->
|
||||
|
||||
<style>
|
||||
[data-composition-id="stat-47"] {
|
||||
/* scoped styles */
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||||
<script>
|
||||
(function () {
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
// Animations here
|
||||
window.__timelines["stat-47"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
Load in the root composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
id="el-stat-47"
|
||||
data-composition-id="stat-47"
|
||||
data-composition-src="compositions/stat-47.html"
|
||||
data-start="3"
|
||||
data-duration="5"
|
||||
data-track-index="4"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
style="z-index:30;"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Constraints
|
||||
|
||||
- **Deterministic.** No `Math.random()`, no `Date.now()`.
|
||||
- **Register timeline.** `window.__timelines["composition-id"] = tl;`
|
||||
- **Scoped CSS.** `[data-composition-id="..."]` prefix on all selectors.
|
||||
- **One infographic per composition.** Don't pack multiple stats into one file.
|
||||
- **Count-up uses `onUpdate`.** This is the one place callback-driven animation is appropriate. The callback must be deterministic (same input → same display at any given time).
|
||||
- **Font loading.** Include `@import url(...)` in the composition's `<style>` block. Don't rely on the parent loading fonts.
|
||||
- **Dark backgrounds for overlays.** If the infographic overlays video, use a semi-transparent or solid dark background so text is readable.
|
||||
@@ -1,23 +0,0 @@
|
||||
# Infographics Skill Evals
|
||||
|
||||
Three scenarios testing whether the skill produces well-designed, correctly animated infographic compositions.
|
||||
|
||||
## Running
|
||||
|
||||
Each eval is a prompt + expected output criteria. Run each prompt in a fresh Claude Code session with the infographics skill installed, then score the output against the criteria.
|
||||
|
||||
```bash
|
||||
# Install skills first
|
||||
npx tsx packages/cli/src/cli.ts skills --claude
|
||||
|
||||
# Run each eval in a fresh session
|
||||
claude "$(cat skills/infographics/evals/eval-1-single-stat.md)"
|
||||
claude "$(cat skills/infographics/evals/eval-2-comparison.md)"
|
||||
claude "$(cat skills/infographics/evals/eval-3-process-steps.md)"
|
||||
```
|
||||
|
||||
## Scoring
|
||||
|
||||
Each eval has PASS/FAIL criteria. A criterion passes if the output meets the requirement. Score = passing criteria / total criteria.
|
||||
|
||||
**Target:** 80%+ pass rate across all evals.
|
||||
@@ -1,43 +0,0 @@
|
||||
Create a HyperFrames composition for a single stat infographic. The narrator says "our conversion rate jumped to forty-seven percent" starting at 2.1 seconds and ending at 3.8 seconds. The stat should appear as an overlay on a dark background at 1920x1080. Save to compositions/stat-conversion.html.
|
||||
|
||||
---
|
||||
|
||||
## Criteria
|
||||
|
||||
### Structure (composition format)
|
||||
|
||||
- [ ] File is a valid `<template>` wrapping a `<div>` with `data-composition-id`
|
||||
- [ ] Has `data-width="1920"` and `data-height="1080"`
|
||||
- [ ] Includes GSAP script tag (`gsap@3.14.2`)
|
||||
- [ ] Registers timeline: `window.__timelines["..."] = tl`
|
||||
- [ ] Timeline created with `{ paused: true }`
|
||||
- [ ] Script wrapped in IIFE
|
||||
|
||||
### Design (typography and layout)
|
||||
|
||||
- [ ] Hero stat font size is 120px or larger
|
||||
- [ ] Label font size is 24-48px
|
||||
- [ ] No more than 2 colors used (accent + neutral)
|
||||
- [ ] Left-aligned or centered — not right-aligned
|
||||
- [ ] Margins are 80px+ from frame edges
|
||||
- [ ] No gradients, shadows, or glows in styles
|
||||
- [ ] No border around the stat
|
||||
- [ ] Uses a professional font (Inter, Montserrat, or similar sans-serif)
|
||||
|
||||
### Animation (count-up and choreography)
|
||||
|
||||
- [ ] Stat counts up from 0 to 47 (not instant appear)
|
||||
- [ ] Count-up uses `onUpdate` callback with `Math.round()`
|
||||
- [ ] Count-up starts at ~2.1s (when narrator says the number)
|
||||
- [ ] Count-up duration roughly matches narration (2.1s to 3.8s = ~1.7s)
|
||||
- [ ] Ease is NOT linear (uses power2.out or similar)
|
||||
- [ ] Label appears AFTER stat lands (not simultaneously)
|
||||
- [ ] Has an exit animation (opacity fade)
|
||||
- [ ] Exit is faster than entrance (0.2-0.4s)
|
||||
|
||||
### Anti-patterns (should NOT be present)
|
||||
|
||||
- [ ] No `Math.random()` or `Date.now()`
|
||||
- [ ] No decorative animation (no bounce, no spin, no wiggle on the stat)
|
||||
- [ ] No `display: none` toggling
|
||||
- [ ] No inline `<style>` without `[data-composition-id]` scoping
|
||||
@@ -1,42 +0,0 @@
|
||||
Create a HyperFrames composition showing a before/after comparison infographic. Before: "12% engagement rate". After: "47% engagement rate". The narrator says "we went from twelve percent to forty-seven percent" starting at 5.0s and ending at 7.2s. Landscape 1920x1080, overlay on dark background. Save to compositions/stat-comparison.html.
|
||||
|
||||
---
|
||||
|
||||
## Criteria
|
||||
|
||||
### Structure
|
||||
|
||||
- [ ] Valid `<template>` with `data-composition-id`
|
||||
- [ ] Has `data-width="1920"` and `data-height="1080"`
|
||||
- [ ] GSAP 3.14.2 included
|
||||
- [ ] Timeline registered in `window.__timelines`
|
||||
- [ ] IIFE-wrapped script
|
||||
|
||||
### Design (comparison layout)
|
||||
|
||||
- [ ] Two distinct stat areas (left/right or before/after labeling)
|
||||
- [ ] "Before" stat is visually muted (lower opacity, smaller, or dimmer color)
|
||||
- [ ] "After" stat is visually prominent (full opacity, accent color, or larger)
|
||||
- [ ] Clear visual hierarchy — the "after" draws the eye first
|
||||
- [ ] Divider or spatial separation between the two stats
|
||||
- [ ] No more than 2 colors
|
||||
- [ ] Margins 80px+ from edges
|
||||
- [ ] No gradients, shadows, or decorative elements
|
||||
|
||||
### Animation (comparison reveal)
|
||||
|
||||
- [ ] "Before" appears first (muted entrance)
|
||||
- [ ] Pause between "before" and "after" reveals (0.3-0.8s gap)
|
||||
- [ ] "After" enters with more energy than "before" (scale, ease, or speed difference)
|
||||
- [ ] "After" uses `back.out` or similar overshoot ease (emphasis)
|
||||
- [ ] "Before" does NOT use overshoot ease (subdued entrance)
|
||||
- [ ] Timing syncs to narration (~5.0s start)
|
||||
- [ ] Exit animation present
|
||||
- [ ] All elements exit together (not reverse choreography)
|
||||
|
||||
### Anti-patterns
|
||||
|
||||
- [ ] No `Math.random()` or `Date.now()`
|
||||
- [ ] No simultaneous entrance of both stats (must be staggered)
|
||||
- [ ] No identical animation for both stats (they should feel different)
|
||||
- [ ] No `display: none` toggling
|
||||
@@ -1,44 +0,0 @@
|
||||
Create a HyperFrames composition showing a 3-step process infographic. Steps: (1) "Record" at 1.0s, (2) "Edit" at 3.5s, (3) "Publish" at 6.0s. Each step has a short description. The narrator introduces each step at the given time. Landscape 1920x1080. Save to compositions/process-steps.html.
|
||||
|
||||
---
|
||||
|
||||
## Criteria
|
||||
|
||||
### Structure
|
||||
|
||||
- [ ] Valid `<template>` with `data-composition-id`
|
||||
- [ ] Has `data-width="1920"` and `data-height="1080"`
|
||||
- [ ] GSAP 3.14.2 included
|
||||
- [ ] Timeline registered in `window.__timelines`
|
||||
- [ ] IIFE-wrapped script
|
||||
|
||||
### Design (process layout)
|
||||
|
||||
- [ ] Three steps are visually distinct (numbered or labeled)
|
||||
- [ ] Step numbers use large, muted typography (dim color or low opacity)
|
||||
- [ ] Step titles are bold and prominent
|
||||
- [ ] Step descriptions are smaller and muted
|
||||
- [ ] Consistent vertical spacing between steps
|
||||
- [ ] Left-aligned layout (not scattered across the frame)
|
||||
- [ ] Margins 80px+ from edges
|
||||
- [ ] No icons or clip art — typography only
|
||||
- [ ] No gradients, shadows, or decorative elements
|
||||
|
||||
### Animation (sequential reveal)
|
||||
|
||||
- [ ] Steps reveal one at a time, not all at once
|
||||
- [ ] Step 1 appears at ~1.0s, Step 2 at ~3.5s, Step 3 at ~6.0s
|
||||
- [ ] Each step fades in with subtle y-offset (upward movement)
|
||||
- [ ] Active step is visually highlighted (full opacity, accent color on number)
|
||||
- [ ] Previous steps dim when next step appears (opacity reduction)
|
||||
- [ ] Previous steps remain visible (dimmed, not hidden)
|
||||
- [ ] Entrance stagger within each step (number → title → description)
|
||||
- [ ] Exit animation for the whole group
|
||||
|
||||
### Anti-patterns
|
||||
|
||||
- [ ] No `Math.random()` or `Date.now()`
|
||||
- [ ] Steps don't all appear simultaneously
|
||||
- [ ] No horizontal entrance directions (steps enter vertically, not from sides)
|
||||
- [ ] No `display: none` toggling
|
||||
- [ ] No decorative animation on step numbers (no spin, bounce, etc.)
|
||||
Reference in New Issue
Block a user