@opendirectory.dev/skills 0.1.69 → 0.1.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package/registry.json
CHANGED
|
@@ -480,6 +480,16 @@
|
|
|
480
480
|
"version": "1.2.0",
|
|
481
481
|
"path": "skills/vid-product-launch"
|
|
482
482
|
},
|
|
483
|
+
{
|
|
484
|
+
"name": "vid-sizzle-reel",
|
|
485
|
+
"description": "Generates a high-energy sizzle reel or hype video (MP4) from brand assets and key messages.",
|
|
486
|
+
"tags": [
|
|
487
|
+
"Branding"
|
|
488
|
+
],
|
|
489
|
+
"author": "OpenDirectory",
|
|
490
|
+
"version": "1.0.0",
|
|
491
|
+
"path": "skills/vid-sizzle-reel"
|
|
492
|
+
},
|
|
483
493
|
{
|
|
484
494
|
"name": "where-your-customer-lives",
|
|
485
495
|
"description": "Given a product utility and ICP, researches the internet to find the specific channels.",
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# vid-sizzle-reel
|
|
2
|
+
|
|
3
|
+
Generate a high-energy sizzle reel or hype video from brand assets and key messages. Fast-paced montage format with dynamic cuts, bold text overlays, and optional beat-synced music.
|
|
4
|
+
|
|
5
|
+
Use it for launch days, investor pitches, conference openers, event promos, and social media campaign kickoffs. The goal is to create excitement, not to explain.
|
|
6
|
+
|
|
7
|
+
This is different from a product launch video. A sizzle reel has no single story arc. It has energy, rhythm, and one punchy message per cut.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx "@opendirectory.dev/skills" install vid-sizzle-reel --target claude
|
|
15
|
+
```
|
|
16
|
+
### Video Tutorial
|
|
17
|
+
Watch this quick video to see how it's done:
|
|
18
|
+
|
|
19
|
+
https://github.com/user-attachments/assets/cea8b565-2002-4a87-8857-d902bfcfdc1c
|
|
20
|
+
|
|
21
|
+
### Step 1: Download the skill from GitHub
|
|
22
|
+
1. Click the **Code** button on this repo's GitHub page.
|
|
23
|
+
2. Select **Download ZIP** to download the repository.
|
|
24
|
+
3. Extract the ZIP file on your computer.
|
|
25
|
+
|
|
26
|
+
### Step 2: Install the Skill in Claude
|
|
27
|
+
1. Open your **Claude desktop app**.
|
|
28
|
+
2. Go to the sidebar on the left side and click on the **Customize** section.
|
|
29
|
+
3. Click on the **Skills** tab, then click on the **+** (plus) icon button to create a new skill.
|
|
30
|
+
4. Choose the option to **Upload a skill**, and drag and drop the `.zip` file (or you can extract it and drop the folder, both work).
|
|
31
|
+
|
|
32
|
+
> **Note:** Make sure you are uploading the folder that contains the `SKILL.md` file!
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## How It Works
|
|
37
|
+
|
|
38
|
+
1. Provide your key messages and brand assets.
|
|
39
|
+
2. The agent builds a HyperFrames HTML composition with GSAP animation timelines.
|
|
40
|
+
3. The HyperFrames CLI captures frames via headless Chromium and assembles an MP4 via FFmpeg.
|
|
41
|
+
|
|
42
|
+
No Runway. No Pika. No AI video APIs. Works offline.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Sizzle Reel Structure
|
|
47
|
+
|
|
48
|
+
| Section | Timing (60s) | Content |
|
|
49
|
+
|---------|-------------|---------|
|
|
50
|
+
| Cold Open | 0-5s | One stat or impact phrase. No brand name. |
|
|
51
|
+
| Build | 5-40s | Key messages flash one at a time, rising energy |
|
|
52
|
+
| Peak | 40-55s | Maximum intensity; strongest message at full scale |
|
|
53
|
+
| Land | 55-60s | Logo, tagline, CTA URL |
|
|
54
|
+
|
|
55
|
+
Timing scales automatically for 30s and 90s durations.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Input Parameters
|
|
60
|
+
|
|
61
|
+
| Parameter | Required | Default | Description |
|
|
62
|
+
|-----------|----------|---------|-------------|
|
|
63
|
+
| `key_messages` | Yes | | 3-5 phrases that flash on screen (you write these) |
|
|
64
|
+
| `brand_assets` | | | Logo URL or path, brand colors (hex), key screenshots |
|
|
65
|
+
| `tone` | | `energetic` | `energetic` / `cinematic` / `emotional` / `professional` |
|
|
66
|
+
| `music` | | | File path or BPM/genre string (e.g. `"128bpm electronic"`) |
|
|
67
|
+
| `duration` | | `60` | `30` / `60` / `90` seconds |
|
|
68
|
+
| `aspect_ratio` | | `16:9` | `16:9` / `9:16` |
|
|
69
|
+
| `cut_style` | | auto | `fast` (1-2s) / `cinematic` (3-5s); auto derives from tone |
|
|
70
|
+
| `end_card` | | auto | Logo + tagline + CTA URL for the Land section |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Tone Reference
|
|
75
|
+
|
|
76
|
+
| Tone | Reference Feel | Cut Style | Best For |
|
|
77
|
+
|------|---------------|-----------|----------|
|
|
78
|
+
| `energetic` | Product Hunt launch day | fast (1-2s) | Social media, launch days, developer tools |
|
|
79
|
+
| `cinematic` | Apple product reveal | cinematic (3-5s) | Investor decks, B2C premium, Series A+ |
|
|
80
|
+
| `emotional` | Kickstarter campaign | mixed (2-4s) | Consumer products, mission-driven brands |
|
|
81
|
+
| `professional` | B2B conference opener | 2s cuts | Enterprise SaaS, internal events, sales decks |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Output
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
sizzle/
|
|
89
|
+
└── [slug]/
|
|
90
|
+
├── index.html (HyperFrames composition source)
|
|
91
|
+
└── sizzle-reel.mp4 (H.264, 1080p, yuv420p)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Open `index.html` in any browser to preview the animation before exporting.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Prompt Tips
|
|
99
|
+
|
|
100
|
+
Write the key messages yourself. These are the exact phrases that appear on screen. The agent cannot invent good copy for your brand. 3 sharp lines beats 10 vague ones.
|
|
101
|
+
|
|
102
|
+
Choose music before visuals. The BPM drives the cut style. The cut style drives every timing decision in the video.
|
|
103
|
+
|
|
104
|
+
Cold open: one number. Not a sentence, not a tagline. One specific, surprising number. It earns 5 seconds of attention before the audience knows who you are.
|
|
105
|
+
|
|
106
|
+
Land section: logo plus one line plus one URL. Anything more dilutes the CTA.
|
|
107
|
+
|
|
108
|
+
Match tone to channel. Energetic for social and Product Hunt. Cinematic for investor decks. Professional for conference openers.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Prompt Examples
|
|
113
|
+
|
|
114
|
+
Good:
|
|
115
|
+
```
|
|
116
|
+
Sizzle reel, 60 seconds. Tone: energetic. Key messages: ['AI skills, ready to install' /
|
|
117
|
+
'52+ skills across GTM, content, and research' / 'Works with Claude, Codex, and Gemini' /
|
|
118
|
+
'Zero setup. Instant value.']. Music: 128bpm electronic. Cut style: fast.
|
|
119
|
+
End card: OpenDirectory + 'AI skills, ready to install' + 'opendirectory.dev'. Aspect: 16:9.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Bad:
|
|
123
|
+
```
|
|
124
|
+
hype video for our company
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Requirements
|
|
130
|
+
|
|
131
|
+
- Node.js 22+
|
|
132
|
+
- FFmpeg (`brew install ffmpeg` / `apt install ffmpeg`)
|
|
133
|
+
- HyperFrames (installed automatically via `npx skills add heygen-com/hyperframes`)
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vid-sizzle-reel
|
|
3
|
+
description: 'Generates a high-energy sizzle reel or hype video (MP4) from brand assets and key messages. Fast-paced montage format with dynamic cuts, bold text overlays, and optional music. 4-section structure: Cold Open, Build, Peak, Land. 4 tone presets. Beat-sync cuts when music is provided. Built on HyperFrames (GSAP + headless Chromium + FFmpeg). Trigger when user says "sizzle reel", "hype video", "highlight reel", "launch hype", "conference opener", "event promo video", "investor pitch video", or "brand video montage".'
|
|
4
|
+
compatibility: [claude-code, gemini-cli, github-copilot]
|
|
5
|
+
author: OpenDirectory
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# vid-sizzle-reel
|
|
10
|
+
|
|
11
|
+
Generates a high-energy sizzle reel or hype video from brand assets and key messages.
|
|
12
|
+
Pipeline: HyperFrames HTML composition (GSAP timelines) → headless Chromium → FFmpeg H.264 MP4.
|
|
13
|
+
No Runway. No Pika. No AI video APIs. Zero runtime cost beyond Node.js + FFmpeg.
|
|
14
|
+
|
|
15
|
+
**Differentiation from `vid-product-launch`:**
|
|
16
|
+
- `vid-product-launch` tells a narrative story — one earned reveal, five sections, tension arc
|
|
17
|
+
- `vid-sizzle-reel` creates energy and excitement — fast cuts, music-first, no single story beat
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Critical Rules (read before every generation)
|
|
22
|
+
|
|
23
|
+
1. **Write the key messages yourself — or ask the user to write them.** These are the exact phrases that appear on screen. "AI will figure it out" produces filler. 3-5 sharp lines is the entire content of a sizzle reel.
|
|
24
|
+
|
|
25
|
+
2. **Brand name appears ONLY in the Land section.** Cold Open and Build create tension without naming the brand. The Land section is the payoff.
|
|
26
|
+
|
|
27
|
+
3. **Declare the rhythm pattern in a comment at the top of the script before writing any HTML.** Format: `// RHYTHM: flash-sequence | Cold[0-5s]: stat | Build[5-40s]: msg(1.5s)|flash|... | Peak[40-55s]: ... | Land[55-60s]: logo+CTA`. Every timing decision checks against this.
|
|
28
|
+
|
|
29
|
+
4. **Build end-state layout in CSS first — no GSAP yet.** Position every element at its most-visible moment in static CSS. Then add GSAP entrances with `gsap.from()` and exits with `gsap.to()`. Never position at animated start state.
|
|
30
|
+
|
|
31
|
+
5. **`class="clip"` on every timed element.** Required by HyperFrames. Without it, the element is invisible to the player.
|
|
32
|
+
|
|
33
|
+
6. **`data-start`, `data-duration`, `data-track-index` on every clip.** No exceptions. Same-track clips cannot overlap — use different track indices.
|
|
34
|
+
|
|
35
|
+
7. **No `Math.random()`.** HyperFrames requires deterministic compositions. Use seeded PRNG (mulberry32) for any pseudo-random values.
|
|
36
|
+
|
|
37
|
+
8. **All GSAP timelines start `{ paused: true }` and register to `window.__timelines["comp-id"]`.** The HyperFrames player controls playback — never call `tl.play()`.
|
|
38
|
+
|
|
39
|
+
9. **Never `position: absolute` on `.scene-content` containers.** Use `width:100%; height:100%; padding:Npx; display:flex`. Reserve `position:absolute` for decorative elements only.
|
|
40
|
+
|
|
41
|
+
10. **Music: separate `<audio>` element with `data-track-index`.** Video must be `muted playsinline`. Never put audio in a `<video>` element.
|
|
42
|
+
|
|
43
|
+
11. **Read `references/cut-patterns.md` AND `references/tone-presets.md` before generating any HTML.**
|
|
44
|
+
|
|
45
|
+
12. **Never dump HTML in chat.** Save to file. Show summary only.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Step 1: Intake
|
|
50
|
+
|
|
51
|
+
**Required:**
|
|
52
|
+
- `key_messages` — 3-5 punchy lines to flash on screen (user must write these)
|
|
53
|
+
|
|
54
|
+
**Optional parameters and defaults:**
|
|
55
|
+
|
|
56
|
+
| Parameter | Default | Description |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| brand_assets | none | Logo URL/path, brand colors (hex), key screenshots |
|
|
59
|
+
| tone | energetic | energetic / cinematic / emotional / professional |
|
|
60
|
+
| music | none | File path, or BPM/genre string (e.g. "128bpm electronic") |
|
|
61
|
+
| duration | 60 | 30 / 60 / 90 seconds |
|
|
62
|
+
| aspect_ratio | 16:9 | 16:9 (1920x1080) / 9:16 (1080x1920) |
|
|
63
|
+
| cut_style | auto | fast (1-2s) / cinematic (3-5s) — auto derives from tone |
|
|
64
|
+
| end_card | auto | Logo + tagline + CTA URL for Land section |
|
|
65
|
+
|
|
66
|
+
`cut_style` auto-defaults: energetic → `fast`; professional → `fast` (2s); cinematic → `cinematic`; emotional → `mixed`
|
|
67
|
+
|
|
68
|
+
**If `key_messages` is missing, ask exactly:**
|
|
69
|
+
|
|
70
|
+
> "To generate the sizzle reel, I need your key messages — the exact phrases that will flash on screen. Give me 3-5 punchy lines. These are the most important thing you're writing for this video.
|
|
71
|
+
>
|
|
72
|
+
> Examples: 'Used by 500+ growth teams' / 'From days to minutes' / 'Works with Claude, Codex, Gemini'
|
|
73
|
+
>
|
|
74
|
+
> Also useful: tone (energetic/cinematic/emotional/professional), duration (30/60/90s), any brand colors or logo URL."
|
|
75
|
+
|
|
76
|
+
If key_messages are present → proceed to Step 2 immediately.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Step 2: Install HyperFrames
|
|
81
|
+
|
|
82
|
+
Install HyperFrames skills (first time only — skip if already installed):
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npx skills add heygen-com/hyperframes
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Verify environment:
|
|
89
|
+
```bash
|
|
90
|
+
node --version # must be >= 22
|
|
91
|
+
ffmpeg -version # must be present
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Scaffold the project:
|
|
95
|
+
```bash
|
|
96
|
+
npx hyperframes init sizzle-[slug] --example kinetic-type --non-interactive
|
|
97
|
+
cd sizzle-[slug]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Slug: kebab-case from end_card brand name or first key_message, max 25 chars.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Step 3: Internal Architecture (never shown to user)
|
|
105
|
+
|
|
106
|
+
**1. Derive cut-point timing from `duration` + `cut_style`:**
|
|
107
|
+
|
|
108
|
+
| Section | 30s | 60s | 90s |
|
|
109
|
+
|---|---|---|---|
|
|
110
|
+
| Cold Open | 0-5s | 0-5s | 0-8s |
|
|
111
|
+
| Build | 5-25s | 5-40s | 8-65s |
|
|
112
|
+
| Peak | 25-28s | 40-55s | 65-80s |
|
|
113
|
+
| Land | 28-30s | 55-60s | 80-90s |
|
|
114
|
+
|
|
115
|
+
Convert every boundary to milliseconds. Calculate per-scene duration from `cut_style`:
|
|
116
|
+
- `fast`: 1.2s-1.8s per message (use 1.5s default)
|
|
117
|
+
- `cinematic`: 3.5s-5.0s per message (use 4.0s default)
|
|
118
|
+
- `mixed`: 2.0s-4.0s varying by section energy
|
|
119
|
+
|
|
120
|
+
**2. Map key_messages to scenes:**
|
|
121
|
+
- Cold Open (1 scene): one impact stat or question — NO brand name, builds intrigue
|
|
122
|
+
- Build: one scene per key_message
|
|
123
|
+
- Peak: repeat the strongest message at double scale, or combine 2 messages in rapid flash
|
|
124
|
+
- Land: brand name + tagline + CTA URL
|
|
125
|
+
|
|
126
|
+
**3. Detect beat sync if music provided:**
|
|
127
|
+
```bash
|
|
128
|
+
npx hyperframes tts --analyze-beats [music-file]
|
|
129
|
+
```
|
|
130
|
+
If unavailable, calculate from BPM: `beat_ms = 60000 / BPM`. Align cuts to every 2nd beat.
|
|
131
|
+
|
|
132
|
+
**4. Select tone preset** — read `references/tone-presets.md` for CSS tokens.
|
|
133
|
+
|
|
134
|
+
**5. Declare rhythm pattern** — write comment at top of script:
|
|
135
|
+
```js
|
|
136
|
+
// RHYTHM: flash-sequence
|
|
137
|
+
// Cold Open [0-5000ms]: stat
|
|
138
|
+
// Build [5000-40000ms]: msg-1(1500ms)|flash|msg-2(1500ms)|flash|msg-3(1500ms)|flash|msg-4(1500ms)|flash|build-accum(10000ms)
|
|
139
|
+
// Peak [40000-55000ms]: msg-strongest(1200ms)|flash|msg-2nd(1200ms)|flash|HOLD(5600ms)
|
|
140
|
+
// Land [55000-60000ms]: logo+tagline+cta
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**6. Determine pixel dimensions:**
|
|
144
|
+
- `16:9` → W=1920, H=1080
|
|
145
|
+
- `9:16` → W=1080, H=1920
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Step 4: HyperFrames HTML Composition
|
|
150
|
+
|
|
151
|
+
Read `references/cut-patterns.md` and the HyperFrames skill (`/hyperframes`) before writing any code.
|
|
152
|
+
|
|
153
|
+
**Required HTML skeleton:**
|
|
154
|
+
|
|
155
|
+
```html
|
|
156
|
+
<!DOCTYPE html>
|
|
157
|
+
<html lang="en">
|
|
158
|
+
<head>
|
|
159
|
+
<meta charset="UTF-8">
|
|
160
|
+
[font CDN link from tone preset]
|
|
161
|
+
<style>
|
|
162
|
+
:root {
|
|
163
|
+
[all CSS tokens from tone preset]
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
|
|
167
|
+
</style>
|
|
168
|
+
</head>
|
|
169
|
+
<body>
|
|
170
|
+
<div
|
|
171
|
+
data-composition-id="sizzle-[slug]"
|
|
172
|
+
data-width="[W]"
|
|
173
|
+
data-height="[H]"
|
|
174
|
+
style="position:relative;width:[W]px;height:[H]px;overflow:hidden;background:var(--bg)"
|
|
175
|
+
>
|
|
176
|
+
|
|
177
|
+
[if cut-flash: true]
|
|
178
|
+
<div id="cut-flash"
|
|
179
|
+
style="position:absolute;inset:0;background:var(--cut-flash-bg);opacity:0;pointer-events:none;z-index:200"></div>
|
|
180
|
+
[end if]
|
|
181
|
+
|
|
182
|
+
[if film-grain: true]
|
|
183
|
+
<canvas id="grain-overlay"
|
|
184
|
+
width="240" height="135"
|
|
185
|
+
style="position:absolute;inset:0;width:[W]px;height:[H]px;pointer-events:none;opacity:0.022;mix-blend-mode:overlay;z-index:50"></canvas>
|
|
186
|
+
[end if]
|
|
187
|
+
|
|
188
|
+
[if vignette: true]
|
|
189
|
+
<div id="vignette-overlay"
|
|
190
|
+
style="position:absolute;inset:0;background:radial-gradient(ellipse at center,transparent 35%,rgba(0,0,0,0.65) 100%);pointer-events:none;z-index:51"></div>
|
|
191
|
+
[end if]
|
|
192
|
+
|
|
193
|
+
<!-- Scenes — one div per scene -->
|
|
194
|
+
<div id="scene-cold"
|
|
195
|
+
class="clip"
|
|
196
|
+
data-start="0"
|
|
197
|
+
data-duration="5"
|
|
198
|
+
data-track-index="0"
|
|
199
|
+
style="position:absolute;inset:0;opacity:0"
|
|
200
|
+
>
|
|
201
|
+
<div class="scene-content" style="width:100%;height:100%;padding:120px;display:flex;flex-direction:column;align-items:center;justify-content:center;box-sizing:border-box">
|
|
202
|
+
[cold open content — one stat or impact phrase, no brand name]
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
[one div per Build scene, data-start increments by cut duration]
|
|
207
|
+
[Peak scene(s)]
|
|
208
|
+
[Land scene — brand name + tagline + CTA]
|
|
209
|
+
|
|
210
|
+
[if music provided]
|
|
211
|
+
<audio id="music"
|
|
212
|
+
class="clip"
|
|
213
|
+
data-start="0"
|
|
214
|
+
data-duration="[total_duration]"
|
|
215
|
+
data-track-index="10"
|
|
216
|
+
data-volume="0.85"
|
|
217
|
+
src="[music_path]"
|
|
218
|
+
></audio>
|
|
219
|
+
[end if]
|
|
220
|
+
|
|
221
|
+
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
|
222
|
+
<script>
|
|
223
|
+
// ── RHYTHM DECLARATION ──────────────────────────────────────────────────────
|
|
224
|
+
// RHYTHM: [flash-sequence | cinematic-hold | beat-sync | mixed]
|
|
225
|
+
// Cold Open [0-Nms]: ...
|
|
226
|
+
// Build [N-Nms]: ...
|
|
227
|
+
// Peak [N-Nms]: ...
|
|
228
|
+
// Land [N-Nms]: ...
|
|
229
|
+
|
|
230
|
+
// ── SEEDED PRNG (for grain only — no other random values) ───────────────────
|
|
231
|
+
function mulberry32(seed) {
|
|
232
|
+
return function() {
|
|
233
|
+
seed |= 0; seed = seed + 0x6D2B79F5 | 0;
|
|
234
|
+
let t = Math.imul(seed ^ seed >>> 15, 1 | seed);
|
|
235
|
+
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
236
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
[if film-grain: true]
|
|
241
|
+
// ── FILM GRAIN (cinematic/emotional only) ───────────────────────────────────
|
|
242
|
+
const grainCanvas = document.getElementById('grain-overlay');
|
|
243
|
+
const grainCtx = grainCanvas ? grainCanvas.getContext('2d') : null;
|
|
244
|
+
// Grain updated by GSAP ticker (not per-frame capture — HyperFrames handles this)
|
|
245
|
+
[end if]
|
|
246
|
+
|
|
247
|
+
// ── GSAP TIMELINE ───────────────────────────────────────────────────────────
|
|
248
|
+
const tl = gsap.timeline({ paused: true });
|
|
249
|
+
|
|
250
|
+
// ── COLD OPEN ───────────────────────────────────────────────────────────────
|
|
251
|
+
[cold open entrance and exit tweens — see cut-patterns.md for exact pattern]
|
|
252
|
+
|
|
253
|
+
// ── BUILD SECTION ───────────────────────────────────────────────────────────
|
|
254
|
+
[per-message tweens — flash-sequence or cinematic-hold from cut-patterns.md]
|
|
255
|
+
|
|
256
|
+
// ── PEAK SECTION ─────────────────────────────────────────────────────────────
|
|
257
|
+
[peak tweens — same pattern as build but tighter timing]
|
|
258
|
+
|
|
259
|
+
// ── LAND SECTION ─────────────────────────────────────────────────────────────
|
|
260
|
+
[land entrances — logo, tagline, CTA. No exit — holds to end]
|
|
261
|
+
|
|
262
|
+
// ── TIMELINE REGISTRATION ────────────────────────────────────────────────────
|
|
263
|
+
window.__timelines = window.__timelines || {};
|
|
264
|
+
window.__timelines["sizzle-[slug]"] = tl;
|
|
265
|
+
</script>
|
|
266
|
+
</div>
|
|
267
|
+
</body>
|
|
268
|
+
</html>
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Design quality rules:**
|
|
272
|
+
- Cold open stat: ≥160px font size for 16:9, ≥100px for 9:16
|
|
273
|
+
- Key messages: ≥80px font size — readable at a glance
|
|
274
|
+
- Land section brand name: ≥120px for 16:9
|
|
275
|
+
- All colors from preset token variables — no free hex except `var(--accent)` literal hex inside canvas `fillStyle`
|
|
276
|
+
- `scene-content` always uses `padding + flex` — never `position:absolute` on content container
|
|
277
|
+
- `class="clip"` on every element with `data-start`
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Step 5: Self-QA (fix every failure before Step 6)
|
|
282
|
+
|
|
283
|
+
**Content:**
|
|
284
|
+
- [ ] `key_messages` — each phrase appears exactly once, no duplicates
|
|
285
|
+
- [ ] Brand name appears ONLY in Land section (not cold open, not build, not peak)
|
|
286
|
+
- [ ] Cold open contains NO brand name and NO product name — only stat or impact phrase
|
|
287
|
+
- [ ] Land section has: brand name + tagline + CTA URL (three elements minimum)
|
|
288
|
+
- [ ] end_card CTA URL present on final frame
|
|
289
|
+
|
|
290
|
+
**HyperFrames contract:**
|
|
291
|
+
- [ ] `class="clip"` on every element with `data-start`
|
|
292
|
+
- [ ] `data-start`, `data-duration`, `data-track-index` on every clip
|
|
293
|
+
- [ ] `data-composition-id` on the root composition div
|
|
294
|
+
- [ ] `window.__timelines["sizzle-[slug]"] = tl` registered
|
|
295
|
+
- [ ] All timelines start `{ paused: true }`
|
|
296
|
+
- [ ] No `Math.random()` — seeded PRNG only
|
|
297
|
+
- [ ] No `tl.play()` or `tl.resume()` calls
|
|
298
|
+
|
|
299
|
+
**GSAP / Layout:**
|
|
300
|
+
- [ ] `gsap.from()` for all entrances (FROM offscreen TO CSS position)
|
|
301
|
+
- [ ] `gsap.to()` for all exits (FROM CSS position TO offscreen)
|
|
302
|
+
- [ ] No `position:absolute` on `.scene-content` containers
|
|
303
|
+
- [ ] Rhythm pattern declared in comment at top of script
|
|
304
|
+
|
|
305
|
+
**Cut timing:**
|
|
306
|
+
- [ ] `fast` tone: average cut duration ≤ 2.0s
|
|
307
|
+
- [ ] `cinematic` tone: average cut duration ≥ 3.0s
|
|
308
|
+
- [ ] Cut flash fires at every cut boundary for `energetic` tone (60ms, opacity 0→1→0)
|
|
309
|
+
- [ ] Same-track clips do NOT overlap (check all `data-track-index` groupings)
|
|
310
|
+
|
|
311
|
+
**SFX:**
|
|
312
|
+
- [ ] `window.__sfxTimeline` present and placed before timeline registration
|
|
313
|
+
- [ ] `word-hit` event per key message
|
|
314
|
+
- [ ] `whoosh` at Build → Peak transition boundary
|
|
315
|
+
- [ ] `cta-chime` at Land start
|
|
316
|
+
- [ ] No SFX fires before 500ms
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Step 6: Lint, Render, Output
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
npx hyperframes lint
|
|
324
|
+
npx hyperframes inspect --json
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Fix all lint errors. Fix all inspect errors (text overflow, clip escaping containers). Then render:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
npx hyperframes render --output sizzle/[slug]/sizzle-reel.mp4
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Output:
|
|
334
|
+
```
|
|
335
|
+
## Sizzle Reel: [brand name from end_card]
|
|
336
|
+
Tone: [tone] | Duration: [N]s | Cut style: [cut_style] | Aspect: [ratio]
|
|
337
|
+
Rhythm: [declared pattern]
|
|
338
|
+
|
|
339
|
+
Sections
|
|
340
|
+
Cold Open [0-Ns]: [impact stat or phrase]
|
|
341
|
+
Build [N-Ns]: [N key messages listed]
|
|
342
|
+
Peak [N-Ns]: [strongest message at max scale]
|
|
343
|
+
Land [N-Ns]: [brand name] + "[tagline]" + [CTA URL]
|
|
344
|
+
|
|
345
|
+
Files
|
|
346
|
+
Source: sizzle/[slug]/index.html
|
|
347
|
+
Output: sizzle/[slug]/sizzle-reel.mp4
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## SFX Timeline (embed in every composition)
|
|
353
|
+
|
|
354
|
+
The same FFmpeg-synthesized SFX system as `vid-product-launch`. Place `window.__sfxTimeline` immediately before the GSAP timeline registration.
|
|
355
|
+
|
|
356
|
+
SFX type reference for sizzle reel:
|
|
357
|
+
|
|
358
|
+
| Type | Sound | Duration | Placement |
|
|
359
|
+
|---|---|---|---|
|
|
360
|
+
| `word-hit` | Sub punch (50Hz) + transient click (2.2kHz) + noise burst | 180ms | One per key_message scene start |
|
|
361
|
+
| `whoosh` | Two-band noise sweep (1.1kHz body + 4-8kHz air) | 700ms | At Build → Peak boundary |
|
|
362
|
+
| `cta-chime` | A major chord (440+554+659+880Hz) + aecho bell shimmer | 1.2s | Exactly at Land start |
|
|
363
|
+
|
|
364
|
+
```js
|
|
365
|
+
window.__sfxTimeline = [
|
|
366
|
+
// one word-hit per key_message (computed from scene start times)
|
|
367
|
+
{ ms: MSG_1_START_MS, sfx: 'word-hit', vol: 0.50 },
|
|
368
|
+
{ ms: MSG_2_START_MS, sfx: 'word-hit', vol: 0.50 },
|
|
369
|
+
{ ms: MSG_3_START_MS, sfx: 'word-hit', vol: 0.50 },
|
|
370
|
+
// ... repeat for each message
|
|
371
|
+
{ ms: PEAK_START_MS - 700, sfx: 'whoosh', vol: 0.55 },
|
|
372
|
+
{ ms: LAND_START_MS, sfx: 'cta-chime', vol: 0.65 },
|
|
373
|
+
];
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Compute all `ms` values from declared section timing constants. Never hardcode.
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## Prompt Tips (show when user asks for guidance)
|
|
381
|
+
|
|
382
|
+
> "Write the key messages yourself. They are the entire content of this video. 3 sharp lines beats 10 vague ones every time."
|
|
383
|
+
>
|
|
384
|
+
> "Choose music before choosing visuals. The BPM determines the cut style. The cut style determines every timing decision."
|
|
385
|
+
>
|
|
386
|
+
> "Cold open: one number. Not a sentence, not a tagline — one specific, surprising number. It earns 5 seconds of attention."
|
|
387
|
+
>
|
|
388
|
+
> "The Land section is not a credits page. Logo + one line + one URL. Anything more dilutes the CTA."
|
|
389
|
+
>
|
|
390
|
+
> "Match tone to channel. Energetic for social and Product Hunt. Cinematic for B2C premium and investor decks. Professional for enterprise conferences. Emotional for crowdfunding."
|
|
391
|
+
|
|
392
|
+
Good:
|
|
393
|
+
```
|
|
394
|
+
Sizzle reel, 60 seconds. Tone: energetic. Key messages: ['AI skills, ready to install' /
|
|
395
|
+
'52+ skills across GTM, content, research' / 'Works with Claude, Codex, Gemini' /
|
|
396
|
+
'Zero setup. Instant value.']. Music: 128bpm electronic. Cut style: fast.
|
|
397
|
+
End card: OpenDirectory + 'AI skills, ready to install' + 'opendirectory.dev'. Aspect: 16:9.
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Bad:
|
|
401
|
+
```
|
|
402
|
+
hype video for our company
|
|
403
|
+
```
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Cut Patterns — vid-sizzle-reel
|
|
2
|
+
|
|
3
|
+
Four named rhythm patterns with GSAP timing examples.
|
|
4
|
+
Read before declaring rhythm in Step 3. Declare the rhythm pattern explicitly before writing any HTML.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## flash-sequence
|
|
9
|
+
|
|
10
|
+
**Use for:** `energetic` tone. Fast 1-2s cuts with white flash at every transition.
|
|
11
|
+
|
|
12
|
+
**Rhythm notation:** `flash-flash-flash-HOLD-flash-flash-PEAK-land`
|
|
13
|
+
|
|
14
|
+
**Flash element (place in every scene, hidden by default):**
|
|
15
|
+
```html
|
|
16
|
+
<div id="cut-flash"
|
|
17
|
+
style="position:fixed;inset:0;background:var(--cut-flash-bg);opacity:0;pointer-events:none;z-index:200"></div>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**GSAP cut flash (fire at every scene end time `T`):**
|
|
21
|
+
```js
|
|
22
|
+
// Fire at T = scene end, duration = 0.06s
|
|
23
|
+
tl.to("#cut-flash", { opacity: 1, duration: 0.03, ease: "none" }, T);
|
|
24
|
+
tl.to("#cut-flash", { opacity: 0, duration: 0.03, ease: "none" }, T + 0.03);
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Full scene GSAP pattern (1.5s scene starting at T):**
|
|
28
|
+
```js
|
|
29
|
+
// Build end-state in CSS first. Then:
|
|
30
|
+
// Entrance: slam-in
|
|
31
|
+
tl.fromTo(".msg-1", { scale: 1.08, opacity: 0 }, { scale: 1, opacity: 1, duration: 0.12, ease: "power3.out" }, T + 0.06);
|
|
32
|
+
// Hold for 1.2s
|
|
33
|
+
// Exit: flash handles visual cut — no explicit exit tween needed for flash-sequence
|
|
34
|
+
// Cut flash at T + 1.5
|
|
35
|
+
tl.to("#cut-flash", { opacity: 1, duration: 0.03, ease: "none" }, T + 1.47);
|
|
36
|
+
tl.to("#cut-flash", { opacity: 0, duration: 0.03, ease: "none" }, T + 1.50);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Scene count per duration:**
|
|
40
|
+
- 30s: 12-18 cuts (avg 1.7s each)
|
|
41
|
+
- 60s: 25-35 cuts (avg 1.8s each)
|
|
42
|
+
- 90s: 35-50 cuts (avg 1.9s each)
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## cinematic-hold
|
|
47
|
+
|
|
48
|
+
**Use for:** `cinematic` and `emotional` tones. 3-5s scenes with slow cross-dissolve transitions.
|
|
49
|
+
|
|
50
|
+
**Rhythm notation:** `slow-SLOW-hold-BREATHE-slow-PEAK-land`
|
|
51
|
+
|
|
52
|
+
**Dissolve pattern (no flash element — opacity handled by GSAP):**
|
|
53
|
+
```js
|
|
54
|
+
const SCENE_DUR = 4.0; // agent adjusts per section
|
|
55
|
+
const FADE_IN = 0.7; // entrance duration
|
|
56
|
+
const FADE_OUT = 0.5; // exit overlap before next scene
|
|
57
|
+
|
|
58
|
+
// Entrance at T
|
|
59
|
+
tl.from(".msg-1", { opacity: 0, filter: "blur(8px)", duration: FADE_IN, ease: "power2.out" }, T);
|
|
60
|
+
// Exit at T + SCENE_DUR - FADE_OUT
|
|
61
|
+
tl.to(".msg-1", { opacity: 0, y: -15, duration: FADE_OUT, ease: "power2.in" }, T + SCENE_DUR - FADE_OUT);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Overlap:** next scene entrance starts `FADE_OUT` before current scene exits — creates cross-dissolve feel.
|
|
65
|
+
|
|
66
|
+
**Scene count per duration:**
|
|
67
|
+
- 30s: 6-8 scenes (avg 4s each)
|
|
68
|
+
- 60s: 12-16 scenes (avg 4s each)
|
|
69
|
+
- 90s: 18-24 scenes (avg 4s each)
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## beat-sync
|
|
74
|
+
|
|
75
|
+
**Use for:** Any tone when `music` is provided as a file. Cut points derived from audio analysis.
|
|
76
|
+
|
|
77
|
+
**How to get cut points:**
|
|
78
|
+
```bash
|
|
79
|
+
npx hyperframes tts --analyze-beats [music-file]
|
|
80
|
+
# Outputs JSON: { beats: [0.48, 0.96, 1.44, ...], bpm: 128 }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
If `npx hyperframes tts` beat analysis is unavailable, calculate from BPM:
|
|
84
|
+
```
|
|
85
|
+
beat_interval_ms = 60000 / BPM
|
|
86
|
+
# 128 BPM → 468.75ms per beat
|
|
87
|
+
# Align cuts to every 2nd or 4th beat for readability
|
|
88
|
+
# 128 BPM → cut every 937.5ms (2 beats) or every 1875ms (4 beats)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**GSAP pattern (cut on beat offset `B`):**
|
|
92
|
+
```js
|
|
93
|
+
const BEATS = [0.94, 1.88, 2.81, 3.75, 5.63, 7.50]; // agent fills from analysis
|
|
94
|
+
BEATS.forEach((b, i) => {
|
|
95
|
+
// Exit current element
|
|
96
|
+
tl.to(`.msg-${i}`, { opacity: 0, scale: 0.95, duration: 0.08, ease: "power2.in" }, b - 0.08);
|
|
97
|
+
// Cut flash (energetic) or instant cut
|
|
98
|
+
if (tone === 'energetic') {
|
|
99
|
+
tl.to("#cut-flash", { opacity: 1, duration: 0.03 }, b - 0.03);
|
|
100
|
+
tl.to("#cut-flash", { opacity: 0, duration: 0.03 }, b);
|
|
101
|
+
}
|
|
102
|
+
// Entrance next element
|
|
103
|
+
tl.from(`.msg-${i + 1}`, { opacity: 0, y: 20, duration: 0.15, ease: "power3.out" }, b + 0.02);
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## build-sequence
|
|
110
|
+
|
|
111
|
+
**Use for:** Build section of all tones. Staggered sequential reveals — no hard cuts, elements accumulate.
|
|
112
|
+
|
|
113
|
+
**Use case:** Multiple data points, feature lists, or stats that build up within a single scene.
|
|
114
|
+
|
|
115
|
+
**Pattern: elements appear and stay (no exit until scene ends)**
|
|
116
|
+
```js
|
|
117
|
+
const ITEMS = [".item-1", ".item-2", ".item-3"]; // max 4 items
|
|
118
|
+
const SCENE_START = 10.0;
|
|
119
|
+
const ITEM_STAGGER = 1.4; // seconds between each item entrance
|
|
120
|
+
|
|
121
|
+
ITEMS.forEach((sel, i) => {
|
|
122
|
+
tl.from(sel, {
|
|
123
|
+
opacity: 0,
|
|
124
|
+
y: 30,
|
|
125
|
+
duration: 0.5,
|
|
126
|
+
ease: "power3.out"
|
|
127
|
+
}, SCENE_START + i * ITEM_STAGGER);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Exit all together at scene end
|
|
131
|
+
tl.to(ITEMS, {
|
|
132
|
+
opacity: 0,
|
|
133
|
+
y: -20,
|
|
134
|
+
stagger: 0.05,
|
|
135
|
+
duration: 0.4,
|
|
136
|
+
ease: "power2.in"
|
|
137
|
+
}, SCENE_START + ITEMS.length * ITEM_STAGGER + 1.0);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Use when:** Build section has 3+ key messages that benefit from accumulation. Switch to `flash-sequence` or `cinematic-hold` for single-message-per-scene pacing.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Rhythm Declaration Format
|
|
145
|
+
|
|
146
|
+
Before writing HTML, write this comment at the top of the composition script:
|
|
147
|
+
|
|
148
|
+
```js
|
|
149
|
+
// RHYTHM: flash-sequence
|
|
150
|
+
// Cold Open [0-5s]: one-stat | flash
|
|
151
|
+
// Build [5-40s]: msg-1(1.5s) | flash | msg-2(1.5s) | flash | msg-3(1.5s) | flash | msg-4(2s) | flash | build-accum(8s)
|
|
152
|
+
// Peak [40-55s]: full-speed-flash | msg-5(1s) | flash | msg-6(1s) | flash | msg-7(1s) | HOLD(4s)
|
|
153
|
+
// Land [55-60s]: logo-fade | tagline | cta
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This is the reference all subsequent timing decisions check against. If a scene doesn't fit the declared rhythm, adjust the scene — not the rhythm.
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Tone Presets — vid-sizzle-reel
|
|
2
|
+
|
|
3
|
+
Four tone-matched presets. Read before generating any HTML.
|
|
4
|
+
Apply ALL tokens from the chosen preset. No free hex values or font-family strings outside these tables.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## energetic
|
|
9
|
+
|
|
10
|
+
**Reference feel:** Product Hunt launch day. High-BPM. Bold all-caps. White flash cuts.
|
|
11
|
+
|
|
12
|
+
**Font CDN:**
|
|
13
|
+
```html
|
|
14
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
15
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
16
|
+
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=DM+Sans:wght@700;900&display=swap" rel="stylesheet">
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**CSS tokens:**
|
|
20
|
+
```css
|
|
21
|
+
:root {
|
|
22
|
+
--bg: #000000;
|
|
23
|
+
--bg-secondary: #0A0A0A;
|
|
24
|
+
--text-primary: #FFFFFF;
|
|
25
|
+
--text-secondary: #888888;
|
|
26
|
+
--accent: #00F0FF;
|
|
27
|
+
--accent-2: #FF2D55;
|
|
28
|
+
--divider: rgba(255,255,255,0.10);
|
|
29
|
+
--font-display: 'DM Sans', system-ui, sans-serif;
|
|
30
|
+
--font-mono: 'DM Mono', monospace;
|
|
31
|
+
--tracking-tight: -0.03em;
|
|
32
|
+
--tracking-wide: 0.08em;
|
|
33
|
+
--display-size: 180px;
|
|
34
|
+
--headline-size: 80px;
|
|
35
|
+
--label-size: 18px;
|
|
36
|
+
--body-size: 22px;
|
|
37
|
+
--cut-flash-bg: #FFFFFF;
|
|
38
|
+
--cut-flash-dur: 0.06s;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Effects:**
|
|
43
|
+
- `film-grain: false`
|
|
44
|
+
- `vignette: false`
|
|
45
|
+
- `cut-flash: true` — white `#FFFFFF` overlay, 60ms opacity 0→1→0 at every cut point
|
|
46
|
+
- `dot-grid: true` — `radial-gradient(circle, rgba(255,255,255,0.04) 1px, transparent 1px); background-size: 48px 48px`
|
|
47
|
+
- Text entrance: slam-in (`scale 1.08→1, opacity 0→1, 120ms`)
|
|
48
|
+
- Text style: ALL CAPS, letter-spacing 0.08em
|
|
49
|
+
|
|
50
|
+
**Cut timing:** `fast` — 1.0s to 1.8s per cut
|
|
51
|
+
|
|
52
|
+
**Background treatment:** Pure `#000000`. Dot-grid on all scenes except cold open (which uses pure black for maximum contrast).
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## cinematic
|
|
57
|
+
|
|
58
|
+
**Reference feel:** Apple product reveal video. Deliberate pacing, premium dark palette.
|
|
59
|
+
|
|
60
|
+
**Font CDN:**
|
|
61
|
+
```html
|
|
62
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
63
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
64
|
+
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300;400;600;700&family=Cormorant:wght@700;800&display=swap" rel="stylesheet">
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**CSS tokens:**
|
|
68
|
+
```css
|
|
69
|
+
:root {
|
|
70
|
+
--bg: #050505;
|
|
71
|
+
--bg-secondary: #0D0D0D;
|
|
72
|
+
--text-primary: #F5F5F5;
|
|
73
|
+
--text-secondary: #999999;
|
|
74
|
+
--accent: #D4AF37;
|
|
75
|
+
--accent-2: rgba(212,175,55,0.25);
|
|
76
|
+
--divider: rgba(255,255,255,0.07);
|
|
77
|
+
--font-display: 'Cormorant', 'Cormorant Garamond', Georgia, serif;
|
|
78
|
+
--font-body: 'Cormorant Garamond', Georgia, serif;
|
|
79
|
+
--tracking-tight: -0.02em;
|
|
80
|
+
--tracking-wide: 0.12em;
|
|
81
|
+
--display-size: 160px;
|
|
82
|
+
--headline-size: 64px;
|
|
83
|
+
--label-size: 16px;
|
|
84
|
+
--body-size: 22px;
|
|
85
|
+
--cut-flash-bg: rgba(255,255,255,0.0);
|
|
86
|
+
--cut-flash-dur: 0s;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Effects:**
|
|
91
|
+
- `film-grain: true` — canvas 240×135, opacity 0.022, seeded PRNG per frame
|
|
92
|
+
- `vignette: true` — `radial-gradient(ellipse at center, transparent 35%, rgba(0,0,0,0.65) 100%)`
|
|
93
|
+
- `cut-flash: false` — cross-dissolve via `opacity 1→0→1` over 400ms instead
|
|
94
|
+
- `dot-grid: false`
|
|
95
|
+
- Text entrance: materialise (`filter blur 8px→0px, opacity 0→1, 700ms, easeOutCubic`)
|
|
96
|
+
- Text style: mixed case, letter-spacing `--tracking-tight`
|
|
97
|
+
|
|
98
|
+
**Cut timing:** `cinematic` — 3.0s to 5.0s per scene
|
|
99
|
+
|
|
100
|
+
**Background treatment:** Pure `#050505`. Film grain + vignette create depth.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## emotional
|
|
105
|
+
|
|
106
|
+
**Reference feel:** Kickstarter campaign video. Warm, personal, intimate.
|
|
107
|
+
|
|
108
|
+
**Font CDN:**
|
|
109
|
+
```html
|
|
110
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
111
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
112
|
+
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400;1,700&family=Lora:wght@400;600&display=swap" rel="stylesheet">
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**CSS tokens:**
|
|
116
|
+
```css
|
|
117
|
+
:root {
|
|
118
|
+
--bg: #FAF7F2;
|
|
119
|
+
--bg-secondary: #F2EDE4;
|
|
120
|
+
--text-primary: #2C1810;
|
|
121
|
+
--text-secondary: #6B4C3B;
|
|
122
|
+
--accent: #B87333;
|
|
123
|
+
--accent-2: rgba(184,115,51,0.18);
|
|
124
|
+
--divider: rgba(44,24,16,0.10);
|
|
125
|
+
--font-display: 'Playfair Display', Georgia, serif;
|
|
126
|
+
--font-body: 'Lora', Georgia, serif;
|
|
127
|
+
--tracking-tight: -0.01em;
|
|
128
|
+
--tracking-wide: 0.06em;
|
|
129
|
+
--display-size: 140px;
|
|
130
|
+
--headline-size: 56px;
|
|
131
|
+
--label-size: 15px;
|
|
132
|
+
--body-size: 21px;
|
|
133
|
+
--cut-flash-bg: rgba(250,247,242,0.0);
|
|
134
|
+
--cut-flash-dur: 0s;
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Effects:**
|
|
139
|
+
- `film-grain: true` — canvas 240×135, opacity 0.018, warm tint (blend: multiply)
|
|
140
|
+
- `vignette: true` — softer, `radial-gradient(ellipse at center, transparent 45%, rgba(44,24,16,0.40) 100%)`
|
|
141
|
+
- `cut-flash: false` — soft cross-dissolve over 600ms
|
|
142
|
+
- `dot-grid: false`
|
|
143
|
+
- Text entrance: word-by-word gentle fade (`opacity 0→1, 500ms, easeOut, 120ms stagger`)
|
|
144
|
+
- Text style: lowercase or mixed case, italic accent words
|
|
145
|
+
|
|
146
|
+
**Cut timing:** `mixed` — 2.0s to 4.0s, varying by scene energy
|
|
147
|
+
|
|
148
|
+
**Background treatment:** `--bg` warm ivory. Vignette + grain create warmth.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## professional
|
|
153
|
+
|
|
154
|
+
**Reference feel:** B2B SaaS conference opener. Clean, structured, trustworthy.
|
|
155
|
+
|
|
156
|
+
**Font CDN:**
|
|
157
|
+
```html
|
|
158
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
159
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
160
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;900&display=swap" rel="stylesheet">
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**CSS tokens:**
|
|
164
|
+
```css
|
|
165
|
+
:root {
|
|
166
|
+
--bg: #FFFFFF;
|
|
167
|
+
--bg-secondary: #F5F7FA;
|
|
168
|
+
--text-primary: #0A0A0A;
|
|
169
|
+
--text-secondary: #6B7280;
|
|
170
|
+
--accent: #4B9FFF;
|
|
171
|
+
--accent-2: rgba(75,159,255,0.12);
|
|
172
|
+
--divider: rgba(10,10,10,0.08);
|
|
173
|
+
--font-display: 'Inter', system-ui, sans-serif;
|
|
174
|
+
--font-body: 'Inter', system-ui, sans-serif;
|
|
175
|
+
--tracking-tight: -0.02em;
|
|
176
|
+
--tracking-wide: 0.04em;
|
|
177
|
+
--display-size: 150px;
|
|
178
|
+
--headline-size: 60px;
|
|
179
|
+
--label-size: 14px;
|
|
180
|
+
--body-size: 20px;
|
|
181
|
+
--cut-flash-bg: rgba(255,255,255,0.0);
|
|
182
|
+
--cut-flash-dur: 0s;
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**Effects:**
|
|
187
|
+
- `film-grain: false`
|
|
188
|
+
- `vignette: false`
|
|
189
|
+
- `cut-flash: false` — clean instant cut via `display` switching (handled by HyperFrames `data-start`)
|
|
190
|
+
- `dot-grid: false`
|
|
191
|
+
- Text entrance: slide up (`y 20→0, opacity 0→1, 350ms, easeOutCubic`)
|
|
192
|
+
- Text style: sentence case, clean weight hierarchy (900 display, 600 headline, 400 body)
|
|
193
|
+
|
|
194
|
+
**Cut timing:** `2s` — 1.8s to 2.4s per scene, consistent rhythm
|
|
195
|
+
|
|
196
|
+
**Background treatment:** White or `--bg-secondary`. Accent blue for key numbers and CTAs.
|