mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-02 11:47:13 +00:00
* docs(studio): the browser editor in six pages, named the browser editor * docs(studio): mute where the editor has it, and no solo control The audio pages still described a solo control and a group-row mute that the editor does not render. Muting is the speaker button on an audio track (Mute track / Unmute track), the same toggle on a selected clip, and the Muted switch; a group is silenced through its members' tracks. The audio reference drops its solo section for the same reason.
478 lines
28 KiB
Plaintext
478 lines
28 KiB
Plaintext
---
|
||
title: "Brand, templates and storyboards"
|
||
sidebarTitle: "Brand and templates"
|
||
description: "Point the agent at a source of brand truth — a design spec, a site, or a Figma file — instead of asking for 'on-brand', and let it compose the frame."
|
||
---
|
||
|
||
import { DocsVideo } from "/snippets/docs-video.jsx";
|
||
|
||
"Make it on-brand" is the vaguest thing you can ask: the agent can't know your brand, so it invents one. Give it a
|
||
**source of brand truth** instead and name it in the prompt: a design spec, your live site, a Figma file, or a brand
|
||
kit in the Studio app. This page also covers templates you reuse and plans that span many scenes.
|
||
|
||
## Point at a spec, don't describe a vibe
|
||
|
||
A HyperFrames project can carry a design spec: `frame.md`. Its frontmatter holds the machine-readable brand — exact hex values, font families, weight relationships. The prose below the frontmatter carries intent and the brand's Do's and Don'ts.
|
||
|
||
When a spec exists, name it:
|
||
|
||
> Use the palette and type from `frame.md`. Build a 15-second feature announcement.
|
||
|
||
- **Avoid:** `make it feel on-brand and premium`
|
||
- **Instead:** `pull colors and fonts from frame.md; premium means generous spacing and one restrained accent`
|
||
|
||
Why this works: `on-brand` is a mood the agent has to guess at. A spec's frontmatter is normative. The agent quotes your hex and font family verbatim instead of approximating, then reads the prose for intent.
|
||
|
||
If your brand lives somewhere else, attach it. A PDF brand guide, a screenshot, or pasted hex codes all read more reliably than a described impression.
|
||
|
||
## Brand is truth for color and type — not for layout
|
||
|
||
A design spec says what the brand *looks like*. It does **not** say how to compose a video frame. Name what's sacred and let the agent stage the rest:
|
||
|
||
> Colors and fonts are locked to the brand — keep the exact hexes and the display/body pairing. Layout, spacing, and motion are yours to compose for video.
|
||
|
||
Why this works: web-scale brand values don't survive video. A `1px` border with a `0.06`-opacity shadow is invisible after H.264 compression. A web body size vanishes on a 1080p frame.
|
||
|
||
So treat the spec in two halves:
|
||
|
||
- **Strict** — brand colors, fonts, weight relationships, and the background choice. If the brand is a light canvas, keep it light.
|
||
- **Scaled up for the medium** — type sizes, decorative opacity, border weight.
|
||
|
||
Over-specifying layout from a web design system fights this. Pin the palette and typography. Delegate the frame.
|
||
|
||
## Use the site's own palette and fonts
|
||
|
||
When there's no spec but the brand is out there, point at it and let the agent extract:
|
||
|
||
> Match this site's look — pull its palette and fonts — and make a 20-second launch clip: `https://…`
|
||
|
||
For a well-known brand, naming it is often enough. The agent researches the palette and typography itself.
|
||
|
||
One caveat is worth stating. A single-page-app homepage often returns a near-empty shell. If the palette comes back thin, point the agent at a blog, press, or docs page instead.
|
||
|
||
This is the same brand-truth move. The *site* is the source instead of a file.
|
||
|
||
## Bringing in a Figma frame, brand, or logo
|
||
|
||
If the brand lives in Figma, ask for it directly. The agent imports it rather than eyeballing a screenshot:
|
||
|
||
> Bring in the brand tokens from this Figma file, then build the intro: `https://figma.com/…`
|
||
|
||
> Import this Figma frame as the opening scene and this logo as an SVG: `<links>`
|
||
|
||
[Figma import](/guides/figma) freezes each import as a local file with recorded provenance. Renders never call Figma, so they stay deterministic. Brand variables come in as composition brand tokens.
|
||
|
||
Two things are worth knowing when you phrase the ask:
|
||
|
||
- **Import tokens before components.** Say "brand tokens first, then the components." That's what lets imported component colors link to your brand variables instead of baking in duplicate hexes.
|
||
- **Storyboard frames are states, not slides.** If you point at a strip of scene frames, ask the agent to *reconstruct the motion between them*. A frame showing an element at four positions is one element animating, not four stills to flip through.
|
||
|
||
## Keeping a multi-video series consistent
|
||
|
||
A series is a launch set, a weekly clip, or a per-region cut. Consistency comes from a **shared source of truth**, not from re-describing the brand each time:
|
||
|
||
> All four videos share `frame.md` for palette and type. Only the headline and the stat change per video.
|
||
|
||
The constant parts come from that one authoring spec, or from one set of imported Figma tokens. The parts that vary become [variables](#templates-and-variables).
|
||
|
||
When `frame.md` changes, ask the agent to rebuild the affected compositions. That's how the authored HTML picks up the new brand value.
|
||
|
||
Some compositions already exist and have to re-skin at render time. Declare the shared brand tokens as composition variables instead. Every scalar variable is applied as a `--{id}` CSS custom property on the composition root, so `var(--id)` in your CSS follows the override.
|
||
|
||
This is where design systems and templating meet. The brand is shared. The content is parameterized.
|
||
|
||
## Supplying brand assets by path
|
||
|
||
Logos, fonts, textures, and product shots are inputs. Hand the agent the path — don't ask it to draw them:
|
||
|
||
> Logo at `assets/logo.svg`, brand font files in `assets/fonts/`, product shot at `assets/hero.png`. Use them; don't invent placeholders.
|
||
|
||
Prefer an SVG logo over a raster one. It scales and it animates.
|
||
|
||
State the paths explicitly. That way the agent wires up the real assets instead of generating stand-ins. It also keeps the render deterministic, because every asset is present locally before the render starts.
|
||
|
||
## Supply brand inputs up front — don't restyle afterward
|
||
|
||
Give the agent your palette, fonts, and logo (or a `frame.md`) before the build. Don't override the composition after the fact.
|
||
|
||
- **Avoid:** `make the launch video, then restyle every scene to my colors afterward`
|
||
- **Instead:** `make the launch video with my palette, fonts, and logo as inputs up front`
|
||
|
||
Why this works: the agent settles the look before the first scene, so colors, spacing, motion, and component treatments hang together as one system.
|
||
|
||
Restyling scene by scene afterward pulls threads out of a design that was balanced as a whole. You spend more effort fighting it than handing over a spec would have cost.
|
||
|
||
## Templates and variables
|
||
|
||
The brand sections above cover what should *never* change per render. Templates
|
||
and variables cover the parts that should. A card per customer. A stat per quarter. A name per recipient.
|
||
|
||
When you know a composition will be reused, say so in the prompt. Name the parts
|
||
that change. The agent turns them into declared
|
||
[variables](/concepts/variables) — typed, labeled slots filled at render time
|
||
instead of hardcoded into the HTML.
|
||
|
||
The trigger phrase is simple. Call out the slots:
|
||
|
||
> Build a 6-second title card. Make the **name**, the **logo**, and the **accent color** variables; everything else stays fixed.
|
||
|
||
<DocsVideo
|
||
title="Validate variables default"
|
||
src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/validate-variables-default.mp4#t=0.1"
|
||
loop
|
||
/>
|
||
*Default variable values.*
|
||
<DocsVideo
|
||
title="Validate variables variant"
|
||
src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/validate-variables-variant.mp4#t=0.1"
|
||
loop
|
||
/>
|
||
*The same composition re-rendered with `--variables` overrides — different name, logo, and accent, zero re-prompting.*
|
||
|
||
The agent declares `data-composition-variables` on the composition root, with
|
||
the right type for each slot. The name is a `string`. The accent is a `color`.
|
||
The logo is an `image`, and a plain URL is a valid value for it. A plain `<img>`
|
||
logo needs no timing attributes. Only `<video>` and `<audio>` variables involve
|
||
the media wiring described in [variables](/concepts/variables). One composition,
|
||
many fills.
|
||
|
||
### Say what type each slot is
|
||
|
||
There are seven variable types: `string`, `number`, `color`, `boolean`, `enum`,
|
||
`font`, and `image`. Each one validates differently at render time. In
|
||
the [browser editor](/studio), `boolean`, `enum`, `color`, and `number` each get
|
||
their own control, while `string`, `font`, and `image` use a plain text input.
|
||
|
||
You don't write the JSON yourself. But naming the type in the prompt removes a
|
||
guess:
|
||
|
||
> Variables: `plan` (enum: Free / Pro / Enterprise), `price` (number, shown as `$`), `featured` (boolean — toggles the ribbon), `headline` (text).
|
||
|
||
- **Avoid:** `make the plan and price editable`
|
||
- **Instead:** `plan is an enum (Free / Pro / Enterprise); price is a number in dollars`
|
||
|
||
The engine rationale: an `enum` with declared options is checked against that
|
||
list at render time, so `enum-out-of-range` gets caught. A `number` can carry
|
||
`min`, `max`, `step`, and a `unit` label, which is what gives the browser editor a real
|
||
slider instead of a bare text box. Say "editable" and you leave the agent to
|
||
pick a type. A mistyped value then surfaces much later.
|
||
|
||
### Template, then render one per record
|
||
|
||
Once the varying parts are variables, the same source renders once per data row.
|
||
This is a real batch mode, not a copy-paste-per-video loop. You author the
|
||
composition once and feed it a list of value sets:
|
||
|
||
> Build this as a template with `name` and `title` variables, then render one video per row of my data — output to `renders/{name}.mp4`.
|
||
|
||
The agent authors the composition, then runs a
|
||
[batch render](/concepts/variables#batch-renders). The batch input is a JSON
|
||
array. Each row is one set of variable values, and each row produces one output
|
||
file. `{key}` placeholders in the output path get filled from that row.
|
||
|
||
If your source is a CSV, say so. The agent converts it to the row array the
|
||
batch expects.
|
||
|
||
Add "fail on any undeclared or mistyped value" and it renders with
|
||
`--strict-variables`. A typo in a column name then stops the run instead of
|
||
silently rendering the default.
|
||
|
||
Everything shares one composition. So a design fix propagates to every output on
|
||
the next render. You are not editing a hundred near-duplicate files.
|
||
|
||
### Personalization asks
|
||
|
||
Personalized-at-scale videos are the same pattern, with the value set coming
|
||
from your data:
|
||
|
||
> A 10-second welcome clip that greets each new signup by first name and shows their company logo. I'll supply a list of `{ firstName, logoUrl }` records.
|
||
|
||
`firstName` is a `string`. `logoUrl` is the image slot your composition binds to
|
||
an `<img src>`.
|
||
|
||
Pass assets as **URL references, not inlined data**. URL-shaped values travel
|
||
cleanly through both the local renderer and distributed
|
||
[Lambda renders](/deploy/templates-on-lambda).
|
||
|
||
Wiring this behind your own product UI or an agent instead of the CLI? The
|
||
[`@hyperframes/sdk`](/packages/sdk) opens a base template and layers a sparse
|
||
override set per instance. The host then stores only each record's delta.
|
||
|
||
### Declare up front — don't bake values in
|
||
|
||
The most common miss is describing the finished video with the values already
|
||
fixed, then asking to "make it reusable" afterward:
|
||
|
||
- **Avoid:** `Make a card that says "Acme — Pro plan — $49". Later I'll want other companies too.`
|
||
- **Instead:** `Make a plan card. Variables: company (text), plan (enum), price (number, $). Show "Acme / Pro / 49" as the default.`
|
||
|
||
The engine rationale: variables are runtime values a script applies to the live
|
||
DOM. They resolve from declared defaults first, then per-instance overrides,
|
||
then the CLI.
|
||
|
||
Declare them up front and the reusable structure exists from the first render.
|
||
The default is then just one more value set. Bake `"Acme — Pro — $49"` into the
|
||
markup and you get a composition with no slots. Reuse then means an edit pass
|
||
over hardcoded text for every variant. That is exactly what variables exist to
|
||
avoid.
|
||
|
||
### Prove the template actually re-skins
|
||
|
||
A template that never re-skins can pass every gate you have. `lint` and `check`
|
||
verify structure. `--strict-variables` catches an undeclared or mistyped key.
|
||
Neither can tell you whether the values you passed ever reached the DOM.
|
||
|
||
The failure looks like success. The render completes, exits clean, and is
|
||
**pixel-identical to the default**.
|
||
|
||
So test it differentially. Render twice and compare:
|
||
|
||
```bash
|
||
hyperframes render --output default.mp4
|
||
hyperframes render --variables '{"ground":"#0d1420","ink":"#c8ff3d"}' --strict-variables --output reskin.mp4
|
||
```
|
||
|
||
Two identical files mean the override never reached the property you expected.
|
||
Check three things. Is the variable ID declared? Does the render command use
|
||
that exact ID? Is the visible property actually bound to its CSS custom property
|
||
or variable value?
|
||
|
||
Render-time `--variables` overrides are global by variable ID. The compiler
|
||
applies a matching override to CSS custom properties on the root and on
|
||
sub-compositions pulled in with `data-composition-src`. `data-variable-values`
|
||
is still the per-instance way to give two mounts different values.
|
||
|
||
Scoped JavaScript inside a sub-composition reads its own per-instance variable
|
||
table. So forward values at the mount point when that script calls
|
||
`getVariables()` instead of reading CSS.
|
||
|
||
The [capstone](/prompting/capstone) keeps its variables on one root file for
|
||
simplicity, not because templates require one file. Sub-compositions work as
|
||
long as shared CSS-bound IDs are declared consistently. Use mount-point values
|
||
for instance-specific or JavaScript-read inputs. Its exact variable clause is
|
||
quoted at the end of this section.
|
||
|
||
### What can't be a variable
|
||
|
||
A few inputs are read once at compile time, and no variable can move them:
|
||
|
||
- composition **dimensions** (`data-width` / `data-height`)
|
||
- the **root composition's total duration**
|
||
- **frame rate**
|
||
- **output format, codec, or quality**
|
||
|
||
So this doesn't do what it reads like:
|
||
|
||
- **Avoid:** `make the video length a variable so each render can be a different duration`
|
||
- **Instead:** `author one composition per target length` — or vary a *clip's* duration,
|
||
which is re-read from the live DOM
|
||
|
||
If total length must differ per output, that is a different root `data-duration`
|
||
per render, not a variable. See
|
||
[what can't be a variable](/concepts/variables) for the
|
||
full list and the compile-time-vs-live-DOM rule behind it.
|
||
|
||
<Note>
|
||
An authored CSS custom property always wins over a same-named variable. Say
|
||
your composition already defines its own `:root { --accent: ... }` as a
|
||
hand-written theme token. A variable called `accent` never overwrites it — the
|
||
authored value stands. A render-time `--variables` override still wins over
|
||
both. So when you need to override an authored value per render, use
|
||
`--variables`, not a same-named declared variable.
|
||
</Note>
|
||
|
||
### Related
|
||
|
||
<CardGroup cols={2}>
|
||
<Card title="Variables (concept)" icon="sliders" href="/concepts/variables">
|
||
The mechanics: declaring types, per-instance overrides, batch renders, precedence.
|
||
</Card>
|
||
<Card title="@hyperframes/sdk" icon="code" href="/packages/sdk">
|
||
Template + sparse-override editing behind your own product UI or agent.
|
||
</Card>
|
||
<Card title="The specification dial" icon="gauge" href="/prompting/overview#how-much-to-specify">
|
||
How much to specify — and why naming the type is cheap precision.
|
||
</Card>
|
||
<Card title="Brand, templates and storyboards" icon="palette" href="/prompting/design-systems">
|
||
Brand tokens as variables that re-skin every reuse from one value.
|
||
</Card>
|
||
</CardGroup>
|
||
|
||
This clause from a [longer HyperFrames film](/prompting/capstone#the-prompt-word-for-word) produced the shot below. You can lift the wording for your own video:
|
||
|
||
> **Variables:** expose `ground` (default `#0a0a0a`) and `ink` (default `#3CE6AC`) as composition variables on the single root file, bound via CSS custom properties everywhere (including the duotoned mural), so one `--variables` call re-skins the entire journey. It will be rendered twice: the default brand palette, and a second full render with `{"ground":"#0d1420","ink":"#c8ff3d"}`.
|
||
>
|
||
> **Architecture constraint (technical):** single composition file — one `index.html`, one variable scope. […] No `data-composition-src` sub-files.
|
||
|
||
## Storyboards
|
||
|
||
[Variables and templating](#templates-and-variables) reuses one composition across many renders. Storyboards are the other axis of scale: one film with many scenes.
|
||
|
||
Past a handful of beats, describing each scene from a blank page is the slow way. "Then frame 2 shows X, then frame 3 shows Y." It also drifts, because nothing ties the frames to each other.
|
||
|
||
Prompt the **plan** once instead — the throughline, the job each frame does, the rule that paces reveals. Then let the build put frames against it.
|
||
|
||
This narrative vocabulary is a writing discipline, not extra `STORYBOARD.md` schema. The workflow translates your plan into the smaller machine-readable shape the build consumes.
|
||
|
||
<Note>
|
||
Asking for a storyboard [before the build](/prompting/overview#before-the-build) means you review the plan before anything is built. Either way, the plan this page teaches is what the build works from.
|
||
</Note>
|
||
|
||
### Prompt the plan, not the scenes
|
||
|
||
A storyboard is a short, structured document that sits above the individual frames. It holds three things:
|
||
|
||
- one arc
|
||
- one direction block that every frame inherits
|
||
- a light per-frame spec — not a full description — for each key moment
|
||
|
||
The workflow reads the plan and builds each frame's HTML sub-composition against it. Be precise about the *shape* of the film, and the frames come out already agreeing with each other on pacing, palette, and payoff. You never restate any of that per frame.
|
||
|
||
The trigger is naming the arc and asking for a storyboard rather than a single scene:
|
||
|
||
> Storyboard a 3-frame piece: hook → substance → landing, silent, ~15 seconds, with a callback that pays off the opening motif.
|
||
|
||
Everything below is the vocabulary that turns "storyboard" from a loose word into a plan the build can execute in one pass.
|
||
|
||
### State the film's shape once
|
||
|
||
Before any frame, fix four things that every frame will be judged against:
|
||
|
||
- **Message** — the one-sentence thesis the whole film has to prove. If a frame doesn't serve it, cut the frame, not the message.
|
||
- **Arc** — the beat sequence, named plainly. `Hook → Substance → Landing`, or `Hook → Problem → Solution → Proof → CTA`. Use a shape word like "listicle" when the frames are parallel entries rather than a rising sequence.
|
||
- **Audience** — who it's for, in a phrase. It calibrates tone and jargon for every frame at once.
|
||
- **Mood** — one music or energy descriptor, like "tense synth pulse, resolving to warm". Every frame's pacing should agree with it, even in a silent piece.
|
||
|
||
Say these four once, up front. Then no individual frame prompt has to re-justify its tone.
|
||
|
||
### Set the direction once, apply it to every frame
|
||
|
||
A storyboard's direction block is the set of rules every frame obeys without restating them. Four are worth naming explicitly.
|
||
|
||
**Two-color discipline.** Name a ground color and one ink color. Then say the rule out loud: nothing ever gets a second hue for emphasis. A bigger moment gets bigger through inversion, weight, scale, or density.
|
||
|
||
- **Avoid:** `use the brand colors, plus a highlight color for the important bits`
|
||
- **Instead:** `ground: deep navy; ink: warm white. Emphasis = invert, scale up, or go denser — never a third color.`
|
||
|
||
**VO-paced reveals.** The rule itself lives in [Add voice, music and sound](/prompting/media-and-audio#pace-reveals-to-the-narration). A storyboard is where you *apply* it per frame. At t=0, only what the narrator is saying is on screen, and each part arrives on its spoken cue.
|
||
|
||
Pair it with a hold behavior. Say whether a held frame stays fully still or gets a subtle idle. Never ask for a slow drift or "breathing" — that reads as unfinished, not as a choice.
|
||
|
||
If the piece is silent, keep the rule's shape and swap the trigger. Reveals land on named timestamps instead of spoken clauses. The pacing still has to be deliberate. There's just no VO to key it to.
|
||
|
||
**One breather.** Across the whole film, name exactly one frame as the breather. It's the deliberately calmer, more static beat, or the longest held read. Every other frame keeps developing continuously.
|
||
|
||
Naming it prevents two failures. The build won't over-animate the one frame that's supposed to let the audience exhale, and it won't under-animate the rest to match it.
|
||
|
||
**The negative list.** One list of banned visual clichés, stated once. It's a standing filter, not a fresh list per frame. Every frame gets checked against it as it's built:
|
||
|
||
> no purple-blue AI gradients, no bokeh, no browser chrome, no drop-shadow cards, no infinite loops or randomness
|
||
|
||
Swap in whatever clichés are wrong for *your* film. The point is naming them before a frame drifts into one.
|
||
|
||
### Give each frame a job
|
||
|
||
The direction block covers everything shared. So each frame's own prompt only needs to say what's different about it:
|
||
|
||
```text
|
||
[type] the frame's category hook · benefit_highlight · social_proof · cta
|
||
[persuasion] the rhetorical device before/after · numbered enumeration · counterexample · callback + distillation
|
||
[beat] the emotional beat recognition + tension · aha · resolve + inevitability
|
||
[focal] the one thing the eye lands on
|
||
[roles] what's foreground / supporting / background, assigned explicitly
|
||
```
|
||
|
||
Never skip `persuasion` and `beat`. Without them, a frame is "a scene that shows the stat." With them, it becomes "a scene that proves the stat, and here's how it *feels* to land."
|
||
|
||
A frame with a named persuasion device and beat gives the build a reason for every choice. A frame with only a visual description gives it none.
|
||
|
||
### The callback
|
||
|
||
Introduce a motif early: a shape, a mark, a phrase, a piece of color. Have it return later, denser or fuller, as a deliberate payoff.
|
||
|
||
Say both halves in the plan — where the motif is planted, and how it changes when it returns.
|
||
|
||
> A single thin accent dot appears top-right in frame 1 at low weight. In the landing frame, that same dot expands and fills into the full logo lockup — same motif, now complete.
|
||
|
||
State the return explicitly. Otherwise a rebuild is free to treat the early motif as throwaway texture. The callback only works if the plan says the second appearance is the *same* element, not a new one that resembles it.
|
||
|
||
### Worked example: a silent 3-frame storyboard
|
||
|
||
<Tip>
|
||
`storyboard-mini` below is deliberately small and silent: three frames, ~15 seconds, no narration. That makes the whole pattern checkable in one cheap render — arc, direction block, per-frame job, one breather, one callback. Do this before you write a longer, narrated storyboard.
|
||
</Tip>
|
||
|
||
> Storyboard a 3-frame, ~15-second, 1920x1080 piece. Silent — no narration, no VO track. Message: "Fernwell gives you back the hours other tools take." Arc: Hook → Substance → Landing. Audience: small-team operators evaluating a new tool. Mood: tense synth pulse resolving to warm.
|
||
>
|
||
> Direction for every frame: ground color deep navy `#0b1220`, ink color warm off-white `#f4efe6`. Nothing else gets a hue — emphasis is inversion, scale, or density only. Reveals stage on internal timestamps, since the piece is silent and there's no spoken cue. At each frame's t=0 only its first element is on screen. The rest arrive on the timestamps below. Holds stay fully still, no drift or breathing. No purple-blue AI gradients, no bokeh, no browser chrome, no drop-shadow cards, no infinite loops or randomness.
|
||
>
|
||
> Frame 1 — Hook (0.0–4.0s), type: hook, persuasion: counterexample, beat: recognition + tension, focal: the headline. At 0.0s: bold ink headline "Most tools slow you down." slams in, centered. At 1.5s: a single thin accent dot (ink color, small, low weight) fades in top-right — the motif, planted quietly. Hold from 3.0–4.0s.
|
||
>
|
||
> Frame 2 — Substance, **the breather** (4.0–10.0s), type: benefit_highlight, persuasion: numbered enumeration, beat: aha, focal: the stat. This is the one deliberately calmer, more static frame in the piece. Everything else develops continuously. This one mostly holds. At 4.0s: the accent dot from frame 1 carries over, now larger, sitting quietly left-of-center. At 5.0s: a big stat "3.2 hrs / week" fades in beside it, no motion after it lands. Static hold 6.0–10.0s.
|
||
>
|
||
> Frame 3 — Landing (10.0–15.0s), type: cta, persuasion: callback + distillation, beat: resolve + inevitability, focal: the completed motif. At 10.0s: the accent dot from frames 1–2 expands and fills into the full Fernwell wordmark lockup — same motif, now complete, denser and larger. At 12.0s: tagline "Fernwell. Built for flow." stamps in below it. Hold 13.5–15.0s.
|
||
|
||
<DocsVideo
|
||
title="Storyboard mini"
|
||
src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/storyboard-mini.mp4#t=0.1"
|
||
loop
|
||
/>
|
||
*Rendered from the prompt above, unedited — no audio track, exactly as asked.*
|
||
|
||
### Related
|
||
|
||
<CardGroup cols={2}>
|
||
<Card title="Anatomy of a one-shot prompt" icon="list-ordered" href="/prompting/overview#the-shape-of-a-strong-prompt">
|
||
The six-part skeleton a single beat uses — the same discipline, one frame at a time.
|
||
</Card>
|
||
<Card title="Recreating something you saw" icon="film" href="/prompting/recreating-references">
|
||
Transcribing motion frame by frame — the same rigor a storyboard's per-frame timestamps need.
|
||
</Card>
|
||
<Card title="Brand, templates and storyboards" icon="palette" href="/prompting/design-systems">
|
||
The two-color discipline and brand tokens a storyboard's direction block draws from.
|
||
</Card>
|
||
<Card title="How a HyperFrames project works" icon="route" href="/concepts">
|
||
`STORYBOARD.md` as a production artifact — where storyboard plans land, downstream of `BRIEF.md`.
|
||
</Card>
|
||
</CardGroup>
|
||
|
||
**In a real film.** This clause from a [longer HyperFrames film](/prompting/capstone#the-prompt-word-for-word) produced the shot below. You can lift the wording for your own video:
|
||
|
||
> **The clip card** — the `<div class="clip">` typed in the opening travels the whole journey: it slides onto the wire as a clip chip after being typed, rides ahead of the camera between regions (handing itself off — visible leaving one region and arriving in the next), and is the thing that finally renders at the end. It is the protagonist.
|
||
|
||
<DocsVideo
|
||
title="Capstone region render"
|
||
src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/capstone-region-render.mp4#t=0.1"
|
||
loop
|
||
/>
|
||
*That clause paying off, rendered — the protagonist chip arriving at the render slot after a full minute on the wire.*
|
||
|
||
## Related
|
||
|
||
<CardGroup cols={2}>
|
||
<Card title="Figma Import" icon="figma" href="/guides/figma">
|
||
Import brand tokens, assets, components, and motion from a Figma file.
|
||
</Card>
|
||
<Card title="Variables and templating" icon="sliders" href="#templates-and-variables">
|
||
Turn brand tokens into variables that re-skin a whole series from one value.
|
||
</Card>
|
||
<Card title="The specification dial" icon="gauge" href="/prompting/overview#how-much-to-specify">
|
||
How pinning exact hexes and type direction removes drift.
|
||
</Card>
|
||
<Card title="Claude Design" icon="message" href="/guides/design-tools">
|
||
Attach a brand guide or screenshot to seed a first draft from your look.
|
||
</Card>
|
||
</CardGroup>
|
||
|
||
**In a real film.** This clause from a [longer HyperFrames film](/prompting/capstone#the-prompt-word-for-word) produced the shot below. You can lift the wording for your own video:
|
||
|
||
> **Design system: the provided `frame.md` is the single source of brand truth — read it first and obey it exactly.** It is the real HyperFrames brand (by HeyGen), dark-first: flat near-black ground […] **mint `#3CE6AC` used sparingly as the single accent — mint means go / primary / active**. The mint→cyan gradient (`#3CE6AC → #00E3FF`) appears in exactly one place in the whole film: the final CTA lockup.
|
||
|
||
<DocsVideo
|
||
title="Capstone region render"
|
||
src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/capstone-region-render.mp4#t=0.1"
|
||
loop
|
||
/>
|
||
*That clause paying off, rendered. The closing lockup is where the brand file's display face and its one sanctioned gradient finally appear together.*
|
||
|