mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-02 20:18:35 +00:00
feat(skill): website-to-hyperframes — concept-first authoring + per-beat read protocol
Rewrite of the website-to-hyperframes skill that came out of 11
evaluation rounds. The honest read of those evals: prose-only
guidance had hit its ceiling — sub-agents kept reporting "0 errors,
looks good" without doing the work, producing slideshow-quality
videos with mismatched brand colors, missing logos, and beats that
didn't serve the storyboard. This restructure addresses the
failure modes that real videos showed, not theoretical ones.
**Step structure (replaces 7-step layout with concept-first 6-step)**
Old: capture → design → script → storyboard → vo → build → validate
New: capture → design → brief → storyboard → vo → build → validate
The brief step (Step 2) is new: a conversation-shaped step that
aligns message + audience + arc before any beat-writing happens.
Concept-first throughout — message → arc → beats that serve the arc
→ which assets and techniques bring each beat to life.
**Step 0 (capture)**
- "View the contact sheets — carefully, every cell, not a glance"
closes the failure mode where agents reported "viewed the contact
sheet" after one scroll and later wrote beats referencing assets
that didn't exist or missed the brand logo.
- Names the right artifacts to read in order (tokens.json →
design-styles.json → asset-descriptions.md → fonts-manifest.json),
with read-on-demand guidance for the rest.
**Step 1 (design)**
- DESIGN.md authoring guide. Restored component CSS sections
(Component Stylings, Spacing & Layout, Depth & Elevation) that
earlier batches over-collapsed.
**Step 2 (brief)**
- Strategy/messaging step. Clear instruction for "Surprise me" /
minimal direction: state the minimum context (where the video
runs, who it's for) and proceed bold.
**Step 3 (storyboard + script)**
- Concept gate at the top — answer "what makes this video distinct"
before writing beat 1.
- Brand-floor MUST rules (logo in opener + closer; signature visual
somewhere in the video).
- Captured assets (SVG logos, illustrations, hero art, gradients)
are first-class beat content alongside composed UIs — many of
them carry beats outright. The constraint is only that you start
from the message, not the asset inventory.
**Step 4 (vo)**
- TTS ranking: HeyGen first (auto word timestamps), ElevenLabs
second, Kokoro free. Audio timing reconciliation gate: if actual
audio duration ≠ storyboard planned ±15%, rescale beats or trim
script before Step 5.
**Step 5 (build) + beat-builder-guide.md**
- Sub-agent template now pastes brand values inline rather than
telling the sub-agent to re-read DESIGN.md. Targeted file reads
with specific sections + line ranges.
- "Patterns that ARE shots" affirmative list (captured logo
draw-on, hero illustration push-in, captured screenshot with
parallax layers, kinetic typography over captured asset).
- Webpage-mimicry patterns (full CSS browser chrome, parked-camera
composition, ±2px breathing motion) marked ⚠ rather than ❌ —
fine when the storyboard genuinely calls for them as the subject.
- Required cinematography per beat: shot type, camera move, depth
strategy, purpose.
**Step 6 (validate) — per-beat read protocol**
This replaces the previous "spawn verify-beats CLI" gate. A grep
of composition HTML can catch structural lies (missing hex codes,
wrong asset paths) but it can't catch boring beats, off-screen
logos, GSAP timelines that only cover the first 2 seconds, or
camera moves that don't match the storyboard. Those failures only
surface when somebody opens the file and reads it.
Per-beat verdict template names the brand hex codes used, captured
asset paths referenced, headline `font-size`, GSAP timeline
coverage, and storyboard alignment. Critic sub-agent scores a
"Captured asset utilization" dimension specifically so the eval
captures whether captured SVGs/illustrations carried beats or got
recreated as divs.
**Asset bundle**
- 20 Pixabay-licensed SFX files with `CREDITS.md` documenting
provenance. SFX assignment moved to Step 3 (creative decision)
so Step 5 implements rather than improvises.
- Capabilities reference + html-in-canvas-patterns updated:
Three.js 0.181.2 + ESM jsm imports, mulberry32 seeded PRNG for
deterministic shatter, 24-effect text-animation catalog
referenced (catalog itself lands in the hyperframes-skill PR).
- Visual vocabulary rewritten: replaces user-word lookup tables
with brand-first derivation across 6 axes; user words land as
modifiers, not replacements.
This commit is contained in:
@@ -6,7 +6,31 @@ description: |
|
||||
|
||||
# Website to HyperFrames
|
||||
|
||||
Capture a website, then produce a professional video from it.
|
||||
Capture a website, then produce a professional video from it — collaboratively with the user.
|
||||
|
||||
**Take your time on thinking and reviewing.** Quality matters more than speed. Read every reference file the steps point to. Look at every snapshot carefully. If a composition looks weak, revise it before moving on. A polished video is worth more than a rushed one delivered 5 minutes faster. That said: don't sit idle on stuck commands — escalate immediately if a process hangs (see Step 4 for escalation order).
|
||||
|
||||
**This is a collaborative workflow by default.** At key moments (marked 💬), you stop and ask the user what they want and refine based on their feedback.
|
||||
|
||||
**Autonomous mode exception:** If the user says "decide for me", "just build it", "surprise me", or gives any signal they don't want to be asked questions — skip ALL 💬 gates. Make all creative decisions yourself (video type, style, voice, storyboard), and present the finished result for feedback at the end. Do not ask four separate questions across four separate steps. Read the room once and commit.
|
||||
|
||||
**Sub-agent mode (default):** Step 5 dispatches one sub-agent per beat. Each sub-agent reads [beat-builder-guide.md](references/beat-builder-guide.md), builds, lints, snapshots, and verifies its own beat before reporting back. The main agent assembles the final video and does a final check.
|
||||
|
||||
**No sub-agents:** If the user says "no sub-agents", "build it yourself", or the runtime doesn't support parallel agents — the main agent builds all compositions sequentially using the same beat-builder-guide workflow. Same quality, just slower.
|
||||
|
||||
**This skill requires image-viewing capability** for the validate step (Step 6). If your agent cannot view PNG files, the snapshot review will be blind. Contact sheets (Step 0 and Step 6) are designed to minimize the number of images needed — but some visual verification is unavoidable.
|
||||
|
||||
---
|
||||
|
||||
## The Creative Tension Principle
|
||||
|
||||
Before writing the first beat of any storyboard, answer this in one sentence:
|
||||
|
||||
> **"What makes this video different from a generic [video type] for any [industry] brand?"**
|
||||
|
||||
If you can't answer it, you haven't thought enough. A product demo for a fintech tool and a product demo for a design tool should not share the same visual DNA. The answer comes from this specific brand's captured assets, its visual language, and what the user said they want — not from a lookup table.
|
||||
|
||||
This principle applies at every creative decision point: picking a visual style, choosing transitions, writing beats, building compositions. Every choice should be traceable to something specific about this brand, not just to "this is what I do for cinematic videos."
|
||||
|
||||
Users say things like:
|
||||
|
||||
@@ -14,79 +38,109 @@ Users say things like:
|
||||
- "Turn this website into a 15-second social ad for Instagram"
|
||||
- "Create a 30-second product tour from https://..."
|
||||
|
||||
The workflow has 7 steps. Each produces an artifact that gates the next.
|
||||
---
|
||||
|
||||
## Step -1: What we're actually making (REQUIRED before Step 0)
|
||||
|
||||
You're not making _a video_. You're making something that **stops scrollers** in the first 1.5 seconds and **feels alive in every single frame** — with motion, depth, momentum, like things exist in a physical world. **Think about how to go viral.** Slow intros are for cinematic trailers; videos shipping anywhere social or feed-based need a hook that beats the 1.5-second scroll threshold.
|
||||
|
||||
**Use the captured assets.** Open every SVG in `capture/assets/svgs/`. Open every illustration in `capture/assets/`. Read the descriptions in `capture/extracted/asset-descriptions.md`. Many of these will carry beats outright — the brand logo SVG drawing itself stroke-by-stroke, the hero illustration breathing as ambient depth, the captured gradient as a full-bleed background, the brand mark stamped onto every scene as identity. These are video gold. The capture exists because the brand's actual visual identity matters; using it is what makes the video feel like _this_ brand and not a generic dark cinematic template.
|
||||
|
||||
**Compose when there's no captured asset that fits.** For product UI sections where a clean captured asset doesn't exist (kanban boards, chat threads, dashboards, terminals, counters, code editors), build them from divs/SVG/CSS rather than pasting a screenshot. SVG path drawing, kinetic typography, counter animations via `tl.set()`, layered panels, shader-driven gradients — these are all part of HyperFrames' toolkit when no captured asset earns the beat.
|
||||
|
||||
**The screenshot trap is specifically about raw product-UI screenshots being pasted as full-bleed beat content.** Captured SVGs, illustrations, logos, hero art, gradients, photography — none of these are screenshots. They're brand assets. Use them. The trap is the "full-bleed dashboard.png + Ken Burns + voiceover" slideshow pattern, not the careful use of captured brand artifacts.
|
||||
|
||||
**This is a VIDEO, not a webpage rebuilt in divs.** Composing from divs is the right _medium_ (no screenshots) — but the WRONG outcome is to build a webpage-style layout and animate it 2 pixels. Videos use cinematic grammar: framing, depth, camera movement, scale, atmosphere. A kanban in a video is not "a kanban board centered in the frame at 80% scale with cards breathing 1px" — it's a SHOT: extreme close-up on a card sliding home, then the camera pulls back to reveal the full board, ambient particles + glow + depth give it weight. The composed divs are the subject; the cinematography is what makes it feel like film.
|
||||
|
||||
**Specific anti-patterns to refuse, every time:**
|
||||
|
||||
- **macOS window chrome** (traffic-light dots, address bars, browser tabs, breadcrumbs) unless the beat IS about the window/browser as the subject
|
||||
- **Centered layout with chrome around it** — sidebar + header + content area + footer — that's a screenshot reproduced in CSS, not a shot
|
||||
- **"Breathing" micro-animations** (y: ±1–2px, scale: 1.01) — invisible at 1080p/4K video scale, useless as motion, a sign the sub-agent ran out of ideas
|
||||
- **Page-level navigation** — sidebars, headers, footers, breadcrumbs, "back" arrows unless the beat is specifically demonstrating navigation
|
||||
- **"Settled" beats** where nothing moves except a counter pulse — every beat must have continuous, _visible_ motion across the entire duration
|
||||
|
||||
**Video grammar to USE in every beat:**
|
||||
|
||||
- **Frame the beat as a SHOT** — close-up / medium / wide / over-the-shoulder / Dutch angle. Pick deliberately, not "centered."
|
||||
- **Camera motion is a primary element** — dolly in, push, parallax pan, orbit, pull-back. The camera moves THROUGH the composition; the composition doesn't sit still in front of the camera.
|
||||
- **Scale as energy** — enter at 1.4× and settle to 1.0; extreme close-up that pulls back to wide; the subject grows or shrinks through the beat
|
||||
- **Depth layers** — ambient background atmosphere, focal midground subject, accent foreground element — each moving at different parallax speed
|
||||
- **Light as choreography** — glow tracks the subject, key moments lit with bloom, transitions happen through light shifts
|
||||
- **Real motion magnitudes** — 30–100px movements, 0→1 opacity reveals, 0.7→1.0 scale changes — values that READ at video scale. Tiny micro-movements feel like a still image with twitches.
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Capture & Understand
|
||||
## Step 0: Capture & Understand the Brand
|
||||
|
||||
**Read:** [references/step-1-capture.md](references/step-1-capture.md)
|
||||
**Read:** [references/step-0-capture.md](references/step-0-capture.md)
|
||||
|
||||
Run the capture, read the extracted data, and build a working summary using the write-down-and-forget method.
|
||||
Capture the site, then read the extracted data to understand the **brand and product** — what it does, who it's for, what voice it speaks in, what mood it lives in. The captured assets are a brand toolkit for later, not the building blocks the video is made from.
|
||||
|
||||
**Gate:** Print your site summary (name, top colors, fonts, key assets, one-sentence vibe).
|
||||
**Gate:** Site summary printed — strategy-first (what the product does, who it's for, brand voice) before the asset / color / font inventory.
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Write DESIGN.md
|
||||
## Step 1: Brand Identity
|
||||
|
||||
**Read:** [references/step-2-design.md](references/step-2-design.md)
|
||||
**Read:** [references/step-1-design.md](references/step-1-design.md)
|
||||
|
||||
Write a simple brand reference for the captured website. 6 sections, ~90 lines. This is a cheat sheet, not the creative plan — that comes in Step 4.
|
||||
Write DESIGN.md — a brand cheat sheet covering the visual identity: colors, typography, component styles, layout principles. Use `design-styles.json` for exact computed values.
|
||||
|
||||
**Gate:** `DESIGN.md` exists in the project directory.
|
||||
**Speed option:** For fast-pacing videos (billboard-per-beat), DESIGN.md can be a 50-line summary of colors + fonts + do's/don'ts — not a 300-line document. The sub-agent prompt in Step 5 pastes brand values directly, so DESIGN.md depth only matters for complex compositions.
|
||||
|
||||
**Gate:** `DESIGN.md` exists (any length) with at minimum: color palette, font choices, and do's/don'ts.
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Write SCRIPT
|
||||
## Step 2: Strategy & Messaging
|
||||
|
||||
**Read:** [references/step-3-script.md](references/step-3-script.md)
|
||||
**Read:** [references/step-2-brief.md](references/step-2-brief.md), [references/visual-vocabulary.md](references/visual-vocabulary.md), [references/capabilities.md](references/capabilities.md) (scan the Table of Contents — deep-dive sections only as needed)
|
||||
|
||||
Write the narration script. The story backbone. Scene durations come from the narration, not from guessing.
|
||||
Align with the user on **what the video must communicate** before talking visuals or assets. Parse the user's prompt — they probably already gave you the video type and style. Ask only what's missing: the ONE thing this video must say, the narrative arc, and the audience.
|
||||
|
||||
**Gate:** `SCRIPT.md` exists in the project directory.
|
||||
**Gate:** Video type, duration, format, and — critically — the message and narrative arc are locked. Without those, Step 3 can't write a concept-first storyboard.
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Write STORYBOARD
|
||||
## Step 3: Storyboard + Script 💬
|
||||
|
||||
**Read:** [references/step-4-storyboard.md](references/step-4-storyboard.md)
|
||||
**Read:** [references/step-3-storyboard.md](references/step-3-storyboard.md)
|
||||
|
||||
Write per-beat creative direction: mood, camera, animations, transitions, assets, depth layers, SFX. This is the creative north star — the document the engineer follows to build each composition.
|
||||
Write the storyboard concept-first: message → narrative arc → beats that serve the arc → techniques per beat → brand accents pass at the end. Then write the narration script to match. Present both to the user with a beat-by-beat summary. Iterate until they approve.
|
||||
|
||||
**Gate:** `STORYBOARD.md` exists with beat-by-beat direction and an asset audit table.
|
||||
**Gate:** `STORYBOARD.md` + `SCRIPT.md` exist AND the user has approved the plan.
|
||||
|
||||
---
|
||||
|
||||
## Step 5: Generate VO + Map Timing
|
||||
## Step 4: VO, Timing + Captions 💬
|
||||
|
||||
**Read:** [references/step-5-vo.md](references/step-5-vo.md)
|
||||
**Read:** [references/step-4-vo.md](references/step-4-vo.md)
|
||||
|
||||
Generate TTS audio, transcribe for word-level timestamps, and map timestamps to beats. Update STORYBOARD.md with real durations.
|
||||
If Step 2 said no narration — ask about background music, then skip to Step 5. Otherwise: ask the user which TTS provider (HeyGen TTS, ElevenLabs, or Kokoro), generate audio, transcribe, map timestamps to beats. Then ask about captions.
|
||||
|
||||
**Gate:** `narration.wav` (or .mp3) + `transcript.json` exist. Beat timings in STORYBOARD.md updated.
|
||||
**Gate:** Either (a) no narration was requested and storyboard has manual beat timings, or (b) `narration.wav` + `transcript.json` exist and beat timings updated with real durations.
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Build Compositions
|
||||
## Step 5: Build Compositions
|
||||
|
||||
**Read:** The `hyperframes` skill (load it — every rule matters)
|
||||
**Read:** [references/step-6-build.md](references/step-6-build.md)
|
||||
**Read:** [references/step-5-build.md](references/step-5-build.md)
|
||||
|
||||
Build each composition following the storyboard. After each one: self-review for layout, asset placement, and animation quality.
|
||||
Build index.html and compositions following the architecture and pacing chosen in the storyboard (Step 3). Sub-agents run `hyperframes lint` and `hyperframes snapshot` on each beat before reporting back.
|
||||
|
||||
**Gate:** Every composition has been self-reviewed. No overlapping elements, no misplaced assets, no static images without motion.
|
||||
**Gate:** **The main agent does NOT trust sub-agents' chat reports.** After every sub-agent completes, the main agent opens each `compositions/beat-N.html` and reads it top-to-bottom. For each beat: does the GSAP timeline use the data attributes correctly, do the brand colors from DESIGN.md actually appear in the CSS, are the captured assets the storyboard called for actually referenced, is the headline at video-readable size, does the beat serve the storyboard arc? Anything off — fix it inline or re-dispatch the sub-agent with the specific problem quoted.
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Validate & Deliver
|
||||
## Step 6: Validate & Deliver
|
||||
|
||||
**Read:** [references/step-7-validate.md](references/step-7-validate.md)
|
||||
**Read:** [references/step-6-validate.md](references/step-6-validate.md)
|
||||
|
||||
Lint, validate, snapshot, preview. Deliver the localhost Studio project URL
|
||||
(`http://localhost:<port>/#project/<project-name>`) to the user first — only
|
||||
render to MP4 on explicit request. Do not treat `index.html` as the project
|
||||
handoff link; it is source-code context only.
|
||||
Lint, validate, take snapshots scaled to video length (formula: `max(beats × 3, ceil(duration_seconds / 2))`), and review each one. Fix issues before delivering. Deliver the localhost Studio project URL — only render to MP4 on explicit user request.
|
||||
|
||||
**Deliver something you're proud of.** Before handing off, ask yourself: would I post this on social media with my name on it? If not, fix what's wrong.
|
||||
|
||||
**Gate:** `npx hyperframes lint` and `npx hyperframes validate` pass with zero errors, and the final response includes the active Studio project URL.
|
||||
|
||||
@@ -96,13 +150,17 @@ handoff link; it is source-code context only.
|
||||
|
||||
### Video Types
|
||||
|
||||
| Type | Duration | Beats | Narration |
|
||||
| --------------------- | -------- | ----- | ---------------------- |
|
||||
| Social ad (IG/TikTok) | 10-15s | 3-4 | Optional hook sentence |
|
||||
| Product demo | 30-60s | 5-8 | Full narration |
|
||||
| Feature announcement | 15-30s | 3-5 | Full narration |
|
||||
| Brand reel | 20-45s | 4-6 | Optional, music focus |
|
||||
| Launch teaser | 10-20s | 2-4 | Minimal, high energy |
|
||||
Typical constraints by video type — use as a starting point, not a formula. Beat count should follow from the content and the narration, not from a target range.
|
||||
|
||||
| Type | Typical duration | Duration driver | Narration |
|
||||
| --------------------- | ---------------- | ------------------ | --------------------- |
|
||||
| Social ad (IG/TikTok) | 10–15s | Platform limit | Optional |
|
||||
| Product demo | 30–60s | Script length | Full narration |
|
||||
| Feature announcement | 15–30s | Feature complexity | Full narration |
|
||||
| Brand reel | 20–45s | Music track | Optional, music focus |
|
||||
| Launch teaser | 10–20s | Hook energy | Minimal |
|
||||
|
||||
Beat count is not in this table intentionally — it should come from the storyboard, not from "social ad = 3-4 beats." A social ad for a complex product might need 5 well-timed beats. A brand reel with one strong visual thesis might need 3.
|
||||
|
||||
### Format
|
||||
|
||||
@@ -110,15 +168,26 @@ handoff link; it is source-code context only.
|
||||
- **Portrait**: 1080x1920 (Instagram Stories, TikTok)
|
||||
- **Square**: 1080x1080 (Instagram feed)
|
||||
|
||||
### User Interaction Points
|
||||
|
||||
| Step | What to ask | Why |
|
||||
| ---------------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
||||
| Step 2 (Strategy) | Message, narrative arc, audience, video type, style, format | The story is what every downstream choice flows from. Without it, beats are arbitrary. |
|
||||
| Step 3 (Storyboard + Script) | Beat-by-beat approval, script review | Cheapest place to iterate. 30s to change a beat, 5min to rebuild a composition. |
|
||||
| Step 4 (VO) | TTS provider choice, API key if needed | Voice quality makes or breaks the video. User may have provider preferences. |
|
||||
|
||||
### Reference Files
|
||||
|
||||
| File | When to read |
|
||||
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [step-1-capture.md](references/step-1-capture.md) | Step 1 — reading captured data |
|
||||
| [step-2-design.md](references/step-2-design.md) | Step 2 — writing DESIGN.md |
|
||||
| [step-3-script.md](references/step-3-script.md) | Step 3 — writing the narration script |
|
||||
| [step-4-storyboard.md](references/step-4-storyboard.md) | Step 4 — per-beat creative direction |
|
||||
| [step-5-vo.md](references/step-5-vo.md) | Step 5 — TTS, transcription, timing |
|
||||
| [step-6-build.md](references/step-6-build.md) | Step 6 — building compositions with self-review |
|
||||
| [step-7-validate.md](references/step-7-validate.md) | Step 7 — lint, validate, snapshot, preview |
|
||||
| [techniques.md](../hyperframes/references/techniques.md) | Steps 4 & 6 — 11 visual techniques with code patterns (SVG drawing, Canvas 2D, 3D, typography, Lottie, video, typing, variable fonts, MotionPath, transitions, audio-reactive) |
|
||||
| File | When to read |
|
||||
| ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [step-0-capture.md](references/step-0-capture.md) | Step 0 — capture, understand the brand and product, write strategy-first site summary |
|
||||
| [step-1-design.md](references/step-1-design.md) | Step 1 — write DESIGN.md brand cheat sheet (6 sections, 250-350 lines) |
|
||||
| [step-2-brief.md](references/step-2-brief.md) | Step 2 — align on message, narrative arc, audience with user |
|
||||
| [capabilities.md](references/capabilities.md) | Steps 2 & 5 — full inventory of what HyperFrames can do (24 sections). Scan the TOC during the brief, deep-dive specific sections during build |
|
||||
| [visual-vocabulary.md](references/visual-vocabulary.md) | Step 2 & 3 — translate subjective terms to concrete techniques. Composable building blocks, not rigid presets |
|
||||
| [step-3-storyboard.md](references/step-3-storyboard.md) | Step 3 — storyboard + script (combined) with user review gate |
|
||||
| [step-4-vo.md](references/step-4-vo.md) | Step 4 — TTS provider choice, generation, timing |
|
||||
| [step-5-build.md](references/step-5-build.md) | Step 5 — build index.html + compositions |
|
||||
| [step-6-validate.md](references/step-6-validate.md) | Step 6 — lint, validate, snapshots (scaled to video length), preview |
|
||||
| [techniques.md](../hyperframes/references/techniques.md) | Steps 3 & 5 — 20 visual techniques with code patterns (adapt, don't copy-paste) |
|
||||
| [html-in-canvas-patterns.md](../hyperframes/references/html-in-canvas-patterns.md) | Step 5 — complete code patterns for HTML-in-Canvas effects (lives in the hyperframes skill) |
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# SFX Credits
|
||||
|
||||
All sound effects in this directory are sourced from [Pixabay](https://pixabay.com/sound-effects/) and used under the [Pixabay Content License](https://pixabay.com/service/license-summary/).
|
||||
|
||||
The Pixabay license allows free use for commercial and non-commercial purposes without attribution, but attribution is appreciated and given here for transparency.
|
||||
|
||||
## Files
|
||||
|
||||
The following `.mp3` files are bundled with this skill:
|
||||
|
||||
- `chime.mp3`
|
||||
- `click.mp3` / `click-soft.mp3`
|
||||
- `error.mp3`
|
||||
- `glitch-1.mp3` / `glitch-2.mp3` / `glitch-3.mp3`
|
||||
- `impact-bass-1.mp3` / `impact-bass-2.mp3`
|
||||
- `key-press.mp3`
|
||||
- `notification.mp3`
|
||||
- `ping.mp3`
|
||||
- `pop.mp3`
|
||||
- `riser.mp3`
|
||||
- `sparkle.mp3`
|
||||
- `typing.mp3`
|
||||
- `whoosh.mp3` / `whoosh-short.mp3` / `whoosh-cinematic.mp3`
|
||||
|
||||
See `manifest.json` for per-file metadata (duration, energy character, recommended use).
|
||||
|
||||
## License
|
||||
|
||||
All files are distributed under the [Pixabay Content License](https://pixabay.com/service/license-summary/), which permits:
|
||||
|
||||
- Commercial and non-commercial use
|
||||
- Modification and remixing
|
||||
- Redistribution as part of derivative works (such as videos rendered with HyperFrames)
|
||||
|
||||
without any attribution requirement.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"chime": {
|
||||
"file": "chime.mp3",
|
||||
"duration": 2.5,
|
||||
"description": "This is a soft, melodic chime sound effect perfect for signaling a gentle transition or a lighthearted moment in a video."
|
||||
},
|
||||
"click-soft": {
|
||||
"file": "click-soft.mp3",
|
||||
"duration": 0.37,
|
||||
"description": "This is a smooth, medium-energy swoosh sound effect, perfect for transitioning between two scenes or highlighting a sleek reveal."
|
||||
},
|
||||
"click": {
|
||||
"file": "click.mp3",
|
||||
"duration": 0.37,
|
||||
"description": "This is a sharp, medium-energy digital \"whoosh\" effect that works perfectly for a quick transition between video clips."
|
||||
},
|
||||
"error": {
|
||||
"file": "error.mp3",
|
||||
"duration": 1.62,
|
||||
"description": "This is a sharp, medium-energy digital glitch sound that serves as an effective, abrupt transition for a video cut or error screen."
|
||||
},
|
||||
"glitch-1": {
|
||||
"file": "glitch-1.mp3",
|
||||
"duration": 2.64,
|
||||
"description": "This is a high-energy, distorted digital impact sound effect that works perfectly for a sudden reveal or a punchy transition in a fast-paced edit."
|
||||
},
|
||||
"glitch-2": {
|
||||
"file": "glitch-2.mp3",
|
||||
"duration": 3.5,
|
||||
"description": "This is a harsh, distorted digital glitch effect with high energy that serves as a jarring transition or a chaotic digital reveal."
|
||||
},
|
||||
"glitch-3": {
|
||||
"file": "glitch-3.mp3",
|
||||
"duration": 3.1,
|
||||
"description": "This is a low-energy, subtle electronic click sound effect that works well as a minimal audio transition or a UI element for a subtle selection reveal."
|
||||
},
|
||||
"impact-bass-1": {
|
||||
"file": "impact-bass-1.mp3",
|
||||
"duration": 2.12,
|
||||
"description": "This is a medium-energy, sharp electronic chime that works perfectly as an accent for a quick transition or a brief, high-tech visual reveal."
|
||||
},
|
||||
"impact-bass-2": {
|
||||
"file": "impact-bass-2.mp3",
|
||||
"duration": 2.59,
|
||||
"description": "This sound effect is a shimmering, ethereal synth riser with a medium energy level, perfect for creating anticipation before a magical transition or reveal."
|
||||
},
|
||||
"key-press": {
|
||||
"file": "key-press.mp3",
|
||||
"duration": 0.4,
|
||||
"description": "This is a medium-energy, distorted digital impact sound effect that works well for a sudden glitch transition or a glitchy text reveal."
|
||||
},
|
||||
"notification": {
|
||||
"file": "notification.mp3",
|
||||
"duration": 2.46,
|
||||
"description": "This is a medium-energy, whimsical digital transition sound effect that fits perfectly with a playful visual reveal or a cute UI interaction."
|
||||
},
|
||||
"ping": {
|
||||
"file": "ping.mp3",
|
||||
"duration": 1.32,
|
||||
"description": "This is a medium-energy, sharp electronic impact sound that works perfectly for punchy transitions or highlighting key on-screen reveals."
|
||||
},
|
||||
"pop": {
|
||||
"file": "pop.mp3",
|
||||
"duration": 0.72,
|
||||
"description": "This is a medium-energy, metallic clinking sound that works perfectly as an accent or a subtle impact for a precise visual reveal or UI element."
|
||||
},
|
||||
"riser": {
|
||||
"file": "riser.mp3",
|
||||
"duration": 10.03,
|
||||
"description": "This is a high-energy cinematic air whoosh transition that builds tension before suddenly cutting, making it perfect for a dramatic scene change or a quick reveal."
|
||||
},
|
||||
"sparkle": {
|
||||
"file": "sparkle.mp3",
|
||||
"duration": 1.8,
|
||||
"description": "This is a bright, high-energy \"whoosh\" transition sound with a fast, ascending pitch that is perfect for a rapid scene change or a quick reveal."
|
||||
},
|
||||
"typing": {
|
||||
"file": "typing.mp3",
|
||||
"duration": 1.5,
|
||||
"description": "This is a hard, high-pitched \"ding\" sound that works well as an accent for a reveal or a quick transition."
|
||||
},
|
||||
"whoosh-cinematic": {
|
||||
"file": "whoosh-cinematic.mp3",
|
||||
"duration": 5.54,
|
||||
"description": "This is a medium-energy, cinematic whoosh effect, ideal for smooth scene transitions or emphasizing a quick reveal."
|
||||
},
|
||||
"whoosh-short": {
|
||||
"file": "whoosh-short.mp3",
|
||||
"duration": 0.57,
|
||||
"description": "This is a medium-energy, organic wooden texture sound effect that works well as a subtle transition or a background accent."
|
||||
},
|
||||
"whoosh": {
|
||||
"file": "whoosh.mp3",
|
||||
"duration": 0.57,
|
||||
"description": "This is a hard, metallic impact sound effect that works well for a sudden reveal or a punchy transition."
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,199 @@
|
||||
# Beat Builder Guide
|
||||
|
||||
You are building ONE beat of a multi-beat video composition. This file tells you what to read, how to build, how to verify, and how to report back.
|
||||
|
||||
## Step 1: Read and understand
|
||||
|
||||
**Required (every beat):**
|
||||
|
||||
1. **Load the `hyperframes` skill** — composition rules, data attributes, timeline contract, deterministic rendering. Read the whole skill.
|
||||
2. **[capabilities.md](capabilities.md)** — full inventory of HyperFrames capabilities (24 sections). Read the Table of Contents first, then deep-dive sections your beat needs.
|
||||
3. **The beat spec** the main agent gave you — concept, choreography, assets, brand values, timing.
|
||||
|
||||
**Read based on what your beat needs (pick relevant ones):**
|
||||
|
||||
| Resource | What it covers | Read when |
|
||||
| ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
|
||||
| [techniques.md](../../hyperframes/references/techniques.md) | 20 visual techniques with code: SVG path drawing, Canvas 2D, CSS 3D, kinetic type, variable fonts, MotionPath, counters | Beat uses any of these techniques |
|
||||
| [text-effects.md](../../hyperframes/references/text-effects.md) | 24 named text animations: soft-blur-in, typewriter, kinetic-center-build, line-reveal, stagger, crossfade, shared-axis | Beat has text animation |
|
||||
| [html-in-canvas-patterns.md](../../hyperframes/references/html-in-canvas-patterns.md) | HTML-in-Canvas: iPhone/MacBook mockups, liquid glass, magnetic, portal, shatter, text cursor | Beat uses device mockups or WebGL effects on HTML |
|
||||
| [transitions.md](../../hyperframes/references/transitions.md) | Shader transition API, HyperShader.init() pattern, all 14 WebGL shaders | Beat has shader transitions |
|
||||
| [transitions/](../../hyperframes/references/transitions/) | 14 CSS transition category files: push, scale, dissolve, blur, 3D flip, light leak, distortion, grid, mechanical, destruction | Beat uses CSS transitions |
|
||||
| [css-patterns.md](../../hyperframes/references/css-patterns.md) | Text markers: highlight sweeps, hand-drawn circles, burst lines, scribble, sketchout | Beat uses text emphasis/markers |
|
||||
| [audio-reactive.md](../../hyperframes/references/audio-reactive.md) | Bass→scale, mid→shape, treble→glow mappings | Beat reacts to music/audio |
|
||||
| [captions.md](../../hyperframes/references/captions.md) | Per-word karaoke, tone-adaptive styling, positioning | Beat includes captions |
|
||||
| [typography.md](../../hyperframes/references/typography.md) | Font hierarchy, variable fonts, responsive type scaling | Beat has complex typography |
|
||||
| [motion-principles.md](../../hyperframes/references/motion-principles.md) | Velocity matching, easing philosophy, motion continuity | Beat needs polished motion design |
|
||||
| [dynamic-techniques.md](../../hyperframes/references/dynamic-techniques.md) | Counter animations, data-driven visuals, dynamic content | Beat has counters or data visualization |
|
||||
| [video-composition.md](../../hyperframes/references/video-composition.md) | Frame composition, color presence, scale, density rules | General composition quality |
|
||||
|
||||
**Other skills you can load if needed:**
|
||||
|
||||
- `/gsap` or `/gsap-core`, `/gsap-timeline`, `/gsap-plugins` — deeper GSAP reference
|
||||
- `/animate-text` — curated text animation catalog with exact JSON specs
|
||||
- `/hyperframes-registry` — if you need to install and wire registry blocks
|
||||
- `/hyperframes-contrast` — audit color contrast (WCAG)
|
||||
- `/lottie`, `/three`, `/waapi`, `/animejs`, `/css-animations` — if beat uses these engines
|
||||
|
||||
**Always open the captured assets folder before designing the beat:**
|
||||
|
||||
- `capture/assets/svgs/` — brand logos, icons, decorative marks. SVGs are infinitely scalable and stroke-animatable (path drawing, dash offset). A logo SVG drawing itself onto frame can carry an entire beat.
|
||||
- `capture/assets/` — hero illustrations, screenshots, product art, gradients, photography. These are first-class beat subjects, not background decoration. A breathing hero illustration with a single line of kinetic type is a complete shot.
|
||||
- VIEW every image before placing text on it. Check safe zones, contrast, actual content, where the focal point sits.
|
||||
|
||||
**If your beat spec names a captured asset, USE it.** Don't substitute a CSS recreation. The user captured these from the real brand site precisely so the video carries the brand's actual visual identity.
|
||||
|
||||
## Step 2: Build the composition
|
||||
|
||||
Save to the path the main agent specified (usually `compositions/beat-N-name.html`).
|
||||
|
||||
```html
|
||||
<template>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
/* your styles */
|
||||
</style>
|
||||
|
||||
<div
|
||||
id="beat-N-name"
|
||||
data-composition-id="beat-N-name"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
style="width:1920px; height:1080px; position:relative; overflow:hidden; background:#YOUR_BG;"
|
||||
>
|
||||
<!-- your elements -->
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var BEAT = 5.5; // MUST match data-duration on the host div in index.html
|
||||
window.__timelines = window.__timelines || {};
|
||||
var tl = gsap.timeline({ paused: true });
|
||||
|
||||
// your GSAP animations
|
||||
|
||||
window.__timelines["beat-N-name"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</template>
|
||||
```
|
||||
|
||||
**Critical:** `data-composition-id`, `data-width`, `data-height` on the root div MUST match the host div in index.html.
|
||||
|
||||
## Step 3: Lint
|
||||
|
||||
```bash
|
||||
npx hyperframes lint .
|
||||
```
|
||||
|
||||
Fix ALL errors. Zero errors required.
|
||||
|
||||
## Step 4: Snapshot and verify
|
||||
|
||||
```bash
|
||||
npx tsx packages/cli/src/cli.ts snapshot . --frames 3
|
||||
```
|
||||
|
||||
**READ the contact sheet** (`snapshots/contact-sheet.jpg`). For each frame:
|
||||
|
||||
- Is content visible? (not black, blank, or loading)
|
||||
- Is text readable, properly positioned, correct font/color?
|
||||
- Are assets at the right size and position?
|
||||
- Does the animation state match the beat spec at this timestamp?
|
||||
|
||||
**If anything is wrong:** fix, re-snapshot, re-check. You are done ONLY when every frame matches the spec.
|
||||
|
||||
## Step 5: Report back honestly
|
||||
|
||||
After lint passes, snapshots are taken, and you've fixed every issue you saw — report back to the main agent with concrete observations. Not "0 errors, looks good." That phrasing is what got prior videos shipped with mismatched brand colors, missing logos, and headlines too small to read.
|
||||
|
||||
**The main agent will OPEN your composition file and read it top-to-bottom** to cross-check against DESIGN.md and STORYBOARD.md — does the brand bg/accent hex actually appear in your CSS, are the captured assets the storyboard called for actually referenced, is the headline ≥80px, does the GSAP timeline cover the full beat duration. You cannot pass that check by claiming things you didn't do; the file is on disk, the truth is in the file.
|
||||
|
||||
So in your report, name the hex codes you used, the captured asset paths you placed, the headline `font-size`, and the GSAP timeline's last `tl.fromTo(...)` timestamp. Brief, concrete, true. If anything diverges from DESIGN.md or the storyboard, say so explicitly — the main agent can decide whether to accept the divergence or send you back to fix it. Surprises caught at this hand-off cost minutes; surprises caught at Step 6 cost iterations.
|
||||
|
||||
---
|
||||
|
||||
## Continuous motion — the most important rule
|
||||
|
||||
A beat is a SHOT in a film, not a webpage with entrance animations. Your GSAP timeline should have events spread across the ENTIRE beat duration — not just entrance tweens in the first 1-2 seconds followed by nothing. If an element is on screen, it should be doing something. After elements enter, add continuous hold motion: camera dolly, parallax layers moving at different speeds, secondary elements appearing mid-beat, real depth shifts.
|
||||
|
||||
## You are building a SHOT, not a webpage
|
||||
|
||||
The storyboard tells you the shot framing (close-up / medium / wide / etc.) and the camera move. Implement them. A beat is a moment, not a screenshot. The distinction is **what the camera is doing**, not whether the subject is a UI element or a logo — a tight push-in on a real product screenshot is a shot; a centered card on a parked camera is a webpage.
|
||||
|
||||
**Patterns that turn a shot back into a webpage:**
|
||||
|
||||
These are defaults to avoid, **not absolute prohibitions.** If the storyboard genuinely calls for "the kanban app interface" or "the browser chrome" as the subject of a specific beat (a product tour, a "this is how it works" demo, a stylized window mockup for the closer), then build it. The rule is: don't reach for these patterns by default when the storyboard didn't ask for them.
|
||||
|
||||
- ⚠ **macOS / browser window chrome reproduced in CSS** — traffic-light dots, URL bars, browser tabs. Fine when the storyboard makes the chrome the subject (e.g. "stylized macOS window framing the product UI" for a closer). NOT fine when it's a frame you added around a card "to make it look like an app."
|
||||
- ⚠ **Full webpage layout** (sidebar + header + footer + main content area) — fine when the beat is genuinely a product tour shot. NOT fine when the beat was supposed to be about _the kanban moment_ and you defaulted to drawing the whole app around it.
|
||||
- ❌ **Parked-camera composition** — centered card with 60–120px margins on all sides and no camera move. Almost always wrong. Either give it a real push-in / dolly / parallax, or reframe.
|
||||
- ❌ **"Hold with breathing"** implemented as `y: ±1–2px` or `scale: 1.01` — invisible at 1920×1080+ scale. If continuous motion is required, use camera dolly (scale 1.0 → 1.05), parallax pan (x/y ±30–80px), or progressive reveals.
|
||||
- ❌ **Hover-state simulations** — videos have no hover. If the brand uses hover effects, show the BEFORE and AFTER as discrete frames in the timeline.
|
||||
- ❌ **Counter pulses + dot pulses + tiny scale wobbles** as the only motion during the hold — these are "I ran out of ideas" filler.
|
||||
|
||||
The test: if the storyboard says _"this beat is the product tour, viewer sees the app interface"_, building a CSS dashboard with chrome is correct. If the storyboard says _"this beat is the kanban moment, single card sliding home"_, drawing the full app around it is wrong. Read the beat spec carefully.
|
||||
|
||||
**Patterns that ARE shots (do these freely):**
|
||||
|
||||
- ✅ **Captured SVG logo drawing itself stroke-by-stroke** (DrawSVG / path dashoffset) — a complete opener or stinger.
|
||||
- ✅ **Captured hero illustration with camera dolly** — push-in from 1.0 → 1.08 over 4s, focal element holds frame.
|
||||
- ✅ **Captured product screenshot with parallax layers** — separate the foreground UI from background panels and move them at different speeds, or use HTML-in-Canvas for an iPhone/MacBook mockup.
|
||||
- ✅ **Captured asset as the bed, kinetic type as the punchline** — the brand's hero image holds the frame while a one-line message arrives, splits, reflows.
|
||||
- ✅ **Composed-from-divs UI moment** when the beat is specifically about that UI's interaction (a card sliding into a column, a search result resolving) — this is the legit case for CSS-only composition.
|
||||
|
||||
**Required motion magnitudes** (anything smaller is invisible at video scale):
|
||||
|
||||
| Motion type | Minimum magnitude |
|
||||
| --------------- | ------------------------------------------- |
|
||||
| Translate (y/x) | 30px (entrance) / 8px (drift during hold) |
|
||||
| Scale | 0.05 change (1.0 → 1.05 or larger) |
|
||||
| Opacity | full 0 → 1 or vice versa for reveals |
|
||||
| Rotate | 4° minimum to read (Dutch angles, ticks) |
|
||||
| Camera dolly | scale 1.0 → 1.06 minimum over beat duration |
|
||||
|
||||
**Required cinematography per beat** (the storyboard should give you these; if it doesn't, escalate):
|
||||
|
||||
- A **shot type** (close-up / medium / wide / over-the-shoulder / Dutch)
|
||||
- A **camera move** (dolly in/out, push, parallax pan, orbit, rack focus)
|
||||
- A **depth strategy** (what's foreground / midground / background)
|
||||
- A **purpose** (what specific feeling or noticing the shot delivers)
|
||||
|
||||
If any are missing from the beat spec, the beat is under-defined. Don't fill the gap with "centered layout + breathing" — re-read the spec, and if it's genuinely missing, ask the main agent.
|
||||
|
||||
## Rules
|
||||
|
||||
- SCRIPT PLACEMENT: scripts inside `<template>`, never after `</template>`. Scripts outside see no DOM.
|
||||
- GSAP FROM TRAP: never `gsap.from(el, {opacity:0})` with CSS `opacity:0`. It animates 0→0. Use `tl.fromTo()`.
|
||||
- STYLE: avoid CSS `opacity:0` on GSAP-animated elements. Use GSAP fromTo for initial states.
|
||||
- ASSET PATHS: project-root-relative. `capture/assets/file.png` ✅ `../capture/assets/file.png` ❌
|
||||
- SVG VIA IMG: `<img src="logo.svg">` can't inherit CSS color. Inline SVG or `filter: brightness(0) invert(1)`.
|
||||
- CSS CENTERING: no `transform: translate(-50%, -50%)` with GSAP transforms. Use flexbox or `xPercent/yPercent`.
|
||||
- QUERYSELECTOR: `document.getElementById("id")` with null guards. No method calls without null check.
|
||||
- CHARACTER SPANS: `display:inline-block` on spaces collapses them. Use ` ` or per-word spans.
|
||||
- COUNTERS: no `onUpdate` callbacks. Discrete `tl.set(el, {textContent: "42"}, 2.5)` at timestamps.
|
||||
- TIMELINE: `window.__timelines["beat-N-name"] = tl` synchronously. Key = `data-composition-id`.
|
||||
- DETERMINISTIC: no `Math.random()`, `Date.now()`, `requestAnimationFrame`, `repeat:-1`.
|
||||
- Always `tl.fromTo()` not `tl.from()` for entrances.
|
||||
- Never stack two transform tweens on same element at same time.
|
||||
- FONTS: brand fonts with `capture/assets/fonts/` path need `@font-face` in `<style>`.
|
||||
|
||||
## Easing — pick per intent
|
||||
|
||||
Do NOT default to `power2.out` on everything.
|
||||
|
||||
| Intent | GSAP Ease | Use for |
|
||||
| --------------- | --------------------- | ------------------------------------ |
|
||||
| Snap (iOS feel) | `power4.out` | Hero text, UI elements |
|
||||
| Whip overshoot | `back.out(1.7)` | Numbers, badges, impact |
|
||||
| Soft land | `expo.out` | Per-word reveals, gentle entrances |
|
||||
| Mechanical | `power1.out` | Terminal text, code typing |
|
||||
| Bounce settle | `elastic.out(1, 0.5)` | Counters, CTA buttons |
|
||||
| Dramatic | `expo.inOut` | Full-screen statements, hero reveals |
|
||||
| Drift | `"none"` | Parallax, Ken Burns, camera drift |
|
||||
|
||||
Staggered items: `power4.out` with `stagger: 0.08` to `0.15`.
|
||||
@@ -0,0 +1,711 @@
|
||||
# HyperFrames — Complete Capabilities Inventory
|
||||
|
||||
Everything possible in HyperFrames as of today's workspace, synthesized from direct source reads of all 7 packages, 16 skills, and the full registry.
|
||||
|
||||
You are NOT limited to what was captured from the website. You can create shaders from scratch, search for and download registry blocks, build Three.js scenes, write custom WebGL effects, use any web API — anything a browser can render.
|
||||
|
||||
For implementation patterns (working code), see `techniques.md`. This file is the WHAT; techniques.md is the HOW.
|
||||
|
||||
## Essential Rules
|
||||
|
||||
- **Deterministic:** No `Math.random()`, no `Date.now()`, no `requestAnimationFrame`, no `repeat: -1`. The render engine seeks to exact timestamps.
|
||||
- **Timeline contract:** `window.__timelines["composition-id"] = tl` must be set synchronously. The timeline length defines the composition duration.
|
||||
- **Sub-compositions:** External `.html` files loaded via `data-composition-src`. Auto-nested timelines, scoped CSS, scoped scripts.
|
||||
- **Linter:** 60+ rules. Run `npx hyperframes lint` before render. Catches missing timelines, overlapping clips, broken paths, GSAP errors.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
| # | Section | What it covers |
|
||||
| --- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 1 | **Composition fundamentals** | Data attributes, timeline contract, resolution presets (1080p, 4K, portrait, square, custom) |
|
||||
| 2 | **Animation engines (6 adapters)** | GSAP + 15 plugins, Anime.js v4, CSS @keyframes, WAAPI, Lottie (lottie-web + dotlottie), Three.js (hf-seek event) |
|
||||
| 3 | **Shader transitions (14 WebGL)** | domain-warp, ridged-burn, whip-pan, sdf-iris, ripple-waves, gravitational-lens, cinematic-zoom, chromatic-split, swirl-vortex, thermal-distortion, flash-through-white, cross-warp-morph, light-leak, glitch — plus custom GLSL |
|
||||
| 4 | **CSS scene transitions (30+)** | Push/slide, scale/zoom, radial/clip, 3D flip, blur, dissolve, cover/blinds, light leak/burn, distortion/glitch, mechanical/shutter, grid dissolve, destruction/burn, VHS/gravity/morph — 6 timing presets |
|
||||
| 5 | **Visual effects + textures** | Text markers (highlight, circle, burst, scribble, sketchout), grain/noise, light leaks, film burn, vignette, glow, paper texture, shimmer sweep |
|
||||
| 6 | **Caption techniques** | Per-word karaoke, intensity tiers, 5 exit styles, 6 tone mappings, per-word styling triggers, 7 audio source formats, positioning helpers |
|
||||
| 7 | **Audio-reactive animation** | Bass→scale, mid→shape, treble→glow; any GSAP property; band extraction script; banned patterns |
|
||||
| 8 | **HTML-in-canvas** | Live DOM as GPU texture (drawElementImage), Three.js planes, WebGL shaders on HTML, 7 VFX blocks (iPhone/MacBook device, liquid, glass, magnetic, portal, shatter, text cursor) |
|
||||
| 9 | **Three.js / WebGL custom scenes** | Full 3D: AnimationMixer, custom GLSL, post-processing, GLTF models, lights, cameras, materials — all deterministic via hf-seek |
|
||||
| 10 | **SVG / canvas / variable fonts** | SVG path drawing, Canvas 2D procedural art, CSS 3D card, per-word type, variable font axes, character typing, velocity-matched cuts, MotionPath |
|
||||
| 11 | **Media: video, audio, TTS** | Video compositing + frame injection, audio mixer (multi-track), Kokoro TTS (54 voices, 9 languages), Whisper/Groq/OpenAI transcription, background removal (u2net) |
|
||||
| 12 | **Registry (51 blocks + 4 components + 8 examples)** | Social overlays (8), showcases (5), data viz (2), logo branding (1), 3D/VFX (7), shader transitions (14), transition galleries (13), components (grain, shimmer, pixelate, texture-mask), 8 starter examples |
|
||||
| 13 | **CLI (25 commands)** | init, add, catalog, play, preview, publish, render (MP4/WebM/MOV/PNG, HDR, GPU, parallel), lint, validate, inspect, snapshot, capture, tts, transcribe, remove-background, doctor, and more |
|
||||
| 14 | **Linter (60+ rules)** | Core, media, GSAP, captions, composition, adapters, textures, fonts — plus async URL checks |
|
||||
| 15 | **Player web component** | `<hyperframes-player>` with seek/play/pause API, 11 events, media mirror, runtime auto-inject |
|
||||
| 16 | **Engine + Producer** | MP4/WebM/MOV/PNG output, HDR (PQ/HLG), transparency (ProRes), GPU encoding (NVENC/VideoToolbox/VAAPI/QSV), parallel rendering, video frame injection |
|
||||
| 17 | **Studio (in-browser NLE)** | Timeline editor, drag/resize clips, asset browser, render queue, lint modal, caption editor, element picker |
|
||||
| 18 | **Determinism guarantees** | No Math.random, no Date.now, no RAF, no repeat:-1, no callbacks, synchronous construction |
|
||||
| 19 | **Variables / parameterization** | Typed runtime variables (string, color, number, boolean, enum), CLI override, strict validation |
|
||||
| 20 | **Sub-compositions** | External file or inline template, auto-nested timelines, scoped CSS, scoped scripts, variable inheritance |
|
||||
| 21 | **Global runtime APIs** | 25+ window globals for timelines, player, variables, adapters, hooks |
|
||||
| 22 | **Skills (16)** | hyperframes, cli, media, registry, contrast, animation-map, website-to-hyperframes, remotion, gsap, animejs, css-animations, waapi, lottie, three, tailwind, contribute-catalog |
|
||||
| 23 | **References (15 docs)** | transitions, css-patterns, dynamic-techniques, motion-principles, typography, narration, captions, audio-reactive, transcript-guide, techniques, beat-direction, visual-styles, and more |
|
||||
| 24 | **Documentation (27 pages)** | Guides + package docs covering rendering, HDR, html-in-canvas, performance, prompting, troubleshooting, etc. |
|
||||
|
||||
---
|
||||
|
||||
## 1. Composition fundamentals
|
||||
|
||||
### Data attributes recognized by the runtime
|
||||
|
||||
- **Root composition:** `data-composition-id`, `data-start`, `data-duration`, `data-width`, `data-height`, `data-composition-src` (external sub-comp), `data-composition-duration`, `data-composition-variables` (JSON), `data-variable-values` (override)
|
||||
- **Every clip:** `id`, `data-start`, `data-duration`, `data-track-index`, `class="clip"`, optional `data-media-start`, `data-volume`, `data-playback-start`
|
||||
- **Sub-composition host:** `data-composition-id`, `data-composition-src` OR inline `<template id="${compId}-template">`
|
||||
- **Parser also reads:** `data-type` (composition|text), `data-end`, `data-keyframes` (JSON), `data-x|y|scale|opacity`, `data-color|font-size|font-weight|font-family|text-shadow|outline|highlight*`, `data-layer` (z-index, deprecated for timeline but used for audio mixer layers), `data-resolution`, `data-composition-width|height`
|
||||
|
||||
### Timeline contract
|
||||
|
||||
- `gsap.timeline({ paused: true })` registered on `window.__timelines["<composition-id>"]`
|
||||
- Master clock (TransportClock + WebAudioTransport) drives the timeline via `tl.totalTime(t, false)` or `tl.seek(t, false)`
|
||||
- Framework auto-nests sub-comp timelines
|
||||
- Duration sourced from `data-duration` on root, not from GSAP length
|
||||
- Synchronous timeline construction required (no async/await/setTimeout)
|
||||
- Looping handled by `<hyperframes-player>`, not GSAP `repeat: -1`
|
||||
|
||||
### Resolution presets
|
||||
|
||||
VALID_CANVAS_RESOLUTIONS: 1920×1080 default, 1080×1920 portrait, 1080×1080 square, 4K, 1440×2560, plus `normalizeResolutionFlag` for `--resolution` CLI flag.
|
||||
|
||||
---
|
||||
|
||||
## 2. Animation engines (6 deterministic frame adapters)
|
||||
|
||||
The runtime registers these adapters in order; each implements `discover()` / `seek({time})` / `pause` / `play?` / `revert`:
|
||||
|
||||
| Adapter | What it drives | How to load | Notable |
|
||||
| ---------------------------------- | ----------------------------------------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
||||
| GSAP (createGsapAdapter) | The primary timeline + all tweens registered on `window.__timelines[<id>]` | CDN `https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js` | Plugins via standard GSAP register; HyperFrames does NOT patch THREE.Clock (uses `__hfThreeTime` instead) |
|
||||
| Anime.js v4 (createAnimeJsAdapter) | Anime instances pushed to `window.__hfAnime` | CDN `animejs@4.0.2/lib/anime.iife.min.js` or ESM | Adapter multiplies composition seconds by 1000 for ms |
|
||||
| CSS animations (createCssAdapter) | Any element with computed `animation-name` | Declarative `@keyframes` | Falls back to negative `animation-delay` when WAAPI unavailable |
|
||||
| WAAPI (createWaapiAdapter) | All Animation objects on document | `element.animate()` | Uses `document.getAnimations()` |
|
||||
| Lottie (createLottieAdapter) | `window.__hfLottie` array; supports lottie-web + dotlottie-web | CDN `lottie.min.js` + `@lottiefiles/dotlottie-web` | `goToAndStop(time*1000)` or `setCurrentRawFrameValue` / `seek(%)` |
|
||||
| Three.js (createThreeAdapter) | `window.__hfThreeTime` + dispatches `CustomEvent("hf-seek", {detail:{time}})` | ESM CDN `three@0.181.2/+esm` | Composition's render loop listens to `hf-seek`; pattern: `mixer.setTime(time)` |
|
||||
|
||||
### GSAP plugins (documented patterns)
|
||||
|
||||
- **TextPlugin** — text mutation in `tl.call` (skills/gsap/references/effects.md)
|
||||
- **MotionPathPlugin** — curve-constrained tweens (skills/hyperframes/references/techniques.md)
|
||||
- **CustomEase** — bezier eases imported from Remotion-style timing
|
||||
- **ScrollTrigger / Flip / SplitText / Draggable / Inertia / Observer / ScrambleText / CustomWiggle / CustomBounce / ScrollSmoother / GSDevTools** — work natively if loaded and tweens are on the registered paused timeline, but no special HyperFrames adapter
|
||||
- Producer injects ScrollTrigger CDN automatically when needed (packages/producer/src/services/htmlCompiler.ts)
|
||||
|
||||
---
|
||||
|
||||
## 3. Shader transitions — @hyperframes/shader-transitions
|
||||
|
||||
14 named WebGL fragment shaders. All share the same uniforms: `u_from`, `u_to`, `u_progress`, `u_resolution`, `u_accent`, `u_accent_dark`, `u_accent_bright`.
|
||||
|
||||
### The 14 shaders
|
||||
|
||||
| Name | Visual | Notes |
|
||||
| ------------------- | -------------------------------------------------------------------------------------- | -------------------------------------- |
|
||||
| domain-warp | Multi-octave FBM warps both scenes oppositely; organic dissolve edge with accent flash | Uses NQ noise bundle |
|
||||
| ridged-burn | Ridged multifractal mask reveals B; accent → bright → white burn ramp; sparks | NQ |
|
||||
| whip-pan | 10-sample horizontal motion blur + lateral crossfade | No noise |
|
||||
| sdf-iris | Aspect-corrected circle SDF expansion + accent-tinted glow rings | — |
|
||||
| ripple-waves | Radial standing-wave UV displacement + tinted crossfade | — |
|
||||
| gravitational-lens | Pinch pull toward center + R/B chromatic separation | — |
|
||||
| cinematic-zoom | 12 RGB-offset radial zoom blur samples (chromatic zoom streak) | — |
|
||||
| chromatic-split | R/B radial channel shift outward / inward; G fixed | Distinct from CSS chromatic aberration |
|
||||
| swirl-vortex | CCW swirl with FBM noise; reciprocal on incoming | NQ |
|
||||
| thermal-distortion | Vertical sin + FBM horizontal displacement; warm haze | NQ |
|
||||
| flash-through-white | Fade through white midpoint; ideal as invisible bridge at `duration: 0.01` | No accent |
|
||||
| cross-warp-morph | FBM vector field displaces both scenes; third FBM biases irregular wipe | NQ |
|
||||
| light-leak | Fixed off-frame leak with exponential falloff + accent warmth + ridge flare | Hard-coded leak anchor |
|
||||
| glitch | Line displacement + RGB lateral split + scan modulation + posterization + flicker | Deterministic |
|
||||
|
||||
### Public API
|
||||
|
||||
```js
|
||||
HyperShader.init({
|
||||
bgColor: "#0b0f14",
|
||||
accentColor: "#f59e42",
|
||||
scenes: ["scene1", "scene2"],
|
||||
transitions: [{ time: 3, shader: "sdf-iris", duration: 0.65, ease: "power2.inOut" }],
|
||||
timeline: gsap.timeline({ paused: true }),
|
||||
compositionId: "main",
|
||||
previewCaptureFps: 30,
|
||||
});
|
||||
```
|
||||
|
||||
- Capability probe: `isHtmlInCanvasCaptureSupported()` (Chrome layoutSubtree/drawElementImage)
|
||||
- Tuning: `?__hf_shader_capture_scale=` (0.25–1), `?__hf_shader_loading=` (internal|player|none)
|
||||
- Cache: IndexedDB for PNG snapshots; max 2 textured transitions live at once
|
||||
- Fallback (`applyFallbackTransition`): smoothstep opacity tween when capture / texImage2D fails
|
||||
- Engine mode skips GL/capture when `window.__HF_VIRTUAL_TIME__` set (producer uses metadata)
|
||||
|
||||
You can also **write custom GLSL shaders from scratch** — any fragment shader works with the standard uniforms.
|
||||
|
||||
---
|
||||
|
||||
## 4. CSS scene transitions (30+ named patterns)
|
||||
|
||||
Documented in skills/hyperframes/references/transitions/ across 14 category files. All GSAP-driven, none mixable with shader transitions in same composition.
|
||||
|
||||
### By category
|
||||
|
||||
| Category | Patterns |
|
||||
| -------------------------------- | ------------------------------------------------------------------------------------------------ |
|
||||
| Push / slide (css-push.md) | Push slide, vertical push, elastic push, squeeze |
|
||||
| Scale / zoom (css-scale.md) | Zoom through, zoom out, scale-up swap |
|
||||
| Radial / clip (css-radial.md) | Circle iris, diamond iris, diagonal split |
|
||||
| 3D (css-3d.md) | 3D card flip, hinge door |
|
||||
| Blur (css-blur.md) | Crossfade, blur crossfade, focus pull |
|
||||
| Dissolve (css-dissolve.md) | Color dip (gap-to-black), staggered color blocks (2-block, 5-block) |
|
||||
| Cover (css-cover.md) | Horizontal blinds, vertical blinds (variable strip counts: 6 / 12 / 20) |
|
||||
| Light (css-light.md) | Light leak overlays, overexposure burn, film burn |
|
||||
| Distortion (css-distortion.md) | Glitch (CSS — RGB layer jitter), chromatic aberration, ripple |
|
||||
| Mechanical (css-mechanical.md) | Shutter (two-half), clock wipe (9-point rotating wedge) |
|
||||
| Grid (css-grid.md) | Grid dissolve (12 or 120 cells), grid pixelate wipe |
|
||||
| Destruction (css-destruction.md) | Page burn (SVG clip-path + canvas char rim) |
|
||||
| Other (css-other.md) | VHS tape (strip-based seeded jitter), gravity drop, morph circle, blur through, directional blur |
|
||||
| Rejected | Star iris, tilt-shift, lens flare (don't use — non-CSS-realistic) |
|
||||
|
||||
### Timing presets
|
||||
|
||||
| Preset | duration | ease |
|
||||
| -------- | -------- | ---------------------- |
|
||||
| snappy | 0.2s | power4.inOut |
|
||||
| smooth | 0.4s | power2.inOut |
|
||||
| gentle | 0.6s | sine.inOut |
|
||||
| dramatic | 0.5s | power3.in → power3.out |
|
||||
| instant | 0.15s | expo.inOut |
|
||||
| luxe | 0.7s | power1.inOut |
|
||||
|
||||
---
|
||||
|
||||
## 5. Visual effects + textures
|
||||
|
||||
### Marker/emphasis patterns (css-patterns.md)
|
||||
|
||||
| Mode | What it does | Implementation |
|
||||
| --------- | --------------------------------- | ----------------------------------------- |
|
||||
| highlight | Yellow bar wipes behind text | CSS bar + GSAP scaleX 0→1 |
|
||||
| circle | Hand-drawn red ring around word | CSS border ellipse + back.out scale |
|
||||
| burst | 12 radial spikes from word center | DOM line array, --len/--angle vars |
|
||||
| scribble | Wavy underline drawn over time | SVG `<path>` quadratic + stroke-dash GSAP |
|
||||
| sketchout | Cross-hatch x-out over text | Two 2px rotated lines |
|
||||
|
||||
### Grain / noise
|
||||
|
||||
- **grain-overlay** (registry component): SVG feTurbulence data-URL + CSS keyframe jitter, `steps(1)`, default opacity 0.15
|
||||
- **Layered radial-gradient grain** (preferred pattern): no SVG, no canvas-taint, fast everywhere
|
||||
|
||||
### Light / film
|
||||
|
||||
- Light leak transitions (CSS + shader variants)
|
||||
- Overexposure burn — `brightness()` ramp + flash overlay
|
||||
- Film burn — multi-layer amber/orange/red radials
|
||||
- Vignette — radial-gradient overlay
|
||||
- Paper texture (in registry/examples/warm-grain/)
|
||||
|
||||
### Glow
|
||||
|
||||
- Caption text glow: textShadow radius keyed to treble bands (always on active words only, never parents)
|
||||
- Radial glow backgrounds: CSS gradients / blurred blobs
|
||||
|
||||
---
|
||||
|
||||
## 6. Caption techniques
|
||||
|
||||
### Animation styles
|
||||
|
||||
- Baseline: per-word karaoke highlight (every energy level)
|
||||
- Intensity tiers: accent + glow + 15% scale (high energy) → 3% scale (low energy)
|
||||
- Exits by energy (dynamic-techniques.md): scatter, drop, collapse, fade+slide, fade
|
||||
- Tone mappings (captions.md): scale-pop `back.out(1.7)`, fade+slide `power3.out`, typewriter, bounce, `elastic.out`, word-by-word
|
||||
|
||||
### Per-word styling triggers
|
||||
|
||||
- Brand/product names
|
||||
- ALL CAPS
|
||||
- Numbers / stats
|
||||
- Emotional keywords
|
||||
- CTAs
|
||||
- Marker highlight modes (5 listed above)
|
||||
|
||||
### Audio sources for caption timing
|
||||
|
||||
| Source | Format | Granularity |
|
||||
| ------------------------------------------ | -------- | ----------------- |
|
||||
| hyperframes transcribe (local whisper.cpp) | JSON | Word-level |
|
||||
| OpenAI verbose_json | JSON | Word-level |
|
||||
| Groq verbose_json | JSON | Word-level |
|
||||
| Manually authored | JSON | Word-level |
|
||||
| SRT | text | Phrase-level only |
|
||||
| VTT | text | Phrase-level only |
|
||||
| hyperframes tts → transcribe chain | wav→json | Word-level |
|
||||
|
||||
### Positioning helpers
|
||||
|
||||
- Landscape: bottom 80–120px centered
|
||||
- Portrait: ~600–700px from bottom
|
||||
- `window.__hyperframes.fitTextFontSize(text, {maxWidth, fontFamily, fontWeight})` for dynamic sizing
|
||||
|
||||
---
|
||||
|
||||
## 7. Audio-reactive animation
|
||||
|
||||
### Data shape
|
||||
|
||||
```js
|
||||
window.AUDIO_DATA = {
|
||||
fps: 30,
|
||||
totalFrames: 900,
|
||||
frames: [{ bands: [0.42, 0.18, ...] }] // bands normalized 0–1 per band across track
|
||||
};
|
||||
```
|
||||
|
||||
Index 0 = bass, higher = treble. Bands range 0–1, normalized across full track length.
|
||||
|
||||
### Mappings documented
|
||||
|
||||
| Band | Property |
|
||||
| --------------------- | ---------------------------- |
|
||||
| Bass (bands[0–1]) | scale (pulse) |
|
||||
| Mid (bands[4–8]) | borderRadius, width |
|
||||
| Treble (bands[12–14]) | textShadow, boxShadow (glow) |
|
||||
| Overall amplitude | opacity, y, backgroundColor |
|
||||
|
||||
Any GSAP-tweenable property is fair game — including clipPath, filter, SVG attrs, CSS variables.
|
||||
|
||||
### Extraction
|
||||
|
||||
```bash
|
||||
python3 .../extract-audio-data.py audio.mp3 --fps 30 --bands 8
|
||||
```
|
||||
|
||||
Pre-extracted only — no Web Audio at render time.
|
||||
|
||||
### Banned in audio-reactive
|
||||
|
||||
EQ bars, spectrum UI, generic waveforms, note clip-art, generic particles, rainbow cycling, white strobe on beats, abstract pulsing orbs.
|
||||
|
||||
---
|
||||
|
||||
## 8. HTML-in-canvas
|
||||
|
||||
Documented in skills/hyperframes/references/html-in-canvas-patterns.md (504 lines).
|
||||
|
||||
### Capability
|
||||
|
||||
- Chrome's experimental `layoutSubtree` + `drawElementImage` rasterizes live DOM into canvas
|
||||
- Feature detection: `isHtmlInCanvasCaptureSupported()`
|
||||
- Used by shader-transitions for scene textures
|
||||
- Combined with Three.js: `CanvasTexture` + post-processing
|
||||
|
||||
### Available patterns
|
||||
|
||||
- HTML on a Three.js plane (displacement, distortion, liquid sim)
|
||||
- HTML in shaders (texture sampling for VFX)
|
||||
- Recursive HTML-in-canvas-in-shader-in-HTML
|
||||
|
||||
### Experimental VFX blocks using this
|
||||
|
||||
- `vfx-iphone-device` (GLTF iPhone + MacBook, HTML screens)
|
||||
- `vfx-liquid-background` (liquid sim displaces HTML)
|
||||
- `vfx-liquid-glass`
|
||||
- `vfx-magnetic`
|
||||
- `vfx-portal`
|
||||
- `vfx-shatter`
|
||||
- `vfx-text-cursor` (chromatic edges, canvas post)
|
||||
|
||||
---
|
||||
|
||||
## 9. Three.js / WebGL custom scenes
|
||||
|
||||
### Integration pattern
|
||||
|
||||
```js
|
||||
window.addEventListener("hf-seek", (e) => {
|
||||
const time = e.detail.time;
|
||||
mixer.setTime(time);
|
||||
shaderUniforms.u_time.value = time;
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
```
|
||||
|
||||
- Load: `import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.181.2/+esm"`
|
||||
- Deterministic: every frame must derive from `time`, never `requestAnimationFrame` / `Date.now()`
|
||||
- Includes: AnimationMixer, custom GLSL shaders, post-processing, GLTF models, lights, cameras, materials
|
||||
|
||||
---
|
||||
|
||||
## 10. SVG / canvas / variable fonts (other authored techniques)
|
||||
|
||||
(From skills/hyperframes/references/techniques.md)
|
||||
|
||||
| Technique | Mechanism |
|
||||
| ------------------------ | ------------------------------------------------------------------------------------ |
|
||||
| SVG path drawing | `strokeDasharray` + `getTotalLength()` + GSAP stroke offset |
|
||||
| Canvas 2D procedural art | Seeded hash function + `tl.to` proxy `{time}` onUpdate |
|
||||
| CSS 3D card | GSAP `rotationY` + `perspective: 900` |
|
||||
| Per-word kinetic type | GSAP timings array, sliding decay |
|
||||
| Variable font axes | Animate CSS vars → `font-variation-settings: "opsz" var(--opsz), "wght" var(--wght)` |
|
||||
| Character typing | `tl.call` text mutation + `steps(1)` cursor blink |
|
||||
| Velocity-matched cuts | Match outgoing blur/translate velocity to incoming for seamless beats |
|
||||
| MotionPathPlugin | `gsap.registerPlugin(MotionPathPlugin)` + path string |
|
||||
|
||||
---
|
||||
|
||||
## 11. Media: video, audio, TTS
|
||||
|
||||
### Video compositing
|
||||
|
||||
- `<video muted playsinline data-start="..." data-duration="..." data-track-index="..." src="...">`
|
||||
- HyperFrames extracts frames at render via videoFrameInjector (avoids unreliable headless `<video>` playback)
|
||||
- Linter forbids `<video>` with audio at the same time — split into separate `<video muted>` + `<audio>`
|
||||
- Video frame extraction uses FFmpeg
|
||||
- HDR videos: PQ or HLG transfer detection + x265 with mastering metadata
|
||||
|
||||
### Audio mixer
|
||||
|
||||
- `<audio id="..." data-start="..." data-duration="..." data-volume="0.8" data-track-index="2" src="...">`
|
||||
- Multiple tracks mixed with `amix normalize=0` + per-track adelay + volume
|
||||
- Master audioGain from EngineConfig
|
||||
- Output: AAC 192kbps
|
||||
|
||||
### TTS (Kokoro-82M, local)
|
||||
|
||||
- 54 bundled voices with prefixes: `a` American EN, `b` British EN, `e` Spanish, `f` French, `h` Hindi, `i` Italian, `j` Japanese, `p` Brazilian Portuguese, `z` Mandarin
|
||||
- Default voice: `af_heart`
|
||||
- Speed: 0.1–3.0 (default 1.0)
|
||||
- Languages: en-us, en-gb, es, fr-fr, hi, it, pt-br, ja, zh (non-EN needs system espeak-ng)
|
||||
- Output: WAV; no pitch/volume CLI flags
|
||||
- No API key required
|
||||
|
||||
### Transcription
|
||||
|
||||
- Whisper.cpp models: tiny, base, small, medium, large-v3, small.en, medium.en (default small)
|
||||
- Groq API: whisper-large-v3 with word granularities
|
||||
- OpenAI API: whisper-1 verbose_json
|
||||
- Imports: SRT, VTT, JSON formats
|
||||
- Quality gates: music-token detection, garbage cleaning, retry with medium.en
|
||||
|
||||
### Background removal
|
||||
|
||||
- u2net ONNX models
|
||||
- Devices: auto / cpu / coreml / cuda
|
||||
- Quality presets: fast / balanced / best
|
||||
- Outputs: transparent WebM, ProRes MOV, PNG sequence
|
||||
- Optional dual output (foreground + extracted background)
|
||||
|
||||
---
|
||||
|
||||
## 12. Registry — 51 blocks + 4 components + 8 examples
|
||||
|
||||
### Blocks by category
|
||||
|
||||
**Social overlays (8):** instagram-follow, tiktok-follow, yt-lower-third, x-post, reddit-post, spotify-card, macos-notification, blue-sweater-intro-video
|
||||
|
||||
**Showcases (5):** app-showcase (3D phones), north-korea-locked-down (map + annotation), apple-money-count (counter + SFX), vpn-youtube-spot (app-store scroll), nyc-paris-flight (map + plane path)
|
||||
|
||||
**Data viz (2):** data-chart (animated bar+line, NYT-style), flowchart + flowchart-vertical (decision tree with SVG connectors, typing correction)
|
||||
|
||||
**Logo / branding (1):** logo-outro (build + glow + tagline + URL pill)
|
||||
|
||||
**3D / experimental VFX (8):** ui-3d-reveal, vfx-iphone-device (GLTF), vfx-liquid-background, vfx-liquid-glass, vfx-magnetic, vfx-portal, vfx-shatter, vfx-text-cursor
|
||||
|
||||
**Single shader transitions (14):** one block per named shader — domain-warp-dissolve, ridged-burn, whip-pan, sdf-iris, ripple-waves, gravitational-lens, cinematic-zoom, chromatic-radial-split, glitch, swirl-vortex, thermal-distortion, flash-through-white, cross-warp-morph, light-leak
|
||||
|
||||
**Transition galleries (13 showcase pieces):** transitions-3d, transitions-blur, transitions-cover, transitions-destruction, transitions-dissolve, transitions-distortion, transitions-grid, transitions-light, transitions-mechanical, transitions-other, transitions-push, transitions-radial, transitions-scale
|
||||
|
||||
### Components (4 reusable snippets)
|
||||
|
||||
- **grain-overlay** — SVG feTurbulence + CSS keyframes
|
||||
- **shimmer-sweep** — Light sweep gradient mask on text
|
||||
- **grid-pixelate-wipe** — Grid squares stagger fade scene wipe
|
||||
- **texture-mask-text** — Luminance-masked letterforms with 66 mask PNGs (Masonry, Stone, Ground/Road, Wood, Metal, Organic/Soft texture categories)
|
||||
|
||||
### Examples (8 starter projects)
|
||||
|
||||
warm-grain, play-mode, swiss-grid, vignelli, decision-tree, kinetic-type, product-promo, nyt-graph
|
||||
|
||||
Install: `npx hyperframes add <name>` for blocks/components, `hyperframes init <dir> --example <name>` for examples.
|
||||
|
||||
---
|
||||
|
||||
## 13. CLI — 25 commands
|
||||
|
||||
| Command | Purpose |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| init | Scaffold project from template/example (interactive or --non-interactive) |
|
||||
| add | Install registry block / component |
|
||||
| catalog | Browse registry blocks/components (--type, --tag, --json, --human-friendly picker) |
|
||||
| play | Lightweight browser player (default port 3003) |
|
||||
| preview | Studio dev server (port 3002; --force-new, --list, --kill-all) |
|
||||
| publish | Zip + upload + return hyperframes.dev URL |
|
||||
| render | Render to MP4 / WebM / MOV / PNG sequence — flags: --fps 24/30/60, --quality draft/standard/high, --workers, --docker, --hdr/--sdr, --crf, --video-bitrate, --gpu, --browser-gpu auto/software/hardware, --max-concurrent-renders 1-10, --variables JSON, --variables-file PATH, --strict-variables, --resolution preset |
|
||||
| lint | Static lint (--json, --verbose) |
|
||||
| validate | Bundle + headless Chrome + console + contrast (--contrast default true, --timeout 3000) |
|
||||
| inspect / layout | Visual layout audit (overflow detection at N timestamps; --samples 9, --at, --tolerance 2, --max-issues 80) |
|
||||
| info | Print project metadata |
|
||||
| compositions | List compositions (root + sub-comps) |
|
||||
| benchmark | 5 preset configs × N runs (--runs 3) |
|
||||
| browser | Manage Chrome (ensure/path/clear) |
|
||||
| remove-background | u2net + FFmpeg → transparent video |
|
||||
| transcribe | whisper.cpp or import SRT/VTT/JSON |
|
||||
| tts | Kokoro-82M (--voice, --speed, --lang, --list) |
|
||||
| docs | Print bundled markdown topics (data-attributes, examples, rendering, gsap, troubleshooting, compositions) |
|
||||
| doctor | Environment checklist (Node, CPU, memory, disk, FFmpeg, FFprobe, Chrome, Docker) |
|
||||
| upgrade | npm update check + optional global install |
|
||||
| skills | Run `npx skills add heygen-com/hyperframes --all` |
|
||||
| telemetry | enable/disable/status |
|
||||
| snapshot | PNG screenshots at timeline timestamps |
|
||||
| capture | Capture URL → site assets + screenshots + design tokens (uses Puppeteer + optional Gemini vision) |
|
||||
|
||||
### Website capture (`hyperframes capture <url>`)
|
||||
|
||||
Detects these libraries on captured sites (for context labeling): GSAP / ScrollTrigger, Three.js, Lottie, Anime.js, PixiJS, Babylon.js, Rive, Matter.js, Lenis, Framer Motion, Tailwind CSS, WebGL (shader fingerprinting). Captured outputs feed the website-to-hyperframes skill workflow.
|
||||
|
||||
---
|
||||
|
||||
## 14. Linter — 60+ rules
|
||||
|
||||
Across 8 files in packages/core/src/lint/rules/:
|
||||
|
||||
| Rule file | Catches |
|
||||
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| core | Missing composition-id, missing dimensions, missing timeline registry, registry mismatch, invalid script syntax, scoped-CSS issues, non-deterministic code |
|
||||
| media | Duplicate media id, video missing muted, video nested in timed element, placeholder URLs, base64 prohibited, missing src/start/id, imperative play()/pause()/seek() |
|
||||
| gsap | Overlapping tweens, exit missing hard kill, GSAP animating .clip element, unscoped selectors, CSS transform conflict, missing GSAP script, infinite repeat (repeat: -1), repeat ceil overshoot, scene layer visibility kill, audio-reactive single-tween-per-group |
|
||||
| captions | Caption exit missing kill, text overflow risk, transcript not inline, parse error, container position, scale mismatch, textShadow on parent container |
|
||||
| composition | File too large, dense tracks, missing class="clip", deprecated data-layer/data-end, split attribute selectors, external script deps, RAF in composition, invalid variable JSON |
|
||||
| adapters | Missing Lottie script, missing Three script |
|
||||
| textures | Drop-shadow on text, class missing base, text missing mask, unknown texture class |
|
||||
| fonts | Google Fonts import (use @font-face), font-family without @font-face |
|
||||
|
||||
Plus async URL checks (`lintMediaUrls`, `lintScriptUrls` — HEAD probes).
|
||||
|
||||
`validateCompositionGsap` also forbids: `Math.random`, `Date.now`, `new Date`, `setTimeout`, `setInterval`, `requestAnimationFrame`, `repeat: -1`.
|
||||
|
||||
**Note:** `onUpdate` callbacks, `tl.call()`, and GSAP event callbacks (`onComplete`, `onStart`, etc.) are NOT banned by the linter — they are required for canvas/WebGL rendering and character-by-character typing patterns. The linter only catches the determinism violations listed above.
|
||||
|
||||
---
|
||||
|
||||
## 15. Player — `<hyperframes-player>` web component
|
||||
|
||||
### Attributes
|
||||
|
||||
`src`, `srcdoc`, `width`, `height`, `controls`, `muted`, `volume`, `poster`, `playback-rate`, `audio-src`, `shader-capture-scale`, `shader-loading` (internal|player|none), `loop`, `autoplay`, `speed-presets`
|
||||
|
||||
### Public API
|
||||
|
||||
`seek(t)` (synchronous when same-origin — uses `iframe.contentWindow.__player.seek` directly), `play()`, `pause()`, `currentTime`, `duration`, `paused`, `ready`, `playbackRate`, `iframeElement`
|
||||
|
||||
### Events
|
||||
|
||||
`ready`, `timeupdate`, `play`, `pause`, `ended`, `volumechange`, `ratechange`, `shadertransitionstate`, `playbackerror`, `error`, `audioownershipchange`
|
||||
|
||||
### Media mirror
|
||||
|
||||
Parent audio/video elements with `data-start` are proxied; `_mirrorParentMediaTime` corrects drift; `_audioOwner` promotes to parent if autoplay blocked.
|
||||
|
||||
### Runtime auto-inject
|
||||
|
||||
Loads `RUNTIME_CDN_URL` (`@hyperframes/core/dist/hyperframe.runtime.iife.js`) if missing `__hf`/`__player` but timelines exist.
|
||||
|
||||
---
|
||||
|
||||
## 16. Engine + Producer — rendering pipeline
|
||||
|
||||
### Output formats
|
||||
|
||||
mp4, webm, mov, png-sequence — with HDR (PQ / HLG / SDR / auto-detect), transparency (ProRes MOV / WebM / PNG), or standard 8-bit SDR
|
||||
|
||||
### Encoding controls
|
||||
|
||||
- `--fps`: 24 / 30 / 60
|
||||
- `--quality`: draft / standard / high
|
||||
- `--crf`: integer (mutually exclusive with `--video-bitrate`)
|
||||
- `--video-bitrate`: e.g. `8M`
|
||||
- `--gpu`: NVENC, VideoToolbox, VAAPI, QSV
|
||||
- `--browser-gpu`: auto / software / hardware
|
||||
- `--workers`: parallel render workers
|
||||
- `--max-concurrent-renders`: 1–10 (sets `PRODUCER_MAX_CONCURRENT_RENDERS`)
|
||||
- `--resolution`: preset (1080p, 4k, portrait, etc.)
|
||||
- `--docker`: render inside Dockerfile.test image (reproducibility)
|
||||
- `--hdr` / `--sdr`: force HDR or SDR pipeline
|
||||
|
||||
### Engine subsystems
|
||||
|
||||
- Frame capture: BeginFrame on Linux headless-shell (fast, no alpha) or `Page.captureScreenshot` (alpha + supersample)
|
||||
- Video frame injector: pre-extracts video to images, swaps `<video>` for `<img>` during capture (LRU cache by path + byte budget)
|
||||
- Audio mixer: FFmpeg-based; per-track delay, volume, master gain, AAC 192k output
|
||||
- Chunk encoder: H.264 / H.265 / VP9 / ProRes presets with optional GPU
|
||||
- Streaming encoder: `streamingEncodeMaxDurationSeconds` for long renders
|
||||
- HDR compositing: `rgba16float` WebGPU readback (headed Chrome), PQ OETF helpers
|
||||
- Layer compositor: groups DOM by z-order; splits HDR elements into separate layers
|
||||
- Alpha blit: matrix3d affine extraction, `blitRgba8OverRgb48le`, `blitRgb48leAffine`
|
||||
- Parallel coordinator: concurrency, coresPerWorker, minParallelFrames, largeRenderThreshold
|
||||
- Browser pool: optional with timeout configs
|
||||
|
||||
### Producer-only
|
||||
|
||||
- `RenderConfig` with `hdrMode` (auto / force-hdr / force-sdr), `outputResolution` mapped to `deviceScaleFactor`
|
||||
- File server injects `HF_EARLY_STUB`, `HF_BRIDGE_SCRIPT`, virtual-time so `window.__hf` bridges `window.__player.renderSeek`
|
||||
- HDR-aware shader transition compositing via `window.__hf.transitions` metadata
|
||||
|
||||
---
|
||||
|
||||
## 17. Studio — in-browser NLE
|
||||
|
||||
Full editor in packages/studio/:
|
||||
|
||||
- **NLELayout**: NLE preview + timeline + controls
|
||||
- **Timeline**: clip rendering, drag to move (`data-start`), resize (`data-duration`), `data-track-index` reassignment, asset drop, file drop
|
||||
- **PlayerControls**: scrub, play, pause, frame step (`stepFrameTime`), `STUDIO_PREVIEW_FPS`
|
||||
- **useTimelinePlayer**: resolves `__player` / `__timeline` / `__timelines`
|
||||
- **LeftSidebar**: compositions list, asset browser
|
||||
- **RenderQueue + useRenderQueue**: queue multiple renders
|
||||
- **LintModal**: in-app lint output
|
||||
- **MediaPreview + AudioWaveform**: waveform rendering
|
||||
- **CaptionOverlay, CaptionTimeline, CaptionPropertyPanel**: caption editor
|
||||
- **useCaptionSync**: word-level sync
|
||||
- **useElementPicker**: click-to-inspect picker mode
|
||||
- Built with Tailwind v3 (separate from Tailwind v4 browser runtime used by compositions).
|
||||
|
||||
---
|
||||
|
||||
## 18. Determinism guarantees
|
||||
|
||||
- No `Math.random()` (use seeded PRNGs; mulberry32 is the pattern in skills)
|
||||
- No `Date.now()` / `new Date()`
|
||||
- No `setTimeout` / `setInterval` in timeline construction
|
||||
- No `requestAnimationFrame` (timeline-driven; engine seeks per frame)
|
||||
- No `repeat: -1` (calculate exact repeats: `Math.ceil(duration / cycleDuration) - 1`)
|
||||
- No `tl.call(fn)` / `tl.add(function)` / `onComplete`/`onStart`/`onUpdate`/`onRepeat` callbacks (engine doesn't fire them)
|
||||
- No `gsap.set` on clips from later scenes (use `tl.set(selector, vars, position)`)
|
||||
- Synchronous timeline construction (no async)
|
||||
- Master clock can clamp at composition end
|
||||
|
||||
---
|
||||
|
||||
## 19. Variables / parameterization
|
||||
|
||||
Compositions support typed runtime variables:
|
||||
|
||||
```html
|
||||
<html
|
||||
data-composition-variables='[
|
||||
{"name":"brand","type":"string","default":"Stripe"},
|
||||
{"name":"primary","type":"color","default":"#635BFF"},
|
||||
{"name":"duration","type":"number","default":15},
|
||||
{"name":"darkMode","type":"boolean","default":false},
|
||||
{"name":"layout","type":"enum","options":["hero","split","stacked"]}
|
||||
]'
|
||||
></html>
|
||||
```
|
||||
|
||||
Access via `window.__hyperframes.getVariables()`. Override at render time:
|
||||
|
||||
```bash
|
||||
npx hyperframes render --variables '{"brand":"Linear","primary":"#5E6AD2"}'
|
||||
npx hyperframes render --variables-file vars.json
|
||||
npx hyperframes render --strict-variables # error if unused / mismatched
|
||||
```
|
||||
|
||||
`validateVariables()` checks values against declarations at the CLI/tooling boundary.
|
||||
|
||||
---
|
||||
|
||||
## 20. Sub-compositions
|
||||
|
||||
Two loading mechanisms:
|
||||
|
||||
- **External file:** `data-composition-src="compositions/act-1.html"` — fetched at runtime
|
||||
- **Inline template:** `<template id="<id>-template">` — extracted by `loadInlineTemplateCompositions`
|
||||
|
||||
Each sub-comp:
|
||||
|
||||
- Has its own `data-composition-id`
|
||||
- Has its own `window.__timelines[<id>]`
|
||||
- Auto-nested into the root timeline
|
||||
- Scoped CSS via `scopeCssToComposition` (`[data-composition-id="<id>"]` selector)
|
||||
- Wrapped scripts via `wrapScopedCompositionScript`
|
||||
- Reads `data-variable-values` merged with own defaults into `window.__hfVariablesByComp[<id>]`
|
||||
- External scripts load with `EXTERNAL_SCRIPT_LOAD_TIMEOUT_MS` timeout. Failed loads emit `external_composition_load_failed` / `external_composition_script_load_issue` diagnostics.
|
||||
|
||||
---
|
||||
|
||||
## 21. Global runtime APIs (`window.*`)
|
||||
|
||||
| Global | Purpose |
|
||||
| ------------------------------------- | ----------------------------------------------------------------------- |
|
||||
| `__hyperframes` | `{ fitTextFontSize, getVariables }` |
|
||||
| `__timelines` | `{ [compositionId]: GsapTimeline }` |
|
||||
| `__player` | Internal player bridge: seek, play, pause, renderSeek, etc. |
|
||||
| `__clipManifest` | Computed clip array (for Studio) |
|
||||
| `__playerReady` | Resolved when player ready |
|
||||
| `__renderReady` | Resolved when ready for render capture |
|
||||
| `__HF_PARITY_MODE` | Engine parity flag |
|
||||
| `__HF_FPS` | Render FPS hint |
|
||||
| `__HF_MAX_DURATION_SEC` | Engine clamp |
|
||||
| `__HF_VIRTUAL_TIME__` | Set by engine in render mode (shader-transitions switches paths) |
|
||||
| `__hfThreeTime` | Current time for Three.js adapter |
|
||||
| `__HF_PICKER_API` | Element picker hook for Studio |
|
||||
| `__hfAnime` | Array of Anime.js instances |
|
||||
| `__hfLottie` | Array of Lottie animations |
|
||||
| `__hfVariables` | Resolved root variables |
|
||||
| `__hfVariablesByComp` | Per-composition variable map |
|
||||
| `__hfRuntimeTeardown` | Cleanup function |
|
||||
| `__tailwindReady` | Tailwind browser build ready (gates capture) |
|
||||
| `__hf.transitions` | Shader transition metadata (read by producer for HDR-aware compositing) |
|
||||
| `__beforeTimeline`, `__afterTimeline` | Optional user hooks |
|
||||
| `__afterRender`, `__beforeRender` | Optional user hooks |
|
||||
| `gsap`, `THREE`, `anime`, `lottie` | Library globals |
|
||||
|
||||
Control bridge actions: play, pause, seek, set-muted, set-playback-rate, enable-pick-mode, disable-pick-mode, set-volume, set-media-output-muted.
|
||||
|
||||
---
|
||||
|
||||
## 22. Skills available — 16
|
||||
|
||||
| Skill | Purpose |
|
||||
| ------------------------- | ----------------------------------------------------------------------- |
|
||||
| hyperframes | Core framework skill (composition authoring) |
|
||||
| hyperframes-cli | All CLI commands as an agent skill |
|
||||
| hyperframes-media | Media workflows (TTS, transcribe, captions integration) |
|
||||
| hyperframes-registry | Installing blocks/components |
|
||||
| hyperframes-contrast | WCAG audit (scripts/contrast-report.mjs) |
|
||||
| hyperframes-animation-map | Per-tween bbox + flags report |
|
||||
| website-to-hyperframes | Capture → DESIGN.md → brief → storyboard+script → VO → build → validate |
|
||||
| remotion-to-hyperframes | Migration patterns + API map + CustomEase |
|
||||
| gsap | GSAP API + plugins reference |
|
||||
| animejs | Anime.js v4 patterns |
|
||||
| css-animations | @keyframes patterns |
|
||||
| waapi | Web Animations API |
|
||||
| lottie | Lottie integration |
|
||||
| three | Three.js + deterministic seek |
|
||||
| tailwind | Tailwind browser runtime v4 |
|
||||
| contribute-catalog | Adding blocks to registry |
|
||||
|
||||
---
|
||||
|
||||
## 23. References inventory (skills/hyperframes/references/)
|
||||
|
||||
16 reference docs covering:
|
||||
|
||||
- text-effects.md — 24 named text animation effects (per-character, per-word, per-line, whole) with exact GSAP specs; bundled in `assets/text-effects/`
|
||||
- transitions.md + transitions/catalog.md + 14 category subfiles
|
||||
- css-patterns.md (marker patterns)
|
||||
- dynamic-techniques.md (caption animation)
|
||||
- motion-principles.md (easing as emotion, choreography)
|
||||
- typography.md (banned-font list, pairing rules, variable fonts)
|
||||
- narration.md (script + VO pacing)
|
||||
- captions.md (caption authoring contract)
|
||||
- audio-reactive.md (band mappings + extraction)
|
||||
- transcript-guide.md (whisper, Groq, OpenAI workflows)
|
||||
- techniques.md (the big technique catalog — SVG, canvas 2D, 3D, kinetic, lottie, variable fonts, MotionPath, audio-reactive)
|
||||
- beat-direction.md, design-picker.md, prompt-expansion.md, video-composition.md
|
||||
- visual-styles.md (8 named visual styles: Swiss Pulse, Velvet Standard, Deconstructed, Maximalist Type, Data Drift, Soft Signal, Folk Frequency, Shadow Cut — available via the `visual-style` skill)
|
||||
|
||||
---
|
||||
|
||||
## 24. Documentation pages (docs/)
|
||||
|
||||
27 mdx pages in docs/guides/ and docs/packages/:
|
||||
|
||||
**Guides:** 4k-rendering, claude-design, common-mistakes, deploy, gsap-animation, hdr, html-in-canvas, hyperframes-vs-remotion, open-design, performance, prompting, remove-background, rendering, timeline-editing, troubleshooting, video-editor-cheatsheet, website-to-video, etc.
|
||||
|
||||
**Packages:** cli.mdx, core.mdx, engine.mdx, player.mdx, producer.mdx, studio.mdx
|
||||
@@ -0,0 +1,92 @@
|
||||
# Step 0: Capture & Understand the Brand
|
||||
|
||||
You're capturing the site **to understand a brand and a product** — not to inventory building blocks. Reading the assets tells you what the product is, who it's for, what voice the brand speaks in, and what mood it lives in. That understanding is the strategic foundation for the video; the assets themselves are decoration the storyboard will reach for late, only where they serve the concept. **The video is not a recombination of the captured assets.**
|
||||
|
||||
## Run the capture
|
||||
|
||||
No API keys required for the base capture. However, before running, ask the user:
|
||||
|
||||
> "For the best results, it is recommended to set a Gemini API key — it gives me AI-powered descriptions of every captured image, which helps me choose the right assets for each scene. It costs about $0.001 per image. You can skip this if you want, but the video quality will be better with it. To set it up: add `GEMINI_API_KEY=your-key` to a `.env` file in the project root. You can get a free key at ai.google.dev."
|
||||
|
||||
If the user provides the key or already has one set, proceed. If they skip it, proceed anyway — the capture works without it, but `asset-descriptions.md` will have DOM-context descriptions only (position, size, alt text) instead of AI vision descriptions (what the image actually shows).
|
||||
|
||||
Create a project directory for your video if it doesn't exist yet, then capture the website into a `capture/` subfolder within it:
|
||||
|
||||
```bash
|
||||
# ⚠ ALWAYS use the local CLI — never `npx hyperframes capture`:
|
||||
npx tsx packages/cli/src/cli.ts capture <URL> -o <project-dir>/capture
|
||||
```
|
||||
|
||||
Example: `npx tsx packages/cli/src/cli.ts capture https://stripe.com -o videos/stripe-launch/capture`
|
||||
|
||||
Keeping the capture artifacts (`screenshots/`, `assets/`, `extracted/`, `AGENTS.md`, `CLAUDE.md`) in a dedicated `capture/` subfolder keeps them isolated from the later build files (`SCRIPT.md`, `STORYBOARD.md`, `DESIGN.md`, `compositions/`, `index.html`, `narration.wav`, `transcript.json`, `renders/`, `snapshots/`), which all live at `<project-dir>/` root.
|
||||
|
||||
For exploratory captures that aren't becoming a video yet, `-o captures/<name>` at the repo root is fine — the isolation convention only matters when you're building a video on top of the capture.
|
||||
|
||||
Wait for the capture to complete. Print how many screenshots, assets, sections, and fonts were extracted.
|
||||
|
||||
## Read and summarize
|
||||
|
||||
Read every file below. After each one, **write a 3-4 sentence summary** of what you learned. These summaries carry forward — the raw file content may be cleared from context later, and your summaries are what keep the capture data usable through the rest of the pipeline.
|
||||
|
||||
### Read these
|
||||
|
||||
1. **View the contact sheets — carefully, every cell, not a glance.** Contact sheets are labeled grids that let you see many images at once. They are paginated: look for `contact-sheet-1.jpg`, `contact-sheet-2.jpg`, etc. (or `contact-sheet.jpg` for older captures). View ALL pages for each category. **For each page, name at least 5 specific assets you can see in it before moving on** — this forces you to actually look at every cell instead of scrolling past. Past agents have reported "viewed the contact sheet" after literally one glance, then later in Step 3 they wrote beats using assets that didn't exist or missed the brand logo entirely. Don't be that agent. The contact sheet is your single best opportunity to learn what's actually available in the capture.
|
||||
- `capture/screenshots/contact-sheet-*.jpg` — scroll screenshots grid. View FIRST. Each cell numbered with scroll percentage. List the directory if unsure how many pages exist.
|
||||
- `capture/assets/contact-sheet-*.jpg` — all downloaded raster images grid. Each cell labeled with filename.
|
||||
- `capture/assets/svgs/contact-sheet-*.jpg` — all SVGs rendered as thumbnails. Each cell labeled with filename. Check `capture/assets/` root too — some captures store SVGs there instead of `svgs/`.
|
||||
|
||||
After viewing the screenshot contact sheets, write 3-4 sentences describing the site's visual mood, layout patterns, color strategy, and overall feel. Then list, by filename, the 5-10 captured assets that look most promising for video use (logo, hero illustration, brand mark, gradient backgrounds, product art). **Open and view those promising assets individually** — the contact sheet thumbnails are too small to judge fine detail, but once you've narrowed to the 5-10 candidates, read each one carefully. Don't just trust the thumbnail.
|
||||
|
||||
2. **`capture/extracted/tokens.json`** — Note the top 5-7 colors (HEX), all font families with their weights (e.g. `Inter (400,700)` or `Sohne (100-900 variable)`), number of sections, and number of headings/CTAs.
|
||||
|
||||
3. **`capture/extracted/design-styles.json`** — Computed styles extracted from live DOM elements. Contains: typography hierarchy (every text role with exact font-size, weight, line-height, letter-spacing), button variants (background, padding, radius, shadow), card/container styles, navigation styles, spacing scale with base unit, border-radius scale, and box-shadow values with usage counts. This is your primary data source for writing DESIGN.md Sections 3-6.
|
||||
|
||||
4. **`capture/extracted/visible-text.txt`** — Each line is prefixed with the HTML tag: `[h1] Heading`, `[p] Body text`, `[a] Link text`. Use these tags to understand hierarchy — headings are key messages, paragraphs are supporting copy. Strip the `[tag]` prefix if quoting text in the script.
|
||||
|
||||
5. **`capture/extracted/asset-descriptions.md`** — One-line-per-file summary of all downloaded assets. Note which assets are most visually striking or useful for video.
|
||||
|
||||
6. **`capture/extracted/fonts-manifest.json`** — Each downloaded font identified by its real family name (read from the binary's OpenType `name` table, so hashed Next.js/Webpack filenames are resolved automatically). Lists per-family aggregates with weights, variable-font axes, and file counts. Read this in Step 1 instead of guessing fonts from filenames. If the manifest's `unidentified[]` is empty, every captured font has a known identity. Skip the file if it doesn't exist (older captures).
|
||||
|
||||
### Required to check and read IF they exist
|
||||
|
||||
7. **`capture/extracted/animations.json`** — See for yourself if the site uses scroll-triggered animations, marquees, canvas/WebGL, or named CSS animations. Just good to know.
|
||||
|
||||
8. **`capture/extracted/lottie-manifest.json`** — View each preview image at `capture/assets/lottie/previews/` to see what the animations look like. It will help you think of what you can do in the video.
|
||||
|
||||
9. **`capture/extracted/video-manifest.json`** — View each preview at `capture/assets/videos/previews/` to see what each video shows.
|
||||
|
||||
10. **`capture/extracted/shaders.json`** — If present, this contains the actual GLSL shader code that powers the site's WebGL visual effects (gradient waves, particle systems, noise fields). Read the fragment shaders to extract: color values used in gradients, noise algorithms, blend functions. You are able to recreate similar effects in your compositions using Canvas 2D, Three.js, HTML-in-canvas or by embedding the shader patterns with a `<canvas>` + WebGL context. Absolutely read the patterns in `techniques.md`!!
|
||||
|
||||
### Required On-demand (only when actually needed in Step 5)
|
||||
|
||||
11. **Individual images in `capture/assets/`** — The contact sheet pages cover all assets. Only open an individual file when:
|
||||
- You are placing text over a screenshot and need to check the safe zone / exact content at full resolution
|
||||
- A storyboard-assigned asset's contact sheet thumbnail is too small to judge its content
|
||||
|
||||
Do NOT batch-view individual assets at this stage. That is what the contact sheets are for.
|
||||
|
||||
### For rich captures (30+ images)
|
||||
|
||||
If asset-descriptions.md has mostly bare descriptions (no AI vision — check if entries say things like 'icon: icon 0' instead of actual descriptions), launch a sub-agent to view and describe all of those.
|
||||
|
||||
## Carry-forward to Step 1
|
||||
|
||||
After reading `tokens.json` and `design-styles.json` here, **summarize the key values** (top colors, font families, key component styles) in your step-0 site summary. Step 1 reads your summary — it does NOT re-read these files. If your summary is thorough, Step 1 can write DESIGN.md without opening them again.
|
||||
|
||||
## Gate
|
||||
|
||||
Print your site summary before proceeding to Step 1. The summary is **strategy-first, not asset-first**:
|
||||
|
||||
- **Site:** [name]
|
||||
- **What the product does:** [one sentence — the product's actual job, what problem it solves]
|
||||
- **Who it's for:** [audience — developers, designers, ops teams, consumers, enterprise, etc.]
|
||||
- **Core value prop:** [the one promise the homepage makes — what the brand is selling, in their own words if visible-text supports it]
|
||||
- **Brand voice:** [one phrase — confident/playful/clinical/premium/urgent/etc., grounded in the copy you read]
|
||||
- **Visual identity:** [one sentence — dominant mood, e.g. "dark cinematic with single saturated accent" or "white-and-color clean consumer"]
|
||||
- **Colors:** [top 3-5 HEX values with roles]
|
||||
- **Fonts:** [font families]
|
||||
- **Sections:** [count] sections, [count] headings, [count] CTAs
|
||||
- **Notable captured assets:** [3-5 assets worth remembering as potential brand accents — typically logo, hero illustration, gradient, brand mark. Note these are candidates, not assignments. Most won't make it into the final video.]
|
||||
|
||||
The first 5 bullets are the strategic frame — they tell you what video to make. The last 4 are the brand toolkit you'll inflect that video with.
|
||||
@@ -1,74 +0,0 @@
|
||||
# Step 1: Capture & Understand
|
||||
|
||||
## Run the capture
|
||||
|
||||
Create a project directory for your video, then capture the website into a `capture/` subfolder within it:
|
||||
|
||||
```bash
|
||||
npx hyperframes capture <URL> -o <project-dir>/capture
|
||||
```
|
||||
|
||||
Example: `npx hyperframes capture https://stripe.com -o videos/stripe-launch/capture`
|
||||
|
||||
Keeping the capture artifacts (`screenshots/`, `assets/`, `extracted/`, `AGENTS.md`, `CLAUDE.md`) in a dedicated `capture/` subfolder keeps them isolated from the later build files (`SCRIPT.md`, `STORYBOARD.md`, `DESIGN.md`, `compositions/`, `index.html`, `narration.wav`, `transcript.json`, `renders/`, `snapshots/`), which all live at `<project-dir>/` root.
|
||||
|
||||
For exploratory captures that aren't becoming a video yet, `-o captures/<name>` at the repo root is fine — the isolation convention only matters when you're building a video on top of the capture.
|
||||
|
||||
No API keys required. The capture extracts design tokens, screenshots, fonts, and assets with DOM-context descriptions automatically.
|
||||
|
||||
**Optional:** Set `GEMINI_API_KEY` (or `GOOGLE_API_KEY`) in a `.env` file at the repo root for richer AI-powered image descriptions via Gemini 3.1 Flash Lite vision (~$0.001/image).
|
||||
|
||||
Wait for it to complete. Print how many screenshots, assets, sections, and fonts were extracted.
|
||||
|
||||
## Read and summarize
|
||||
|
||||
Read each file below. After reading each one, **write a 1-2 sentence summary** of what you learned. These summaries are your working memory — the raw file content may be cleared from context later.
|
||||
|
||||
### Must read (do not skip)
|
||||
|
||||
1. **View the scroll screenshots** — viewport-sized captures covering the full page height (the number depends on the page length). Start with:
|
||||
- `capture/screenshots/scroll-000.png` — the hero section at full 1920x1080 resolution. This is the most important image. Describe: is the background light or dark? What's the dominant visual element? What colors jump out?
|
||||
- Then scan through the rest to see the full page. Each screenshot overlaps the previous by ~30%.
|
||||
|
||||
After viewing them, write 3-4 sentences describing the site's visual mood, layout patterns, color strategy, and overall feel.
|
||||
|
||||
2. **`capture/extracted/tokens.json`** — Note the top 5-7 colors (HEX), all font families with their weights (e.g. `Inter (400,700)` or `Sohne (100-900 variable)`), number of sections, and number of headings/CTAs.
|
||||
|
||||
3. **`capture/extracted/visible-text.txt`** — Each line is prefixed with the HTML tag: `[h1] Heading`, `[p] Body text`, `[a] Link text`. Use these tags to understand hierarchy — headings are key messages, paragraphs are supporting copy. Strip the `[tag]` prefix when quoting text in the script.
|
||||
|
||||
4. **`capture/extracted/asset-descriptions.md`** — One-line-per-file summary of all downloaded assets. Note which assets are most visually striking or useful for video (hero images, logos, product screenshots).
|
||||
|
||||
### Read if they exist
|
||||
|
||||
5. **`capture/extracted/animations.json`** — Note if the site uses scroll-triggered animations, marquees, canvas/WebGL, or named CSS animations.
|
||||
|
||||
6. **`capture/extracted/lottie-manifest.json`** — View each preview image at `capture/assets/lottie/previews/` to see what the animations look like.
|
||||
|
||||
7. **`capture/extracted/video-manifest.json`** — View each preview at `capture/assets/videos/previews/` to see what each video shows.
|
||||
|
||||
8. **`capture/extracted/shaders.json`** — If present, this contains the actual GLSL shader code that powers the site's WebGL visual effects (gradient waves, particle systems, noise fields). Read the fragment shaders to extract: color values used in gradients, noise algorithms, blend functions. You can recreate similar effects in your compositions using Canvas 2D or by embedding the shader patterns with a `<canvas>` + WebGL context. See the Canvas 2D and procedural art patterns in `techniques.md`.
|
||||
|
||||
### On-demand (read when building scenes)
|
||||
|
||||
9. **Individual images in `capture/assets/`** — Use `capture/extracted/asset-descriptions.md` as your index. View specific images when you need them for a beat.
|
||||
|
||||
10. **`capture/extracted/assets-catalog.json`** — Use to find remote URLs when you need an asset that wasn't downloaded.
|
||||
|
||||
### For rich captures (30+ images)
|
||||
|
||||
Launch a sub-agent to view all images and SVGs:
|
||||
|
||||
> "Read every image in capture/assets/ and every SVG in capture/assets/svgs/. For each, write one line: filename — what it shows, dominant colors, approximate size. Return the complete catalog."
|
||||
|
||||
Use the sub-agent's catalog as your asset reference for the rest of the workflow.
|
||||
|
||||
## Gate
|
||||
|
||||
Print your site summary before proceeding to Step 2:
|
||||
|
||||
- **Site:** [name]
|
||||
- **Colors:** [top 3-5 HEX values with roles]
|
||||
- **Fonts:** [font families]
|
||||
- **Sections:** [count] sections, [count] headings, [count] CTAs
|
||||
- **Key assets:** [3-5 most useful assets for video]
|
||||
- **Vibe:** [one sentence describing the visual identity]
|
||||
@@ -0,0 +1,317 @@
|
||||
# Step 1: Write DESIGN.md (the brand-truth cheat sheet)
|
||||
|
||||
DESIGN.md is a **brand-truth cheat sheet** — colors and fonts you'll **weave into your composed builds**. It is NOT a layout spec, not a moodboard, not a 400-line design system audit.
|
||||
|
||||
DESIGN.md is the brand inflection sub-agents layer on top of every composed beat: which color is "primary," which font is "headlines," what tone the brand carries — the load-bearing knobs they flip while building. The beats themselves are composed from divs/SVG/CSS at build time; DESIGN.md tells them in which colors and which fonts.
|
||||
|
||||
**Target length: 250–350 lines.** Sub-agents in Step 5 compose UIs from scratch (divs/SVG/CSS) using your DESIGN.md as the spec — the more precise the component CSS values you encode here, the more brand-faithful the composed beats will look. Going under 200 lines tends to produce generic-looking dark-cinematic videos because sub-agents have no brand component DNA to compose with.
|
||||
|
||||
**User preferences always override brand rules.** If the user says "make it bright even though the site is dark" or "use serif fonts even though the brand is sans" — follow the user. DESIGN.md describes the captured website. The video might deliberately break that.
|
||||
|
||||
You read `tokens.json` and `design-styles.json` in Step 0. If you remember the values, use them; if not, re-read. Don't guess.
|
||||
|
||||
**Font availability check — do this before writing anything else.** Read `capture/extracted/fonts-manifest.json`. The capture pipeline reads the OpenType `name` table embedded in every downloaded font file, so even hash-renamed Next.js/Webpack fonts are identified by their real family name (Inter, JetBrains Mono, Geist Mono, etc.). No guessing required.
|
||||
|
||||
The manifest gives you two views:
|
||||
|
||||
- `families[]` — one entry per distinct family with the weights captured, whether it's a variable font, and the files belonging to it
|
||||
- `files[]` — one entry per downloaded font with family, subfamily, weight, style, and any variation axes
|
||||
|
||||
**How to use it:**
|
||||
|
||||
- For each family you'll reference in DESIGN.md, name it by what's in `families[].family` (e.g. "Inter", not "f266e704 hashed font"). The hashed filenames are the `@font-face src` paths — they stay as-is on disk; only the display name comes from the manifest.
|
||||
- If a family has `variable: true` and `variationAxes` includes `"wght"`, you can use any weight 100-900 via `font-variation-settings: 'wght' <value>` even if only one static weight appears in the captured files. Note this in DESIGN.md so sub-agents know they have the full weight range available.
|
||||
- If the manifest's `unidentified[]` is non-empty, those files failed name-table extraction (rare — heavily subset fonts that strip metadata). Flag them as `unknown` in DESIGN.md and suggest a fallback rather than guessing.
|
||||
- Commercial fonts hosted on brand CDNs (GT Walsheim, Söhne, Graphik, Canela) won't be in the manifest because they aren't downloaded. Detect this by checking what the site uses (from `design-styles.json`) against what's in the manifest — anything used but missing is a CDN-hosted font. Flag explicitly: "Söhne not in capture; use Inter 600 as substitute."
|
||||
|
||||
Sub-agents try to use the fonts you list. The manifest tells you exactly what's available — there's no excuse for claiming "Charlie Display 700" when no such file exists.
|
||||
|
||||
---
|
||||
|
||||
## The 6 sections to write
|
||||
|
||||
### `## 1. Visual Theme (one paragraph)`
|
||||
|
||||
3–5 sentences describing the brand's visual personality. Cover: dark-first or light-first, contrast strategy, dominant visual elements (gradients, illustrations, photography, UI mockups), overall mood, what makes it distinctive vs. generic.
|
||||
|
||||
This is the only prose section. Make it specific to _this_ brand — not template-filling. A sentence that could describe any well-designed website is not useful.
|
||||
|
||||
**Example:**
|
||||
|
||||
> Stripe's visual language is light-first and clean, with deep navy (`#061B31`) and pure white as the foundation. The accent stack — Stripe Purple (`#533AFD`) for CTAs, Vibrant Orange (`#FF6118`) for energetic emphasis — keeps interactive elements unmistakable. Type is sohne-var Light (300) for display, weight 400 for body; the brand achieves hierarchy through size and weight, never color shifts. The mood is confident financial-tech — premium without theatrical drama. Distinctive: gradient overlays at 135° between purple and orange appear as subtle washes over white backgrounds, never as bold focal elements.
|
||||
|
||||
---
|
||||
|
||||
### `## 2. Quick Reference`
|
||||
|
||||
A flat lookup of the values sub-agents grab while composing beats. Two sub-sections — keep them tight.
|
||||
|
||||
#### Colors
|
||||
|
||||
List 8–12 colors with brand-specific names + HEX + role. Not generic ("Accent 1") but evocative ("Stripe Purple", "Deep Navy", "Slate Border"). The name carries meaning; "blue 4" doesn't.
|
||||
|
||||
**Example:**
|
||||
|
||||
```markdown
|
||||
#### Colors
|
||||
|
||||
- **Stripe Purple** (`#533AFD`): Primary CTA, interactive elements, focus rings — the brand's action signal
|
||||
- **Deep Navy** (`#061B31`): Primary text, headings — gravitas color
|
||||
- **Pure White** (`#FFFFFF`): Page background, card surfaces
|
||||
- **Light Gray** (`#F5F7FA`): Surface tier 2 (cards on white pages, alternating sections)
|
||||
- **Slate Blue** (`#273951`): Secondary text, subheadings, lower-emphasis content
|
||||
- **Light Slate** (`#64748D`): Metadata, captions, disabled-adjacent text
|
||||
- **Subtle Border** (`#D4DEE9`): Card borders, dividers
|
||||
- **Vibrant Orange** (`#FF6118`): Energy accent — gradient endpoints, highlight bursts (never primary)
|
||||
- **Error Red** (`#FF0022`): Validation errors
|
||||
- **Success Green** (`#4CD963`): Confirmation states
|
||||
```
|
||||
|
||||
#### Fonts
|
||||
|
||||
List font families (with availability notes) + the headline / body / mono trio if applicable:
|
||||
|
||||
**Example:**
|
||||
|
||||
```markdown
|
||||
#### Fonts
|
||||
|
||||
- **Display + Body:** `sohne-var` (variable 100–900, captured ✓) — weights 300 / 400 used in production
|
||||
- **Mono:** `"JetBrains Mono"` — code, metadata, technical content
|
||||
- **Fallback stack:** `-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif`
|
||||
|
||||
The brand uses **size for hierarchy, weight for emphasis**. Display 1: 48px/300, Display 2: 32px/300, Body: 14px/400. Never use weights above 400 — this brand has no bold variant in production.
|
||||
```
|
||||
|
||||
That's the whole typography section. If sub-agents need exact line-heights or letter-spacing, they read `design-styles.json` directly.
|
||||
|
||||
---
|
||||
|
||||
### `## 3. Component Stylings` (the build-step's spec sheet)
|
||||
|
||||
This is the section sub-agents consult most when composing UIs from divs in Step 5. **Without exact per-component CSS, sub-agents fall back to generic "dark bg + glow + centered text" patterns regardless of brand** — which is why every video starts looking the same. Encode the brand's actual component DNA here.
|
||||
|
||||
Target **6-12 distinct components**. Document what the site actually uses; skip categories the brand doesn't have. For each component, name it descriptively ("Stripe Primary Button" not "Button 1") and provide exact CSS-level properties: background, text color, padding, border-radius, border, font size/weight, height, box-shadow, and any hover/active/disabled states.
|
||||
|
||||
#### Buttons (always required)
|
||||
|
||||
Cover every variant the site uses — typically Primary, Secondary/Ghost, and Icon. **Example:**
|
||||
|
||||
```markdown
|
||||
#### Primary Button (Stripe Purple)
|
||||
|
||||
- **Background:** `#533AFD`
|
||||
- **Text color:** `#FFFFFF`
|
||||
- **Font:** sohne-var 16px / 400
|
||||
- **Padding:** `15.5px 24px 16.5px 24px`
|
||||
- **Border radius:** `4px`
|
||||
- **Border:** none
|
||||
- **Height:** `48px` (with padding)
|
||||
- **Box shadow:** none
|
||||
- **Hover:** background `#4329E8`, opacity `0.95`
|
||||
- **Active:** background `#3720D4`, scale `0.98`
|
||||
- **Disabled:** background `#C9C3F0`, cursor `not-allowed`
|
||||
|
||||
#### Secondary Button (outline)
|
||||
|
||||
- **Background:** `#FFFFFF`
|
||||
- **Text color:** `#533AFD`
|
||||
- **Border:** `1px solid #533AFD`
|
||||
- **Padding / radius / font:** same as Primary
|
||||
- **Hover:** background `#F3F0FF`, border `#4329E8`
|
||||
|
||||
#### Ghost Button (text-only link)
|
||||
|
||||
- **Background:** transparent
|
||||
- **Text color:** `#533AFD`
|
||||
- **Font:** sohne-var 14px / 400
|
||||
- **Padding:** `12px 0`
|
||||
- **Hover:** background `rgba(83, 58, 253, 0.08)`, optional underline
|
||||
```
|
||||
|
||||
#### Cards & Containers (always required if the site uses any)
|
||||
|
||||
Document each distinct card type — Standard, Feature Highlight, Glass, Pricing, Testimonial — whatever this brand actually uses. **Example:**
|
||||
|
||||
```markdown
|
||||
#### Standard Card
|
||||
|
||||
- **Background:** `#FFFFFF`
|
||||
- **Border:** `1px solid #D4DEE9`
|
||||
- **Border radius:** `5px`
|
||||
- **Padding:** `32px`
|
||||
- **Box shadow:** `0 1px 2px rgba(0, 0, 0, 0.04)` (default), `0 4px 12px rgba(0, 0, 0, 0.08)` (hover)
|
||||
- **Hover:** border `#B8CCDB`
|
||||
|
||||
#### Feature Highlight Card (gradient backdrop)
|
||||
|
||||
- **Background:** linear-gradient(180deg, rgba(83, 58, 253, 0.05) 0%, rgba(255, 97, 24, 0.03) 100%)
|
||||
- **Border:** `1px solid #E5EDF5`
|
||||
- **Padding:** `36px`
|
||||
- **Box shadow:** none
|
||||
```
|
||||
|
||||
#### Distinctive components (anything else the brand actually shows)
|
||||
|
||||
Logo marquees, testimonial carousels, pricing tables, gradient overlays, glassmorphism panels, bento grids, code blocks, terminal UIs, dashboard mockups — name and document anything visually distinctive. Sub-agents will reach for these specs when the storyboard calls for "compose the X UI."
|
||||
|
||||
```markdown
|
||||
#### Glass Container (frosted overlay)
|
||||
|
||||
- **Background:** `rgba(255, 255, 255, 0.9)`
|
||||
- **Border:** `1px solid rgba(255, 255, 255, 0.2)`
|
||||
- **Backdrop filter:** `blur(8px)`
|
||||
- **Use:** floating chat widgets, modal overlays, hero callouts only — the only place transparent fills appear in the system
|
||||
```
|
||||
|
||||
**The rule:** if a sub-agent in Step 5 has to invent CSS values for a component this brand actually uses, you under-documented this section. The values should be lookup-able, not guessable.
|
||||
|
||||
---
|
||||
|
||||
### `## 4. Spacing & Layout`
|
||||
|
||||
The brand's rhythm. Three sub-sections, kept tight.
|
||||
|
||||
#### Spacing scale
|
||||
|
||||
Identify the **base unit** (typically `4px` or `8px`) and the full scale with usage context. **Example:**
|
||||
|
||||
```markdown
|
||||
**Base unit:** `4px`
|
||||
|
||||
| Token | Value | Used for |
|
||||
| ----- | ------- | --------------------------------------------------------- |
|
||||
| xs | `4px` | Inline icon gaps, tight badge padding |
|
||||
| sm | `8px` | Button-group gaps, small component padding |
|
||||
| md | `16px` | Card padding, form-field gaps, standard component spacing |
|
||||
| lg | `32px` | Section vertical spacing, large card padding |
|
||||
| xl | `60px` | Major section separation |
|
||||
| 2xl | `100px` | Page-level rhythm, hero section padding |
|
||||
|
||||
Never use odd values (`13px`, `17px`) — the system only uses multiples of 4.
|
||||
```
|
||||
|
||||
#### Border-radius scale
|
||||
|
||||
Every radius the site uses, with what uses it.
|
||||
|
||||
```markdown
|
||||
- `0px`: Form labels, technical UI markers
|
||||
- `4px`: Primary buttons, inputs, small badges
|
||||
- `8px`: Standard cards, dropdowns
|
||||
- `12px`: Feature cards, larger callouts
|
||||
- `40px`: Icon buttons (square pill)
|
||||
- `9999px`: Pill-shaped CTAs, status chips
|
||||
```
|
||||
|
||||
#### Whitespace philosophy (one paragraph)
|
||||
|
||||
How does this brand use whitespace — generous and architectural? Tight and information-dense? Section gaps in the 60–100px range, or 20–40px? Document the brand's actual rhythm.
|
||||
|
||||
```markdown
|
||||
Generous whitespace as confidence. Section gaps are always `60–100px`. Content never touches viewport edges — minimum `40px` horizontal padding on mobile, `80–160px` on desktop. The brand uses negative space as active design, not emptiness.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `## 5. Depth & Elevation`
|
||||
|
||||
Document the brand's shadow philosophy and the actual shadow values used.
|
||||
|
||||
#### Shadow table
|
||||
|
||||
```markdown
|
||||
| Level | Value | Used for |
|
||||
| ------------ | -------------------------------- | ----------------------------------------------- |
|
||||
| Flat (0) | none | Default — most surfaces, inputs, body text |
|
||||
| Raised (1) | `0 2px 8px rgba(0, 0, 0, 0.1)` | Cards on white, hovered surfaces, floating CTAs |
|
||||
| Elevated (2) | `0 4px 12px rgba(0, 0, 0, 0.15)` | Dropdown menus, popovers |
|
||||
| Floating (3) | `0 8px 24px rgba(0, 0, 0, 0.2)` | Modals, important overlays |
|
||||
```
|
||||
|
||||
#### Shadow philosophy (one paragraph)
|
||||
|
||||
How does this brand use shadows? Sparingly with soft falloff, or dramatically with hard edges? Are they present by default or only on hover? On dark backgrounds, do shadows invert to glow effects?
|
||||
|
||||
```markdown
|
||||
Shadows are minimal — used only to signal interactivity (hover) or layering (modals). All shadows are soft-edged (blur ≥ 8px). On dark backgrounds, shadows convert to subtle glow (`0 0 24px rgba(255, 99, 99, 0.15)` using the brand's accent color). Hard shadows do not exist in this system.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `## 6. Iteration Guide` (the load-bearing section)
|
||||
|
||||
5–10 numbered rules that encode the most important brand decisions. Each rule is a **single actionable sentence stating what to do, with the specific values from this site.** These are the "if in doubt, do this" rules sub-agents consult while composing beats.
|
||||
|
||||
**The single most common failure mode is writing generic rules that could apply to any well-designed website.** A rule that doesn't name a specific value, a specific color, or a specific component this brand actually uses is doing nothing.
|
||||
|
||||
**Test for any rule you write:** can you swap this brand for a different brand and have the rule still make sense? If yes, it's too generic. If no, ship it.
|
||||
|
||||
#### ❌ Generic vs ✅ site-specific
|
||||
|
||||
| Generic (delete) | Site-specific (keep) |
|
||||
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Use the primary brand color for CTAs. | All primary CTAs use Stripe Purple (`#533AFD`). Secondary actions use white background with `#533AFD` border + text. **There is no third button color anywhere in the system.** |
|
||||
| Maintain visual hierarchy through color contrast. | Body text is `#000000` on white, `#FFFFFF` on dark. Metadata uses `#64748D` on white only — never on dark. The brand has no mid-gray text on dark backgrounds. |
|
||||
| Use clear typographic hierarchy. | All type is sohne-var. H1 `48px`/300, H2 `32px`/300, body `14px`/400. **Never use weights above 400** — this brand has no bold variant. |
|
||||
| Use consistent spacing. | Spacing is from a fixed scale: `4, 8, 12, 16, 20, 24, 32, 40, 60` px. Section gaps are always `60–100px`. Card padding is always `32px`. No exceptions. |
|
||||
| Buttons should have rounded corners. | Buttons are `40px` tall minimum, `4px` radius, `15.5px 24px` padding. Pill-shape `9999px` radius is reserved for the floating chat trigger only. |
|
||||
|
||||
#### One worked example (Framer — 5 rules)
|
||||
|
||||
```markdown
|
||||
### Iteration Guide
|
||||
|
||||
1. **All interactive elements use Framer Blue (`#0000EE`)** — links, primary buttons, active states, focus indicators. Secondary uses `#0099FF` for hover. **No other interactive color exists in the system.**
|
||||
|
||||
2. **Typography: GT Walsheim Medium for headings, Inter for body.** Hierarchy enforced through size only, never color. H2 `62px`, H5 `85px`, body `14px`, labels `12px`/500. Text defaults to `#000000` on white, `#FFFFFF` on dark.
|
||||
|
||||
3. **Spacing is base-4** — every margin / padding / gap is a multiple of `4px`. Section gaps `60–100px`. **Never use odd values like `13px` or `17px`** — the system has no place for them.
|
||||
|
||||
4. **Cards: white (`#FFFFFF`), `1px` border `#EFEFEF`, `8px` radius, `16–20px` padding, no shadow by default.** Dark-mode cards swap to `#1A1A1A` background with `#242424` border. Shadow only appears on hover.
|
||||
|
||||
5. **Glass containers** use `rgba(255,255,255,0.9)` background, `1px` border `rgba(255,255,255,0.2)`, optional `backdrop-filter: blur(8px)`. **These are the only place transparent fills appear** — everywhere else uses solid color.
|
||||
```
|
||||
|
||||
If your draft has a rule like "all interactive elements require visible focus states for accessibility" — delete it. Not wrong, just not load-bearing for _this_ brand.
|
||||
|
||||
---
|
||||
|
||||
## Rules
|
||||
|
||||
- Use **exact values** from `capture/extracted/tokens.json`. Cross-reference with screenshots when needed.
|
||||
- Name colors and components descriptively — "Stripe Purple" not "Accent 1."
|
||||
- When you can't extract exact values, estimate from visual inspection and note it.
|
||||
- Target **250–350 lines total.** Component CSS specs and the brand's spacing/depth values are load-bearing — sub-agents need them to compose UIs faithfully. Going much over 350 lines means you're over-investing in prose; going much under 200 means you've under-documented the component DNA and sub-agents will fall back to generic patterns.
|
||||
- No "Assets" section — `capture/extracted/asset-descriptions.md` is the asset index.
|
||||
- No "Motion" section — the storyboard specifies motion per-beat.
|
||||
- No "Components" section beyond what fits in Quick Reference — sub-agents compose UIs at build time from divs/SVG/CSS using the brand colors and fonts from this doc, not from CSS specs encoded here.
|
||||
- No "Depth & Elevation" tables — shadow language is implied by the brand's mood (heavy shadows for premium, no shadows for flat/clean); sub-agents pick appropriate values without a table.
|
||||
|
||||
---
|
||||
|
||||
## Quick User Check (before moving to Step 2)
|
||||
|
||||
30-second sanity check before Step 2:
|
||||
|
||||
> "Here's what I extracted as [Brand Name]'s visual identity:
|
||||
>
|
||||
> - **Colors:** [primary], [accent], [2-3 others with roles]
|
||||
> - **Fonts:** [headline font], [body font]
|
||||
> - **Tone:** [1 sentence on the brand feel]
|
||||
>
|
||||
> Does this match how you want the video to feel? Any corrections or overrides before I start the storyboard?"
|
||||
|
||||
If the user has corrections ("use the blue, not the gray" / "ignore the dark mode" / "we just rebranded, use [these values] instead") — update DESIGN.md now. One minute here saves thirty minutes of rebuilding.
|
||||
|
||||
---
|
||||
|
||||
## What makes a useful DESIGN.md
|
||||
|
||||
A sub-agent reading just your Quick Reference + Iteration Guide should be able to:
|
||||
|
||||
1. Pick the right color for any primary action, secondary action, body text, error state
|
||||
2. Pick the right font/weight/size for any headline, body, metadata
|
||||
3. Know which 2-3 rules they cannot break without losing the brand
|
||||
|
||||
That's the test. If they can answer those three questions from a 60–120 line doc, you've nailed it. If they need to read 400 lines of mood-board prose to find a color, you've buried the signal.
|
||||
@@ -0,0 +1,165 @@
|
||||
# Step 2: Strategy & Messaging
|
||||
|
||||
**First, scan the Table of Contents in [capabilities.md](capabilities.md)** — the 24-row TOC tells you everything HyperFrames can do. You need this to tell users what's possible. Deep-dive specific sections only if a beat needs them.
|
||||
|
||||
You've captured the site and you now understand the brand — what the product does, who it's for, what voice it speaks in, what mood it lives in. Before any creative decisions, **align with the user on the story this video must tell.** Captured assets exist as a brand toolkit you'll reach for late in Step 3; they are not what the conversation in this step is about.
|
||||
|
||||
**Parse the user's prompt first.** Read what they already told you — video type, style, specific requests, duration. Only ask about things they DIDN'T specify. If they said "product demo, show me the kanban board and chat, moderate pace" — that's most of the brief already. Don't ask "what type of video?" when they literally said "product demo."
|
||||
|
||||
Skip questions the user already answered. Ask only what's missing. If the prompt is detailed enough to build from, confirm the direction in one message and move to Step 3. The goal is to fill gaps, not interrogate.
|
||||
|
||||
---
|
||||
|
||||
## What to Ask
|
||||
|
||||
After presenting the site summary (from Step 0), engage the user with these questions. Use your agent's question/answer UI if available (multi-choice with custom option). If not, ask conversationally.
|
||||
|
||||
### Question 1: What's this video for?
|
||||
|
||||
Present options based on what makes sense for the captured site:
|
||||
|
||||
**Example (Not a required options)**
|
||||
|
||||
- **Social ad** (15–20s) — Instagram, TikTok, LinkedIn. Fast, punchy, hook in first 2s.
|
||||
- **Product demo** (30–60s) — Walk through key features. Narrated, professional.
|
||||
- **Launch teaser** (15–25s) — Build hype for a new feature or product. Dramatic reveal.
|
||||
- **Brand reel** (20–45s) — Showcase the brand identity. Visual-forward, minimal narration.
|
||||
- **Feature announcement** (15–30s) — Highlight a specific feature or update.
|
||||
- Or describe something else.
|
||||
|
||||
This determines duration, beat count, narration density, and overall energy.
|
||||
|
||||
### Question 2: What style/vibe?
|
||||
|
||||
Ask the user to describe what they want — or react to concrete framings that describe motion and energy, not aesthetic presets.
|
||||
|
||||
Do NOT present a labeled menu of styles with pre-filled descriptions ("Cinematic = dark + glow + Apple keynote energy"). Those descriptions become the brief even when they don't match the brand. "Cinematic" for a wellness brand should look completely different from "cinematic" for a security tool — but a label with a baked-in description collapses that distinction.
|
||||
|
||||
Instead, ask them across the six axes from [visual-vocabulary.md](visual-vocabulary.md) — framed as approachable questions, not a form:
|
||||
|
||||
> "A few questions to get the direction right:
|
||||
>
|
||||
> - **Pace:** Should the video move slowly and let moments breathe, or be fast and punchy? Or somewhere in between?
|
||||
> - **Mood:** What atmosphere matches how you want viewers to feel — dark and dramatic, clean and light, energetic and vibrant, or something else?
|
||||
> - **Narration:** Should a voice guide viewers through the video, or let the visuals carry it?
|
||||
> - **Anything specific?** Any moments, techniques, or references you're drawn to? Or say 'surprise me' and I'll work from what I found in the capture."
|
||||
|
||||
Their answers modify the brand-derived baseline you built in Step 1. Don't override the brand with their words — let the brand and their direction converge. See [visual-vocabulary.md](visual-vocabulary.md) for how to handle conflicts.
|
||||
|
||||
### Question 3: What's the ONE thing this video must communicate?
|
||||
|
||||
This is the strategy question. Every effective marketing video has a single core message — the one idea that has to land. Every beat serves that idea, or it doesn't belong. Get the user to articulate this BEFORE talking about visuals, assets, or specific scenes.
|
||||
|
||||
Frame it like this:
|
||||
|
||||
> "From your site, here's the brand frame I'm working from:
|
||||
>
|
||||
> - **What the product does:** [one sentence from the site summary — not features, the actual job]
|
||||
> - **Audience:** [who it's for, derived from copy and visual tone]
|
||||
> - **Brand voice:** [confident / playful / clinical / urgent / premium — what tone the brand speaks in]
|
||||
>
|
||||
> Before we plan visuals, two questions to anchor the story:
|
||||
>
|
||||
> 1. **What's the ONE thing this video must communicate?** If a viewer remembers only one sentence after watching, what should it be? (the value prop, a launch announcement, a specific feature claim, a brand feeling, a problem-solution pair, etc.)
|
||||
> 2. **What's the narrative shape?** Possible arcs: _Problem → Solution_ (most demos), _Reveal_ (launches, teasers), _Demonstration_ (feature showcase, walkthroughs), _Vibe piece_ (brand reels — feeling over information), _Comparison_ (vs. competitor / before-after). Pick or describe your own.
|
||||
>
|
||||
> Either give me your own answers, or say 'surprise me' and I'll make the call based on the brand and what you said in Question 1 ([video type])."
|
||||
|
||||
Once those answers exist, **then** sketch the composed-beat directions — but ground each one in the message and arc, not in the asset list:
|
||||
|
||||
> "Given [the message] and [the arc], here's how I'd shape it:
|
||||
>
|
||||
> - [Compose-first sketch grounded in the answer to Q1, e.g., "Open with the problem stated as kinetic typography — 'You waste 4 hours a week on context switches.' Cut to a composed kanban board where cards animate from chaos into organization. Close on the brand mark + tagline."]
|
||||
> - [Alternative sketch with a different arc, e.g., "Reveal arc: dark canvas → particles converging → product wordmark drawn stroke-by-stroke as the first feature lands. No problem statement — pure announcement energy."]
|
||||
> - [If user wants demo: "Three composed UI panels — kanban, AI chat, command palette — each in your palette with the brand logo stamped top-left. Narration walks through each. Closer holds the wordmark."]
|
||||
>
|
||||
> Brand accents I could layer in: [list 1-3 captured assets that *might* earn a place: the SVG logo for opener/closer, a hero illustration as a depth layer in one scene, a gradient image as an ambient bg wash. Note these are candidates, not assignments — most beats won't need any.]"
|
||||
|
||||
**Important:** Lead every direction with **what the beat communicates and what it's composed of** — never with "the [asset] does X." If your first instinct is "the dashboard screenshot flies in," flip it: "Compose the dashboard from divs and animate it inside a 3D MacBook." If your first instinct is "the hero illustration centers the opener," flip it: "Open with kinetic typography of the value prop; the hero illustration can wash behind it as ambient depth."
|
||||
|
||||
The captured assets are a brand toolkit you reach for late, where they serve the concept — never the starting point.
|
||||
|
||||
Present options:
|
||||
|
||||
- **I have specific ideas** — let me describe them
|
||||
- **Surprise me** — you make the creative calls, I'll review the storyboard
|
||||
- **Let me see some options first** — propose 2–3 different creative directions and I'll pick
|
||||
|
||||
### Question 4: Narration?
|
||||
|
||||
Not every video needs a voiceover. Ask:
|
||||
|
||||
- **Yes, with narration** — a voice guides the viewer through the video (most product demos, launch teasers, feature announcements)
|
||||
- **No narration, visual-only** — music/SFX only, the visuals tell the story (brand reels, social ads, music-driven pieces)
|
||||
- **Minimal narration** — just a hook sentence or tagline, rest is visual (short social ads, teasers)
|
||||
|
||||
This decision changes the pipeline:
|
||||
|
||||
- **With narration:** Step 3 includes a full script. Step 4 generates TTS, transcribes, maps timestamps to beats.
|
||||
- **Without narration:** Step 3 has no script (VO cues in storyboard are empty). Step 4 is skipped — beat durations are planned manually in the storyboard based on rhythm and pacing.
|
||||
|
||||
### Question 5 (if applicable): Format?
|
||||
|
||||
Only ask if not already specified by the user:
|
||||
|
||||
- **Landscape** (1920×1080) — YouTube, LinkedIn, website embeds (default)
|
||||
- **Portrait** (1080×1920) — Instagram Stories, TikTok, YouTube Shorts
|
||||
- **Square** (1080×1080) — Instagram feed, Twitter/X
|
||||
|
||||
---
|
||||
|
||||
## How to Handle Responses
|
||||
|
||||
### "Surprise me" / minimal direction
|
||||
|
||||
When the user gives no creative direction, default to what the brand's visual identity and the video's purpose suggest. The minimum context you need before defaulting: **where the video is going** (social feed / landing page / pitch deck / TV ad) and **who it's for** (developers / consumers / enterprise / general audience). If either is missing, ask once — "where will this run, and who's the audience?" — then proceed.
|
||||
|
||||
With that minimum in hand, still write an ambitious storyboard. "Surprise me" means "impress me," not "play it safe." Go bold.
|
||||
|
||||
### Specific direction
|
||||
|
||||
Map their words to visual-vocabulary.md dimensions. If they say something vague ("make it really cool"), push back gently:
|
||||
|
||||
> "I want to make sure I nail what you're imagining. When you say 'cool' — do you mean: dramatic/cinematic(slow reveals and dark atmosphere)? Or high-energy (fast cuts and bold motion)? Or something else entirely?"
|
||||
|
||||
### Mixed direction
|
||||
|
||||
Parse each component separately. "Minimal but with cinematic transitions and a fast feature section" becomes:
|
||||
|
||||
- **Base style:** Minimal (moderate pacing, minimal density, elegant motion)
|
||||
- **Transitions override:** Dramatic (shader effects for key moments)
|
||||
- **Beats 3–5 override:** Fast pacing, balanced density, energetic motion
|
||||
|
||||
Note these per-beat overrides — they go into the storyboard.
|
||||
|
||||
### "Let me see options"
|
||||
|
||||
Propose 2–3 brief creative directions (3–4 sentences each) with different **narrative arcs** — what story the video tells, not what assets it shows. Each option leads with the message and the arc; visuals are composed scenes that serve them.
|
||||
|
||||
> **Option A — Problem → Solution (cinematic, narrated):** Open with the problem stated as kinetic typography over a dark canvas with a single accent glow. Cut to a composed kanban board where chaotic cards animate into organized columns as narration lands the value prop. Closer: brand mark drawn stroke-by-stroke on a shader bloom of the brand gradient. Apple-keynote register. ~25s with full VO.
|
||||
>
|
||||
> **Option B — Reveal arc (announcement, music-led):** Cold open: particles converging in darkness, no copy. The product wordmark draws itself across the frame as the first beat lands. Three composed feature panels each unveiled by a hard cut — kinetic typography labels, brand color washes, no screenshots. Closes on the mark + tagline + macOS hint. ~15s, music-driven, minimal narration.
|
||||
>
|
||||
> **Option C — Demonstration (narrated walkthrough):** Three composed UI scenes — kanban from cards-as-divs, AI chat with typewriter narration sync, command palette with character-typed search — each in the brand palette with the captured logo stamped top-left as identity. CSS crossfades between. Narration walks each one. ~35s, full VO.
|
||||
|
||||
Each option states: the arc, the composed visuals carrying it, where (if anywhere) a captured asset shows up as an accent. **Never** an option whose primary content is "the screenshot of X" — if you find yourself writing one, flip it: name what gets composed, then where the brand accent lands on top.
|
||||
|
||||
Let the user pick one or combine elements.
|
||||
|
||||
---
|
||||
|
||||
## Gate
|
||||
|
||||
Lock all of these before moving to Step 3. The first three are the strategic frame Step 3 builds the storyboard from — without them, the storyboard cannot land.
|
||||
|
||||
1. **Message** — the ONE thing this video must communicate, in a single sentence. (Required. Step 3 fails without this.)
|
||||
2. **Narrative arc** — Problem→Solution / Reveal / Demonstration / Vibe / Comparison / custom. (Required.)
|
||||
3. **Audience** — who's watching, where they're watching. (Required.)
|
||||
4. **Video type** — social ad / product demo / launch teaser / brand reel / feature announcement / etc. Infer from prompt.
|
||||
5. **Duration** — infer from type if not stated (demo: 30-45s, social: 15-20s, teaser: 15-25s).
|
||||
6. **Style direction** — map their words to visual-vocabulary dimensions.
|
||||
7. **Specific requests** — any scenes/effects/beats they explicitly asked for.
|
||||
8. **Narration** — yes / no / minimal.
|
||||
9. **Format** — landscape unless specified otherwise.
|
||||
|
||||
**Do not ask the user to confirm what they already said.** If the prompt was "make a product demo for huly.io, show the kanban board, dark cinematic feel, full narration" — you already have type (demo), style (dark cinematic), specific requests (kanban board), and narration (full). Still need to derive or ask: the **message** ("the everything app for teams that hate context switches"), the **arc** (Demonstration), and the **audience** (small teams / fast-moving orgs). Proceed to Step 3 only when all 9 are locked.
|
||||
@@ -1,178 +0,0 @@
|
||||
# Step 2: Write DESIGN.md
|
||||
|
||||
DESIGN.md is a **brand cheat sheet** for the captured website. It encodes the visual identity so you can reference exact colors, fonts, and patterns while writing the storyboard and compositions.
|
||||
|
||||
DESIGN.md is NOT the creative plan. The STORYBOARD (Step 4) drives creative direction. DESIGN.md is a reference you consult, not a document you follow slavishly.
|
||||
|
||||
## The 6 Sections
|
||||
|
||||
### `## Overview`
|
||||
|
||||
3-4 sentences. Describe the visual identity factually: layout patterns (bento grid, logo wall, hero section), color strategy, typography tone, overall feel. Be precise, not poetic.
|
||||
|
||||
### `## Colors`
|
||||
|
||||
5-10 key colors with HEX values from `capture/extracted/tokens.json` and their roles:
|
||||
|
||||
```
|
||||
- **Primary Surface**: `#020204` — deep black background
|
||||
- **Primary Content**: `#FFFFFF` — high-purity white for text and borders
|
||||
- **Accent Warm**: `#FB923C` — orange for CTAs and highlights
|
||||
```
|
||||
|
||||
Include semantic colors if the site uses color to differentiate product areas.
|
||||
|
||||
### `## Typography`
|
||||
|
||||
Font families with weights, roles, and any distinctive usage:
|
||||
|
||||
```
|
||||
- **Serif**: Cormorant Garamond (Italic). Major headings, brand identity.
|
||||
- **Monospace**: Geist Mono. Subheaders, labels, terminal readouts. High tracking (0.1-0.3em), all-caps.
|
||||
- **Sans-Serif**: Inter. Body copy, interface elements. Small sizes (9-14px).
|
||||
```
|
||||
|
||||
Include sizing hierarchy if notable (hero: 64px, section: 32px, body: 16px).
|
||||
|
||||
### `## Elevation`
|
||||
|
||||
One paragraph on depth strategy: Does the site use borders, shadows, glassmorphism, or flat color shifts? Reference specific patterns (e.g., "1px borders at white/10 opacity" or "layered backdrop-blur with thin borders").
|
||||
|
||||
### `## Components`
|
||||
|
||||
Name every notable UI component you see in the screenshot. Be specific:
|
||||
|
||||
- "Cinematic Accordion" not "Cards"
|
||||
- "Logo Marquee" not "Scrolling section"
|
||||
- "Glass Cards with grain overlay" not "Content containers"
|
||||
|
||||
For each, note the distinctive visual treatment (border-radius, spacing, hover behavior).
|
||||
|
||||
### `## Do's and Don'ts`
|
||||
|
||||
3-5 rules each, derived from what the site actually does and doesn't do:
|
||||
|
||||
```
|
||||
### Do's
|
||||
- Use thin subtle borders (white/10) to separate sections
|
||||
- Keep imagery desaturated with dark gradients for text readability
|
||||
|
||||
### Don'ts
|
||||
- Do not use bright solid background colors — stay in "The Void"
|
||||
- Do not use standard drop shadows — use radial glow or bloom effects
|
||||
- Do not use sharp high-speed animations — all motion should be fluid
|
||||
```
|
||||
|
||||
## Rules
|
||||
|
||||
- Use **exact HEX values** from `capture/extracted/tokens.json`. Do not approximate.
|
||||
- Name components by what you see in the screenshot, not generic terms.
|
||||
- Keep it under 100 lines. This is a cheat sheet, not a design system document.
|
||||
- No "Style Prompt" section — the storyboard handles creative direction.
|
||||
- No "Assets" section — `capture/extracted/asset-descriptions.md` already covers this.
|
||||
- No "Motion" section — the storyboard specifies motion per-beat.
|
||||
|
||||
## Example
|
||||
|
||||
This is a real DESIGN.md from a production capture (Soulscape 2026):
|
||||
|
||||
```markdown
|
||||
# Design System
|
||||
|
||||
## Overview
|
||||
|
||||
Soulscape 2026 is a cinematic, "high-signal" digital experience that positions itself as the vanguard of AI filmmaking. The visual personality is dark, technical, and premium, characterized by high-contrast "Flare" on "Void" (white on black) aesthetics. The layout is dense but organized, utilizing heavy horizontal layering and border-defined sections to evoke a wide-screen cinematic feel. Motion is a core tenet, with atmospheric grain overlays, shifting light leaks, and slow-moving marquees creating constant, breathing texture.
|
||||
|
||||
## Colors
|
||||
|
||||
- **Primary Surface**: `#020204` (Void) - Deep black for the entire background.
|
||||
- **Primary Content**: `#FFFFFF` (Flare) - High-purity white for typography and primary borders.
|
||||
- **Accent 1 (Warm)**: `#FB923C` - Orange for industry/executive tiers and primary CTAs.
|
||||
- **Accent 2 (Cool)**: `#60A5FA` - Blue for creative voices and summit-focused components.
|
||||
- **Subtle Overlays**: `rgba(255, 255, 255, 0.02)` to `0.08` for glass backgrounds.
|
||||
|
||||
## Typography
|
||||
|
||||
- **Serif**: Cormorant Garamond (Italic). Major headings and "Soul" brand identity. Classical cinematic contrast.
|
||||
- **Monospace**: Geist Mono. Subheaders, labels, terminal readouts. High tracking (0.1-0.3em), all-caps.
|
||||
- **Sans-Serif**: Inter. Body copy and interface elements. Small sizes (9-14px).
|
||||
|
||||
## Elevation
|
||||
|
||||
- **Glassmorphism**: Components use backdrop-filter blur(10px) with thin borders (1px solid rgba(255, 255, 255, 0.08)).
|
||||
- **Layering**: Depth via fixed global grain-overlay and localized light-leak gradients rather than box-shadows.
|
||||
- **Interaction**: Hover triggers subtle translateY(-5px) and increased border opacity.
|
||||
|
||||
## Components
|
||||
|
||||
- **Cinematic Accordion**: Expanding horizontal/vertical card system where panels expand from compressed state to reveal full-bleed imagery and large serif typography.
|
||||
- **HUD Explorer**: Floating mobile navigation trigger styled as a "Lens" with pulsing glow and terminal readouts.
|
||||
- **Slow Marquees**: Continuous horizontal tickers for partner logos and veteran listings.
|
||||
- **Glass Cards**: Content containers with subtle gradients, rounded corners (2.5rem), and high-contrast iconography.
|
||||
- **Grain & Flicker**: Global CSS noise filters and holographic flicker animations on UI labels.
|
||||
|
||||
## Do's and Don'ts
|
||||
|
||||
### Do's
|
||||
|
||||
- Use thin subtle borders (white/10) to separate sections rather than solid color changes.
|
||||
- Maintain high letter-spacing on all Geist Mono labels.
|
||||
- Use serif italics for emotional or visionary statements.
|
||||
- Keep imagery desaturated or stylized with dark gradients for readability.
|
||||
|
||||
### Don'ts
|
||||
|
||||
- Do not use bright solid background colors — the page must remain in "The Void."
|
||||
- Do not use standard drop shadows — use radial glow or bloom effects instead.
|
||||
- Do not use sharp high-speed animations — all motion should be fluid and breathing.
|
||||
```
|
||||
|
||||
Here is a contrasting example from a light, corporate brand to show the range:
|
||||
|
||||
```markdown
|
||||
# Design System
|
||||
|
||||
## Overview
|
||||
|
||||
Stripe's visual personality is defined by high-precision, technical sophistication, and a fluid, forward-moving motion language. The layout is dense but expertly balanced, utilizing a "canary" grid system that favors high-density data visualizations and modular bento-style layouts. The tone is authoritative and innovative, characterized by smooth CSS animations, complex SVG graphics that mimic UI dashboards, and the iconic "hero wave" background that uses layered gradients to create depth and movement.
|
||||
|
||||
## Colors
|
||||
|
||||
- **Brand Primary**: #635bff (The signature Stripe Blurple)
|
||||
- **Text Solid**: #0a2540 (Deep navy for primary headings)
|
||||
- **Text Soft**: #424770 (Subdued slate for descriptions and secondary text)
|
||||
- **Surface Background**: #ffffff (White primary surface)
|
||||
- **Surface Subdued**: #f6f9fc (Light gray for section contrast)
|
||||
- **Accent Green**: #212d45 (Used in high-converting success UI graphics)
|
||||
- **Accent Orange**: #ff6118 (Used for specific product highlights like Connect)
|
||||
- **Accent Yellow**: #fc5 (Warm highlight used in bento cards)
|
||||
- **Border Quiet**: #e6ebf1 (Soft borders for cards and dividers)
|
||||
|
||||
## Typography
|
||||
|
||||
- **Primary Font**: Sohne (sohne-var), a custom neo-grotesque that balances technical precision with approachability. Used across all headers and body copy.
|
||||
- **Monospace Font**: SourceCodePro-Medium, specifically for code snippets, tabular data, and technical UI identifiers.
|
||||
- **Heading Scale**: hds-heading--xxl ~3rem, hds-heading--lg ~1.5rem, hds-heading--md ~1.125rem
|
||||
- **Body Scale**: Standard body text centers around 1rem (16px) with a line-height of 1.5-1.6.
|
||||
|
||||
## Elevation
|
||||
|
||||
- **Shadows**: Multi-layered shadow system (e.g., 0 30px 60px -12px rgba(50,50,93,0.25)). Shadows are diffused and deep for a floating effect.
|
||||
- **Borders**: Heavy use of 1px solid borders to define bento grid boundaries instead of shadows in flat sections.
|
||||
- **Glass/Layering**: Navigation overlays use backdrop-filter blur(5px) with translucent white background.
|
||||
|
||||
## Components
|
||||
|
||||
- **Navigation Popover**: Animated dropdown spanning page margin with multi-column bento layouts.
|
||||
- **Bento Cards**: Interactive grid-aligned containers with gradient hover effects that follow the cursor.
|
||||
- **Customer Marquee**: Seamless horizontal scrolling loop of flat-colored SVG logos.
|
||||
- **UI Graphics**: Custom HTML/CSS representations of the Stripe Dashboard with tabular numbers and mini-charts.
|
||||
- **CTA Buttons**: Rounded-pill shapes with subtle scale transforms on hover.
|
||||
|
||||
## Do's and Don'ts
|
||||
|
||||
- **Do**: Use smooth cubic-bezier(.25, 1, .5, 1) transitions for all hover states and entering animations.
|
||||
- **Do**: Maintain strict vertical alignment between iconography and text labels.
|
||||
- **Don't**: Use sharp-cornered cards; always apply a border-radius.
|
||||
- **Don't**: Over-saturate backgrounds; stick to white or #f6f9fc and let brand assets provide color pop.
|
||||
```
|
||||
@@ -1,9 +0,0 @@
|
||||
# Step 3: Write the Narration Script
|
||||
|
||||
**Before writing, re-read DESIGN.md** — specifically the Overview and Components sections. The script should reference real product features, real stats, and real components that the website highlights. Use exact numbers from `capture/extracted/visible-text.txt`.
|
||||
|
||||
The script is the backbone. Everything downstream — scene durations, animation timing, beat pacing — comes from the narration. Write it before the storyboard.
|
||||
|
||||
Save as `SCRIPT.md` in the project directory.
|
||||
|
||||
Read [../../hyperframes/references/narration.md](../../hyperframes/references/narration.md) for the full narration guide.
|
||||
@@ -0,0 +1,531 @@
|
||||
# Step 3: Storyboard + Script
|
||||
|
||||
Marketing videos are made concept-first. **The order is: message → narrative arc → beats that serve the arc → which assets and techniques bring each beat to life.** Captured assets (SVG logos, brand illustrations, hero art, gradients) are first-class beat content alongside composed UIs — many of them will carry their own beats. The constraint is only that you shouldn't _start_ from the asset inventory ("we have these screenshots, let's build a slideshow"). Start from the message, then weave in the right captured assets and the right composed elements per beat.
|
||||
|
||||
**Read `capture/extracted/asset-descriptions.md` before writing beats.** Know what's in the capture. The brand's actual visual identity — its real logo, its real illustrations, its real gradients, its real hero art — is what makes the video feel like _this_ brand and not a generic dark cinematic template. Most beats will use one or two captured assets layered with composed motion.
|
||||
|
||||
## First decision: CONCEPT
|
||||
|
||||
Before pacing, before beats, before anything else — write the concept block at the top of `STORYBOARD.md`. Carry forward what was decided in Step 2's brief:
|
||||
|
||||
```markdown
|
||||
**Message:** [the ONE thing this video must communicate — one sentence]
|
||||
**Arc:** [Problem→Solution / Reveal / Demonstration / Vibe / Comparison — and a one-sentence shape of how it unfolds]
|
||||
**Audience:** [who's watching, where they're watching — TikTok scrollers, LinkedIn viewers, embedded on landing page]
|
||||
**Brand voice:** [confident / playful / clinical / urgent / premium — pulled from DESIGN.md]
|
||||
**Why this matters now:** [GTM context if relevant — launch, feature ship, brand reposition, ongoing demo]
|
||||
```
|
||||
|
||||
If any of those rows are blank, the storyboard cannot land. Go back to the brief — don't substitute "show the kanban" for a message.
|
||||
|
||||
**The single-sentence test:** _"What makes this video different from a generic [video type] for any [industry] brand?"_ If you can't answer it from the rows above, the concept isn't sharp enough. Sharpen it before writing pacing or beats.
|
||||
|
||||
---
|
||||
|
||||
## Second decision: PACING
|
||||
|
||||
With the concept locked, pick the pacing that serves it. This determines beat count, beat duration, and architecture — every downstream choice flows from here.
|
||||
|
||||
Read the message and arc from the concept block above plus the style direction from Step 2's brief. Map to one of these:
|
||||
|
||||
| User says | Pacing | Beat count | Beat duration | Architecture |
|
||||
| ----------------------------------------------------------- | ------------ | ---------- | ------------- | ---------------------------------------------------------- |
|
||||
| "fast", "punchy", "rapid cuts", "energetic", "social ad" | **Fast** | 8–15 | 0.7–1.8s | Single-file stacked beats, hard cuts |
|
||||
| "demo", "walkthrough", "product tour", "show features" | **Moderate** | 4–6 | 3–5s | Sub-compositions, CSS crossfades |
|
||||
| "cinematic", "premium", "slow", "let it breathe", "elegant" | **Slow** | 3–4 | 5–8s | Sub-compositions, long crossfades |
|
||||
| "launch", "announcement", "story", "narrative" | **Arc** | 5–7 | varies | Slow opener → building middle → fast peak → resolved close |
|
||||
|
||||
**Write your pacing choice at the top of STORYBOARD.md.** Example: `**Pacing: Fast** — 12 beats, stacked divs, hard cuts.`
|
||||
|
||||
If the user said "dark cinematic feel" — that's SLOW, not fast. If they said "rapid cuts, bold typography" — that's FAST. Don't default to moderate when the prompt gives you a clear signal.
|
||||
|
||||
---
|
||||
|
||||
## Technique-pick checklist (REQUIRED, do this BEFORE writing beat copy)
|
||||
|
||||
For every beat you plan, name **2–4 techniques** it will use. A beat with one technique is a slideshow frame — if you can't name two, redesign that beat.
|
||||
|
||||
Pick from the inventory in [capabilities.md](capabilities.md) and implementation patterns in [techniques.md](../../hyperframes/references/techniques.md). Examples of composable beats:
|
||||
|
||||
```
|
||||
Beat 3: composed kanban (4 cards-as-divs per column) + counter chip on In-Progress + back.out entrance stagger
|
||||
techniques: layered panels (capabilities §1), counter via tl.set (techniques #15),
|
||||
GSAP stagger with back.out(1.7) (techniques #4)
|
||||
customize: real project name "Atlas Q3", brand purple #5b3fff, realistic backlog items
|
||||
```
|
||||
|
||||
**Customize is the actual deliverable** — what makes this beat THIS brand's beat. Brand colors, real content, narration-sync timing. Generic "show the kanban" with no concrete techniques, no customize plan, no brand-specific data = lazy thinking. Beats must be invented from this brand's identity, not assembled from generic UI shapes.
|
||||
|
||||
---
|
||||
|
||||
**Re-read these files before writing:**
|
||||
|
||||
- **DESIGN.md** — your color palette, font rules, components, Do's/Don'ts. Every visual must be grounded in this brand identity. If it says "white backgrounds with purple accent" — plan light scenes, not dark moody ones.
|
||||
- **[visual-vocabulary.md](visual-vocabulary.md)** — translate the user's style direction into concrete dimension values (pacing, density, transitions, mood, motion, audio). Note any per-beat overrides the user requested.
|
||||
- **Asset discovery — use the contact sheets.** View `capture/assets/contact-sheet-*.jpg` and `capture/assets/svgs/contact-sheet-*.jpg`. Each grid cell is labeled with the filename. This is how you browse what's available without opening 50 individual files. When you find an asset that earns its place as a brand accent, note the filename from the label and reference it as `capture/assets/<filename>`. If an asset looks promising but you need to check resolution or detail, THEN open the individual file. Also read `capture/extracted/asset-descriptions.md` for one-line summaries. **Understand what each asset IS before using it.** Product screenshots show what the product does — useful for understanding the brand, but **compose the UI from divs/CSS in your beats rather than pasting the screenshot** (see Per-Beat Direction below). The strongest captured assets for video accents are usually the brand logo (SVG), the hero illustration, and gradient/texture backgrounds. **Never use contact sheets or scroll screenshots in the video** — contact sheets have grid labels and headers baked in, scroll screenshots are raw browser captures. Both are for AI to BROWSE and understand the site, not to place in compositions.
|
||||
- **[techniques.md](../../hyperframes/references/techniques.md)** — 20 visual techniques with code patterns. Pick for beats, these are starting points to adapt, not templates to copy.
|
||||
- **[text-effects.md](../../hyperframes/references/text-effects.md)** — 24 named text animation effects bundled in the repo. Read the catalog now and assign a specific effect ID to every headline, label, and copy element in every beat — not generic "fades in" descriptions.
|
||||
|
||||
The storyboard is the creative north star. It tells the engineer exactly what to build for each beat — mood, camera, animations, transitions, assets, appearance, sound. Write it as if you're briefing a motion designer who's never seen the website.
|
||||
|
||||
**Incorporate the user's specific requests.** If they asked for "a 3D MacBook reveal" — that's in the storyboard. If they said "surprise me" — go ambitious, but just stay within the style direction.
|
||||
|
||||
Save as `STORYBOARD.md` in the project directory.
|
||||
|
||||
---
|
||||
|
||||
## Consider: Would Research Improve This Video?
|
||||
|
||||
Before diving into beats, pause and think: **would focused research make this video meaningfully better?**
|
||||
|
||||
This is NOT always needed. A simple social ad for a SaaS product probably doesn't need market research. But some videos benefit from context the website alone doesn't provide:
|
||||
|
||||
**Research when:**
|
||||
|
||||
- The video is for a competitive market — look at how competitors present their product, what visual language the industry uses, what trends are hot
|
||||
- The video represents a company/product you know little about — search for reviews, press coverage, user opinions, company history to understand what matters to their audience
|
||||
- The user asked for something specific to their field — a fintech launch video benefits from understanding how Stripe, Ramp, Mercury position themselves visually
|
||||
- The video needs to reference real-world data, trends, or context not on the website
|
||||
|
||||
**Skip research when:**
|
||||
|
||||
- It's a straightforward brand reel or social ad from a clear website
|
||||
- The user gave very specific creative direction ("I want exactly X, Y, Z")
|
||||
- The website already contains all the context needed (features, stats, testimonials)
|
||||
|
||||
**What to research:** Competitor videos in the space, trending visual styles for the industry, audience expectations, any company context that helps you make better creative decisions. A 2-minute web search can give you the edge between a generic video and one that feels like it was made by someone who understands the market.
|
||||
|
||||
---
|
||||
|
||||
## Global Direction
|
||||
|
||||
Every STORYBOARD.md starts with global settings:
|
||||
|
||||
```markdown
|
||||
**Format:** 1920×1080
|
||||
**Audio:** [TTS provider] voiceover + underscore + SFX
|
||||
**VO direction:** [voice character — e.g., "mid-age male, calm confident delivery,
|
||||
Apple keynote register — economy of words, silence between sentences is a feature"]
|
||||
**Style basis:** DESIGN.md (brand colors, fonts, components from the captured site)
|
||||
```
|
||||
|
||||
**Global guardrails** — read [video-composition.md](../../hyperframes/references/video-composition.md) first. It defines the medium rules: density, color presence, scale, frame composition, and how design.md is brand truth not layout spec. Then apply these capture-specific additions:
|
||||
|
||||
- Captured assets are accents on composed beats, not the beats themselves — see Asset Audit below for which assets earn a place (typically 2-4 across the whole video).
|
||||
- Use different techniques from techniques.md — not across the whole video, per beat. Don't default to basic fade/scale/opacity — mix in SVG path drawing, HTML-in-canvas, shaders, scrolling effects or movement effect, CSS 3D transforms, typing effects, counter animations, canvas procedural art. Each beat should feel like its own visual world. Use as many as makes sense for the storyboard.
|
||||
|
||||
**Underscore/music direction** (if applicable):
|
||||
|
||||
- Describe the mood, reference artists, when it swells or drops
|
||||
- Example: "Minimal electronic. Warm sustained pad already playing when the video starts. Sits underneath everything, never competing with VO. Swells gently during the flex section, drops to near-nothing for the comparison, resolves on a final chord."
|
||||
|
||||
---
|
||||
|
||||
## Required Capabilities Discovery
|
||||
|
||||
Before writing any beats, you have to run these commands and paste the output below the Global Direction section. This tells you what's available beyond the standard techniques.
|
||||
|
||||
```bash
|
||||
# 1. Check available shader transitions (installed in registry/blocks/)
|
||||
ls registry/blocks/ 2>/dev/null | grep -E 'chromatic|cinematic|cross-warp|domain-warp|flash|glitch|gravitational|light-leak|ridged|ripple|sdf|swirl|thermal|whip' || echo "No shader transitions installed"
|
||||
|
||||
# 2. Check available VFX blocks
|
||||
ls registry/blocks/ 2>/dev/null | grep vfx || echo "No VFX blocks installed"
|
||||
|
||||
# 3. Browse what's available to install
|
||||
npx hyperframes catalog --type block 2>/dev/null | head -40
|
||||
```
|
||||
|
||||
There might be VFX blocks available (vfx-liquid-glass, vfx-iphone-device, vfx-shatter, vfx-portal, etc.), use them for hero treatments instead of basic perspective tilt. You need to install any you want with `npx hyperframes add <name>`. Don't use too many shaders — maximum 2 per video unless user wants differently.
|
||||
|
||||
**Shader transitions — block name ≠ shader name.** When you run the commands above and see `domain-warp-dissolve` in `registry/blocks/`, the HyperShader runtime name is `domain-warp` (without "-dissolve"). After installing a block, open its showcase HTML (`compositions/<block-name>.html`) and find the actual shader name used in `HyperShader.init()`. That is what you put in the storyboard. Then delete the showcase file — it's a demo only and will pollute your compositions/ directory with lint warnings.
|
||||
|
||||
### HTML-in-Canvas — plan for it here, build in Step 5
|
||||
|
||||
The `drawElementImage` Chrome API captures any live HTML/CSS as a GPU-accelerated texture at 60fps. This is HyperFrames' highest-impact capability — it lets you render captured product screenshots or UI through:
|
||||
|
||||
- **3D geometry** — a rotating iPhone or laptop model, a sphere, a curved surface
|
||||
- **WebGL shaders** — liquid glass refraction, shatter into fragments, portal reveal, noise distortion
|
||||
- **Post-processing** — bloom, depth-of-field, film grain, color grading
|
||||
|
||||
When planning beats, decide which ones deserve an HTML-in-Canvas treatment vs. a standard GSAP animation. If you want it, name it in the storyboard — Step 5 will read [`../../hyperframes/references/html-in-canvas-patterns.md`](../../hyperframes/references/html-in-canvas-patterns.md) for implementation. You don't need to specify the API details here.
|
||||
|
||||
### SFX assignment — happens here, not in Step 5
|
||||
|
||||
**Before writing beats,** read `skills/website-to-hyperframes/assets/sfx/manifest.json` (or your local copy at `sfx/manifest.json` if already copied to the project). Each entry has a filename, duration in seconds, and description. Assign **specific SFX files** to exact moments in the storyboard. Step 5 implements what you specify here — it makes no SFX decisions.
|
||||
|
||||
Per beat, specify SFX like:
|
||||
|
||||
- `sfx/impact-bass-1.mp3` at `0.2s`, volume `0.35` — on the hero image snapping into frame
|
||||
- `sfx/chime.mp3` at `3.8s`, volume `0.5` — on the logo appearing
|
||||
|
||||
**Less is more.** Most beats need zero SFX. One SFX per beat is typical; multiple only if the beat has genuinely distinct punctuation moments. Never place SFX on shader transitions directly — shader transitions are already an audio-visual event.
|
||||
|
||||
**How to place each sound type** (industry-standard rules):
|
||||
|
||||
- **Impact/hit sounds** (`impact-bass-1`, `ping`, `pop`, `glitch-*`): peak is at the start of the clip. Trigger exactly at the visual moment. Let the decay tail bleed into the next scene — this is normal, called a J-Cut, and sounds professional. `data-duration` = full manifest duration, never trimmed.
|
||||
- **Riser/build-up sounds** (`riser`, `whoosh-cinematic`): peak is at the END of the clip. To make the peak land on a climax moment (a transition, a reveal), trigger at `climax_time - sfx_duration`. For `riser.mp3` (10.03s) peaking at a t=20s transition: trigger at t=9.97s.
|
||||
- **Short accent sounds** (`click`, `click-soft`, `chime`, `sparkle`, `ping`): trigger at the exact visual punctuation moment. Duration is short, no tail concern.
|
||||
|
||||
**Volume when SFX overlaps narration:** HyperFrames has no automatic audio ducking. If an SFX plays under spoken narration, set its volume to 0.2–0.3 max, not 0.5+. Specify this in the storyboard entry so Step 5 wires it correctly.
|
||||
|
||||
**data-duration rule** (for Step 5 to implement): always equals the manifest's duration field exactly. Never set it shorter to "fit" the remaining beat time — truncating an impact mid-decay is the exact problem causing the cut-off sounds in v2 videos.
|
||||
|
||||
### Architecture Constraint: Each Beat is an Independent Composition
|
||||
|
||||
Each beat is built as a separate HTML file (`compositions/beat-N.html`). These are loaded independently — they do NOT share state, WebGL contexts, Three.js scenes, or DOM elements with other beats. This means:
|
||||
|
||||
- **No "persistent" elements across beats** — you can't have a MacBook model that stays on screen while only the screen content changes between beats 2, 3, 4. Each beat loads its own MacBook from scratch. If you want visual continuity, each beat must independently set up the element at the same position/rotation, so it APPEARS continuous.
|
||||
- **No shared 3D scenes** — each beat that uses Three.js creates its own renderer, scene, and camera. If beats 2 and 3 both show a rotating laptop, they each load the model independently and must start from matching positions.
|
||||
- **Shader transitions happen between beats** (in index.html), not within beats. Don't plan a shader transition "inside" a beat.
|
||||
|
||||
Plan your storyboard within these constraints. If you describe "the MacBook stays in place while content swaps," you need to specify that each beat independently recreates the MacBook at the same position — not that it persists.
|
||||
|
||||
### Device Mockups: Use the Registry Block
|
||||
|
||||
If the storyboard calls for a MacBook or iPhone mockup, use the pre-built `vfx-iphone-device` registry block — it has both **iPhone 15 Pro Max AND MacBook Pro** GLTF models with live HTML-in-Canvas screens, camera choreography, and glass lens morphing. Install with `npx hyperframes add vfx-iphone-device`.
|
||||
|
||||
Do NOT hand-code a Three.js device scene from scratch. The registry block handles UV mapping, screen textures, lighting, and camera angles correctly. Hand-coded versions consistently produce broken screen textures, wrong UV flipping, and path resolution bugs. Use the block.
|
||||
|
||||
---
|
||||
|
||||
## Per-Beat Direction
|
||||
|
||||
Each beat is a SHOT, not a layout. Write what the CAMERA does and what the FRAME reveals — not "what's positioned where on the page."
|
||||
|
||||
### A beat is a shot — pick the framing before writing CSS
|
||||
|
||||
Every beat header should declare its shot type in the first line. **Shot types:**
|
||||
|
||||
| Shot | Use for | What the frame contains |
|
||||
| --------------------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
|
||||
| **Extreme close-up** | a single card / number / character / cursor / button as the entire subject | one element fills 60–90% of frame, everything else blurred or absent |
|
||||
| **Close-up** | a small UI region (a single column, a card stack, a chart, a code block) | the subject fills 40–60% of frame with depth-layered context behind |
|
||||
| **Medium** | a section of UI — kanban with 3 columns, chat with 3 messages, dashboard with 2-3 panels | the subject fills 60–80% of frame, edges of nearby UI bleed in |
|
||||
| **Wide** | full UI assembly visible — only when the WHOLE thing is the point | full UI at 70–90% scale with deliberate negative space |
|
||||
| **Over-the-shoulder** | viewer "behind" the user — cursor / hands / device foreground, UI midground | foreground element bottom 1/3, UI fills upper 2/3 with parallax depth |
|
||||
| **Dutch angle** | tension, urgency, "something's off" | the frame is tilted 4–8°, content composed to feel unstable |
|
||||
|
||||
**The "wide shot" trap:** _Every_ beat at wide framing looks like a screenshot in CSS. Most product-demo videos should be 60% close-up + close-up + 20% medium + 10% wide + 10% extreme close-up. Wide is the rare establishing shot, not the default.
|
||||
|
||||
### Camera motion is the subject, not the elements
|
||||
|
||||
In website thinking: elements animate in, then sit still while the user reads. In video thinking: the camera moves THROUGH the scene. The composition shifts.
|
||||
|
||||
Every beat needs at least one camera-style move. Pick from:
|
||||
|
||||
- **Dolly in** — composition scales 1.0 → 1.08 over the beat duration, slight x/y drift
|
||||
- **Dolly out / pull-back** — composition scales 1.15 → 1.0, revealing more context
|
||||
- **Push** — fast scale-up (1.0 → 1.05, ~0.5s power3.out) on a key moment
|
||||
- **Parallax pan** — background drifts opposite to foreground at different speeds
|
||||
- **Orbit** — the subject rotates in 3D, or the camera circles it
|
||||
- **Rack focus** — blur shifts from one element to another (background blurs as foreground sharpens)
|
||||
|
||||
If a beat has NO camera-style move and elements only animate inward at the start, it will read as a webpage with entrance animations. That's not a video beat.
|
||||
|
||||
### Forbidden patterns (the video-as-webpage failures)
|
||||
|
||||
These appear in nearly every iteration where sub-agents revert to website thinking. Refuse to write any beat that includes:
|
||||
|
||||
- ❌ **macOS / browser window chrome** as a frame around the content — traffic-light dots, URL bars, browser tabs, breadcrumbs — UNLESS the beat IS specifically about that chrome (e.g., "the macOS window itself is the subject of the shot")
|
||||
- ❌ **Sidebars, navigation rails, page headers, page footers** unless the beat demonstrates navigation as its concept
|
||||
- ❌ **"Centered card / panel / window with 60–120px margin on all sides"** — that's the standard webpage layout; videos use the full frame and meaningful negative space
|
||||
- ❌ **"Hold with breathing" micro-animations** where elements move y: ±1–2px or scale 1.01 — invisible at video resolution; this is sub-agents pretending the beat has motion when it doesn't
|
||||
- ❌ **Settled holds longer than 1.5s** with no continuous camera or compositional change — fix by adding camera dolly, depth-layer parallax, or new sub-elements entering mid-beat
|
||||
- ❌ **Hover-state demonstrations** — videos have no hover; if the brand has a hover effect to communicate, find a way to show the BEFORE and AFTER as discrete frames, not a hover simulation
|
||||
- ❌ **Tooltips and modal cards "for context"** that explain what something is — videos communicate through visual language, not popup hint text
|
||||
|
||||
### Required for every beat (the floor for video grammar)
|
||||
|
||||
Every beat must specify, in its visual description:
|
||||
|
||||
1. **Shot type** (one of the six above)
|
||||
2. **Camera move** (which one, when it starts, how long it lasts)
|
||||
3. **Depth strategy** (what's in foreground / midground / background, how they parallax)
|
||||
4. **Motion magnitudes** that read at video scale (30px+ y/x movements, scale changes ≥0.05, opacity transitions ≥0.5)
|
||||
5. **The shot's purpose** — what specifically is the viewer supposed to feel or notice in this 3–5 seconds?
|
||||
|
||||
---
|
||||
|
||||
### Existing beat-level fields (below) layer on top of the shot grammar above
|
||||
|
||||
Each beat is a WORLD, not a layout. Write what the viewer EXPERIENCES before you write CSS specs.
|
||||
|
||||
**Motion verbs** — every animated element gets one. Pick from the beat's concept, not from an energy bucket:
|
||||
|
||||
- **Impact:** SLAMS, CRASHES, PUNCHES, DROPS, SHATTERS
|
||||
- **Directional:** SLIDES, PUSHES, WIPES, CUTS
|
||||
- **Reveals:** DRAWS, FILLS, GROWS, ASSEMBLES, COUNTS UP
|
||||
- **Organic:** FLOATS, DRIFTS, BREATHES, PULSES, ORBITS
|
||||
- **Mechanical:** TYPES ON, CLICKS, LOCKS IN, SNAPS, STEPS
|
||||
|
||||
**Transition decision matrix** — shader vs CSS vs hard cut:
|
||||
| Shader transition for | CSS crossfade for | Hard cut for |
|
||||
|---|---|---|
|
||||
| Hero reveals, logo unveils, "wow" moments | Continuous motion between beats, editorial pacing | Rapid-fire lists, percussive edits, comedy timing |
|
||||
|
||||
1–2 shader transitions per video (hero + CTA). Too many flatten their impact. Mix shader and CSS crossfade in one HyperShader composition by omitting `shader` on any transition entry.
|
||||
|
||||
**Rhythm** — declare your scene rhythm before implementing: fast-fast-SLOW-fast-SHADER-hold. The rhythm comes from the brand and content, not a template.
|
||||
|
||||
Use the pacing you decided at the top of this step. The beat count, duration, and architecture are already set.
|
||||
|
||||
**Cut the video to match the narration length** — if the script produces 22 seconds of audio, the video should be 24 seconds with a 2-second CTA hold, not 30 seconds with 8 seconds of dead silence. Empty time at the end where nothing is happening loses the viewer.
|
||||
|
||||
**Frame-filling rule:** When describing visuals per beat, specify sizes as FRAME FILL PERCENTAGES, not pixels. "Product screenshot fills 80% of frame" not "600px wide card."
|
||||
|
||||
**Compose the load-bearing visuals yourself.** Build the kanban from cards-as-divs. Draw the logo with SVG paths. Paint the gradient with shader noise. Animate the counter with `tl.set()`. The video should feel **alive in every frame** — motion that's continuous and tangible, **like things exist in a physical world**. Captured assets (brand logo, hero illustrations, gradient backgrounds, product photography) are accents you layer onto composed beats — they decorate, they don't carry. Find the most suitable combinations: composed UIs grounded in the brand's actual colors and fonts, with captured brand marks stamped in as identity, not as content. For every beat where the storyboard pull is "show the kanban / dashboard / chat / terminal," the answer is build it from divs and CSS, not paste a screenshot.
|
||||
|
||||
**Opener default: fast intro to stop the scrollers.** Even a cinematic video should start with a punch — a flash, a shader bloom, a logo strike, a kinetic word build, a particle burst — anything that lands inside the first 1.0–1.5 seconds. Slow intros work for prestige trailers; videos shipping anywhere social or feed-based need a hook that beats the 1.5-second scroll threshold. Plan the opener as the most ambitious beat in the storyboard, not the gentlest one.
|
||||
|
||||
**CTA / closing beats** are consistently the weakest. Agents treat them as "logo + tagline + done." A good CTA should: make the logo entrance an event (SVG path draw, scale with overshoot, or anything awesome really), have continuous background motion, and hold only 2-3 seconds after the last spoken word — NOT 8-10 seconds of silence.
|
||||
|
||||
**VO start timing — decide here, not in Step 5.** When does the narration actually begin relative to the first visual? Options: (a) VO starts over the visual intro (heard before content settles — creates urgency), (b) VO starts after the visual intro settles (viewer sees the opening, then hears the voice — creates drama), (c) a few seconds of music-only visual before VO enters. None of these is a default — pick based on the brand and the opening beat's concept. State the intended narration start time explicitly in the storyboard's Global Direction, e.g. `**Narration start:** 0.8s (after hero intro settles)`. Step 5 wires this as the audio element's `data-start`.
|
||||
|
||||
**Concept-first beats.** Every beat starts with its CONCEPT — not "what technique to use" but "what does this scene should show, what did the previous showed and what will the next show...?" What idea is being communicated? The crazy and interesting concept drives every technical decision.
|
||||
|
||||
In the capture pipeline, each beat includes:
|
||||
|
||||
### Concept
|
||||
|
||||
What does this scene REPRESENT in terms of previous (if exists) and next scenes? Not "show features" but a specific idea and logic.
|
||||
|
||||
### VO cue
|
||||
|
||||
Which narration line plays over this beat (Also keep in mind the whole narration of the video to understand and keep in mind the flow).
|
||||
|
||||
### Visual description
|
||||
|
||||
What the viewer sees — described cinematically, not as CSS specs. Use camera language and production motion designer vocabulary (pan, zoom, drift, settle, and more of those words). Think in layers — what's supposed to happen in the foreground, midground, background simultaneously?
|
||||
|
||||
**For the rare beat where a captured asset is the primary visual** (e.g., a homepage-reveal beat where the literal site IS the subject, or a customer-photo beat where the photo is the content): specify which asset, how much of the frame it fills (%), and where text/labels go relative to its safe zones. Don't blindly center text over busy product UI. **These beats should be the exception, not the rule** — if every beat's primary visual is a captured asset, you've defaulted to the slideshow pattern this workflow exists to break.
|
||||
|
||||
### Composition + Accents
|
||||
|
||||
Two things, both required:
|
||||
|
||||
**Composed (load-bearing — what carries the beat):**
|
||||
|
||||
- Describe the UI / element / scene you're building from scratch: markup structure, the techniques powering it (cite [capabilities.md](capabilities.md) sections + [techniques.md](../../hyperframes/references/techniques.md) entries), key animation events. E.g. "Composed kanban: 3 column divs, 4 cards each, drag-and-drop with `back.out(1.7)` entrance stagger, counter chip on In-Progress incrementing via `tl.set()`."
|
||||
- **Brand-inflect:** brand colors from DESIGN.md, real product data (project names, real metrics, real copy — not placeholder labels), narration-sync moments. Make this beat THIS brand's beat, not a generic UI demo.
|
||||
|
||||
**Accents (decoration only — what brand-inflects the beat):**
|
||||
|
||||
- Optional. Most beats need 0-1 accent. Format: `capture/assets/<filename>` — how it appears: position, opacity, treatment, motion (e.g. `capture/assets/logo.svg` — top-left, 60×60, fades in at 0.4s, breathes during hold).
|
||||
- Common accent uses: brand logo stamped on composed UI, hero illustration as depth layer, gradient image as ambient bg wash, brand mark on a composed pricing card.
|
||||
- If a beat has no obvious accent need, leave this blank. The composed visual is enough.
|
||||
|
||||
Write this section for THIS project's actual brand and the assets audited above — not from memory.
|
||||
|
||||
### Text Animations
|
||||
|
||||
Every text element in this beat must name a specific effect from `skills/hyperframes/references/text-effects.md`. Read the catalog, pick what fits the brand and this beat's mood — don't default to the same effect every beat.
|
||||
|
||||
Format (FORMAT EXAMPLES of structure, not prescriptions — pick based on brand/mood/context):
|
||||
|
||||
- `[element — e.g. "main headline"]`: `[effect-id]` — `skills/hyperframes/assets/text-effects/effects/[id].json`
|
||||
- `[element — e.g. "eyebrow label"]`: `[effect-id]` — `skills/hyperframes/assets/text-effects/effects/[id].json`
|
||||
|
||||
The sub-agent reads the named JSON file and implements from `showcase.library_adapters.gsap`. No creative decisions at build time.
|
||||
|
||||
### Beat Timing
|
||||
|
||||
Two numbers Step 5 needs to wire `data-start` and `data-duration` correctly:
|
||||
|
||||
- **HyperShader transition in at:** `[time]s` (the `time:` value in the transitions array for the transition INTO this beat — or 0 for beat 1)
|
||||
- **GSAP timeline duration:** `[duration]s` (how long this beat's internal animations run — when does the last tween end?)
|
||||
|
||||
Example: `Transition in at: 4.2s · GSAP duration: 5.5s` → Step 5 sets `data-start="4.2" data-duration="5.5"`.
|
||||
|
||||
### Animation Sequence — must span the ENTIRE beat
|
||||
|
||||
A beat is a SCENE with internal life, not a single entrance followed by a static hold. Things should be happening throughout the entire duration — new elements appearing, existing elements transforming, camera drifting, details revealing, sub-moments unfolding.
|
||||
|
||||
If your animation sequence only has events in the first 2 seconds and the beat lasts longer, the rest is dead air. Plan moments across the full duration. Nothing should sit unchanged for more than ~2 seconds — if an element is on screen, give it continuous motion (drift, breathe, pulse, parallax).
|
||||
|
||||
Describe the feel precisely: "snappy overshoot bounce settling into place" → back.out; "slow heavy drift" → power1.inOut. Vague adjectives are useless.
|
||||
|
||||
---
|
||||
|
||||
## Brand Accents Pass (LAST creative decision — happens after beats are written)
|
||||
|
||||
Your beats are now conceptually defined. Each one has a composed visual that carries it. **Now**, do a single pass to decide which captured assets — if any — earn an accent role on which beat.
|
||||
|
||||
This is the LAST creative pass before file-tree time. It comes here intentionally: assets decorate concept-defined beats; they do not seed them. If you find yourself wanting to add a beat _because_ an asset would look cool, the asset is doing the storyboarding — go back and rewrite that beat from the message instead.
|
||||
|
||||
### The brand-inflection floor (REQUIRED minimums)
|
||||
|
||||
Two hard rules — the main agent checks them at Step 5 (reading each beat HTML top-to-bottom for asset references), and the deliverable fails the brand-floor check if they're missing:
|
||||
|
||||
1. **The brand mark (logo / wordmark SVG) MUST appear in the opener AND the closer beat.** A brand video that doesn't show the brand mark in the first and last frame is failing its job. The only exception is when STORYBOARD.md explicitly overrides this with a written reason (e.g., "opener is pure kinetic typography to delay brand reveal until beat 3 for narrative tension"). If you override, write the reason in that beat's Composition + Accents section so the verifier sees it.
|
||||
|
||||
2. **The site's signature visual MUST appear somewhere in the video.** Every captured site has one: the gradient wave, the hero illustration, the distinctive product UI mark, the wordmark animation, the color combination, the hero photograph. It's whatever a viewer who knows the brand would point at and say "that's them." Find it during Step 0; place it as an accent in at least one beat.
|
||||
|
||||
These are floors, not ceilings. Beyond them, aim for 2-4 brand accents total across the whole video, not per beat. Most beats need 0-1. Everything beyond the floor has to justify itself against the question: _"Does this asset make the beat MORE this brand, or is it filler?"_
|
||||
|
||||
Print this table once your beats are written:
|
||||
|
||||
| Asset | Type | Where (beat #) | Role |
|
||||
| ------------------------------ | -------- | --------------- | ------------------------------------------------------------------------------- |
|
||||
| stripe-logo.svg | SVG | Beat 1 + Beat N | Brand mark (opener stroke-draw, closer hold) |
|
||||
| wave-fallback-desktop.png | Gradient | Beat 3 bg layer | Ambient depth wash behind composed dashboard |
|
||||
| datavizstatic3x.png | Data viz | SKIP | Compose the stats from divs + counter animations instead |
|
||||
| enterprise-accordion-hertz.png | Photo | SKIP | Compose the customer-story UI from divs with the brand's testimonial card style |
|
||||
| icon-3.svg | Icon | SKIP | Decorative, too small to matter |
|
||||
|
||||
Mark assets `SKIP` when a composed equivalent (dashboards, kanban, chat, terminal, file tree, calendar, pricing cards, etc.) does a better job — that's the strong default for product UI. Use the brand's _real_ data (project names, real metrics, real product copy) in composed beats — never the placeholder labels a screenshot would have.
|
||||
|
||||
**Update each beat's Composition + Accents section** based on what this pass produced. Most beats stay accent-free. The few that earn one get a single line under "Accents" with the file, position, opacity, and motion.
|
||||
|
||||
**The bar:**
|
||||
|
||||
- Every beat's primary visual stays composed from divs / SVG / CSS / GSAP at build time
|
||||
- Accents are a thin layer of brand inflection on top — never the carrier
|
||||
- A beat with no obvious accent need stays accent-free. The composed visual is enough.
|
||||
|
||||
---
|
||||
|
||||
## Production Architecture
|
||||
|
||||
Include this file tree at the bottom of the storyboard:
|
||||
|
||||
```
|
||||
project/
|
||||
├── index.html root — VO + underscore + beat orchestration
|
||||
├── DESIGN.md brand reference (from Step 1)
|
||||
├── SCRIPT.md narration text (from Step 3)
|
||||
├── STORYBOARD.md THIS FILE — creative north star
|
||||
├── transcript.json word-level timestamps (from Step 4)
|
||||
├── narration.wav TTS audio (from Step 4)
|
||||
├── capture/ captured website data (from Step 0)
|
||||
│ ├── screenshots/
|
||||
│ ├── assets/
|
||||
│ │ ├── svgs/
|
||||
│ │ ├── fonts/
|
||||
│ │ ├── lottie/
|
||||
│ │ └── videos/
|
||||
│ ├── extracted/
|
||||
│ │ ├── tokens.json
|
||||
│ │ ├── design-styles.json
|
||||
│ │ ├── visible-text.txt
|
||||
│ │ ├── asset-descriptions.md
|
||||
│ │ ├── animations.json
|
||||
│ │ ├── assets-catalog.json
|
||||
│ │ └── detected-libraries.json
|
||||
│ ├── AGENTS.md
|
||||
│ └── CLAUDE.md
|
||||
└── compositions/
|
||||
├── beat-1-hook.html
|
||||
├── beat-2-features.html
|
||||
├── ...
|
||||
└── captions.html
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example: Beat-by-Beat Format
|
||||
|
||||
The two beats below are from the real Claude Design × HyperFrames production video. They show the expected level of specificity — exact timing, exact GSAP values, exact animation sequences.
|
||||
|
||||
**Why only 2 beats are shown:** Earlier versions of this reference showed all 10 beats, and agents pattern-matched from them regardless of the brand being captured. Moodboard layouts, capabilities grids, and orbital letter closers started appearing in every video. The concepts in those beats are specific to HyperFrames as a product — they should not appear in a video about a fintech tool or a wellness app. Only two beats are shown here to demonstrate the format level, not to suggest these specific techniques.
|
||||
|
||||
### BEAT 1 — LIGHT BALL OPENER (0:00–0:03)
|
||||
|
||||
**Concept:** No title card, no fade from black. A single point of warm light appears in total darkness. It blooms into a horizon-spanning glow. The viewer leans in before a single word is spoken.
|
||||
|
||||
**Visual:** Deep black canvas (#050507) with grain overlay (mix-blend-mode: overlay, 0.12 opacity) and extended vignette (inset: -200px for long falloff). The `.ball-core` is a 40px radial-gradient orb (white center → accent → transparent). Animation sequence:
|
||||
|
||||
- 0.0s: Orb appears tiny (scale: 0.15, opacity: 0→1, 0.18s, expo.out)
|
||||
- 0.18s: Orb grows continuously (scale: 0.4→1.4, 0.7s, power1.in). Simultaneously the `.ball-halo` (140% width, 70% height ellipse, accent-tinted radial-gradient, blur: 60px) blooms in (scale: 0.4→1, opacity: 0→1, 0.55s, sine.out)
|
||||
- 0.65s: Orb keeps growing as it fades (scale: 1.4→8, opacity: 1→0, 0.4s, power2.in) — the point of light dissolves into pure glow. Halo expands further (scale: 1→1.25, opacity: 0.85)
|
||||
- 0.85s: Horizontal beam line emerges from center (scaleX: 0→1, 0.4s, expo.out) with warm box-shadow glow (0 0 24px 1px rgba(255,240,220,0.4))
|
||||
- 1.0s: Title "Claude Design × HyperFrames" fades up above the line (opacity: 0→1, y: 14→0, 0.7s, power3.out). Ampersand in italic accent color.
|
||||
- 1.3s: Date subtitle appears below the line (0.6s, power2.out). Monospace font, 0.32em letter-spacing, uppercase.
|
||||
- 2.2s: Bottom credit line fades in ("This entire video was made with HyperFrames in Claude Design")
|
||||
- 3.0–4.4s: Hold — halo breathes (opacity drifts to 0.55, scale to 1.4, sine.inOut), headline drifts slightly (y: -3px)
|
||||
- 4.4s: Everything fades to black together (0.6s, power2.in)
|
||||
|
||||
Corner marks (monospace, 11px, 0.45 opacity) at top-left and bottom-right for editorial feel.
|
||||
|
||||
**SFX:** Deep ambient bass pad already playing from frame 1.
|
||||
|
||||
---
|
||||
|
||||
_(Beats 2–9 intentionally omitted. See above for why.)_
|
||||
|
||||
### BEAT 10 — ORBITAL LETTERS / CLOSE (example of a closing beat spec)
|
||||
|
||||
**VO:** (resolving — the brand name assembles)
|
||||
|
||||
**Concept:** Individual letterforms of "HYPER FRAMES" burst in from alternating sides, each with rotation and offset. They bounce into place with back.out(2.0) overshoot. An accent line draws itself across the width. An orbit ring expands with a glowing dot tracing a full 360° rotation. A tagline types itself out: "HTML in. Video out." with deliberate pauses after each word. Everything breathes after assembly — letters float gently, glow pulses, connector lines shimmer.
|
||||
|
||||
**Visual:** Deep black. Center glow: 900px radial-gradient orb (accent #e8a769 at 0.35 → 0.12 → 0.025 → transparent), blur(100px).
|
||||
|
||||
**Animation sequence:**
|
||||
|
||||
- 0.1s: 12 character elements ("H Y P E R [space] F R A M E S") enter staggered 0.06s apart, each from y: 80 with alternating x offset (odd: -30, even: +30) and rotation: -15. Landing: back.out(2.0), 0.7s — gives each letter a satisfying overshoot bounce.
|
||||
- 1.0s: Accent SVG line draws across the full 1920px width (strokeDashoffset: 1920→0, 0.6s, power3.out). #e8a769 stroke, 2px.
|
||||
- 1.0s: Glow breathes in (opacity: 0→0.2, sine.inOut, 0.4s), then back to 0.1.
|
||||
- 1.4s: Orbit ring (600px circle, 1px border rgba(accent, 0.3)) expands from scale: 0.5 to 1.0 (expo.out, 0.5s). A glowing orbit dot (8px, accent color, box-shadow glow) on the ring traces a full 360° rotation over 2.5s (linear easing — constant speed).
|
||||
- 1.25s onward: Letters begin a subtle float — alternating directions (y: ±2px, sine.inOut, 1.4s, yoyo, repeat 1), staggered 0.04s. Keeps the assembled word feeling alive.
|
||||
- 1.8s: Tagline types itself in monospace (24px, accent color, 0.15em letter-spacing): "HTML" (pause 0.2s), " in." (pause 0.25s), " Video" (pause 0.1s), " out." — each segment at 0.03s per character using steps(N) easing for discrete character appearance.
|
||||
- 1.8s onward: Glow continues gentle breathing (opacity: 0.1→0.14, sine.inOut, 1.2s, yoyo, repeat 1).
|
||||
|
||||
**SFX:** Soft chime on letter assembly completion. Silence under the tagline typing — let it land.
|
||||
|
||||
---
|
||||
|
||||
## Write the Narration Script (same step — write alongside the storyboard)
|
||||
|
||||
The script and storyboard are one step. Every beat already has a VO cue — the script is just all those VO cues assembled into a single document. As you write each beat, write its narration line. Then assemble them into `SCRIPT.md`.
|
||||
|
||||
The script serves the storyboard — write words that fit the visual plan, not the other way around. Reference real product features, real stats, and real components from `capture/extracted/visible-text.txt`. Use exact numbers.
|
||||
|
||||
**Script length depends on the creative direction, not a formula.** A cinematic video with dramatic pauses and visual-only moments might have 40 words across 30 seconds. A rapid feature showcase might pack 100 words into 30 seconds. The storyboard's pacing and style (from Step 2's brief) determine how much narration vs. silence the video needs. Some beats are narrated; some are pure visual. Let the creative plan drive the word count, not the other way around.
|
||||
|
||||
The key constraint: don't pad with dead silence where nothing is happening. If a beat has no narration, something visual must be carrying the viewer's attention. Empty frames = lost viewers.
|
||||
|
||||
Save as `SCRIPT.md` in the project directory.
|
||||
|
||||
**Script writing rules:**
|
||||
|
||||
- ~2.5 words/sec natural pace. 15s = ~37 words, 30s = ~75 words.
|
||||
- Use contractions ("it's", "you'll"). Read it out loud — if it sounds robotic, rewrite.
|
||||
- Write numbers as spoken: `$1.9T` → "nearly two trillion dollars", `API` → "A P I", `10x` → "ten times"
|
||||
- **Hook first** — bold claim, provocative question, contrast, or shocking number. Never "Welcome to..." or "Introducing..."
|
||||
- Structure: Hook → Story → Proof → CTA. 15s ads can skip Story.
|
||||
|
||||
---
|
||||
|
||||
## User Review Gate
|
||||
|
||||
After writing the storyboard AND the script, present BOTH to the user for review. The storyboard and script are coupled — the user needs to see them together to judge whether the video works.
|
||||
|
||||
### How to Present
|
||||
|
||||
Summarize the plan clearly. Don't dump the full STORYBOARD.md — give the user a beat-by-beat overview they can scan in 30 seconds:
|
||||
|
||||
> **Here's what I've planned for your [duration] [type]:**
|
||||
>
|
||||
> **Beat 1 (0:00–0:04):** [one sentence — what happens visually + what the narration says]
|
||||
> **Beat 2 (0:04–0:10):** [one sentence]
|
||||
> **Beat 3 (0:10–0:18):** [one sentence] _(hero beat — 3D MacBook reveal with bloom effect)_
|
||||
> ...
|
||||
> **Beat N (closing):** [one sentence — CTA/logo]
|
||||
>
|
||||
> **Style:** [dimension summary — e.g., "Cinematic pacing, dark mood, dramatic transitions for hero, clean for the rest"]
|
||||
> **Narration:** [first and last line of the script]
|
||||
> **Total duration:** [X]s with [N] beats
|
||||
>
|
||||
> **Does this match what you envisioned?** I can adjust: beats, pacing, specific effects, the script tone, or anything else. Or if this looks good, I'll proceed to voice generation.
|
||||
|
||||
### What to do with feedback
|
||||
|
||||
- **"Looks good" / approval** → proceed to Step 4 (VO)
|
||||
- **Specific feedback** ("make beat 3 longer", "change the opening to be faster", "I don't want the typing effect") → update STORYBOARD.md and SCRIPT.md, re-present
|
||||
- **Major direction change** ("actually I want it more playful, not cinematic") → revisit Step 2's brief dimensions, rewrite storyboard
|
||||
- **Iterate until the user is satisfied.** This is the cheapest place to make changes — changing a storyboard beat costs 30 seconds. Changing a built composition costs 5 minutes.
|
||||
|
||||
### Gate
|
||||
|
||||
Both STORYBOARD.md and SCRIPT.md exist AND the user has explicitly approved the plan.
|
||||
@@ -1,169 +0,0 @@
|
||||
# Step 4: Write the Storyboard
|
||||
|
||||
**Before writing anything, fully re-read these files:**
|
||||
|
||||
- **DESIGN.md** — your color palette, font rules, components, Do's/Don'ts. Every creative decision must be grounded in this brand identity. If it says "white backgrounds with purple accent" — plan light scenes, not dark moody ones.
|
||||
- **`capture/extracted/asset-descriptions.md`** — read EVERY line. This is your menu of available visuals. Each line describes what the image actually shows (e.g., "translucent ribbons in orange, pink, and purple on white background" or "a high-speed train under a dark starry sky"). Use these descriptions to decide which assets belong in which beat. Assets you don't understand from the description — view them directly before assigning.
|
||||
- **[techniques.md](../../hyperframes/references/techniques.md)** — 11 visual techniques (SVG path drawing, Canvas 2D art, CSS 3D, per-word typography, Lottie, video compositing, typing effect, variable fonts, MotionPath, velocity transitions, audio-reactive). Pick 2-3 per beat and specify them in the storyboard.
|
||||
|
||||
The storyboard is the creative north star. It tells the engineer exactly what to build for each beat — mood, camera, animations, transitions, assets, sound. Write it as if you're briefing a motion designer who's never seen the website.
|
||||
|
||||
Save as `STORYBOARD.md` in the project directory.
|
||||
|
||||
---
|
||||
|
||||
## Global Direction
|
||||
|
||||
Every STORYBOARD.md starts with global settings:
|
||||
|
||||
```markdown
|
||||
**Format:** 1920×1080
|
||||
**Audio:** [TTS provider] voiceover + underscore + SFX
|
||||
**VO direction:** [voice character — e.g., "mid-age male, calm confident delivery,
|
||||
Apple keynote register — economy of words, silence between sentences is a feature"]
|
||||
**Style basis:** DESIGN.md (brand colors, fonts, components from the captured site)
|
||||
```
|
||||
|
||||
**Global guardrails** — read [video-composition.md](../../hyperframes/references/video-composition.md) first. It defines the medium rules: density, color presence, scale, frame composition, and how design.md is brand truth not layout spec. Then apply these capture-specific additions:
|
||||
|
||||
- Use as many captured assets as the creative vision allows. Scatter framework icons around a dashboard. Layer enterprise photos behind stats. Use product screenshots as floating cards. The assets exist — use them generously.
|
||||
- Use at least 2-3 different techniques from techniques.md per beat — not across the whole video, per beat. Don't default to basic fade/scale/opacity — mix in SVG path drawing, CSS 3D transforms, typing effects, counter animations, canvas procedural art. Each beat should feel like its own visual world.
|
||||
|
||||
**Underscore/music direction** (if applicable):
|
||||
|
||||
- Describe the mood, reference artists, when it swells or drops
|
||||
- Example: "Minimal electronic. Warm sustained pad already playing when the video starts. Sits underneath everything, never competing with VO. Swells gently during the flex section, drops to near-nothing for the comparison, resolves on a final chord."
|
||||
|
||||
---
|
||||
|
||||
## Asset Audit
|
||||
|
||||
Before writing any beats, audit every captured asset. Print this table:
|
||||
|
||||
| Asset | Type | Assign to Beat | Role |
|
||||
| ------------------------------ | ---------- | -------------- | ------------------------------------- |
|
||||
| wave-fallback-desktop.png | Hero image | Beat 1 | Full-bleed animated background |
|
||||
| enterprise-accordion-hertz.png | Photo | Beat 3 | Enterprise credibility, Ken Burns pan |
|
||||
| stripe-logo.svg | SVG | Beat 1, Beat 5 | Brand mark opener + closer |
|
||||
| datavizstatic3x.png | Data viz | Beat 3 | Supporting visual behind stats |
|
||||
| icon-3.svg | Icon | SKIP | Decorative, too small |
|
||||
|
||||
**Minimum utilization:**
|
||||
|
||||
- At least 50% of product screenshots and hero images must appear
|
||||
- Brand logo appears in the first AND last beat
|
||||
- The site's signature visual (gradient wave, hero illustration, key product UI) must appear — it's the most recognizable brand element
|
||||
- Maximum 2 consecutive text-only beats. The 3rd must contain a visual asset
|
||||
- Opening beat must contain a visual asset, not text-only
|
||||
|
||||
---
|
||||
|
||||
## Per-Beat Direction
|
||||
|
||||
Read [beat-direction.md](../../hyperframes/references/beat-direction.md) for the general beat template: concept, mood, animation choreography (energy verbs), transitions (shader vs CSS vs hard cut decision matrix), depth layers, SFX cues, rhythm planning, and velocity-matched transitions.
|
||||
|
||||
In the capture pipeline, each beat also includes:
|
||||
|
||||
### VO cue
|
||||
|
||||
Which narration line plays over this beat.
|
||||
|
||||
### Visual description
|
||||
|
||||
What the viewer sees — described cinematically, not as CSS specs. Use camera language (pan, zoom, drift, settle). Describe at least 5 visual elements, not just text + background. Think in layers — what's moving in the foreground, midground, background simultaneously?
|
||||
|
||||
### Assets
|
||||
|
||||
Which captured files to use, referenced by filename:
|
||||
|
||||
- "Background: `capture/assets/wave-fallback-desktop.png` — full-bleed, slow zoom 1→1.04 over beat duration"
|
||||
- "Logo: `capture/assets/svgs/stripe-logo.svg` — centered, fades in at 0.5s"
|
||||
- "Enterprise photo: `capture/assets/enterprise-accordion-hertz.png` — Ken Burns pan, 70% opacity overlay"
|
||||
|
||||
---
|
||||
|
||||
## Production Architecture
|
||||
|
||||
Include this file tree at the bottom of the storyboard:
|
||||
|
||||
```
|
||||
project/
|
||||
├── index.html root — VO + underscore + beat orchestration
|
||||
├── DESIGN.md brand reference (from Step 2)
|
||||
├── SCRIPT.md narration text (from Step 3)
|
||||
├── STORYBOARD.md THIS FILE — creative north star
|
||||
├── transcript.json word-level timestamps (from Step 5)
|
||||
├── narration.wav TTS audio (from Step 5)
|
||||
├── capture/ captured website data (from Step 1)
|
||||
│ ├── screenshots/
|
||||
│ ├── assets/
|
||||
│ │ ├── svgs/
|
||||
│ │ ├── fonts/
|
||||
│ │ ├── lottie/
|
||||
│ │ └── videos/
|
||||
│ ├── extracted/
|
||||
│ │ ├── tokens.json
|
||||
│ │ ├── visible-text.txt
|
||||
│ │ ├── asset-descriptions.md
|
||||
│ │ ├── animations.json
|
||||
│ │ ├── assets-catalog.json
|
||||
│ │ └── detected-libraries.json
|
||||
│ ├── AGENTS.md
|
||||
│ └── CLAUDE.md
|
||||
└── compositions/
|
||||
├── beat-1-hook.html
|
||||
├── beat-2-features.html
|
||||
├── ...
|
||||
└── captions.html
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example: Beat-by-Beat Format
|
||||
|
||||
Here are three beats from a production storyboard showing the level of detail expected.
|
||||
|
||||
### BEAT 1 — COLD OPEN (0:00–0:05)
|
||||
|
||||
**VO:** "Your AI agent already knows how to make videos."
|
||||
|
||||
**Concept:** We're already in motion when the video starts. No title card, no fade from black. We're mid-flight over an infinite creative workspace — dozens of living compositions scattered below us like a city seen from a drone. Each one is alive, running a different animation. The message is clear before any words: this tool makes videos. Lots of them.
|
||||
|
||||
**Visual:** Slow smooth diagonal drift over a vast canvas (3600×2200px plane). Scattered across it: 25 composition cards at organic angles (±5-15° rotation), soft shadows, thin borders. Each card contains a DIFFERENT running animation — kinetic type, gradient morph, data viz, particle system, logo assembly, SVG drawing, shader noise, 3D rotating object. Depth-of-field: close cards slightly blurred, focal sweet-spot in mid-distance, far cards smaller and desaturated.
|
||||
|
||||
**Camera:** Diagonal drift top-left to bottom-right, slight 2-3° rotation over 5s. power1.inOut ease. Zoom accelerates in final second as we approach one specific card.
|
||||
|
||||
**Assets:** Product screenshots and logo on cards. Each card is a mini-composition with its own animation.
|
||||
|
||||
**SFX:** Ambient warmth pad already playing. Faint textured hum — overhearing creative activity from a distance.
|
||||
|
||||
---
|
||||
|
||||
### BEAT 5 — THE THESIS (0:20–0:24)
|
||||
|
||||
**VO:** "Anything a browser can render can be a frame in your video."
|
||||
|
||||
**Mood:** Big statement. This sentence gets its own canvas. Clean, spacious, typographic.
|
||||
|
||||
**Visual:** Words appear as staggered kinetic typography. "Anything a browser can render" — distinctive serif, gentle fade + rise (y: 24px → 0, opacity 0 → 1, 0.4s, power2.out). Held beat — one second of stillness. "can be a frame in your video." appears below. As the final word lands, the entire text pulses once — a brief warm flash, subtle scale bump to 101%.
|
||||
|
||||
**Transition OUT:** Whip pan left — x:-400, blur:24px, opacity:0.4, 0.3s power3.in
|
||||
|
||||
**SFX:** Silence under the first line. On the capture pulse — a soft analog shutter click.
|
||||
|
||||
---
|
||||
|
||||
### BEAT 7 — THE CONTRAST (0:38–0:44)
|
||||
|
||||
**VO:** "No new framework for the agent to learn. Just HTML."
|
||||
|
||||
**Mood:** Clean comparison. Light base. Two worlds side by side.
|
||||
|
||||
**Visual:** Left half: dense code, small, compressed, overwhelming. Scrolls slowly upward. Slightly desaturated. Right half: spacious HTML, syntax-highlighted, generous line spacing, inviting. On "Just HTML." — the left side folds inward along its center line, like a book closing. The right side expands to fill the frame. Warm glow rises behind it.
|
||||
|
||||
**Transition IN:** Zoom through — scale 0.75→1, blur 20px→0, 0.5s expo.out
|
||||
**Transition OUT:** Velocity-matched upward — y:-150, blur:30px, 0.33s power2.in
|
||||
|
||||
**Assets:** Real framework code on the left (actual content, not lorem ipsum). Real HyperFrames HTML on the right.
|
||||
|
||||
**SFX:** Left side carries a faint low drone. On fold: drone cuts. Silence. Then a single clean chime as the right side expands.
|
||||
@@ -0,0 +1,224 @@
|
||||
# Step 4: VO, Timing + Captions
|
||||
|
||||
## If Step 2 said "no narration"
|
||||
|
||||
Skip the TTS sections below. The storyboard already has beat durations planned based on pacing and rhythm — those become `data-start` and `data-duration` values directly in Step 5.
|
||||
|
||||
**Background music:** Ask the user before moving to Step 5:
|
||||
|
||||
> "Do you have a music track for this video? If not, I can suggest where to find one:
|
||||
>
|
||||
> - **Artlist.io** or **Musicbed** — licensed music for commercial use
|
||||
> - **Uppbeat.io** or **Pixabay Music** — free tracks with attribution
|
||||
> - **Freesound.org** — free samples and loops
|
||||
>
|
||||
> Or share a reference track ('something like this') and I can find something similar."
|
||||
|
||||
If the user provides a track: note the file path and BPM in the storyboard for Step 5 to wire into `index.html`. If they skip music entirely, the video uses SFX only — confirm that's intentional.
|
||||
|
||||
Move to Step 5.
|
||||
|
||||
---
|
||||
|
||||
## Generate a test clip before full narration — calibrate timing first
|
||||
|
||||
Generate a 2-sentence test clip NOW using the script's opening lines. Measure the actual duration. Kokoro compresses scripts by ~40% (35s planned → 19s actual) and HeyGen runs faster than expected. If you discover the audio is 40% shorter than expected, you'll need to revise the storyboard beat timings before investing time in full narration generation.
|
||||
|
||||
**Do this before committing to beat count and durations:**
|
||||
|
||||
```bash
|
||||
# Quick Kokoro test (2 sentences):
|
||||
npx hyperframes tts "First sentence. Second sentence." --voice af_nova --output /tmp/test-tts.wav
|
||||
# Measure: seconds ÷ words × total script words = estimated full audio length
|
||||
```
|
||||
|
||||
If the estimate puts your video at ±15% of the planned duration, proceed. If it's more than 15% off, recalibrate the script length first.
|
||||
|
||||
## Background music
|
||||
|
||||
**Always ask about background music** — even when narration is present:
|
||||
|
||||
> "Do you want background music under the narration? (Artlist.io, Musicbed for licensed; Uppbeat/Pixabay for free; or share a reference track). Even a subtle ambient underscore makes pauses between sentences feel intentional rather than empty."
|
||||
|
||||
If they want music, note the track in the storyboard for Step 5 to wire into `index.html`.
|
||||
|
||||
## TTS Provider
|
||||
|
||||
Ask the user which voice provider they'd like:
|
||||
|
||||
> **Which voice provider would you like to use for narration?**
|
||||
>
|
||||
> 1. **HeyGen TTS** — Good quality voices, and it returns word-level timestamps automatically (saves a separate transcription step). Requires HeyGen API key.
|
||||
> 2. **ElevenLabs** — Large voice library, very natural output. Requires ElevenLabs API key. Does not return word timestamps — you'll transcribe separately.
|
||||
> 3. **Kokoro** (Free) — Runs locally, no API key needed. Decent quality but more robotic than the others. Good for drafts or budget runs.
|
||||
|
||||
If the user picks ElevenLabs or HeyGen and doesn't have a key set up yet, help them:
|
||||
|
||||
- **ElevenLabs:** "Add `ELEVENLABS_API_KEY=your-key` to a `.env` file in the project root, or just paste it here and I'll set it up."
|
||||
- **HeyGen:** "Add `HEYGEN_API_KEY=your-key` to a `.env` file, or paste it here."
|
||||
|
||||
Don't judge or critique if the user pastes a key directly in chat — just use it and move on.
|
||||
|
||||
## Audition voices
|
||||
|
||||
After the provider is selected, audition at least 2 voices with the first sentence of SCRIPT.md.
|
||||
|
||||
**ElevenLabs:**
|
||||
|
||||
- If the ElevenLabs MCP is available: use `mcp__elevenlabs__search_voices` to browse, `mcp__elevenlabs__text_to_speech` to generate.
|
||||
- If no MCP: call the REST API directly:
|
||||
|
||||
```bash
|
||||
# List voices
|
||||
curl -s "https://api.elevenlabs.io/v1/voices" \
|
||||
-H "xi-api-key: $ELEVENLABS_API_KEY" | jq '.voices[:5] | .[].name'
|
||||
|
||||
# Generate speech (replace VOICE_ID with chosen voice)
|
||||
curl -s -X POST "https://api.elevenlabs.io/v1/text-to-speech/VOICE_ID" \
|
||||
-H "xi-api-key: $ELEVENLABS_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"text":"First sentence of your script","model_id":"eleven_multilingual_v2"}' \
|
||||
--output narration.mp3
|
||||
```
|
||||
|
||||
- Does not return word timestamps — transcribe separately after generating.
|
||||
|
||||
**HeyGen TTS:**
|
||||
|
||||
- If the HeyGen MCP is available: use the TTS tool directly.
|
||||
- If no MCP: use the v3 API (current; v1/v2 deprecated, supported until Oct 2026):
|
||||
|
||||
```bash
|
||||
# List voices — response shape: { "data": [...], "has_more": bool }
|
||||
# data is a direct list (NOT data.voices — that was v2)
|
||||
curl -s "https://api.heygen.com/v3/voices?engine=starfish&type=public&limit=20" \
|
||||
-H "x-api-key: $HEYGEN_API_KEY" | python3 -c \
|
||||
"import json,sys; v=json.load(sys.stdin)['data']; [print(x['voice_id'], x['name'], x['language']) for x in v[:10]]"
|
||||
|
||||
# Generate audio — response: { "data": { "audio_url": ..., "word_timestamps": [...] } }
|
||||
curl -s -X POST "https://api.heygen.com/v3/voices/speech" \
|
||||
-H "x-api-key: $HEYGEN_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"text":"Your script here","voice_id":"VOICE_ID","speed":1.0}' \
|
||||
| python3 -c "
|
||||
import json,sys
|
||||
r=json.load(sys.stdin)
|
||||
d=r['data']
|
||||
print(d['audio_url'])
|
||||
open('transcript_raw.json','w').write(json.dumps(d.get('word_timestamps',[]),indent=2))
|
||||
"
|
||||
|
||||
# Then download the audio
|
||||
curl -sL "AUDIO_URL_FROM_ABOVE" --output narration.mp3
|
||||
```
|
||||
|
||||
- Returns word-level timestamps directly in the response — no separate transcription step needed.
|
||||
|
||||
**Kokoro (free, local):**
|
||||
|
||||
```bash
|
||||
npx hyperframes tts SCRIPT.md --voice af_nova --output narration.wav
|
||||
```
|
||||
|
||||
No API key, no MCP needed. Runs locally. Use `--list` to see all 54 available voices.
|
||||
|
||||
Pick the voice that sounds most natural and conversational. Listen for pacing — does it breathe between sentences? Does it sound like a person or a robot?
|
||||
|
||||
## Script length check
|
||||
|
||||
Before generating, verify the script makes sense for the video. Word count depends entirely on the creative direction. The storyboard's pacing and style determine how much narration the video needs.
|
||||
|
||||
The key check: are there stretches where NOTHING is happening — no narration AND no compelling visual movement? Those are dead spots that lose the viewer. Every second needs either spoken words or strong visual energy carrying it.
|
||||
|
||||
## Generate full narration
|
||||
|
||||
Generate the full script as `narration.wav` (or `.mp3`) in the project directory.
|
||||
|
||||
**If any command hangs for more than 60 seconds — don't just wait.** The user is sitting there watching you do nothing. Escalation order:
|
||||
|
||||
1. **Try again** — kill the process, run the same command again (transient failures are common)
|
||||
2. **Try different flags** — smaller model (`--model tiny.en`), different voice, shorter test sentence first
|
||||
3. **Try a different tool for the same task** — if `hyperframes transcribe` hangs, try `whisper-cli` directly, or Groq API (`npx hyperframes transcribe --provider groq`), or OpenAI API
|
||||
4. **Switch provider entirely** — if ElevenLabs is down, try HeyGen or Kokoro. If Kokoro hangs, try ElevenLabs.
|
||||
|
||||
Never sit idle for 10 minutes hoping a stuck process will finish.
|
||||
|
||||
**Kokoro pronunciation issues:** Kokoro mispronounces product names and tech terms. Always apply substitutions before generating. Known problems and fixes:
|
||||
|
||||
- `API` → `A P I` (spell it out)
|
||||
- `UI` → `U I`, `SaaS` → `sass`, `DevOps` → `dev ops`
|
||||
- Product names with unusual spelling: test the first sentence first and listen. Common failure: "Vercel" → "versatile", "WorkOS" → "work O S", "One API" → "Wanna PI"
|
||||
- If a name sounds wrong: write it phonetically in `narration.txt` (e.g., `Vercel` → `Ver-sell`, `Supabase` → `Soopa-base`)
|
||||
- Always generate a short test clip with the first 2 sentences before generating the full audio
|
||||
- **No SSML tags** — Kokoro reads them as literal text. `<break time="1s"/>` is spoken as "break time equals one slash." Use blank lines or `...` for pauses in `narration.txt`
|
||||
|
||||
For ElevenLabs and HeyGen TTS, substitutions are usually unnecessary — they handle product names correctly.
|
||||
|
||||
**Also save the exact spoken text** — with pronunciation substitutions applied (e.g., `API` → `A P I`, `$2T` → `two trillion` and etc.) — as `narration.txt` in the same directory. This is the string passed to TTS, distinct from `SCRIPT.md` which is the human-readable creative doc. Having `narration.txt` makes it trivial to regenerate the audio later with a different voice without re-deriving the substitutions. Name it exactly `narration.txt`.
|
||||
|
||||
## Transcribe for word-level timestamps
|
||||
|
||||
**If you used HeyGen v3 TTS:** word timestamps were returned in the generate call. Normalize the format before saving — HeyGen v3 uses `word` but the pipeline expects `text`:
|
||||
|
||||
```python
|
||||
import json
|
||||
raw = json.load(open('transcript_raw.json'))
|
||||
normalized = [{"text": w["word"], "start": w["start"], "end": w["end"]} for w in raw]
|
||||
json.dump(normalized, open('transcript.json', 'w'), indent=2)
|
||||
```
|
||||
|
||||
No separate transcription step needed.
|
||||
|
||||
**If you used ElevenLabs or Kokoro:**
|
||||
|
||||
```bash
|
||||
npx hyperframes transcribe narration.wav
|
||||
```
|
||||
|
||||
Produces `transcript.json` with `[{ text, start, end }]` for every word. These timestamps are the source of truth for all beat durations.
|
||||
|
||||
## Map timestamps to beats
|
||||
|
||||
Go through STORYBOARD.md beat by beat. For each beat:
|
||||
|
||||
1. Find the first word of that beat's VO cue in `transcript.json`
|
||||
2. Find the last word of that beat's VO cue
|
||||
3. Set `beat.start = firstWord.start`, `beat.end = lastWord.end`
|
||||
4. Add 0.3-0.5s padding at the end for visual breathing room
|
||||
|
||||
Update STORYBOARD.md with real durations. Replace estimated times (e.g., "0:00-0:05") with actual timestamps as precise as possible (e.g., "0.00-3.21s").
|
||||
|
||||
Beat boundaries land on word onsets — hard cuts to the VO.
|
||||
|
||||
## Timing reconciliation — required before Step 5
|
||||
|
||||
After mapping all beats, compare real total audio duration against the storyboard's planned duration:
|
||||
|
||||
```
|
||||
real_total = last_word.end + cta_hold (typically 2–3s)
|
||||
planned_total = sum of all beat planned durations
|
||||
delta = |real_total - planned_total|
|
||||
```
|
||||
|
||||
**If delta > 15% of planned total — do not proceed to Step 5 without resolving it.** Common causes and fixes:
|
||||
|
||||
- **Audio shorter than planned (most common with Kokoro):** Kokoro generates compressed speech with minimal pauses. Proportionally scale all non-CTA beat durations down to match the real audio. Example: planned 30s, audio 19s — multiply each beat duration by 19/30 (excluding the CTA hold). Update STORYBOARD.md.
|
||||
- **Audio much longer than planned (>30% over):** The script was too long for the intended duration. Trim the script (remove one beat's VO), regenerate audio, re-transcribe.
|
||||
- **CTA beat timing:** The CTA beat should hold for 2–3 seconds after the last spoken word — not extend to fill empty time. `cta_start = last_word.end + 0.3s`, `cta_duration = 2.5s`. Hard cap. Dead silence after the CTA hold loses the viewer.
|
||||
|
||||
**Always tell the user** if you adjusted durations significantly from the storyboard plan. They approved a specific beat structure — if it changed, they need to know.
|
||||
|
||||
## Captions
|
||||
|
||||
After the narration is generated and transcribed, ask the user:
|
||||
|
||||
> **Would you like captions on the video?**
|
||||
>
|
||||
> - **Yes** — per-word captions synced to the narration. Great for social media (most viewers watch on mute) and accessibility.
|
||||
> - **No** — narration audio only, no text overlay.
|
||||
|
||||
If yes, captions are built as a separate composition (`compositions/captions.html`) in Step 5. The `transcript.json` drives the timing — each word appears/highlights as it's spoken. Read [the captions reference](../../hyperframes/references/captions.md) for styling options (scale-pop, typewriter, fade+slide, etc.) and positioning rules.
|
||||
|
||||
## Save timing data for Step 5
|
||||
|
||||
Record the final beat timings (start, duration) so Step 5 (Build) can use them when building `index.html`. The storyboard now has real timestamps — these become `data-start` and `data-duration` values on each scene slot when the root composition is assembled in Step 5.
|
||||
@@ -0,0 +1,419 @@
|
||||
# Step 5: Build Compositions
|
||||
|
||||
**Captions rule — read before building anything:** Never create `compositions/captions.html` with an empty transcript (`const script = []`). If the VO/transcript step was skipped or failed, do not create a captions composition at all. An empty captions file silently does nothing and wastes a track slot. Only create it when `transcript.json` has real word timestamps.
|
||||
|
||||
**Captions stacking bug:** Every caption word group must start with `opacity: 0` (or `visibility: hidden`) and be positioned `position: absolute`. Never show more than one group at a time — GSAP controls visibility sequentially. If multiple groups are visible simultaneously it means either (a) the initial CSS state isn't hidden, or (b) a group's exit tween is missing before the next group's entrance fires. After building captions.html, take a snapshot at 3–4 timestamps mid-narration and verify only one word group is visible per frame.
|
||||
|
||||
**Before building, verify you have:**
|
||||
|
||||
- **STORYBOARD.md** — the beat-by-beat plan. Re-read it now if you don't remember every beat's concept, assets, and techniques.
|
||||
- **DESIGN.md** — if you need to check a specific value (color, font, component style) you can't recall, look it up. Don't re-read the whole file.
|
||||
- **`capture/extracted/asset-descriptions.md`** — when the storyboard assigns an asset to a beat, check the description to understand what it shows. Re-read this file if you can't recall the asset inventory.
|
||||
- **transcript.json** — word-level timestamps that drive scene durations.
|
||||
|
||||
Load the `hyperframes` skill — it has the rules for data attributes, timeline contracts, deterministic rendering, and layout. Read it now if you haven't already this session.
|
||||
|
||||
**For capabilities.md and techniques.md:** read the Table of Contents to orient yourself, then go deep only on the sections your storyboard actually calls for. You don't need to re-read sections for animation engines, registry blocks, or techniques that none of your beats use.
|
||||
|
||||
---
|
||||
|
||||
## 1. Copy SFX to project
|
||||
|
||||
```bash
|
||||
cp -r skills/website-to-hyperframes/assets/sfx/ <project-dir>/sfx/
|
||||
# If skill is installed elsewhere:
|
||||
find . -path "*/website-to-hyperframes/assets/sfx" -exec cp -r {} <project-dir>/sfx/ \;
|
||||
```
|
||||
|
||||
## 2. Build the root index.html
|
||||
|
||||
Create `index.html` yourself. This is the orchestrator — it holds beat slots, narration audio, SFX, and shader transitions (if any).
|
||||
|
||||
**Critical CSS — every beat must overlap in the same frame:**
|
||||
|
||||
```css
|
||||
.scene {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
overflow: hidden;
|
||||
}
|
||||
```
|
||||
|
||||
**Beat structure:**
|
||||
|
||||
```html
|
||||
<div
|
||||
id="root"
|
||||
data-composition-id="main"
|
||||
data-start="0"
|
||||
data-duration="TOTAL"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
>
|
||||
<div
|
||||
id="beat-1"
|
||||
class="scene"
|
||||
data-composition-id="beat-1-hook"
|
||||
data-composition-src="compositions/beat-1-hook.html"
|
||||
data-start="0"
|
||||
data-duration="5.5"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
|
||||
<!-- more beats... -->
|
||||
|
||||
<audio
|
||||
id="narration"
|
||||
src="narration.wav"
|
||||
data-start="0"
|
||||
data-duration="NARRATION_LENGTH"
|
||||
data-track-index="0"
|
||||
data-volume="1"
|
||||
></audio>
|
||||
|
||||
<!-- SFX on content moments, NOT on shader transitions -->
|
||||
<audio
|
||||
id="sfx-impact"
|
||||
src="sfx/impact-bass-1.mp3"
|
||||
data-start="0.3"
|
||||
data-duration="2.1"
|
||||
data-track-index="41"
|
||||
data-volume="0.35"
|
||||
></audio>
|
||||
</div>
|
||||
```
|
||||
|
||||
SFX were assigned in the storyboard (Step 3) — implement exactly what STORYBOARD.md specifies. Each SFX entry has a file, trigger time, and volume. Wire each one as an `<audio>` element with the exact `data-start`, `data-duration`, and `data-volume` from the storyboard. Do not add, remove, or substitute SFX beyond what the storyboard says.
|
||||
|
||||
**Choose architecture based on pacing (from Step 3)**
|
||||
|
||||
| Pacing | Architecture | Why |
|
||||
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
|
||||
| **Fast** (billboard-per-beat) | Single `index.html`, stacked `<div class="beat">` elements, GSAP opacity sequencing. NO sub-compositions, NO HyperShader. Hard cuts via `tl.set()`. See stacked-beats pattern below. | Sub-compositions add latency; hard cuts need instant swaps. One file = zero load delay. |
|
||||
| **Moderate / Slow / Arc** | Sub-compositions with `HyperShader.init()`. Each beat in `compositions/beat-N.html`. CSS crossfades or shader transitions between scenes. | Transitions need HyperShader's compositing. Sub-agents build each beat independently. |
|
||||
|
||||
If the storyboard says "fast" pacing: use the stacked-beats pattern below. Do not use HyperShader — it adds scene registration overhead that creates gaps between hard cuts. Every frame is content, no transition frames.
|
||||
|
||||
**Stacked-beats pattern (fast pacing):**
|
||||
|
||||
Each beat is a composed scene — composed from divs, SVG, canvas, and CSS. Never a full-bleed screenshot. Each beat's structure (cards, panels, layered text, SVG-drawn mark, etc.) comes from the storyboard's Composition + Accents spec.
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="video"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
data-start="0"
|
||||
data-duration="TOTAL"
|
||||
style="position:relative;width:1920px;height:1080px;"
|
||||
>
|
||||
<!-- Beat 1: kinetic-typography hook (composed from per-word spans) -->
|
||||
<div class="beat" id="b01" style="opacity:1;">
|
||||
<div class="mega">
|
||||
<span class="w">Stop</span>
|
||||
<span class="w">context-switching.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Beat 2: composed kanban — 3 columns of cards-as-divs, NOT a screenshot -->
|
||||
<div class="beat" id="b02">
|
||||
<div class="kanban">
|
||||
<div class="col">
|
||||
<div class="card">Triage tickets</div>
|
||||
<div class="card">Review PR</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card active">Design spec</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card">Ship v2.1</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Beat 3: SVG logo draw — composed, not an <img> -->
|
||||
<div class="beat" id="b03">
|
||||
<svg viewBox="0 0 200 200"><path class="mark" d="..." /></svg>
|
||||
</div>
|
||||
<!-- more beats — each a composed scene with its own visual world -->
|
||||
</div>
|
||||
```
|
||||
|
||||
If you ever find yourself writing `<img src="capture/assets/...">` as a beat's primary visual, stop. That's the slideshow pattern this skill exists to break. Build the UI element from divs and CSS using the brand colors from DESIGN.md. The only legitimate `<img>` uses are: (a) the brand logo when it's purely raster, (b) a hero illustration layered as ambient depth behind composed content, (c) a gradient/texture image as a background wash. Never a product UI screenshot as the load-bearing visual.
|
||||
|
||||
```css
|
||||
.beat {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
```
|
||||
|
||||
```javascript
|
||||
var beats = [
|
||||
{ id: "b01", at: 0, dur: 1.8 },
|
||||
{ id: "b02", at: 1.8, dur: 1.0 },
|
||||
// ...
|
||||
];
|
||||
beats.forEach(function (b) {
|
||||
var el = document.getElementById(b.id);
|
||||
if (b.id !== "b01") tl.set(el, { opacity: 1 }, b.at);
|
||||
gsap.set(el, { scale: 1.012 });
|
||||
tl.to(el, { scale: 1, duration: 0.25, ease: "power2.out" }, b.at);
|
||||
if (b !== beats[beats.length - 1]) tl.set(el, { opacity: 0 }, b.at + b.dur);
|
||||
});
|
||||
```
|
||||
|
||||
Each beat gets its own visual world — different background, different color, different energy. No two consecutive beats should look alike. Scale pulse (1.012→1.0) on every beat entry is subtle but felt.
|
||||
|
||||
If the storyboard says "slow" or "cinematic": build each beat as a sub-composition. Use long crossfades (0.8–1.2s `duration` with no `shader` key = CSS crossfade). Inside each beat, use continuous subtle motion — nothing is static:
|
||||
|
||||
- Slow camera drift on the composed scene root: `tl.fromTo(scene, {scale:1.05, x:20}, {scale:1, x:-20, duration: BEAT, ease:"none"})` (Ken-Burns style, but on your composed elements — not on a screenshot)
|
||||
- Parallax text layers: `tl.fromTo(text, {y:30}, {y:-30, duration: BEAT, ease:"power1.inOut"})`
|
||||
- 1–2s breathing room before text enters (don't animate everything at t=0)
|
||||
- Soft easing: `expo.out` for entrances, `power1.inOut` for drifts
|
||||
|
||||
**Multi-scene index.html with HyperShader — for moderate/slow/arc pacing**
|
||||
|
||||
For videos with sub-composition beats and scene transitions, `index.html` MUST use `HyperShader.init()`. This is the entire scene orchestration layer. Do NOT try to use registry block sub-compositions (e.g. `compositions/domain-warp-dissolve.html`) for transitions — those are standalone showcase demos, not how HyperShader works in multi-scene compositions.
|
||||
|
||||
Copy the local shader build first:
|
||||
|
||||
```bash
|
||||
cp packages/shader-transitions/dist/index.global.js <project-dir>/hyper-shader-local.js
|
||||
```
|
||||
|
||||
Full working `index.html` pattern — every field matters:
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||||
<script src="hyper-shader-local.js"></script>
|
||||
|
||||
<div id="root" data-composition-id="main" data-start="0" data-duration="TOTAL"
|
||||
data-width="1920" data-height="1080">
|
||||
|
||||
<!-- Host divs: MUST have both id AND data-composition-id matching the same value.
|
||||
HyperShader.init() uses getElementById() — without id="beat-1" it fails with
|
||||
"scene ids not found in DOM". -->
|
||||
<div id="beat-1" class="scene"
|
||||
data-composition-id="beat-1-hook"
|
||||
data-composition-src="compositions/beat-1-hook.html"
|
||||
data-start="0" <!-- transition INTO this beat starts here -->
|
||||
data-duration="4.5" <!-- must match the GSAP BEAT constant in the composition -->
|
||||
data-track-index="1"
|
||||
data-width="1920" data-height="1080"
|
||||
style="background: #YOUR_BEAT_BG_COLOR;"><!-- background here OR in sub-comp CSS — both work -->
|
||||
</div>
|
||||
|
||||
<div id="beat-2" class="scene"
|
||||
data-composition-id="beat-2-features"
|
||||
data-composition-src="compositions/beat-2-features.html"
|
||||
data-start="4.0"
|
||||
data-duration="5.5"
|
||||
data-track-index="2" <!-- use sequential track indices (1,2,3...) to avoid linter errors -->
|
||||
data-width="1920" data-height="1080"
|
||||
style="background: #YOUR_BEAT_BG_COLOR;">
|
||||
</div>
|
||||
|
||||
<!-- ... more beats ... -->
|
||||
|
||||
<!-- ALWAYS add a dummy s-end scene as the LAST entry.
|
||||
HyperShader renders scenes[N-1] as black in some contexts.
|
||||
s-end is invisible — it just prevents your CTA from being last. -->
|
||||
<div id="s-end" class="scene"
|
||||
data-composition-id="s-end"
|
||||
data-start="TOTAL_MINUS_0.1"
|
||||
data-duration="0.1"
|
||||
data-track-index="N"
|
||||
data-width="1920" data-height="1080">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.__timelines = window.__timelines || {};
|
||||
var tl = HyperShader.init({
|
||||
bgColor: "#000000",
|
||||
accentColor: "#YOUR_ACCENT",
|
||||
scenes: ["beat-1", "beat-2", "beat-3", ..., "s-end"],
|
||||
transitions: [
|
||||
{ time: 4.0, shader: "sdf-iris", duration: 0.7 }, // WebGL shader
|
||||
{ time: 9.5, duration: 0.5 }, // CSS crossfade (no shader)
|
||||
// ... one transition per scene boundary ...
|
||||
{ time: TOTAL_MINUS_0.1, duration: 0.1 } // dummy → s-end
|
||||
],
|
||||
});
|
||||
// Add ALL beat animations to the returned tl AFTER init()
|
||||
window.__timelines["main"] = tl;
|
||||
</script>
|
||||
```
|
||||
|
||||
**Track index and the linter:** Use sequential track indices (`data-track-index="1"`, `"2"`, `"3"`...) for each beat — NOT all on track `"1"`. The linter flags overlapping clips on the same track as an error, and HyperShader compositions always have overlapping beats (the transition window). Using sequential indices silences the linter; HyperShader manages which scene is VISIBLE via opacity regardless of track index.
|
||||
|
||||
**Scene background colors:** setting `style="background: #3139FB"` on the host `<div id="beat-1">` in index.html is the simplest pattern — it's visible at a glance from the root file. Setting background inside the sub-composition's CSS also works. Either is fine; host div is preferred for clarity.
|
||||
|
||||
**Critical: beat host divs must have sequential `data-start` and matching `data-duration`.** Do NOT set `data-start="0"` on all beats — the render engine seeks each beat's GSAP timeline to `global_time - data_start`. At t=10s with `data-start=0`, a 5.5s timeline is seeked past its end and all content disappears.
|
||||
|
||||
`data-duration` must match the GSAP `BEAT` constant in the composition (the length of the sub-composition's internal timeline). If the two disagree, animations get cut off.
|
||||
|
||||
**Storyboard Beat Timing section** tells you both values — use them directly:
|
||||
|
||||
- `data-start` = "Transition in at:" value from the storyboard
|
||||
- `data-duration` = "GSAP duration:" value from the storyboard
|
||||
|
||||
**Font handling:** Common fonts are auto-resolved by the renderer: use `"Inter"` (not `"Inter Variable"` — the compiler only maps the base name), `"Roboto"`, `"JetBrains Mono"`, `"Poppins"`. If a composition uses `"Inter Variable"` it will log compiler warnings and may fall back incorrectly — always use `"Inter"`. Only brand-specific fonts (GT Walsheim, Aeonik, etc.) need `@font-face`. Check `capture/assets/fonts/` — hashed filenames are Google Fonts subsets that auto-resolve; recognizable filenames (e.g. `BrandSans-Bold.woff2`) are brand fonts that need `@font-face` declarations.
|
||||
|
||||
**Brand font @font-face:** If the storyboard's BRAND VALUES lists a brand-specific font with a path in `capture/assets/fonts/`, add the `@font-face` block at the top of each composition that uses it — sub-agents won't do this unless you tell them explicitly. Paste the exact `@font-face` declaration in the sub-agent prompt's BRAND VALUES section. Without this, every composition falls back to `system-ui` and the brand typeface never loads.
|
||||
|
||||
**⚠ ASSET PATHS — most common sub-agent mistake (5+ agents per run):** When a composition references a captured accent (logo, gradient layer, hero illustration), the path must be relative to the **PROJECT ROOT**, not to the composition file. `compositions/beat-N.html` lives one directory deep, but paths must be written as if from the root.
|
||||
|
||||
- ✅ `capture/assets/logo.svg`
|
||||
- ❌ `../capture/assets/logo.svg`
|
||||
|
||||
The Studio preview server rewrites base URLs to the project root — `../` paths that seem to work locally will 404 in preview and in renders. Add this verbatim to every sub-agent prompt's RULES section.
|
||||
|
||||
## 3. Build each composition — USE SUB-AGENTS
|
||||
|
||||
**Before dispatching, re-read DESIGN.md and STORYBOARD.md.** You wrote these files earlier in the session and you think you remember them. You don't — not the exact hex values, not the specific font families, not the button border-radius, not the Do's/Don'ts. Re-read them now so you can paste accurate brand rules and beat specs into each sub-agent prompt.
|
||||
|
||||
**If your runtime supports parallel sub-agents** (Claude Code, Cursor, most agent frameworks): dispatch one sub-agent per beat — 3 to 4× faster than building sequentially. For 3+ beats, always dispatch in parallel. For 1–2 beats, sequential is fine.
|
||||
|
||||
**If your runtime does not support parallel sub-agents** (some Codex setups, serial-only models): build sequentially using the same context-packing template below. The template gives each build pass the same context a sub-agent would get — paste prev/this/next beat + brand values — so output quality is the same, just slower.
|
||||
|
||||
In either case, use the template. Do not skip it and build from memory.
|
||||
|
||||
Each sub-agent reads [beat-builder-guide.md](beat-builder-guide.md) — it has everything: rules, easing, file references, validation commands. **Do not try to paste all rules into the prompt yourself.** Instead, tell the sub-agent to read the guide file. You paste only the beat-specific context: the storyboard sections, brand values, and asset paths.
|
||||
|
||||
```
|
||||
Build the composition for Beat N. Save to compositions/beat-N-name.html.
|
||||
|
||||
FIRST: Read skills/website-to-hyperframes/references/beat-builder-guide.md end to end.
|
||||
It has your full workflow, all rules, easing vocabulary, and file references.
|
||||
Follow its workflow exactly:
|
||||
build → lint (`npx hyperframes lint .`)
|
||||
→ snapshot (`npx tsx packages/cli/src/cli.ts snapshot . --frames 3`)
|
||||
→ view contact sheet AND read snapshots/descriptions.md
|
||||
→ fix issues
|
||||
|
||||
After you finish, the main agent will READ your composition HTML top-to-bottom
|
||||
and cross-check it against DESIGN.md and STORYBOARD.md — does the brand bg/accent
|
||||
hex actually appear in your CSS, are the captured assets the storyboard called
|
||||
for actually referenced, is the headline ≥80px, does the GSAP timeline cover
|
||||
the full beat duration. Do the work honestly. Reports of "looks good" without
|
||||
the work being done will be caught when the main agent opens the file.
|
||||
|
||||
═══ PREVIOUS BEAT (Beat N-1) ═══
|
||||
[paste the FULL previous beat section from STORYBOARD.md]
|
||||
|
||||
═══ THIS BEAT (Beat N) ═══
|
||||
[paste the FULL beat section from STORYBOARD.md — this IS the build spec]
|
||||
|
||||
═══ NEXT BEAT (Beat N+1) ═══
|
||||
[paste the FULL next beat section from STORYBOARD.md]
|
||||
|
||||
═══ BRAND VALUES (from DESIGN.md) ═══
|
||||
Colors:
|
||||
--bg: #[hex] primary background
|
||||
--fg: #[hex] primary text
|
||||
--accent: #[hex] CTA / highlights
|
||||
--surface: #[hex] card / panel backgrounds
|
||||
[add more if needed]
|
||||
|
||||
Fonts:
|
||||
Headlines: [font family], [weight]
|
||||
Body: [font family], [weight]
|
||||
[brand font path if needed: capture/assets/fonts/Brand.woff2]
|
||||
|
||||
Key component styles:
|
||||
[paste relevant lines from DESIGN.md]
|
||||
|
||||
═══ CAPTURED ASSETS FOR THIS BEAT ═══
|
||||
[Paste ACTUAL file paths + descriptions from asset-descriptions.md:
|
||||
|
||||
- capture/assets/hero-dashboard.png — full-bleed product dashboard, dark theme
|
||||
- capture/assets/logo.svg — brand wordmark, white on transparent
|
||||
|
||||
Do NOT say "see asset-descriptions.md". Paste the paths here.]
|
||||
```
|
||||
|
||||
The storyboard beat already contains everything — the concept, the visual choreography with exact timings, the CSS values, the SFX cues. The sub-agent's job is to translate that description into working HTML/CSS/GSAP, not to re-invent the creative direction. If you want, you can also paste any other relative and useful context to subagents if think it's good, why not.
|
||||
|
||||
### Per-composition process
|
||||
|
||||
For each beat:
|
||||
|
||||
**1. Read the storyboard beat.** The storyboard IS the build spec. It tells you what elements exist, how they enter, what they do during the beat, and how they exit. Follow it. If something in the storyboard isn't clear or seems impossible, research how to do it or ask — don't silently skip it.
|
||||
|
||||
**2. Build the static end-state first.** Position every element at its most visible moment. HTML+CSS only, no GSAP yet. The CSS position is the ground truth.
|
||||
|
||||
**3. Add the animation sequence.** Follow the storyboard's choreography — it specifies what happens and when. Use `tl.fromTo()` (not `tl.from()`) for entrances. Build the timeline in the order the storyboard describes.
|
||||
|
||||
**4. Add exit** (if CSS transition out). If shader transition — no exit animation needed.
|
||||
|
||||
**5. View the result.** After building, take a snapshot of this beat at different timestamps (where things are supposed to happen, animate, move and etc) and look at it from all angles, corners and positinos. Is the frame full and everything is exactly where it supposed to be? Are you sure??? Are elements readable? Does it match what the storyboard describes?
|
||||
|
||||
### Technical rules
|
||||
|
||||
- **No `repeat: -1`** — calculate exact repeats from beat duration
|
||||
- **No `Math.random()`** — use a seeded PRNG
|
||||
- **No bare `gsap.to()`** — all tweens on `tl`, never standalone
|
||||
- **No full-screen dark linear gradients** — H.264 banding
|
||||
- **Minimum fonts**: 80px+ headlines, 20px+ body
|
||||
- **WCAG contrast on gradient backgrounds:** The contrast validator samples actual background pixels under the text element — if the background is a gradient image, darker parts of the image make the measured ratio _worse_ when you darken the text color, not better. Fix: either place text over a solid-color zone, or add `data-layout-ignore` attribute to decorative labels that don't need WCAG compliance. Don't blindly darken text color when the background isn't solid.
|
||||
|
||||
## 4. After all compositions are built — reconciliation check
|
||||
|
||||
Before moving to Step 6, run this sanity check:
|
||||
|
||||
```bash
|
||||
# List every file in compositions/ and verify each one has a host div in index.html
|
||||
ls compositions/
|
||||
```
|
||||
|
||||
For every `.html` file in `compositions/`, confirm that `index.html` has a `data-composition-src="compositions/<filename>"` pointing to it. If any composition file is not referenced in `index.html`, add the missing host div now — an unreferenced composition is completely invisible at runtime.
|
||||
|
||||
**Captions stub rule:** Never create a `compositions/captions.html` with an empty transcript (`const script = [];`). If the VO/transcript step was skipped or failed, do not create the captions composition at all. An empty captions file that returns immediately is worse than no captions file — it silently does nothing and wastes a track slot.
|
||||
|
||||
## 5. Read each beat HTML top-to-bottom — REQUIRED gate before Step 6
|
||||
|
||||
**Do not declare Step 5 complete on sub-agents' word.** Earlier sessions had sub-agents reply "looks good, 0 errors" and the main agent trusted them — that's how videos shipped with mismatched colors, missing logos, headlines too small to read. Close the trust path by opening every file the sub-agent produced.
|
||||
|
||||
For each `compositions/beat-N.html`:
|
||||
|
||||
1. **Open the file and read it top-to-bottom.** Not a glance. Not a grep. Read the `<style>` block, then the markup, then the `<script>` block. Understand what's actually there.
|
||||
2. **Cross-check against DESIGN.md:**
|
||||
- Does the `--bg` / primary background hex from DESIGN.md appear in the CSS or inline styles?
|
||||
- Does the accent hex appear (if this beat uses an accent)?
|
||||
- Are fonts the ones DESIGN.md specified? If `@font-face` is declared, does the path match a real file under `capture/assets/fonts/` or a published `@fontsource/*` import?
|
||||
- Is the headline `font-size` ≥80px?
|
||||
3. **Cross-check against STORYBOARD.md (this beat's section):**
|
||||
- Are the captured assets the storyboard called for actually referenced in the HTML (`<img src=...>`, inline SVG, `background-image: url(...)`, etc.)? Open the asset paths and confirm the files exist.
|
||||
- Does the GSAP timeline cover the full beat duration, not just the first 1-2 seconds of entrance tweens? Look for events spread across the `BEAT` constant.
|
||||
- Does the shot framing/camera move described in the storyboard show up in the GSAP code (scale/x/y/yPercent transforms with meaningful magnitudes)?
|
||||
4. **Check the technical gates inline:**
|
||||
- `data-composition-id` on the root div matches the `window.__timelines["..."]` key in the script
|
||||
- `data-width` and `data-height` match the host div in index.html
|
||||
- The script is INSIDE the `<template>`, not after `</template>`
|
||||
- No bare `gsap.to(...)`, no `Math.random()`, no `repeat: -1`
|
||||
5. **Open each frame in `snapshots/beat-N/`** and confirm visually that the entrance, hold, and exit moments look like what the storyboard described. If `snapshots/descriptions.md` exists, read Gemini's per-frame analysis of this beat in particular.
|
||||
|
||||
**Anything off — fix it inline (small CSS / GSAP correction) or re-dispatch the sub-agent with the specific problem quoted.** Do not move to Step 6 until every beat has been read top-to-bottom and the cross-checks pass.
|
||||
|
||||
### Brand-floor check (whole-video, after every beat passes its own read)
|
||||
|
||||
- First beat references a brand logo / wordmark SVG from `capture/assets/svgs/`
|
||||
- Last beat references the brand logo / wordmark
|
||||
- If either is missing without an explicit STORYBOARD.md override (e.g. "opener is pure kinetic type"), fix it — videos that don't open or close on the brand are failing their job.
|
||||
|
||||
Once every beat reads clean and the brand-floor check passes, move to Step 6 (Validate & Deliver) for lint, validate, snapshots, and visual review.
|
||||
@@ -1,42 +0,0 @@
|
||||
# Step 5: Generate VO + Map Timing
|
||||
|
||||
## Audition voices
|
||||
|
||||
Never use the first voice you find. Audition 2-3 voices with the first sentence of SCRIPT.md:
|
||||
|
||||
- **Kokoro** (try first — free, no API key) — `npx hyperframes tts SCRIPT.md --voice af_nova --output narration.wav`. Runs locally on CPU. Requires Python 3.10+ (macOS system Python 3.9 won't work — if it fails with an onnxruntime error, move to the next option).
|
||||
- **ElevenLabs** (best voice quality, widest selection) — `mcp__elevenlabs__search_voices` to browse, `mcp__elevenlabs__text_to_speech` to generate. Does not return timestamps — transcribe separately after.
|
||||
- **HeyGen TTS** (returns word timestamps automatically — saves a transcribe step) — `mcp__claude_ai_HeyGen__text_to_speech`. Use when you want timestamps without a separate transcription pass.
|
||||
|
||||
Pick the voice that sounds most natural and conversational. Listen for pacing — does it breathe between sentences? Does it sound like a person or a robot?
|
||||
|
||||
## Generate full narration
|
||||
|
||||
Generate the full script as `narration.wav` (or `.mp3`) in the project directory.
|
||||
|
||||
**Also save the exact spoken text** — with pronunciation substitutions applied (e.g., `API` → `A P I`, `$2T` → `two trillion`) — as `narration.txt` in the same directory. This is the string passed to TTS, distinct from `SCRIPT.md` which is the human-readable creative doc. Having `narration.txt` makes it trivial to regenerate the audio later with a different voice without re-deriving the substitutions. Name it exactly `narration.txt`.
|
||||
|
||||
## Transcribe for word-level timestamps
|
||||
|
||||
```bash
|
||||
npx hyperframes transcribe narration.wav
|
||||
```
|
||||
|
||||
Produces `transcript.json` with `[{ text, start, end }]` for every word. These timestamps are the source of truth for all beat durations.
|
||||
|
||||
## Map timestamps to beats
|
||||
|
||||
Go through STORYBOARD.md beat by beat. For each beat:
|
||||
|
||||
1. Find the first word of that beat's VO cue in `transcript.json`
|
||||
2. Find the last word of that beat's VO cue
|
||||
3. Set `beat.start = firstWord.start`, `beat.end = lastWord.end`
|
||||
4. Add 0.3-0.5s padding at the end for visual breathing room
|
||||
|
||||
Update STORYBOARD.md with real durations. Replace estimated times (e.g., "0:00-0:05") with actual timestamps (e.g., "0.00-3.21s").
|
||||
|
||||
Beat boundaries land on word onsets — hard cuts to the VO.
|
||||
|
||||
## Update index.html
|
||||
|
||||
Update each scene slot's `data-start` and `data-duration` to match the real beat timings from the transcript. Also update the total composition duration and audio element duration.
|
||||
@@ -1,229 +0,0 @@
|
||||
# Step 6: Build Compositions
|
||||
|
||||
**Before building, fully re-read these files:**
|
||||
|
||||
- **DESIGN.md** — your color palette, fonts, components, and Do's/Don'ts. Every composition must use EXACT hex colors and font families from this file. If it says "white backgrounds" — use white, not dark.
|
||||
- **STORYBOARD.md** — the beat-by-beat plan you're executing. Each beat specifies assets, animations, transitions, and which techniques to use.
|
||||
- **`capture/extracted/asset-descriptions.md`** — when the storyboard assigns an asset to a beat, re-read the description to understand what it shows and how to position/style it correctly.
|
||||
- **[techniques.md](../../hyperframes/references/techniques.md)** — code patterns for the 10 visual techniques. When the storyboard says "SVG path drawing" or "per-word kinetic typography" — read the code pattern from this file and adapt it.
|
||||
- **transcript.json** — word-level timestamps that drive scene durations.
|
||||
|
||||
**Split the work: spawn a sub-agent for each beat.** By this step your context is full of captured data, DESIGN.md, SCRIPT, STORYBOARD, and transcript. Building compositions on top of all that means the detailed rules below compete with thousands of tokens of prior work. Each sub-agent gets a fresh context focused on one beat — dramatically better output.
|
||||
|
||||
**How to dispatch each sub-agent:**
|
||||
|
||||
Pass file PATHS, not file contents. The #1 failure mode is reading an asset file and pasting its SVG/image data into the sub-agent prompt. The sub-agent then uses inline content instead of referencing the file on disk. Same with fonts — pass the local woff2 path, don't substitute Google Fonts.
|
||||
|
||||
```
|
||||
Build the composition for beat 1. Save to compositions/beat-1-hook.html.
|
||||
|
||||
STORYBOARD for this beat:
|
||||
[paste the beat section from STORYBOARD.md]
|
||||
|
||||
ASSETS — reference by path, do NOT read/inline the file contents:
|
||||
- Logo: <img src="../capture/assets/favicon.svg"> (top-left, 40x40px)
|
||||
- Hero image: <img src="../capture/assets/hero-bg.png"> (full-bleed background)
|
||||
- Noise texture: ../capture/assets/noise.png (full-frame overlay, 3% opacity)
|
||||
|
||||
FONTS — use @font-face with the captured font files, NOT Google Fonts:
|
||||
@font-face { font-family: 'BrandFont'; src: url('../capture/assets/fonts/BrandFont-Regular.woff2'); }
|
||||
|
||||
Read DESIGN.md for exact colors and Do's/Don'ts.
|
||||
Read techniques.md for animation code patterns.
|
||||
Load the `hyperframes` skill for composition structure rules.
|
||||
```
|
||||
|
||||
After each sub-agent finishes, verify the composition references `../capture/assets/` — if it used inline SVGs or Google Fonts instead of the captured files, fix it before moving on.
|
||||
|
||||
Load the `hyperframes` skill first — it has the rules for data attributes, timeline contracts, deterministic rendering, and layout. Everything below supplements those rules, not replaces them.
|
||||
|
||||
---
|
||||
|
||||
## Per-Composition Process
|
||||
|
||||
For each beat in the storyboard:
|
||||
|
||||
### 1. Read the beat's storyboard section
|
||||
|
||||
Know the mood, visual description, assets, animation choreography, transition, and SFX before writing any HTML.
|
||||
|
||||
### 2. Build the static end-state first
|
||||
|
||||
Position every element where it should be at its **most visible moment** — the frame where everything is fully entered and correctly placed. Write this as static HTML+CSS. No GSAP yet.
|
||||
|
||||
This is the "Layout Before Animation" principle from the compose skill. The CSS position is the ground truth. Animations describe the journey to and from it.
|
||||
|
||||
### 3. Verify the static layout
|
||||
|
||||
Look at it. Check:
|
||||
|
||||
- Are elements where the storyboard says they should be?
|
||||
- Are depth layers present (foreground / midground / background)?
|
||||
- Do any elements overlap unintentionally?
|
||||
- Are assets sized correctly? (hero images should fill 50-70% of frame, not sit at 100x100px)
|
||||
|
||||
### 4. Add entrance animations
|
||||
|
||||
Use `gsap.from()` — animate FROM offscreen/invisible TO the CSS position. The CSS position is where the element ends up.
|
||||
|
||||
### 5. Add mid-scene activity
|
||||
|
||||
Every visible element must have continuous motion. A still image on a still background is a JPEG with a progress bar.
|
||||
|
||||
| Element type | Mid-scene activity |
|
||||
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Image / screenshot | Slow zoom (scale 1→1.03), slow pan, or Ken Burns |
|
||||
| Stat / number | Counter animates from 0 to target |
|
||||
| Logo grid | Subtle shimmer sweep, or gentle scale pulse |
|
||||
| Any persistent element | Subtle float (y ±4-6px, sine.inOut, yoyo) |
|
||||
| Logo / CTA (with music or dramatic VO) | Audio-reactive scale/glow — bass pulses the logo (3–4%), treble glows the CTA. See technique #11 in `techniques.md` for the sampling pattern |
|
||||
|
||||
### 6. Add exit / transition
|
||||
|
||||
Check the storyboard's transition specification for this beat:
|
||||
|
||||
- **CSS transition**: implement the exit animation (e.g., `y:-150, blur:30px, 0.33s power2.in`). The next composition handles its own entry.
|
||||
- **Shader transition**: no exit animation needed — the shader handles the blend. Read `packages/shader-transitions/README.md` for the API, available shaders, and setup. The package handles WebGL init, capture, and GSAP integration — do not copy raw GLSL manually.
|
||||
- **Hard cut**: no exit animation. The scene simply ends.
|
||||
|
||||
For all CSS transition types and their GSAP implementations, read `skills/hyperframes/references/transitions/catalog.md`.
|
||||
|
||||
### 7. Asset cross-reference
|
||||
|
||||
Before self-review, verify you actually used the assets you planned to:
|
||||
|
||||
1. Open STORYBOARD.md and find this beat's asset assignments
|
||||
2. List every asset that was assigned to this beat
|
||||
3. Search the composition HTML for each filename (e.g., grep for "wave-fallback-desktop")
|
||||
4. If any assigned asset is missing from the HTML, add it now
|
||||
5. Check for the inline anti-pattern: if the HTML contains `<svg xmlns=` or `data:image/` but no `../capture/assets/` references, the assets were inlined instead of referenced. Replace inline content with `<img src="../capture/assets/filename.svg">`
|
||||
6. Check fonts: if the HTML uses `fonts.googleapis.com` but there are captured fonts in `capture/assets/fonts/`, replace with `@font-face` pointing to the local files (e.g., `src: url('../capture/assets/fonts/BrandFont-Regular.woff2')`)
|
||||
|
||||
This step catches the two most common failures: compositions ending up text-only, and assets being inlined instead of file-referenced.
|
||||
|
||||
### 8. Self-review
|
||||
|
||||
After building the composition, check WITH ACTUAL CODE:
|
||||
|
||||
- [ ] Asset cross-reference passed (step 7 above — every assigned asset is in the HTML)
|
||||
- [ ] Elements are where the storyboard says they should be (no misplacement)
|
||||
- [ ] No overlapping text (text covering text is always ugly)
|
||||
- [ ] Depth layers present (2+ layers minimum)
|
||||
- [ ] Every visible element has mid-scene activity (not just entrance + exit)
|
||||
- [ ] Font sizes above minimum (20px body text, 16px labels — sub-14px is unreadable after encoding)
|
||||
- [ ] No full-screen dark linear gradients (H.264 creates visible banding — use solid + localized radial glows)
|
||||
- [ ] Timeline registered: `window.__timelines["comp-id"] = tl`
|
||||
- [ ] Colors match DESIGN.md exactly (paste the HEX value, don't approximate)
|
||||
- [ ] **Every `<template>` root element** — not just `index.html`, but every sub-composition's root — has `data-start="0"`. The linter warns `root_composition_missing_data_start` when missing. Authoring `data-duration="<beat_seconds>"` on the root is also recommended for compositions whose GSAP timeline uses repeating animations (`repeat: -1` or large `repeat: N`); without it the runtime may infer `Infinity` and stall playback. The linter flags those repeating shapes directly via `gsap_infinite_repeat` and `gsap_repeat_ceil_overshoot`.
|
||||
- [ ] **Caption exits have a hard kill.** If you animate captions out with `tl.to(groupEl, { opacity: 0 }, group.end)`, follow it with `tl.set(groupEl, { opacity: 0, visibility: "hidden" }, group.end)` as a deterministic kill — per-word karaoke tweens can override the exit tween and leave captions stuck on screen. Linter: `caption_exit_missing_hard_kill`.
|
||||
- [ ] **No duplicate media nodes.** If the same image/video source is referenced twice with identical `data-start` + `data-duration`, the compiler discovers it twice and can double-render. Dedupe by using a single `<img>` with appropriate z-layering, or stagger the `data-start` values. Linter: `duplicate_media_discovery_risk`.
|
||||
|
||||
**If `skills/hyperframes-animation-map/` is installed**, run it:
|
||||
|
||||
```bash
|
||||
node skills/hyperframes-animation-map/scripts/animation-map.mjs <composition-dir>
|
||||
```
|
||||
|
||||
Read the summaries. Fix every flag: offscreen, collision, invisible, pacing issues.
|
||||
|
||||
### 9. Move to the next composition
|
||||
|
||||
---
|
||||
|
||||
## Asset Presentation
|
||||
|
||||
Never embed a raw flat image. Every image must have motion treatment:
|
||||
|
||||
- **Perspective tilt**: use `gsap.set(el, { transformPerspective: 1200, rotationY: -8 })` + `box-shadow` — creates depth. Do NOT use CSS `transform: perspective(...)` as GSAP will overwrite it.
|
||||
- **Slow zoom (Ken Burns)**: GSAP `scale: 1` → `1.04` over beat duration — makes photos cinematic
|
||||
- **Device frame**: Wrap in a laptop/phone shape using CSS `border-radius` and `box-shadow`
|
||||
- **Floating UI**: Extract a key element and animate it at a different z-depth for parallax
|
||||
- **Scroll reveal**: Clip the image to a viewport window and animate `y` position
|
||||
|
||||
---
|
||||
|
||||
## Audio Wiring
|
||||
|
||||
In the root `index.html`:
|
||||
|
||||
- **Narration**: `<audio id="narration" src="narration.wav" data-start="0" data-duration="..." data-track-index="0" data-volume="1">`
|
||||
- **Underscore/music** (if storyboard specifies): `<audio id="underscore" src="underscore.mp3" data-start="0" data-duration="..." data-track-index="3" data-volume="0.15">`
|
||||
- **SFX** (if storyboard specifies): individual `<audio>` elements at specific `data-start` timestamps
|
||||
- **Captions** (optional — only if user requests): sub-composition on a parallel track. Skip unless explicitly asked for.
|
||||
|
||||
---
|
||||
|
||||
## Critical Rules
|
||||
|
||||
These exist because the capture engine is deterministic. Violations produce broken output.
|
||||
|
||||
- **No `repeat: -1`** — calculate exact repeats from beat duration
|
||||
- **No `Math.random()`** — use a seeded PRNG (mulberry32)
|
||||
- **Register every timeline**: `window.__timelines["comp-id"] = tl`
|
||||
- **Synchronous timeline construction** — no async/await wrapping timeline code
|
||||
- **Never use ANY CSS `transform` for centering** — not `translate(-50%, -50%)`, not `translateX(-50%)`, not `translateY(-50%)`. GSAP animates the `transform` property, which overwrites ALL CSS transforms including centering. The element flies offscreen. Use flexbox centering instead: `display:flex; align-items:center; justify-content:center` on a wrapper div. The linter catches this (`gsap_css_transform_conflict`) but only if you run it.
|
||||
- **Minimum font sizes**: 20px body, 16px labels
|
||||
- **No full-screen dark linear gradients** — H.264 banding
|
||||
|
||||
---
|
||||
|
||||
## Load-bearing rules for animation authoring
|
||||
|
||||
Rules below came out of two independent website-to-hyperframes builds (2026-04-20) where compositions lint-clean and still ship broken — elements that never appear, ambient motion that doesn't scrub, entrance tweens that silently kill their target. The linter cannot catch these; the rules must be followed by the author.
|
||||
|
||||
- **No iframes for captured content.** Iframes do not seek deterministically with the timeline — the capture engine cannot scrub inside them, so they appear frozen (or blank) in the rendered output. If the source you're stylizing is a live web app, use the screenshots from `capture/` as stacked panels or layered images, not live embeds.
|
||||
|
||||
- **Never stack two transform tweens on the same element.** A common failure: a `y` entrance plus a `scale` Ken Burns on the same `<img>`. The second tween's `immediateRender: true` writes the element's initial state at construction time, overwriting whatever the first tween set — leaving the element invisible or offscreen with no lint warning. A secondary mechanism: `tl.from()` resets to its declared "from" state when the playhead is seeked past the timeline's end, so an element that looked correct in linear playback vanishes in the capture engine's non-linear seek. Fix one of two ways:
|
||||
|
||||
```html
|
||||
<!-- BAD: two transforms on one element -->
|
||||
<img class="hero" src="..." />
|
||||
<script>
|
||||
tl.from(".hero", { y: 50, opacity: 0, duration: 0.6 }, 0);
|
||||
tl.to(".hero", { scale: 1.04, duration: beat }, 0); // kills the entrance
|
||||
</script>
|
||||
|
||||
<!-- GOOD option A: combine into one tween -->
|
||||
<script>
|
||||
tl.fromTo(
|
||||
".hero",
|
||||
{ y: 50, opacity: 0, scale: 1.0 },
|
||||
{ y: 0, opacity: 1, scale: 1.04, duration: beat, ease: "none" },
|
||||
0,
|
||||
);
|
||||
</script>
|
||||
|
||||
<!-- GOOD option B: split across parent + child -->
|
||||
<div class="hero-wrap"><img class="hero" src="..." /></div>
|
||||
<script>
|
||||
tl.from(".hero-wrap", { y: 50, opacity: 0, duration: 0.6 }, 0); // entrance on parent
|
||||
tl.to(".hero", { scale: 1.04, duration: beat }, 0); // Ken Burns on child
|
||||
</script>
|
||||
```
|
||||
|
||||
- **Prefer `tl.fromTo()` over `tl.from()` inside `.clip` scenes.** `gsap.from()` sets `immediateRender: true` by default, which writes the "from" state at timeline construction — before the `.clip` scene's `data-start` is active. Elements can flash visible, start from the wrong position, or skip their entrance entirely when the scene is seeked non-linearly (which the capture engine does). Explicit `fromTo` makes the state at every timeline position deterministic:
|
||||
|
||||
```js
|
||||
// BRITTLE: immediateRender interacts badly with scene boundaries
|
||||
tl.from(el, { opacity: 0, y: 50, duration: 0.6 }, t);
|
||||
|
||||
// DETERMINISTIC: state is defined at both ends, no immediateRender surprise
|
||||
tl.fromTo(el, { opacity: 0, y: 50 }, { opacity: 1, y: 0, duration: 0.6 }, t);
|
||||
```
|
||||
|
||||
- **Ambient pulses must attach to the seekable `tl`, never bare `gsap.to()`.** Auras, shimmers, gentle float loops, logo breathing — all of these must be added to the scene's timeline, not fired standalone. Standalone tweens run on wallclock time and do not scrub with the capture engine, so the effect is absent in the rendered video even though it looks correct in the studio preview:
|
||||
|
||||
```js
|
||||
// BAD: lives outside the timeline, never renders in capture
|
||||
gsap.to(".aura", { scale: 1.08, yoyo: true, repeat: 5, duration: 1.2 });
|
||||
|
||||
// GOOD: seekable, deterministic, renders
|
||||
tl.to(".aura", { scale: 1.08, yoyo: true, repeat: 5, duration: 1.2 }, 0);
|
||||
```
|
||||
|
||||
- **Hard-kill every scene boundary, not just captions.** The caption hard-kill rule above generalizes: any element whose visibility changes at a beat boundary needs a deterministic `tl.set()` kill after its fade, because later tweens on the same element (or `immediateRender` from a sibling tween) can resurrect it. Apply to every element with an exit animation:
|
||||
|
||||
```js
|
||||
tl.to(el, { opacity: 0, duration: 0.3 }, beatEnd);
|
||||
tl.set(el, { opacity: 0, visibility: "hidden" }, beatEnd + 0.3); // deterministic kill
|
||||
```
|
||||
@@ -0,0 +1,208 @@
|
||||
# Step 6: Validate & Deliver
|
||||
|
||||
This is the quality gate. Before the user sees anything, YOU verify that the video matches the storyboard, the creative direction from Step 2, and DESIGN.md. Deliver something you'd be proud to post with your name on it.
|
||||
|
||||
## Definition of Done — required before ANY preview or summary
|
||||
|
||||
**You may not say the video is ready, looks good, or present a preview URL until every item below is checked.** No exceptions. Do not summarize your impressions — paste the actual evidence for each.
|
||||
|
||||
Score each item 1–5. If any item scores below 3, fix it before continuing. **Do not rush these.** Each checkbox is its own pass through the artifacts — slow down, look at every frame, write the actual observation, not a summary impression.
|
||||
|
||||
```
|
||||
[ ] Every beat HTML read top-to-bottom → see "Per-beat file read" below; paste the per-beat verdict
|
||||
[ ] Lint: zero errors → paste the lint output (not "lint passed")
|
||||
[ ] Snapshot taken, N frames confirmed → state the exact frame count
|
||||
[ ] descriptions.md read in full → quote the WORST frame Gemini described, verbatim
|
||||
[ ] Contact sheet viewed cell-by-cell → for EACH beat, one sentence: what's in frame, what's moving, what brand assets are present
|
||||
[ ] No mid-video dark frames → state explicitly which frames (if any) are dark and why
|
||||
[ ] Brand assets actually visible → for each beat, name which captured SVG / illustration / screenshot is on screen and at what timestamp. If a beat shows zero captured assets, justify why.
|
||||
[ ] Audio duration matches video ±0.5s → paste both numbers
|
||||
[ ] Critic sub-agent run → paste its single biggest quality gap finding, verbatim
|
||||
```
|
||||
|
||||
### Per-beat file read
|
||||
|
||||
This is what verification means now: you open each `compositions/beat-N.html` and read it top-to-bottom against DESIGN.md and STORYBOARD.md. Step 5 already required this once before advancing here — repeat it here as the final check, in case fixes during Step 5 introduced new problems.
|
||||
|
||||
For each beat, write a per-beat verdict in this form:
|
||||
|
||||
```
|
||||
Beat N (Ns–Ns) — <name>
|
||||
CSS bg: <hex> (DESIGN.md says <hex>, matches: yes/no)
|
||||
CSS accent: <hex> (DESIGN.md says <hex>, matches: yes/no)
|
||||
Headline font-size: <px> (≥80: yes/no)
|
||||
Captured assets referenced: <list of paths from <img>, inline SVG, background-image> (storyboard called for: <list>)
|
||||
GSAP timeline coverage: events from <first t> to <last t>, beat duration <N>s (full coverage: yes/no)
|
||||
Storyboard alignment: <one sentence — does this beat deliver what its STORYBOARD.md section described>
|
||||
VERDICT: PASS / NEEDS FIX (<what specifically>)
|
||||
```
|
||||
|
||||
The pre-fix-era flow took longer specifically because it caught these problems. Don't trade the careful look for a green checkmark.
|
||||
|
||||
**Why this matters:** The natural tendency is to look at a contact sheet, see that content is present, and declare it done. That is not verification — that is pattern-matching to a completion signal. Verification means opening every file the sub-agents produced, reading every line, and reporting the raw result. "Frame 7 at 14.2s shows the Raycast logo SVG drawing its final stroke at 0.85 opacity against #07080A, the headline 'Crush your sprint' has settled in 96px Inter SemiBold below" is evidence. "The video looks great" is not.
|
||||
|
||||
---
|
||||
|
||||
## Lint + Validate + Snapshot
|
||||
|
||||
The `hyperframes` skill (which you loaded in Step 5) already covers the mechanics of linting, validating, and snapshotting. Follow those rules — run lint, validate, take snapshots scaled to the video length (formula: `max(beats × 3, ceil(duration_seconds / 2))`). Fix errors. This step adds the **pipeline-specific verification** on top of that.
|
||||
|
||||
**Errors:** Fix ALL of them. These are real problems — missing timeline registration, broken scripts, missing assets.
|
||||
|
||||
**Warnings:** Read each one and decide. Some are real quality issues you must fix:
|
||||
|
||||
- **GSAP tween overlaps** — elements fighting over the same property = visual glitches
|
||||
- **Unscoped selectors** — will target elements in ALL compositions when bundled, causing data loss
|
||||
- **Missing `class="clip"`** — element visible for entire video instead of its scheduled time
|
||||
- **Missing `data-start` on root** — playback won't begin
|
||||
|
||||
Some are style suggestions you can safely ignore:
|
||||
|
||||
- **File too large** — composition works fine, just harder to read
|
||||
- **Deprecated attributes** (data-layer, data-end) — still work, just not preferred
|
||||
- **Dense tracks** — informational, not a bug
|
||||
|
||||
Don't blindly ignore 158 warnings. Don't blindly fix all of them either. Read them.
|
||||
|
||||
## Visual Verification (snapshot)
|
||||
|
||||
After lint and validate pass, capture snapshot frames to SEE your own output. **Take many snapshots — as much as you can actually read and view all of them without hitting diminishing returns**. This is your only visual feedback before the user sees the project. You wanna be honored and proud of what you give to the user.
|
||||
|
||||
Scale snapshot count to the video — not a fixed number. Formula: `max(beats × 3, ceil(duration_seconds / 2))`. A 3-beat 10s video: max(9, 5) = 9 frames. An 8-beat 60s video: max(24, 30) = 30 frames. Aim for at least 3 frames per beat: entrance, hold, and near-exit.
|
||||
|
||||
**⚠ NEVER use `npx hyperframes snapshot`.** The published CLI (0.6.6) is missing critical fixes: sub-comps load before capturing, local-time seek for last beats, Gemini vision descriptions. Always use the local CLI below or all beats after the first may appear black and descriptions.md won't be generated.
|
||||
|
||||
```bash
|
||||
# The local CLI auto-loads .env from the current working directory, so a
|
||||
# .env file in <project-dir> with GEMINI_API_KEY=... is enough — no explicit
|
||||
# export needed. If you've set GEMINI_API_KEY directly in your shell env that
|
||||
# also works.
|
||||
npx tsx packages/cli/src/cli.ts snapshot <project-dir> --frames <N>
|
||||
|
||||
# Pass a custom question to Gemini instead of the default prompt:
|
||||
npx tsx packages/cli/src/cli.ts snapshot <project-dir> --frames <N> \
|
||||
--describe "Is the brand logo visible in every beat? Is any beat showing a black or blank frame?"
|
||||
```
|
||||
|
||||
Output lands in `<project-dir>/snapshots/`. Gemini writes `snapshots/descriptions.md` automatically.
|
||||
|
||||
**If `descriptions.md` is missing or empty after the snapshot:** `GEMINI_API_KEY` was not set — confirm it's in `<project-dir>/.env` (the CLI loads .env from CWD) or in your shell environment. Re-run after fixing. Do not proceed without Gemini descriptions — visual inspection alone is not sufficient verification.
|
||||
|
||||
**Gemini descriptions will flag two frames as "blank/black" — these two are expected and not bugs:**
|
||||
|
||||
- `frame-00-at-0.0s.png` — always dark, animations haven't started
|
||||
- The last frame of the video — always dark, the s-end dummy scene is intentionally invisible
|
||||
|
||||
Every other frame described as "black," "blank," "no visible content," or "loading screen" in the middle of the video IS a bug. Investigate and fix it.
|
||||
|
||||
**Two required reads — both, not one. Then a per-beat verdict.**
|
||||
|
||||
1. **Read `snapshots/descriptions.md`** — Gemini's objective written analysis of every frame. Read every line. Do not skim.
|
||||
|
||||
2. **View `snapshots/contact-sheet.jpg` cell-by-cell.** Not a glance. Look at every cell, name what's in it. Past agents have reported "contact sheet looks good" after a single scan and missed: a beat that was visually black for 80% of its duration, a logo placed off-screen, a headline clipped at the canvas edge, captions running off the bottom. The contact sheet is the only place these failures are visible together. **For each cell, write one sentence: what's in frame, what's moving, which brand assets are present, anything that looks wrong.** If you find yourself wanting to summarize the contact sheet as a whole, stop and go back to cell-by-cell.
|
||||
|
||||
After reading both, write a per-beat verdict for every beat:
|
||||
|
||||
```
|
||||
Beat 1 (0.0s–4.5s): [what Gemini described] | [what contact sheet shows] | PASS / NEEDS FIX
|
||||
Beat 2 (4.0s–9.5s): ...
|
||||
Beat 3 ...
|
||||
CTA beat: ...
|
||||
```
|
||||
|
||||
A beat PASSES only if:
|
||||
|
||||
- Gemini description matches what STORYBOARD.md says should be happening
|
||||
- Contact sheet shows visible content (not black, not blank, not loading)
|
||||
- Brand colors/fonts visible
|
||||
- No elements clipped or mispositioned
|
||||
|
||||
A beat that "has some content" does not automatically pass. Compare against what was _planned_, not just "something is there."
|
||||
|
||||
**If any beat fails: fix it, re-snapshot, re-read descriptions.md, re-write the per-beat verdict from scratch.** Do not carry forward old verdicts after a fix — re-evaluate everything because fixes can break adjacent beats.
|
||||
|
||||
**Keep iterating until every beat passes.** There is no time limit. A video with one black CTA beat is not done.
|
||||
|
||||
## Critic Sub-Agent — do not skip
|
||||
|
||||
**This is not optional. Run it after your per-beat verdicts all pass — before you start preview.**
|
||||
|
||||
Spawn a sub-agent with this exact prompt:
|
||||
|
||||
```
|
||||
You are a senior motion designer and creative director reviewing a brand video before it ships. You have high standards and have seen hundreds of these.
|
||||
|
||||
Read these files:
|
||||
- STORYBOARD.md (what was planned)
|
||||
- DESIGN.md (brand rules)
|
||||
- snapshots/descriptions.md (what Gemini sees in each frame)
|
||||
- snapshots/contact-sheet.jpg (view it)
|
||||
|
||||
Score each dimension 1–5. Be specific — name the beat and timestamp for every problem you identify.
|
||||
|
||||
1. **Beat execution** (1–5): Does every beat deliver what STORYBOARD.md planned? Name any beat that underdelivers and what exactly is wrong.
|
||||
2. **Brand accuracy** (1–5): Does this feel made for THIS brand specifically, or could it be for any company? Name one element that is distinctly on-brand and one that is generic.
|
||||
3. **Captured asset utilization** (1–5): The user captured the brand's actual SVG logos, hero illustrations, and screenshots into `capture/assets/`. Are they on screen in this video, or did the agents recreate everything from divs and CSS? List which captured assets appear in which beats. If beats are missing them, flag it — a video that recreates everything in CSS is generic, not branded.
|
||||
4. **Visual quality** (1–5): Any blank frames, clipped text, centering failures, invisible elements? Cite exact frame timestamps.
|
||||
5. **Motion design** (1–5): Do animations feel intentional and polished, or default and mechanical? Name the weakest transition and why.
|
||||
6. **CTA beat** (1–5): Is the final beat clear, centered, readable, and does it hold long enough? Describe exactly what is visible on the CTA frame.
|
||||
|
||||
End with: What is the single most important fix before this ships? Name the beat, the element, and the specific change.
|
||||
|
||||
If you cannot find any problems and want to score everything 4–5, you are not looking hard enough. Look again.
|
||||
```
|
||||
|
||||
Read every score. Fix anything below 3 before showing the user. If the CTA scores below 3, fix the CTA. Do not rationalize low scores as "the user can decide."
|
||||
|
||||
## Preview (always do this)
|
||||
|
||||
Always start the preview so the user can see and scrub through the project:
|
||||
|
||||
```bash
|
||||
npx hyperframes preview
|
||||
```
|
||||
|
||||
The Studio URL is the deliverable. In your final response, always include it:
|
||||
|
||||
```text
|
||||
http://localhost:<port>/#project/<project-name>
|
||||
```
|
||||
|
||||
Use the actual port and project name from the preview command output. Do NOT present `index.html` as the project link — that's the source file. The user-facing project is the running Studio preview.
|
||||
|
||||
## Render (on-demand only)
|
||||
|
||||
**Do NOT render automatically.** Preview is the delivery — the user scrubs, spots tweaks, and you iterate. Rendering takes minutes per pass and is wasted if the user wants changes.
|
||||
|
||||
Only render when the user **explicitly asks** — "render it", "make the final", "export the MP4", "I'm happy, produce the file."
|
||||
|
||||
When rendering, **always specify quality and resolution explicitly.** Don't use defaults silently — pick the right settings for the use case and tell the user what you're rendering:
|
||||
|
||||
```bash
|
||||
# Standard quality, 1080p landscape (default for most videos)
|
||||
npx hyperframes render --output renders/<name>.mp4 --quality standard --fps 30
|
||||
|
||||
# High quality for final delivery
|
||||
npx hyperframes render --output renders/<name>.mp4 --quality high --fps 30
|
||||
|
||||
# Portrait for Instagram Stories / TikTok
|
||||
npx hyperframes render --output renders/<name>.mp4 --quality standard --fps 30 --resolution portrait
|
||||
|
||||
# 4K for premium output
|
||||
npx hyperframes render --output renders/<name>.mp4 --quality high --fps 30 --resolution 4k
|
||||
```
|
||||
|
||||
**Available options:**
|
||||
|
||||
| Flag | Values | Notes |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
|
||||
| `--quality` | `draft`, `standard`, `high` | draft = fast/low, standard = balanced, high = slow/best |
|
||||
| `--fps` | `24`, `30`, `60` | 30 is standard, 24 for cinematic feel, 60 for smooth motion |
|
||||
| `--resolution` | `landscape` (1920×1080), `portrait` (1080×1920), `landscape-4k` (3840×2160), `portrait-4k` | Aliases: `1080p`, `4k`, `uhd` |
|
||||
| `--format` | `mp4`, `webm`, `mov`, `png-sequence` | mp4 default. mov/webm for transparency. png-sequence for AE/Nuke |
|
||||
| `--output` | path | Always set to `renders/<project-name>.mp4` for readable names |
|
||||
| `--gpu` | flag | Use GPU encoding if available (faster) |
|
||||
| `--crf` | integer | Override encoder quality (lower = better, mutually exclusive with --video-bitrate) |
|
||||
| `--video-bitrate` | e.g. `10M` | Target bitrate (mutually exclusive with --crf) |
|
||||
|
||||
Tell the user what you're rendering and why: "Rendering at standard quality, 1080p landscape, 30fps — this gives good quality with reasonable render time. Want me to use high quality or 4K instead?"
|
||||
@@ -1,114 +0,0 @@
|
||||
# Step 7: Validate & Deliver
|
||||
|
||||
## Lint + Validate
|
||||
|
||||
Run in sequence. Fix all errors before proceeding to the next command.
|
||||
|
||||
```bash
|
||||
npx hyperframes lint
|
||||
npx hyperframes validate
|
||||
```
|
||||
|
||||
`lint` checks HTML structure statically — missing attributes, timeline registration, tween conflicts, CSS transform + GSAP conflicts (including inline styles).
|
||||
`validate` loads the composition in headless Chrome and catches runtime JS errors, missing assets, and failed network requests.
|
||||
|
||||
## Visual Verification (snapshot)
|
||||
|
||||
After lint and validate pass, capture snapshot frames to SEE your own output. **Always use `hyperframes snapshot`** — do not roll your own ffmpeg/headless Chrome script; the default naming (`frame-XX-at-Ys.png`) is expected by later tooling.
|
||||
|
||||
```bash
|
||||
npx hyperframes snapshot <project-dir> --at <beat-midpoints>
|
||||
```
|
||||
|
||||
If the snapshot command isn't available, fall back to:
|
||||
|
||||
```bash
|
||||
npx tsx packages/cli/src/cli.ts snapshot <project-dir> --at <beat-midpoints>
|
||||
```
|
||||
|
||||
Calculate the midpoint of each beat from your STORYBOARD.md timings. For a 4-beat video with beats at 0-5.8s, 5.8-15.0s, 15.0-22.5s, 22.5-25.3s:
|
||||
|
||||
```bash
|
||||
npx hyperframes snapshot <project-dir> --at 2.9,10.4,18.7,23.9
|
||||
```
|
||||
|
||||
This renders one frame per beat at the moment when content is most visible. Use timestamps where the most content is on screen — usually 60-70% into each beat, after entrances finish but before exits start. Output lands in `<project-dir>/snapshots/` with filenames like `frame-00-at-2.9s.png`.
|
||||
|
||||
**View every snapshot image carefully.** Don't glance and move on. For each frame, check:
|
||||
|
||||
**Visibility:**
|
||||
|
||||
- Is there visible content? All-white or all-black frames mean compositions aren't rendering.
|
||||
- Can you read ALL text? White text on white/light background is invisible. Dark text on dark background is invisible. Every text element needs contrast against what's directly behind it.
|
||||
- Are images and assets showing? Empty space where an image should be means a path issue or missing file.
|
||||
|
||||
**Positioning and layout:**
|
||||
|
||||
- Do background images fill the entire frame? If an image only covers half the screen, the `object-fit`, `width`, `height`, or position values are wrong.
|
||||
- Are elements where the storyboard says they should be? Compare the snapshot to the beat description.
|
||||
- Is there too much empty/dead space? If more than 40% of the frame is a flat solid color with nothing on it, the composition is sparse.
|
||||
- Are elements overlapping incorrectly? Text over text, or content bleeding off the edges?
|
||||
|
||||
**Visual quality:**
|
||||
|
||||
- Are overlays too heavy? If a background image is barely visible through a dark overlay, reduce the overlay opacity.
|
||||
- Is the visual hierarchy clear? One dominant element per frame, supporting elements secondary.
|
||||
- Do the colors match DESIGN.md? Check actual rendered colors against what was planned.
|
||||
|
||||
**Code vs. rendered verification:**
|
||||
|
||||
- For each beat, check: does the snapshot show the assets you referenced in the HTML? If a composition has `<img src="...wave.png">` but the snapshot shows no wave — the image isn't loading, the path is wrong, or it's hidden behind another element.
|
||||
- If a snapshot shows nothing at a timestamp, try a slightly different time (1-2 seconds later). Compositions may still be in entrance animations.
|
||||
- The snapshot command is fast — run it multiple times at different timestamps if needed.
|
||||
|
||||
If any frame has issues, go back to Step 6 and fix that composition before proceeding.
|
||||
|
||||
## Preview
|
||||
|
||||
```bash
|
||||
npx hyperframes preview
|
||||
```
|
||||
|
||||
Open the studio in a browser. Scrub through every beat.
|
||||
|
||||
### Handoff URL
|
||||
|
||||
The Studio URL is the project handoff surface. In the final response, report the
|
||||
active preview URL with the project hash:
|
||||
|
||||
```text
|
||||
http://localhost:<port>/#project/<project-name>
|
||||
```
|
||||
|
||||
Use the actual port selected by `hyperframes preview` and the project name shown
|
||||
by the preview command. If you run `hyperframes preview --port 3017` for a
|
||||
project directory named `codex-openai-video`, the project URL is:
|
||||
|
||||
```text
|
||||
http://localhost:3017/#project/codex-openai-video
|
||||
```
|
||||
|
||||
Do **not** present `index.html` as the project link. `index.html` is the source
|
||||
file for agents and editors; the user-facing project is the running HyperFrames
|
||||
Studio preview. You may include source file links as secondary context, but the
|
||||
primary "Project" or "Preview" line must be the localhost Studio URL.
|
||||
|
||||
If a render was also requested, still include the Studio URL first so the user
|
||||
can scrub and inspect the project. Include the MP4 path as the rendered output,
|
||||
not as a replacement for the project URL.
|
||||
|
||||
## Render (on-demand only)
|
||||
|
||||
**Do NOT render automatically as part of the pipeline.** Preview is the delivery — the user scrubs, spots anything they want tweaked, and you iterate. Rendering to MP4 takes minutes of wall-clock time per pass and is wasted work if the user wants changes.
|
||||
|
||||
Only run `hyperframes render` when the user **explicitly asks** — e.g. "render it", "make the final", "export the MP4", "I'm happy, produce the file". Until then, stop at preview + snapshots.
|
||||
|
||||
When the user does ask to render, always pass `--output renders/<project-name>.mp4` so the final file has a predictable, human-readable name. The CLI default is timestamped (`<project>_YYYY-MM-DD_HH-MM-SS.mp4`) which is hard to reference from docs or later iterations.
|
||||
|
||||
```bash
|
||||
npx hyperframes render --output renders/<project-name>.mp4
|
||||
```
|
||||
|
||||
Example: `npx hyperframes render --output renders/stripe-launch.mp4`
|
||||
|
||||
For social-media vertical output, check `npx hyperframes render --help` for viewport/format flags.
|
||||
@@ -0,0 +1,160 @@
|
||||
# Visual Vocabulary
|
||||
|
||||
A vocabulary for talking about how a video looks and moves, organized along six independent axes. **The agent's job is to derive a value for each axis from the brand,** then treat the user's words as _modifiers_ on that brand-derived baseline.
|
||||
|
||||
The older version of this file had a "user says X → fill these 6 dimensions" lookup table. That table is gone. The failure mode it produced — "energetic wellness app" and "energetic fintech tool" rendering with the same 6-dimension recipe because both triggered the same user-word match — was the whole problem this skill is trying to solve.
|
||||
|
||||
The new flow:
|
||||
|
||||
1. **Read DESIGN.md and the captured site.** What cues does this brand give for each of the six axes? Each axis below lists what brand evidence suggests each value.
|
||||
2. **Derive a baseline.** Write down what this _specific brand_ suggests for each axis, in one phrase per axis. This is the brand-native interpretation.
|
||||
3. **Apply user modifiers.** If the user said "cinematic" or "fast" or "playful," treat that as a push on the baseline — not a replacement. "Cinematic" pushes toward slow pacing and dramatic transitions on top of what the brand already suggested; it doesn't override the brand.
|
||||
4. **Resolve conflicts toward the brand.** If the user's word and the brand's evidence disagree strongly, raise it. Don't silently flatten the brand to fit the word.
|
||||
|
||||
---
|
||||
|
||||
## The Six Axes
|
||||
|
||||
Each axis below has values, and for each value, **brand cues that suggest it**. Read brand evidence first; the values are what you derive, not what you start with.
|
||||
|
||||
### 1. Pacing — how fast things move and change
|
||||
|
||||
| Value | Animation durations | Brand cues that suggest this value |
|
||||
| ---------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Slow** | 1.5–3s per move | Hero text dominates the homepage at large scale, copy uses long sentences and full paragraphs, whitespace is generous in the captured layout, serif or thin-weight sans typography, scroll animations on the site are fade-based and unhurried, brand language is mature ("decades of," "the standard for," "founded in") |
|
||||
| **Moderate** | 0.8–1.5s per move | Standard product-marketing layout — hero plus three columns plus testimonials, sans-serif body type, content is sectioned but not dense, copy is professional but not formal, scroll animations exist but aren't dramatic |
|
||||
| **Fast** | 0.3–0.6s per move | Dense feature grids, multi-column comparison tables, video/gif assets autoplay in the hero, second-person urgent copy ("crush your goals," "ship faster"), social-media-first iconography, brand voice is energetic or consumer-facing |
|
||||
| **Arc (varies)** | Slow→build→peak→resolve | The site itself has narrative pacing — a long-scroll story, sequential reveals, a "this is the problem / here's the solution / here's the proof" structure. Most launch and announcement videos benefit from arc pacing regardless of brand. |
|
||||
|
||||
### 2. Density — how much shares the frame
|
||||
|
||||
| Value | Focus | Brand cues that suggest this value |
|
||||
| ------------ | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Sparse** | One element dominates, generous breathing room | Homepage is hero-then-scroll with one element per viewport, design uses architectural negative space, type carries the work without supporting imagery, brand is confident/restrained (luxury, mature B2B, art) |
|
||||
| **Balanced** | Primary plus 2–3 supporting | Standard marketing layout — hero with one secondary image, feature sections with icon + headline + body, professional but not minimal |
|
||||
| **Rich** | Multiple elements share attention | Dashboard or product-tour-heavy site, feature comparison grids, sites with charts/data visualizations as primary content, sites with dense pricing tables, consumer apps showing many screenshots simultaneously |
|
||||
|
||||
### 3. Transitions — how scenes change
|
||||
|
||||
| Value | What happens | Brand cues that suggest this value |
|
||||
| ------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **Dramatic** | GPU shader effects, ~0.5–0.8s | Brand has high-stakes positioning (security, finance, dramatic reveals), homepage already uses dramatic transitions or shader effects, brand language uses words like "introducing," "finally," "the future of," brand has theatrical confidence |
|
||||
| **Smooth** | CSS-based fades, slides, blurs, ~0.3–0.6s | Most brands. The professional default. Brand reads as competent and current without theatrical aspiration. |
|
||||
| **Energetic** | Whip pans, fast zooms, ~0.2–0.4s | Consumer apps, social-first brands, brands targeting younger demographics, gaming, fast-moving consumer goods, brand voice uses imperatives and exclamation |
|
||||
| **Hard cut** | Instant switches | Editorial brands, news, brands with confident type-driven identity, anything where rhythm/cadence is the design feature |
|
||||
|
||||
**A note on dramatic transitions:** Even when the brand suggests dramatic, the storyboard should not use shader transitions on every scene change. One to two shader moments in a video is the ceiling. Beyond that the effects flatten each other.
|
||||
|
||||
### 4. Mood — visual atmosphere
|
||||
|
||||
| Value | Characteristics | Brand cues that suggest this value |
|
||||
| --------------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Dark** | Deep backgrounds, glow accents, light from darkness | Captured site uses dark theme as default, primary background is near-black or deep neutral, single saturated accent against the dark, brand operates in technical/dramatic/luxury space |
|
||||
| **Light** | Bright backgrounds, brand colors as accents | Captured site is white-or-near-white background, structure comes from borders and shadows not from color, brand is consumer-facing, friendly, or corporate-clean |
|
||||
| **Vibrant** | Multiple saturated colors, gradient backgrounds | Brand uses multiple primary colors (not one accent), captured site uses gradient or aurora effects, brand voice is celebratory or energetic, consumer or creative product |
|
||||
| **Atmospheric** | Dark base with gradient depth, color temperature shifts | Captured site uses dark base + colored gradients, brand has cinematic positioning, AI/computational brands often land here |
|
||||
|
||||
**Critical:** This axis comes more from the brand than any other. A dark-themed site gets dark mood; a white corporate site gets light mood. Don't override mood from a user word — if the user wants "cinematic" for a bright consumer brand, light-cinematic is a real thing (think Apple keynotes pre-2018) and you should reach for it rather than flipping the brand dark.
|
||||
|
||||
### 5. Motion language — how elements move
|
||||
|
||||
| Value | Easing flavor | Brand cues that suggest this value |
|
||||
| -------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **Cinematic** | Slow drifts, parallax, Ken Burns | Brand has theatrical or premium positioning, captured site uses parallax or scroll-driven storytelling, brand pace is unhurried |
|
||||
| **Dynamic** | Bounce, overshoot, elastic | Consumer-facing brand, playful or energetic voice, captured site has bouncy micro-interactions, brand targets younger or general-consumer audience |
|
||||
| **Elegant** | Smooth precise reveals without overshoot | Editorial or premium brand with restraint, captured site has clean fades and considered transitions, brand voice is confident without being theatrical |
|
||||
| **Restrained** | Controlled, grid-aligned, no overshoot | Technical product, dev tool, data-focused, captured site is minimal-decoration / function-first, brand voice is direct and unornamented |
|
||||
|
||||
### 6. Audio — how sound supports the visual
|
||||
|
||||
This axis has the least brand evidence to draw from (captured sites don't have soundtracks), so it leans more on user direction and video type. But there are still brand cues:
|
||||
|
||||
| Value | Voice / music / SFX character | Brand cues that suggest this value |
|
||||
| ------------ | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------- |
|
||||
| **Ambient** | Calm voice, sustained pads, sparse SFX | Brand voice in copy is measured and unhurried, brand operates in considered/premium space |
|
||||
| **Punchy** | Confident upbeat voice, rhythmic music, impact SFX | Consumer brand, energetic voice in copy, urgency language, social-first |
|
||||
| **Minimal** | Silence and texture, voice carries everything, almost no SFX | Editorial brand, restraint-heavy identity, brand whose homepage uses no decorative motion |
|
||||
| **Dramatic** | Slow voice with pauses, tension pads, deliberate silence | High-stakes brand positioning, theatrical voice in copy ("we believe," "the future demands") |
|
||||
|
||||
---
|
||||
|
||||
## How user words modify the baseline
|
||||
|
||||
After deriving a baseline from the brand, **read what the user actually said** and apply it as a modifier. Some user words map cleanly to single-axis pushes; some are vibe words that touch several axes; some only modify one part of the video.
|
||||
|
||||
The user word is a _direction of push_, not a replacement for the brand-derived value.
|
||||
|
||||
### Common user words and what they push
|
||||
|
||||
These are pushes, not recipes. They modify whatever baseline you derived from the brand — they don't replace it.
|
||||
|
||||
- **"Cinematic"** — pushes pacing slower (or toward arc), transitions toward dramatic for hero moments only, motion toward cinematic. Does _not_ automatically push mood toward dark — a cinematic light video is real (premium hotels, fashion, architecture).
|
||||
- **"High-energy"** — pushes pacing faster, transitions toward energetic, motion toward dynamic, audio toward punchy. Does _not_ automatically push mood toward vibrant — a dark high-energy video is real (action movies, gaming launches).
|
||||
- **"Minimal" / "clean"** — pushes density toward sparse, transitions toward smooth, motion toward elegant or restrained. Does _not_ automatically push mood toward light — minimal-dark is a major aesthetic (Bang & Olufsen, Aesop, most luxury).
|
||||
- **"Professional"** — usually means "don't do anything weird." Mostly a no-op push that confirms the baseline; sometimes pulls dynamic or punchy axes slightly toward elegant or ambient.
|
||||
- **"Playful" / "fun"** — pushes motion toward dynamic, transitions toward energetic, audio toward punchy. Does _not_ automatically push pacing to fast — playful-slow is a real thing (children's books, charm-forward brands).
|
||||
- **"Premium" / "luxury"** — pushes pacing slower, density sparser, motion toward cinematic or elegant. Does _not_ automatically push mood toward dark — premium-light is the dominant aesthetic of most actual luxury brands today.
|
||||
- **"Technical" / "developer"** — pushes motion toward restrained, density toward balanced or rich, audio toward minimal. Mood follows the brand — most dev tools are dark but not all.
|
||||
|
||||
Notice that every entry above includes what the word _doesn't_ do. That's deliberate — the previous file mapped each word onto all six axes simultaneously, which is what produced the homogeneity.
|
||||
|
||||
### When the user word and the brand conflict
|
||||
|
||||
If the user says "cinematic" and the brand is a brightly-colored playful consumer app, you have a conflict. Three options:
|
||||
|
||||
1. **Trust the brand and the word together.** Cinematic-playful is a real aesthetic (think Wes Anderson) — slow pacing, sparse density, but vibrant mood and elegant-with-personality motion. Borrow the dimensions that _can_ coexist; don't flatten one for the other.
|
||||
2. **Ask.** "You said cinematic — I want to check, because your brand is bright and playful. Are you imagining slow dramatic reveals (which would mean leaning away from your brand's energy) or something more like Wes Anderson's pacing applied to your existing palette?"
|
||||
3. **Default to brand if you can't ask.** When a video has to ship and the user isn't available, the brand-derived baseline is the safer choice — the user can always say "make it more cinematic" on review, but a video that contradicts the brand is harder to come back from.
|
||||
|
||||
---
|
||||
|
||||
## Lazy Defaults to Question
|
||||
|
||||
When you find yourself reaching for any of these as automatic responses, pause and ask whether it's coming from the brand or from a pattern-match:
|
||||
|
||||
- "Cinematic" → automatic dark mood + slow pace + dramatic transitions, regardless of what the brand actually looks like
|
||||
- "Technical" → automatic dark mode + terminal font + restrained motion, regardless of what the dev tool's actual brand is
|
||||
- "Premium" → automatic slow + sparse + dark, regardless of whether the brand is actually a light-premium or vibrant-premium aesthetic
|
||||
- "Launch" → automatic dramatic transitions on every scene because "this is a big announcement"
|
||||
- "Social ad" → automatic fast pacing + punchy audio + hard cuts, even when the brand's social presence is actually slow and editorial
|
||||
|
||||
If you catch yourself doing one of these, the fix is to go back to the brand evidence and re-derive. The user word should modify what the brand suggests — not replace it.
|
||||
|
||||
---
|
||||
|
||||
## Per-beat overrides
|
||||
|
||||
The baseline you derive applies to the whole video by default. The storyboard can override a single axis on a single beat — "this beat is faster" or "the transition into beat 4 is dramatic." These overrides should appear in the storyboard's notes, with a one-sentence reason rooted in this beat's purpose, not in a style preset.
|
||||
|
||||
Example override note:
|
||||
|
||||
> "Beat 4 — transition override to dramatic shader. Reason: this is the product-reveal beat and the brand's homepage has a similar dramatic moment on first scroll. The shader is doing what the brand already does at this moment in its own story."
|
||||
|
||||
The reason is the load-bearing part. "Use dramatic shader on beat 4" with no reason is style-by-fiat; the version with a reason is style-by-derivation.
|
||||
|
||||
---
|
||||
|
||||
## A worked example
|
||||
|
||||
Captured brand: a wellness app with light cream backgrounds, lowercase humanist serif type, soft pastel accents, first-person copy ("we believe in small daily rituals"), no urgency language, slow scroll-driven photography of hands.
|
||||
|
||||
User direction: "I want it high-energy for TikTok."
|
||||
|
||||
**Brand-derived baseline:**
|
||||
|
||||
- Pacing: slow (cream + serif + slow scroll photography + unhurried copy)
|
||||
- Density: sparse (architectural negative space on site)
|
||||
- Transitions: smooth (no dramatic transitions on the captured site)
|
||||
- Mood: light (cream backgrounds are the brand's signature)
|
||||
- Motion: elegant or cinematic (slow drifts on the captured site)
|
||||
- Audio: ambient (unhurried copy voice)
|
||||
|
||||
**User modifier:** "high-energy for TikTok" pushes pacing faster, transitions toward energetic, motion toward dynamic, audio toward punchy.
|
||||
|
||||
**Conflict resolution:** the user's push is in direct conflict with the brand. Three options as above:
|
||||
|
||||
1. Borrow what can coexist — keep light mood and sparse density (brand-true), but accelerate pacing slightly and add motion personality. Result: a faster wellness video that still feels like a wellness video, not a fitness video.
|
||||
2. Ask: "Your brand is paced slowly — for TikTok, do you want me to push it faster than your brand normally moves, or keep the calm pacing but design for vertical and short attention?"
|
||||
3. If you can't ask: write the brand-true version and flag the tension in the Creative Direction Summary so the user can respond on review.
|
||||
|
||||
The wrong move is to read "high-energy" and produce a fast, punchy, vibrant video — which is what the old recipe table would have produced, and which would not be a video of this wellness brand. It would be a generic high-energy TikTok with a wellness logo pasted on.
|
||||
Reference in New Issue
Block a user