docs(prompting): complete plan — variant validation, vocab clips, worked specs, measured motion

Validates 16 more published prompts end-to-end (variants across every
video type, caption styles, overlays with proven alpha, code diff and
highlight, edit verbs against the real attribute map, a generated-avatar
talking-head through embedded-captions, a presented slideshow deck) and
fixes every prompt flaw the builds surfaced. Adds keyword-to-render
grids for the easing, camera, and marker vocabulary; two more worked
visual specs with renders; a measured before/after pair proving the
motion grammar (frozen frames vs all-alive, 211KB vs 2.5MB); before/
after render pairs on editing and generated-artwork pages; and proof
renders on the overview.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-07-09 22:21:12 -07:00
co-authored by Claude Fable 5
parent 99ff79bc60
commit 2f958d1197
16 changed files with 149 additions and 14 deletions
@@ -20,7 +20,10 @@ If the words themselves need to read, you want captions. If you want a produced
Captions route by **identity**, not by mode. You pick one look from the catalog; the engine behind it is a lookup detail you never have to name. The default is a clean verbatim rail — `anchor` — with the occasional peak word composited behind the subject.
> /embedded-captions Add captions to ./interview.mp4. Use the `anchor` identity — clean verbatim rail carrying the spoken words, readable lower-third. Promote just the two hardest-hitting lines to an embed behind the speaker; highlight the key word in each rail line. 9:16. Footage stays untouched.
> /embedded-captions Add captions to ./interview.mp4. Use the `anchor` identity — clean verbatim rail carrying the spoken words, readable lower-third. Promote the single hardest-hitting word to an embed behind the speaker; highlight one key word in each rail line. Keep the source aspect ratio. Footage stays untouched.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/captions-anchor-rail.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Rendered from the prompt above on generated avatar footage, unedited — one earned embed behind the speaker, everything else on the rail.*
The rail carries most of the text; an **embed** is the scarce, earned peak — one big word matted behind the subject at the climax, never every line. Embedding the whole transcript is the most common mistake this skill guards against.
+8
View File
@@ -48,8 +48,16 @@ Three [Text Effects](/catalog/components/morph-text) components do one focused j
> Hype captions with [`caption-kinetic-slam`](/catalog/components/caption-kinetic-slam): one full-screen word per beat, alternating slam-in direction.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/caption-kinetic-slam.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Rendered from the prompt above with an authored 24-word line, unedited.*
> Neon music-video captions using [`caption-neon-glow`](/catalog/components/caption-neon-glow). Make brand names larger with an accent color and highlight the numbers differently.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/caption-neon-glow.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Rendered from the prompt above, unedited — the brand renders 1.4x in magenta, numbers in amber, distinct from the default cyan.*
> Fill the hero word "STONE" with [`texture-mask-text`](/catalog/components/texture-mask-text) using the rock texture.
## Knobs
+5 -2
View File
@@ -23,9 +23,12 @@ Verified, from the [examples](/prompting/examples) page — a 30-second feature
<AccordionGroup>
<Accordion title="Changelog roundup">
> /pr-to-video Make a ~40-second 1920x1080 changelog video from [PR URL]. Changelog angle: open with the release line, then one beat per notable change — a short label and a one-line "what it does" each. Show at most two `code-diff` hunks across the whole video. End on version + repo URL. Calm male TTS narration.
> /pr-to-video Make a ~40-second 1920x1080 changelog video from [PR URL]. Changelog angle: open with the release line, then one beat per notable change — a short label and a one-line "what it does" each. Show at most two `code-diff` hunks across the whole video. End on version + repo URL. Calm male TTS narration, no captions.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/variant-pr-changelog.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Rendered from this prompt with [PR URL] = heygen-com/hyperframes#2092, unedited.*
A changelog trades depth for breadth — many small changes, each a beat, rather than one change explored deeply. Keep code beats sparse so the pace stays fast.
A changelog trades depth for breadth — many small changes, each a beat, rather than one change explored deeply. Keep code beats sparse so the pace stays fast. A PR doesn't carry its shipping version — the agent finds it from the release tag or the package manifest on main.
</Accordion>
<Accordion title="Fix explainer">
> /pr-to-video Make a ~40-second 1920x1080 fix-explainer from [PR URL], for developers. Fix angle: state the bug's symptom first, then the root cause, then the one-line fix on the `code-diff` block. End on version + repo URL. No narration, kinetic captions.
+9 -1
View File
@@ -58,13 +58,21 @@ The first four are the workhorses of a code *walkthrough* — they keep the code
For "here's what changed," hand `code-diff` the before and after and let it color the delta. For "look at *this* line," give `code-highlight` the full context and name the target line.
> /motion-graphics 6-second 1920x1080 video. Show this edit as a colored diff — the removed line collapses in red, the added line expands in green:
> /motion-graphics 6-second 1920x1080 video. Show this edit to `api.ts` as a colored diff — the removed line collapses in red, the added line expands in green:
> removed: `const res = await fetch(url)`
> added: `const res = await fetch(url, { signal })`
> Use the `code-diff` registry block. No audio.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/validate-code-diff.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Rendered from the prompt above, unedited.*
> /motion-graphics 5-second 1920x1080 video. Show a 12-line config file; a highlight band sweeps to line 7 (`timeout: 30_000`) while the surrounding lines dim. Hold with line 7 lit. Use the `code-highlight` registry block. No audio.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/validate-code-highlight.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Rendered from the prompt above, unedited — the agent authors plausible surrounding config lines; paste all 12 if the exact file matters.*
**Name the target line unambiguously.** The block dims context around one line — tell it which.
- ❌ `highlight the important line`
- ✅ `highlight line 7 (timeout: 30_000)`
+11 -4
View File
@@ -5,7 +5,7 @@ description: "Direct the agent like an editor — trim, move, retime, swap, rest
Most HyperFrames time isn't the first render — it's the twenty edits after it. A composition is plain HTML with `data-*` timing attributes and a GSAP timeline, so every edit you'd make in a non-linear editor maps to a specific, inspectable change in the source. You don't re-specify the video; you name the edit the way you'd say it to a human editor, and the agent makes the smallest change that does it.
This page maps the editor verbs to the prompts that land them. Two habits from [Iterating](/prompting/iterating) apply to every one of them, so keep them in mind: **change one thing per render**, and **state targets as absolute values** ("scene 2 = 2 seconds", not "a bit shorter") so the agent lands it in a single pass instead of oscillating.
This page maps the editor verbs to the prompts that land them. The examples name elements from a typical composition — swap the noun ("the lower third", "scene 2") for whatever yours is called. Two habits from [Iterating](/prompting/iterating) apply to every one of them, so keep them in mind: **change one thing per render**, and **state targets as absolute values** ("scene 2 = 2 seconds", not "a bit shorter") so the agent lands it in a single pass instead of oscillating.
## The verb → edit map
@@ -21,7 +21,7 @@ Every timeline verb resolves to a `data-*` attribute or an inline style. This is
| "the audio bed is too loud" | Level | `data-volume` |
<Note>
The mental model the Studio timeline uses: **move** changes when a clip *starts*, **right trim** changes when it *ends*, and **front trim** only exists for media clips — a `<video>` or `<audio>` can skip into its own content, but a GSAP-driven `<div>` can't start halfway through its animation. See [Timeline editing](/guides/timeline-editing) for the full clip-type breakdown.
The mental model the Studio timeline uses: **move** changes when a clip *starts*, **right trim** changes when it *ends*, and **front trim** only exists for media clips — a `<video>` or `<audio>` can skip into its own content, but a GSAP-driven `<div>` can't start halfway through its animation. See [Timeline editing](/guides/timeline-editing) for the full clip-type breakdown. One more surface the map can't show: retiming a scene that spans the whole composition also needs the root's `data-duration` bumped — the root governs total length, so a longer child never renders past it.
</Note>
## Trim, move, and restack
@@ -30,15 +30,22 @@ These are the pure-timing edits — no visual change, just when and where a laye
> Trim the intro so it ends at 0:03 instead of 0:05.
> Move the lower third to start at 0:08.
> Move the lower third to start at 0:06.
> The captions are rendering behind the video — put them on a higher track so they sit on top.
Absolute targets matter most here. "Make the intro shorter" invites a guess; "the intro should end at 3.0s" is a single `data-duration` write with nothing to overshoot.
Bound moves by the composition's length — a 4-second clip moved to 0:08 in a 10-second video barely appears before the end. And absolute targets matter most here: "make the intro shorter" invites a guess; "the intro should end at 3.0s" is a single `data-duration` write with nothing to overshoot.
- ❌ `tighten up the opening`
- ✅ `intro clip duration = 3s; leave its animation and position alone` — one attribute, and the freeze clause stops a rebuild from drifting on axes you'd already settled
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/editing-before.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Before — the untouched composition.*
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/editing-after.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*After — four verbatim edits from this page (move, right-trim, retime, restyle-with-freeze); each touched exactly the attribute the verb map promises, gates green after every edit.*
## Split a scene
The Studio timeline exposes move and trim as drag gestures but does **not** yet offer split, slip, slide, ripple, or roll. You can still split by directing the agent, because it edits the HTML directly — a split is just one clip becoming two with adjusted `data-start` / `data-duration`:
+6 -2
View File
@@ -25,9 +25,13 @@ Note the `~` — with a supplied script the runtime follows the spoken words, so
<AccordionGroup>
<Accordion title="30-second landscape topic explainer (16:9)">
> /faceless-explainer Make a ~30-second 1920x1080 explainer on how HTTPS keeps a request private, for a non-technical audience. Concept angle: one idea per scene, big geometric type, a simple lock/key diagram as the centerpiece. Deep blue on off-white. Female TTS voice, warm and clear. Embedded captions, key terms highlighted in the accent color.
> /faceless-explainer Make a ~30-second 1920x1080 explainer on how HTTPS keeps a request private, for a non-technical audience — the takeaway: your data is sealed before it leaves the browser. Concept angle: one idea per scene, big geometric type, a simple lock-and-key diagram as the centerpiece (swap the metaphor with the topic). Near-black ink on off-white with a deep-blue accent. Female TTS voice, warm and clear. Embedded captions, key terms highlighted in the accent color.
Shorter runtime, landscape for YouTube / embed. Fewer scenes means the topic has to compress — naming the takeaway tells the workflow what to keep.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/variant-explainer-landscape.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Rendered from this prompt with the topic swapped to HTTP caching (cache diagram as the metaphor), unedited — 26s, because the narration sets the length.*
Shorter runtime, landscape for YouTube / embed. Fewer scenes means the topic has to compress — name the single takeaway so the workflow knows what to keep.
</Accordion>
<Accordion title="Listicle">
> /faceless-explainer Make a ~45-second 1080x1920 listicle: "5 habits of fast-shipping teams". Listicle angle — one habit per scene, each with a big number and a one-line label, escalating energy toward #1. Off-black with a lime accent. Male TTS voice, upbeat. Embedded captions, the habit label highlighted each scene.
+10
View File
@@ -12,3 +12,13 @@ Three rules that make this work:
1. **Generate on a solid contrasting background** (magenta works) so the subject keys out cleanly. A light subject on a light background gets silently eaten.
2. **Key flat vector-style art with a chroma key** (`ffmpeg colorkey`), not AI background removal — `remove-background`'s matting model is tuned for photographic and human subjects and reads flat art unreliably, sometimes keeping the background instead of the subject. Reserve `remove-background` for photographs.
3. **Put a restraint clause in the generation prompt** ("minimal, lots of negative space") — image models fill the frame by default, and a busy generated texture reads as cheap as bad vector art.
## The difference, side by side
The same brief — four people arm in arm, warm gradient sweaters, flat-illustration style — built both ways. Same animation beats, same craft layer (lighting, atmosphere, grade); the only variable is where the figures came from.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/artwork-hand-drawn.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Hand-drawn SVG figures — clean, but the proportions and gesture read as clipart.*
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/artwork-generated.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Generated illustration animated as layers — real anatomy and editorial shading; the animated line still passes behind the figures because the artwork was keyed to transparency.*
+12
View File
@@ -11,3 +11,15 @@ Static frames can be perfect and the video still feels cheap if the motion is de
4. **Overshoot and follow-through.** Every pop scales past its target and settles back; letters can tumble in individually with rotation.
5. **Depth planes.** One or two large, heavily-blurred foreground elements drifting near the lens sell depth instantly.
6. **Match pacing to genre.** Showreel-style cuts run 1.5-4 seconds per idea; a stretched 8-second version of a 2-second idea feels slow no matter how it's animated.
## The grammar, measured
The same composition built twice — identical content, identical layout; the only variable is the motion treatment. The first build commits the anti-patterns above: simultaneous identical entrances, no camera, a frozen final 2.4 seconds. The second applies the six rules.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/motion-before.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Every anti-pattern: tiles enter together, nothing overlaps, the last seconds are a freeze-frame.*
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/motion-after.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*The six rules: staggered overshoot entrances, a continuous 5% push, ambient idle, a blurred foreground plane, sparkline draw-ins as secondary motion.*
The difference is measurable, not just visible: in the final second the frozen build has bit-identical consecutive frames, while the motion-grammar build changes every single frame — corroborated by the encoder (211KB vs 2.5MB for the same content). A frozen final second is the cheap-motion tell you can test for.
+1 -1
View File
@@ -14,7 +14,7 @@ description: "Two music- and slide-driven outputs that look alike in a brief but
`/music-to-video` turns a **music track** — an audio file, a video to pull audio from, or a track generated from a mood brief — into a beat-synced video. The music drives all pacing; any photos or clips you supply are cut onto the same beat grid, and a complete video needs zero assets (typography carries it otherwise). There is no narration and no website capture.
`/slideshow` authors a HyperFrames deck — discrete slides with fragment reveals, hotspot branching, and a built-in presenter mode with speaker notes. Its output is the **running deck**, served with `hyperframes present`. Do not point `render` at a deck: it resolves only the first scene and emits a silently truncated MP4. If the user didn't explicitly ask for a slideshow, the skill confirms the deck route before authoring — that's a routing decision, not a style preference.
`/slideshow` authors a HyperFrames deck — discrete slides with fragment reveals, hotspot branching, and a built-in presenter mode with speaker notes. Its output is the **running deck**, served with `hyperframes present`. Do not point `render` at a deck: it resolves only the first scene and emits a silently truncated MP4. If the user didn't explicitly ask for a slideshow, the skill confirms the deck route before authoring — that's a routing decision, not a style preference. One authoring detail worth knowing: fragment reveal times are absolute positions on the deck's master timeline, not per-slide offsets.
## Base prompt — beat-synced slideshow
+9 -1
View File
@@ -57,12 +57,20 @@ Quote the exact copy — unquoted names and titles get paraphrased (see [anatomy
Give a lower third at least the block's own timeline length (most run ~5 seconds including their designed exit) — a shorter window hard-cuts the block before its settle-out animation plays.
</Note>
> Podcast clip. Bring in [`lt-bold-block`](/catalog/blocks/lt-bold-block) when the guest starts talking — name "MARCUS LEE", tag "GUEST" — brand accent #FF5A1F.
> Podcast clip. Bring in [`lt-bold-block`](/catalog/blocks/lt-bold-block) when the guest starts talking, holding 5 seconds — name "MARCUS LEE", tag "GUEST" — brand accent #FF5A1F.
> During the intro, show an [`x-post`](/catalog/blocks/x-post) card with the quote "we shipped it in a weekend" and 12.4K likes, then slide it out before the demo.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/overlay-xpost.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Rendered from the prompt above over stand-in scenes, unedited — the card's built-in like-tap ticks 12.4K → 12.5K.*
> /motion-graphics Transparent overlay only — a [`spotify-card`](/catalog/blocks/spotify-card) now-playing widget animating in, bottom-left. Export as transparent WebM so I can drop it over footage in my editor.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/overlay-spotify-preview.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*MP4 preview of the transparent WebM over a checkerboard — the delivered file carries real VP9 alpha (verified via ALPHA_MODE + alphaextract).*
## Knobs
- **Timing.** "at 0:03," "for 4 seconds," "slide it out before the demo" set the block's start and duration — an overlay is a timed clip, so it needs both.
+19
View File
@@ -116,6 +116,25 @@ Warm-start prompts produce richer, more grounded videos because the agent is wri
## What a prompt buys you
Three prompts from this guide and their unedited renders — one workflow warm start, one registry-block piece, one dense freeform spec:
> /product-launch-video Make a 45-second 1920x1080 launch video for https://linear.app. Energetic but minimal, use the site's own palette and screenshots. Structure: hook stating the problem, 3 feature beats with UI captures and one-line captions, end card with logo + "Try it free". Female TTS voice, confident tone, subtle electronic BGM under -18dB.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/example-product-launch.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Rendered from the prompt above, unedited.*
> /motion-graphics 6-second 1920x1080 video, dark navy background. Beat 1 (0-1s): label "ARR" fades up small, top-center. Beat 2 (1-4s): a giant number counts up to $4.2M with an odometer roll, easing out as it lands. Beat 3 (4-6s): "+312% YoY" stamps in below in green, then everything settles into a gentle ambient idle. Use the `apple-money-count` registry block as base. No narration.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/example-stat-countup.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Rendered from the prompt above, unedited.*
And at the far end of the [specification dial](/prompting/specification-dial), a full visual+motion spec one-shots a broadcast-style animated globe — see [Recreating something you saw](/prompting/recreating-references) for the spec:
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/recreate-globe-oneshot.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*One-shot render from the distilled spec, no iteration.*
## Explore the guide
<CardGroup cols={2}>
+6 -2
View File
@@ -37,9 +37,13 @@ Read the [anatomy](/prompting/anatomy) of that skeleton — route, spec, structu
A teaser trades feature coverage for pace — fewer beats, one idea each. Keep the destination (Shorts / TikTok → 9:16) and let the workflow scale the story to the shorter runtime.
</Accordion>
<Accordion title="Pasted script, no capture">
> /product-launch-video Make a ~30-second 1920x1080 launch video from this script — use it verbatim: "Your CRM is three hours of busywork a day. AutoCRM logs every call, email, and meeting for you. 200 teams already switched. Try it free at autocrmhq.com." No site to capture — invent clean product-y visuals from the script. Male TTS voice, calm and confident; subtle BGM under -18dB.
> /product-launch-video Make a ~20-second 1920x1080 launch video from this script — use it verbatim: "Your CRM is three hours of busywork a day. AutoCRM logs every call, email, and meeting for you. 200 teams already switched. Try it free at autocrmhq.com." No site to capture — invent clean product-y visuals from the script. Male TTS voice, calm and confident; subtle BGM under -18dB.
With no URL the workflow takes the no-capture path: no screenshots, no site palette to borrow, so name your brand colors and fonts if you have them (or the agent invents a palette). Verbatim scripts set the duration — figure roughly 130 spoken words per minute, so a 30-second video wants a 6570 word script. Saying "use it verbatim" pre-answers the workflow's keep-or-restructure question.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/variant-launch-script.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Rendered from this prompt shape with a different, longer script (78 words, fictional dev-tool "Relay"), unedited — it ran 35.5s because the words set the length.*
With no URL the workflow takes the no-capture path: no screenshots, no site palette to borrow, so name your brand colors and fonts if you have them. The workflow will ask once whether to keep your wording verbatim or restructure it.
</Accordion>
<Accordion title="Brand name only (agent finds the URL)">
> /product-launch-video Make a ~45-second 1920x1080 launch video for Linear. Find the official site, capture it, and use its own palette and screenshots. Angle: speed as the whole pitch. End card with logo + "Try it free". Confident female TTS voice, subtle electronic BGM under -18dB.
+4
View File
@@ -41,6 +41,10 @@ Transparency also only *means something* on a design that has empty space to see
- ❌ `render my full-screen product promo as a transparent WebM`
- ✅ `render the promo as MP4; export just the lower-third overlay as transparent WebM` — transparency belongs to the layer meant to sit *over* other footage, not the finished full-frame film
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/overlay-spotify-preview.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*A transparent VP9 WebM overlay previewed over a checkerboard. To verify alpha from the CLI: VP9 stores it out-of-band, so look for ALPHA_MODE=1 in ffprobe (a pix_fmt-only check false-negatives) or extract it with ffmpeg alphaextract.*
<Note>
A transparent render also depends on the composition leaving `html` / `body` backgrounds unset — the transparency comes through only where nothing is painted. The workflow skills handle this; see the [Rendering guide](/guides/rendering#transparent-video) if you're hand-authoring an overlay.
</Note>
+8
View File
@@ -14,10 +14,18 @@ This is the one pin to state every time. For anything with genuine **depth, ligh
- ❌ `isometric cards floating in CSS 3D with perspective`
- ✅ `build the isometric scene in Three.js via the adapter, with real depth and lighting`
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/example-3d-cards.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*The Three.js version of the isometric-cards prompt — real shadows and lighting, one-shot.*
The engine rationale: CSS `perspective` transforms skew flat planes — they read flat the moment lighting or parallax matters, because there is no light source and no camera, only projected rectangles. Three.js is a first-party seek-safe runtime (`hf-seek` events plus `window.__hfThreeTime`), so a real 3D scene renders frame-accurately like everything else. This is a validated default, not a preference — treat "real 3D" as "Three.js" unless you specifically want a flat, stylized fake-3D look.
Camera moves are part of the same rule. A "drone orbit", dolly, or push-in only exists where there's an actual camera:
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/camera-orbit.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*A seek-driven Three.js drone orbit — the camera sweeps a continuous arc; impossible with CSS transforms.*
- ❌ `a drone-orbit camera move around the logo` (with no runtime named — CSS has no camera to orbit)
- ✅ `orbit the camera around the logo — Three.js via the adapter`
+15
View File
@@ -11,3 +11,18 @@ Every element is a primitive the agent can build directly. Two honest limits:
- **Organic illustration** (drawn characters, painterly texture) can't be fully carried by text — words underdetermine a drawing. Steer to geometric shape language ("flat rounded-geometric figure, circle head, no facial features"), or generate the artwork (see [When to generate artwork](/prompting/generated-artwork)).
- **Photographic and live-action content** must be supplied as files — mention the paths explicitly.
## Two more worked specs
The same density applied to a product-UI piece and a typographic piece — both one-shot from these exact words. Where a builder had to make a judgment call on the first pass, the spec below pins it, which is the editing loop these specs live by: build, see what the words underdetermined, tighten the words.
> 6-second 1920x1080. A frosted-glass command palette (640x84px, 20px radius, rgba(255,255,255,0.08) fill, 1px rgba(255,255,255,0.25) border, heavy backdrop blur) centered on a #0b0f1a field with two soft accent glows drifting slowly — #5b6cff upper-left, #22d3a5 lower-right, ~400px, 20% opacity. At 0.4s the palette scales in 0.96→1 settling with back.out(1.2). At 0.8s a grey placeholder "Search commands…" types on; at 2.2s it fades out over 0.2s and the query "render 4k" types in white. At 2.8s three result rows (56px tall, 12px gaps: icon square, label, shortcut chip) cascade in as a detached list below the fixed bar, staggered 0.12s, each rising 12px with back.out(1.4). At 4.2s a 10%-opacity #5b6cff fill sweeps left to right across the first row and its shortcut chip pulses once. Rows and glows keep a barely-visible drift to the end. No audio.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/spec-command-palette.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Rendered from the spec above, unedited.*
> 7-second 1920x1080. Off-black #101014 field with fine static film grain at 4%. The word "PRECISION" in ~220px heavy condensed caps (a heavy system face condensed with scaleX 0.82), white, 0.02em tracking, centered: its letters assemble from alternating top/bottom 40px offsets with power3.out and a 0.05s stagger, starting 0.3s. At 1.8s a 2px hairline rule draws left-to-right beneath the word, 60% of its width, centered. At 2.4s a 40px tabular-mono counter fades in below and ticks 99.999 → 00.001 mm over 2.2s with expo.out deceleration. At 5.2s the whole lockup eases to 1.03 scale over 0.5s while the word cools from white to #d8d8de, then settles into a slow ±1% breathing idle to the end. No audio.
<video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/spec-precision-type.mp4" style={{ borderRadius: "0.5rem", marginTop: "0.75rem" }}></video>
*Rendered from the spec above, unedited.*
+22
View File
@@ -20,6 +20,14 @@ Describe how motion should *feel* and the agent picks the matching GSAP ease:
**Timing shorthand:** fast (0.2s) = energy, medium (0.4s) = professional, slow (0.6s) = luxury, very slow (12s) = cinematic.
Each word, rendered — the same move, only the ease changes:
<table><tbody>
<tr><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/ease-power2-out.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>smooth · power2.out</div></td><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/ease-power4-out.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>snappy · power4.out</div></td><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/ease-back-out.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>bouncy · back.out</div></td></tr>
<tr><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/ease-elastic-out.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>springy · elastic.out</div></td><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/ease-expo-out.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>dramatic · expo.out</div></td><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/ease-sine-inout.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>dreamy · sine.inOut</div></td></tr>
</tbody></table>
### Camera language
Compositions have no physical camera, but camera words translate directly into scene transforms (or real camera moves in Three.js scenes):
@@ -34,6 +42,14 @@ Compositions have no physical camera, but camera words translate directly into s
| whip to | fast blurred slide into the next framing |
| parallax | layers translating at different rates for depth |
The same scene under each camera word:
<table><tbody>
<tr><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/camera-push-in.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>slow push-in</div></td><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/camera-pull-back.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>pull back</div></td><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/camera-pan.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>pan across</div></td><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/camera-crane.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>crane down</div></td></tr>
<tr><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/camera-whip.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>whip to</div></td><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/camera-parallax.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>parallax</div></td><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/camera-orbit.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>drone orbit (Three.js)</div></td></tr>
</tbody></table>
### Depth language
| Say this | Agent builds |
@@ -137,6 +153,12 @@ Hand-drawn emphasis effects for text:
"Add burst lines around 'AMAZING'"
```
The five modes on the same sentence:
<table><tbody>
<tr><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/marker-highlight.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>highlight</div></td><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/marker-circle.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>circle</div></td><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/marker-burst.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>burst</div></td><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/marker-scribble.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>scribble</div></td><td style={{ padding: "6px", border: "none" }}><video controls muted loop playsinline preload="metadata" src="https://static.heygen.ai/hyperframes-oss/docs/images/prompting/marker-sketchout.mp4" style={{ width: "100%", borderRadius: "0.4rem" }}></video><div style={{ fontSize: "0.8em", textAlign: "center", opacity: 0.7 }}>sketchout</div></td></tr>
</tbody></table>
### Text-to-speech voices
TTS runs locally via Kokoro (no API key needed). Describe the content and the agent picks a voice, or request one directly: