mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-12 15:20:13 +00:00
refactor(skills): rebuild faceless-explainer + pr-to-video on the shot-sequence architecture (#1778)
* refactor(skills): rebuild faceless-explainer + pr-to-video on the shot-sequence architecture Move both skills onto the current shot-sequence authoring architecture and the latest shared engine, then re-narrate to each domain. The engine fixes (pre-assembly frame guards + BGM loop-extend in assemble-index, dark-ground caption contrast, brand-accent selection + mono role in tokens, dark-mode polarity invert / weight-clamp / icon-font filter in build-frame) had only landed in one copy; both skills were a generation behind. - Authoring model: visual-design now writes a time-coded shot sequence (Scene windows paced to the voiceover) instead of the older effects-id phased note; motion-language carries the move vocabulary + the tightened motion doctrine (smooth over bouncy) + the seek-safe core (fromTo entrances, no CSS-transition motion); add cut-catalog (within-frame velocity-matched seams); frame-worker and SKILL Step 4/5 move to blueprint instantiation + shot-sequence fidelity. - faceless-explainer: fold the standalone composition.md into visual-design (inventing-the-visual / portrait / caption geometry); keep the explainer story doctrine; graft cue-segmented VO + candidate-blueprint-from-Step-3. - pr-to-video: keep the ingest pipeline (fetch-pr / ingest / fetch-people-avatars) and code-vocabulary; preserve the code-beat (code-* block as focal, Scenes choreograph the surround) and mechanism-beat treatments under the new model. - Drop stage-assets from both (no captured assets to stage); remove derivation references so each skill reads standalone. bun run scripts/lint-skills.ts passes; all scripts node --check clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(skills): resync skills-manifest after format pass The pre-commit skills-manifest hook hashed the skills before the format hook reformatted cut-catalog.md, so the committed manifest lagged the on-disk content and CI's "Skills: manifest in sync" check failed. Regenerated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
c811a2750a
commit
7cb8386539
@@ -1,123 +0,0 @@
|
||||
# Composition — PR-to-video visual-design judgment
|
||||
|
||||
> The composition-judgment layer for **Step 4 (Visual design)**. You read it while enriching `STORYBOARD.md` frames: which layout, how much frame the hero fills, how many depth layers — **director decisions**. Concrete px (safe margins 96-150), scale (1.05 / 0.92), three-layer `box-shadow`, `perspective` values are the **frame worker's** job; you name the intent in the frame's composition note. Video composition is closer to film / poster design than webpage layout — no scrolling, no reflow; every frame is a fixed canvas, every pixel matters. Default canvas **1920×1080**; portrait `1080×1920` / square `1080×1080` per the storyboard `format`.
|
||||
|
||||
## Squint test
|
||||
|
||||
Squint (or blur the frame). Can you still pick out the most important element, the second, and clear spatial groups? If everything has equal weight after blur, hierarchy is broken — redesign before writing the note. The strongest frames pass this: one dominant block + one supporting structural element, everything else demoted.
|
||||
|
||||
## Canvas zones (conceptual)
|
||||
|
||||
```
|
||||
+--------------------------------------------------+
|
||||
| Optional top chrome |
|
||||
| +----------------------------------------------+ |
|
||||
| | Safe margin | |
|
||||
| | +----------------------------------------+ | |
|
||||
| | | Primary content area | | |
|
||||
| | | (center 65-75% of frame) | | |
|
||||
| | +----------------------------------------+ | |
|
||||
| | | Caption band (bottom ~17%, HARD w/ captions) | |
|
||||
| | +----------------------------------------+ | |
|
||||
| +----------------------------------------------+ |
|
||||
+--------------------------------------------------+
|
||||
```
|
||||
|
||||
- **Top chrome** — rarely needed in a faceless explainer; skip unless a frame intentionally mocks an interface.
|
||||
- **Safe margin** — key content stays off the edges; hero / editorial frames need more air.
|
||||
- **Primary content area** — the center 65-75% is where the eye rests; body text never presses the edge.
|
||||
- **Caption band (bottom ~17%, HARD-reserved when captions are on)** — when the film has captions enabled (the frame's `Captions:` flag), the bottom ~17% of **canvas height** is reserved (landscape 1080h → bottom 180px, y 900-1080; portrait 1920h → bottom 320px, y 1600-1920): primary content and key visuals **cap at the band top**, and a centered hero anchors at **y ≈ 0.42 × height** (landscape ≈454, portrait ≈806), not the canvas midpoint. Background / ambient / surface layers are exempt and may stay full-bleed. Captions disabled → keep the zone clear anyway for bottom-edge consistency across frames.
|
||||
|
||||
You write "hero word centered with generous safe margins"; you do not write `padding: 150px 120px 92px`.
|
||||
|
||||
## Portrait & square (non-16:9 canvases)
|
||||
|
||||
The zones, density, hierarchy, and depth principles all still apply; the **aspect ratio** changes, and a wide-frame layout does not transplant into a tall one. Design for the storyboard's `format` from the start — never plan landscape and "crop."
|
||||
|
||||
- **Stack vertically, not side-by-side.** Portrait has little horizontal room: split-screen / triptych / 60-40 asymmetry become **top/bottom stacks**, vertical step lists, stacked bands. Square tolerates side-by-side only for two compact items.
|
||||
- **Vertical center moves with the canvas** — anchor a centered hero around **y ≈ 0.42 × height** (portrait ≈806, square ≈454), not a fixed 540.
|
||||
- **Type runs larger, fewer words per line** — narrow frames wrap long headlines badly; prefer short kinetic lines, bigger type, more vertical rhythm.
|
||||
- **Travels well to portrait:** Centered, Layered Depth, Full-Width Strip (stacked band), vertical Rule-of-Thirds. **Avoid** wide Split Screen and Triptych — use stacked equivalents.
|
||||
- **Density still rules** — primary visual ≥ 40% of canvas, ≥ 3 depth layers, measured against the tall frame; an empty top or bottom third reads as placeholder.
|
||||
|
||||
## 7 composition templates
|
||||
|
||||
Use ≥3 different templates per video (5 frames → 3+, 9 frames → 4+). **Don't default every frame to centered**; never use the same layout class twice in a row.
|
||||
|
||||
1. **Centered (hero / climax)** — one dominant element, generous breathing room. Concept name, key takeaway, the hero word, the closing principle.
|
||||
2. **Rule of thirds** — anchor on a thirds intersection; remaining space carries support or negative space. A mechanism step + its label.
|
||||
3. **Split screen (comparison / dual focus)** — left/right halves carry separate elements. Before/after, common-belief vs reality, two options.
|
||||
4. **Layered depth (immersive)** — foreground / midground / background differ in scale + opacity. Opening hooks, atmosphere, the "imagine…" scenario.
|
||||
5. **Asymmetric (editorial)** — primary content pushed to one side (60/40, 70/30); intentional imbalance → tension + sophistication. A dense diagram with a caption rail.
|
||||
6. **Triptych (three-panel)** — three equal zones for three items / beats at once. The rule-of-three landing.
|
||||
7. **Full-width strip** — one horizontal band (a number line, a timeline, an enumeration), usually ~20% of canvas height.
|
||||
|
||||
## Frame density — avoid empty frames
|
||||
|
||||
Common failure: small elements floating in the center with empty space around them. Every frame must feel **intentionally filled**.
|
||||
|
||||
- **Primary visual occupies ≥ 40% of canvas** — hero text 50-75% height × 60-80% width; a centered card 30-50% × 50-70%; a diagram big enough to read its labels.
|
||||
- **≥ 3 visual layers** — background (gradient / particles / grid) + midground (main content) + foreground (emphasis / decoration).
|
||||
- **Openings and closings** are prone to emptiness — a bare background + a lonely line of text reads as placeholder. Add environmental layers: dual-radial swell, floating particles, brand-color ambient texture, low-opacity scanlines or a hairline grid.
|
||||
- **Text-only frames still need visual elements** — a coined-term card, an icon, a halftone field, brand-derived geometry, an underline that draws on.
|
||||
|
||||
**Fullness test:** could this frame stand as a poster or social graphic? If it looks like a sparse slide → add layers.
|
||||
|
||||
## Negative space
|
||||
|
||||
Whitespace directs attention, it isn't waste. Tight grouping (icon + label) → small spacing; unrelated groups → large separation; asymmetric outer margins feel more designed than equal padding; a hero word keeps large side whitespace so one word carries the weight. **Failure modes:** everything equidistant (no grouping); unintended overlap; text tight against an edge; captions colliding with bottom visuals; the framework's default padding everywhere.
|
||||
|
||||
## In-frame visual hierarchy
|
||||
|
||||
Visual weight, strong → weak: **large element** › **motion** (moving beats static) › **high contrast** › **type scale** › **position** (center + upper third are golden). Combine **at least two** — an element that is large, moving, and upper-third is unquestionably primary.
|
||||
|
||||
A title that is only _larger_ (sharing weight/color/spacing with body) reads weak. Stack dimensions:
|
||||
|
||||
| Dimension | Strong contrast |
|
||||
| --------- | ------------------------------------------- |
|
||||
| Size | 3:1 ratio or larger |
|
||||
| Weight | 800-900 vs 400 |
|
||||
| Color | high contrast against background |
|
||||
| Motion | one element moving vs all else static |
|
||||
| Position | top / left = primary |
|
||||
| Space | large surrounding whitespace vs equidistant |
|
||||
|
||||
## Cards and grouping
|
||||
|
||||
Spacing + alignment can group without a card container. **Use cards** when content is genuinely distinct (a list item, a definition, a stat callout) or when shadow-stacking communicates "lifted." **Don't** card for mere separation (use whitespace) or for a continuous diagram. **Never nest cards** — claustrophobic, muddy hierarchy.
|
||||
|
||||
## Inventing the visual — diagrams, type, data-viz
|
||||
|
||||
This is a **faceless** explainer: the frame's hero is something you design, not a screenshot. The three first-class treatments:
|
||||
|
||||
- **Typographic / kinetic type** — the hero word, the coined term, a number, a short enumeration. Treat type as the subject: full-bleed scale, weight contrast, one emphasized term. Strongest for hooks, concept names, takeaways.
|
||||
- **Abstract graphics** — shapes, fields, paths, geometry that _embody_ the idea (the snowball, the spotlight, the staircase-not-cliff). Build the metaphor the script names; don't decorate with generic bokeh.
|
||||
- **Diagram / data-viz** — nodes + edges, a chart, a number line, a formula, a process flow. The build (each part appearing on beat) is the teaching — design it to assemble, not appear whole.
|
||||
|
||||
Make the invented hero **fill 40-60% of the frame** — a diagram big enough to read, a hero word near full-bleed. Don't shrink the one designed element into decoration around empty space.
|
||||
|
||||
## Depth on a 2D canvas
|
||||
|
||||
Layer **2-3 depth techniques** per frame to avoid a flat poster (concrete perspective / rotate / scale values are the worker's):
|
||||
|
||||
| Technique | Effect |
|
||||
| ---------------- | ------------------------------------------------------------------------------------------ |
|
||||
| Size difference | larger = nearer, smaller = farther |
|
||||
| Blur | blurred = background, sharp = foreground |
|
||||
| Opacity gradient | low = receding, full = primary |
|
||||
| Overlap | foreground partially covers background |
|
||||
| Shadow stacking | three-layer shadow = lift + brand feel |
|
||||
| Motion speed | faster parallax = closer |
|
||||
| Counter-scale | camera pushes toward focus → background appears larger, focal CSS scale <1 but fills frame |
|
||||
|
||||
You write "3 depth layers: background swell + midground diagram + foreground label glow; background counter-scales for the push"; the worker writes the scale values.
|
||||
|
||||
## What should not appear
|
||||
|
||||
Nav bars, footers, cookie banners, scrollbars, cursor arrows, browser chrome, unclickable buttons, generic decorative shapes standing in for a designed metaphor, floating bokeh / purple-to-blue AI gradients (the "default AI cliché," banned). Faceless explainers have no real interface to show — an interface mock is correct **only** when the topic itself is about that interface and the frame intentionally reconstructs it.
|
||||
|
||||
## Composition note example
|
||||
|
||||
> "Composition: asymmetric 60/40 — the node-graph diagram occupies left 60%, the layer label + caption right 40%. Generous safe margin; text capped inside the primary content area. 3 depth layers: background hairline grid + midground graph + foreground active-node glow. Density: primary visual ~55%, ambient adds a 5% scanline."
|
||||
|
||||
One line per frame; never concrete px / scale / shadow recipes (the worker writes those).
|
||||
@@ -0,0 +1,215 @@
|
||||
# Cut catalog — within-frame seams (worker-built)
|
||||
|
||||
> **A worker build-recipe (Step 5) — the sibling of `../hyperframes-animation/rules/`, not a second motion doc.** These are within-frame cuts the **frame worker builds INSIDE its own composition** (Z-scale + blur + opacity tweens, or per-word x-staggers, all on the frame's own paused GSAP timeline). They are **not** the between-frame transition: story owns that via `transition_in`, which the harness's injector stamps from a **separate registry vocabulary** (`crossfade` / `blur-crossfade` / `push-slide` / `zoom-through` / `squeeze`) — the catalog names here (**cut-the-curve / inverse-zoom / waterfall**) are **not** valid `transition_in` values. Use this catalog when a frame's shot sequence has an internal seam — a within-scene text/element swap, a **Scene-to-Scene** cut (a `Scene` is a time window WITHIN one frame, **not** a frame-to-frame boundary), or a text-to-text line change — and you want it to read as one continuous move instead of a hard slideshow cut. (`zoom-through` lives in both worlds: a whole-frame wrapper transition in the registry, an element-level Z-cut here — same idea, different scope.)
|
||||
|
||||
Four techniques that create depth and continuity:
|
||||
|
||||
1. **Zoom-Through** — within-scene text swaps, Z-axis, moving TOWARD the viewer
|
||||
2. **Inverse Zoom-Through** — Z-axis swaps moving AWAY from the viewer
|
||||
3. **Cut the Curve** — between-scene transitions on x/y
|
||||
4. **Waterfall Cut** — word-by-word cut-the-curve with staggered exits and entries
|
||||
|
||||
All four are the same underlying principle: **cut at peak velocity, match direction and
|
||||
speed on both sides of the cut.** The differences are axis, scope, and granularity.
|
||||
|
||||
**Choosing which at a seam:** for an UNFINISHED phrase (building one larger idea across
|
||||
several visually distinct scenes that still approach the same point — multi-line text, a
|
||||
run of consecutive cards) use **cut-the-curve** / **waterfall**. For a STATE CHANGE (turning
|
||||
to a NEW part of the video — most often hook → context, between two distinct chapters) use
|
||||
**zoom-through**, and **inverse zoom-through** for an arrival / payoff beat. Chain these so
|
||||
the frame's internal seams feel like one camera moving through the content.
|
||||
|
||||
---
|
||||
|
||||
## Blur Logic (applies to all Z-axis variants)
|
||||
|
||||
Blur sells the speed at the cut, but it must scale with the SUBJECT SIZE:
|
||||
|
||||
| Subject | Peak blur | Why |
|
||||
| ------------------------------------------------------ | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Text-scale (headline, line, word group) | **10px** | At 20px text smears into illegibility — the eye loses the word it was tracking and the cut reads as a glitch, not speed. At 20px letterforms go mushy mid-cut; 10px keeps them readable. |
|
||||
| Full-frame surface (terminal window, card, screenshot) | **18–20px** | Big surfaces have edges and texture that survive heavy blur; lighter blur on a full-frame move reads as a rendering hiccup instead of motion. |
|
||||
|
||||
Both sides of a cut use the SAME peak blur — the value must match at the swap frame.
|
||||
Apply blur to the WRAPPER, never to individual children.
|
||||
|
||||
---
|
||||
|
||||
## 1. Zoom-Through (forward)
|
||||
|
||||
### The Problem
|
||||
|
||||
Text enters, holds, exits. Then next text enters, holds, exits. Each text block is
|
||||
independent — no depth, no continuity. The video feels like a slideshow.
|
||||
|
||||
### The Principle
|
||||
|
||||
A velocity-matched cut on the Z-axis. You **never see both texts at the same time.** The
|
||||
outgoing text scales toward the viewer (accelerating), blur and opacity peak at the cut
|
||||
point hiding a hard swap, and the incoming text continues scaling up from behind
|
||||
(decelerating into the focal plane). One continuous forward motion, two different texts.
|
||||
|
||||
### The Three Phases
|
||||
|
||||
**Phase 1: Exit** — text accelerates forward (toward viewer)
|
||||
|
||||
- Scale: `1.0 -> 1.2`, Blur: `0px -> 10px` (text-scale; see Blur Logic), Opacity: `1.0 -> 0.15`
|
||||
- Scale/blur easing: `power3.in` (steep acceleration)
|
||||
- Opacity easing: `none` (linear — even dimming, separated from scale)
|
||||
- Duration: 0.2s
|
||||
|
||||
**Phase 2: Hard cut** at peak velocity + peak blur
|
||||
|
||||
- Outgoing: `opacity: 0` (instant via `tl.set`)
|
||||
- Incoming: `opacity: 0.15, scale: 0.75, blur: 10px` (instant via `tl.set`)
|
||||
- All properties match at the cut: blur, opacity, and scale DIRECTION (both scaling up)
|
||||
|
||||
**Phase 3: Entry** — text continues forward (growing into focal plane)
|
||||
|
||||
- Scale: `0.75 -> 1.0`, Blur: `10px -> 0px`, Opacity: `0.15 -> 1.0`
|
||||
- Easing: `expo.out` (steep initial burst matching exit velocity, long settle)
|
||||
- Duration: 0.5s
|
||||
|
||||
### Why Opacity Must Be Separate on Exit
|
||||
|
||||
Scale uses `power3.in` but that keeps opacity near 1.0 for most of the tween. Splitting
|
||||
opacity to its own tween with linear ease makes the dimming even. On entry, all properties
|
||||
can share `expo.out`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Inverse Zoom-Through (backward)
|
||||
|
||||
The mirror: the camera "pulls back" instead of pushing through. The outgoing element
|
||||
RECEDES away from the viewer; the incoming element arrives OVERSIZED (as if it had been
|
||||
just behind the camera) and retracts into the focal plane. Both move in the shrinking
|
||||
direction — same-direction rule preserved, just reversed.
|
||||
|
||||
**When to use over the forward variant:** arrival beats. The incoming element lands with
|
||||
presence because it comes from larger-than-frame — right for a payoff line ("That changes
|
||||
today."), a giant reply, or a held end-state. Forward zoom-through reads as _progressing
|
||||
through_ content; inverse reads as _arriving at_ content.
|
||||
|
||||
### The Three Phases
|
||||
|
||||
**Phase 1: Exit** — element recedes (away from viewer)
|
||||
|
||||
- Scale: `1.0 -> 0.8`, Blur: `0px -> 10px` (text-scale)
|
||||
- Scale/blur easing: `power3.in`; Opacity: `1.0 -> 0.15` on `none` (separate tween)
|
||||
- Duration: 0.2s
|
||||
|
||||
**Phase 2: Hard cut**
|
||||
|
||||
- Outgoing: `opacity: 0` via `tl.set`
|
||||
- Incoming: `opacity: 0.15, scale: 1.25, blur: 10px` via `tl.set`
|
||||
|
||||
**Phase 3: Entry** — incoming retracts into place
|
||||
|
||||
- Scale: `1.25 -> 1.0`, Blur: `10px -> 0px`, Opacity: `0.15 -> 1.0`
|
||||
- Easing: `expo.out`, Duration: 0.5s
|
||||
|
||||
---
|
||||
|
||||
## 3. Cut the Curve (Scene Transitions)
|
||||
|
||||
### The Principle
|
||||
|
||||
Use cut-the-curve for **all scene-to-scene transitions** on x and y axes. The outgoing
|
||||
scene's hero element accelerates in one direction, the cut lands mid-motion, and the
|
||||
incoming scene's hero element continues moving in the **same direction** and decelerates.
|
||||
Nothing exits fully off-screen and nothing enters from fully off-screen — **speed plus
|
||||
opacity fading trick the eye**; the partial moves are enough.
|
||||
|
||||
### Same Path, Same Direction
|
||||
|
||||
If Scene A's hero slides left, Scene B's hero enters from the right and continues sliding
|
||||
left. Both move leftward. One continuous motion.
|
||||
|
||||
| Direction | Scene A exit | Scene B entry start | Scene B entry end |
|
||||
| --------- | -------------- | ------------------- | ----------------- |
|
||||
| Leftward | `x: 0 -> -230` | `x: +230` | `x: 0` |
|
||||
| Rightward | `x: 0 -> +230` | `x: -230` | `x: 0` |
|
||||
| Upward | `y: 0 -> -230` | `y: +230` | `y: 0` |
|
||||
| Downward | `y: 0 -> +230` | `y: -230` | `y: 0` |
|
||||
|
||||
### Velocity matching via mirrored eases
|
||||
|
||||
The cleanest match: exit `power4.in` and entry `power4.out` with the SAME distance and
|
||||
duration — mathematically the two halves of one `power4.inOut` composite, so the entering
|
||||
element picks up at exactly the 50% point of the notional path at identical velocity
|
||||
(e.g. 230px / 0.3s ≈ 3,070 px/s at the cut on both sides).
|
||||
|
||||
The fade trick: the exit's opacity completes at ~25–30% of its travel (fade duration
|
||||
≈ 0.18–0.3s vs motion 0.3–0.34s) — the element vanishes while still visibly accelerating,
|
||||
and nothing has to reach the frame edge. Entry fades IN fast from ~0.35 under its
|
||||
deceleration. Time the LAST fading element to die right at the hard cut — gaps where
|
||||
nothing is moving read as awkward dead air.
|
||||
|
||||
### Rules
|
||||
|
||||
- Use cut-the-curve for all scene transitions — it's the default, not an accent
|
||||
- Same direction on both sides; mirrored `.in`/`.out` eases, same distance + duration
|
||||
- Exit duration short (0.2–0.4s), entry duration >= exit duration
|
||||
- Partial travel + fade, never full off-screen moves
|
||||
|
||||
---
|
||||
|
||||
## 4. Waterfall Cut (word-by-word cut-the-curve)
|
||||
|
||||
Cut-the-curve at WORD granularity — the strongest version of the leftward cut for
|
||||
text-to-text seams. Each word of the outgoing line ramps out on its own pronounced curve;
|
||||
each word of the incoming line cascades in mid-flight. The stagger turns the cut into a
|
||||
wave the eye rides across the seam.
|
||||
|
||||
### Exit (per word)
|
||||
|
||||
- Motion: `x: 0 -> -230` over 0.34s on **power4.in** — a much more pronounced ramp than
|
||||
the usual power2: the word barely creeps, then RIPS
|
||||
- Fade: `opacity -> 0` over 0.18s (separate tween, `power1.in`) — completes when the word
|
||||
is only ~25–30% into its travel
|
||||
- Stagger: reading order, ~0.022s per word, timed so the LAST word finishes fading right
|
||||
at the hard cut
|
||||
|
||||
### Entry (per word)
|
||||
|
||||
- `fromTo x: +230 -> 0, opacity: 0.35 -> 1` over 0.3s on **power4.out** — the mirrored
|
||||
back half of the composite; every word ignites already moving at matched velocity
|
||||
- Waterfall stagger with SHRINKING gaps (start 0.05s, multiply by ~0.84 per word) so the
|
||||
cascade accelerates across the line — the cascade should speed up word over word, not run
|
||||
at a flat per-word delay
|
||||
- Pre-set all words to `x: +230, opacity: 0` at build time — `immediateRender: false`
|
||||
alone leaves un-started words sitting visible at rest during the stagger window
|
||||
|
||||
### Whole-line variant
|
||||
|
||||
A single-line beat (e.g. a big intro line) exits as one group with the same pronounced
|
||||
ramp, but stretch its fade to ~0.3s ending ~0.02s before the cut — a lone element that
|
||||
fades early leaves dead air that a word cascade would have covered.
|
||||
|
||||
---
|
||||
|
||||
## Choosing a Variant
|
||||
|
||||
| | Zoom-Through | Inverse Zoom | Cut the Curve | Waterfall Cut |
|
||||
| -------------- | --------------------------- | --------------------------- | ----------------- | ------------------------- |
|
||||
| Scope | Within-scene text swap | Arrival/payoff beat | Between scenes | Text-to-text seam |
|
||||
| Axis | Z, toward viewer | Z, away from viewer | X / Y | X, per-word |
|
||||
| Peak blur | 10px text / 20px full-frame | 10px text / 20px full-frame | none required | none (fade does the work) |
|
||||
| Opacity at cut | 0.15 | 0.15 | exit faded by cut | last word dies at cut |
|
||||
| Feel | progressing through | arriving at | carried sideways | a wave across the seam |
|
||||
|
||||
---
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
| Don't | Why | Instead |
|
||||
| ---------------------------------------- | ------------------------------------------- | ------------------------------------------------------ |
|
||||
| Two texts visible during a zoom-through | Overlapping text breaks the Z-axis illusion | Hard cut at blur peak, one text at a time |
|
||||
| 20px blur on text-scale subjects | Letterforms smear; reads as a glitch | 10px for text, 18–20px only full-frame |
|
||||
| Elements on different paths across a cut | Eye tracks one direction, cut goes another | Same property, same direction |
|
||||
| Mismatched blur/opacity at the swap | Visible flash or brightness jump | Identical values at the cut frame |
|
||||
| Gentle easing on entry (`power2.out`) | Entry velocity feels slower than exit | Mirror the exit: `power4.out` / `expo.out` |
|
||||
| Full off-screen exits / entries | Wastes time and breaks the speed illusion | Partial travel + early fade |
|
||||
| Lone element fading long before its cut | Dead air at the seam | Fade ends ~0.02s before the cut, or use a word cascade |
|
||||
| Zoom-through on body text | Small text at 0.75 scale is unreadable | Only headlines and short phrases |
|
||||
| Scene cuts without cut-the-curve | Static cuts feel like a slideshow | Cut-the-curve is the default |
|
||||
@@ -1,141 +1,156 @@
|
||||
# Motion language — PR-to-video visual-design judgment
|
||||
# Motion language — the move vocabulary + the motion doctrine + the seek-safe core
|
||||
|
||||
> The motion-judgment layer for **Step 4 (Visual design)**. You name **each shot's choreography, spring intent, beat rhythm, holds, stillness, and the idle-motion budget** while enriching `STORYBOARD.md` frames; the **frame worker** maps intent to concrete GSAP eases / ms / stagger / code (via `hyperframes-animation`). A good explainer feels like one continuous whole — one camera, one spring feel, **every shot directed across its full length** — not a pile of slides that animate once and freeze. You reference motion by **role**, never by curve: eases / durations resolve from `frame.md`'s motion tokens, named `entry` / `emphasis` / `exit` / `drift` (the pack's exact keys may differ); the worker maps the curve. Between-frame **transitions are not yours** — story names `transition_in`, the harness injects it.
|
||||
> The motion layer for **Step 4 (Visual design)**. When you write a frame's **time-coded shot sequence**, you name each scene's move **inline from the vocabulary below** — a named palette of the moves the golden corpus actually uses. Each move carries the **backing rule id** in this skill's local `../hyperframes-animation/rules/`; cite that id so the move resolves to a real recipe when a **frame worker** implements it in Step 5 (the worker reads the rule body in `../hyperframes-animation/rules/<id>.md` — it reproduces the move, it does not guess from the name). You name motion by **role / move name**, never by raw GSAP curve, ms, or stagger formula — the worker maps the curve. Between-frame **transitions are not yours**: story names `transition_in`, the harness injects it; that injected transition **is** the frame's exit. For cuts a worker builds INSIDE a frame (within-scene swaps, scene-to-scene seams), see the catalog in `cut-catalog.md`.
|
||||
|
||||
## A frame is a shot, not a slide
|
||||
A good code-change explainer feels like one continuous film — one camera, one motion feel, **smooth and timed to the voiceover** — not a pile of slides that animate once and freeze. In a PR explainer the development often _is_ the reveal: the diff hunk typing in, the before→after morph, the impact stat landing. The doctrine in Part 2 is load-bearing: when in doubt, do what it says.
|
||||
|
||||
The single failure that makes an explainer read as PowerPoint: a frame whose content **animates in over the first ~0.8s, then freezes** for the rest of its duration while a slow drift plays underneath. The entrance is not the shot — it's the **first beat** of it. You direct the **whole duration**.
|
||||
---
|
||||
|
||||
In explainers especially, the development beat _is_ the teaching: the formula assembling term by term, the diagram gaining a layer, the count-up landing. Don't waste it on a frozen hold.
|
||||
# Part 1 — the move vocabulary
|
||||
|
||||
Three layers fill a shot, each governed by a different rule:
|
||||
Reach into this palette when naming a scene's motion. Pick the move that matches the beat, name it in the shot sequence, and cite the rule id after `→`. The blueprints (`../hyperframes-animation/blueprints/`) name these same moves in their `rule mapping`; you're drawing from one shared palette. Compose 2–4 across a shot's scenes (entrance → sequential reveal → settle), not all at once.
|
||||
|
||||
| Layer | What | Rule |
|
||||
| ------------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------- |
|
||||
| **Camera** (macro) | ONE correlated move on the frame root — slow drift / dolly / push / parallax pan | **always on, the whole shot** — this is the "someone is filming this" layer |
|
||||
| **Choreography** (action) | the beat develops: entrance → mid-shot move (reveal / rearrange / morph / emphasis hit) → settle | **fill the duration** — a shot animated only at entry is a slide |
|
||||
| **Idle life** (texture) | ambient continuation on the 1-2 elements that hold a live slot — breathing, glow, float | **budgeted** — this is where screensaver lives; cap it |
|
||||
## Kinetic type
|
||||
|
||||
The reconciliation that matters: **mandate choreography, budget idle life.** Purposeful, sequential motion that carries information should fill the shot; ambient, simultaneous motion that carries none should be capped. Many elements each floating independently reads as _screensaver_; a shot that only enters then freezes reads as _slideshow_. Avoid both — **one camera move + a directed multi-phase action + 1-2 living elements**, nothing scattered.
|
||||
- **hard-cut / flash word-swap** — a word or line replaces the previous one on an instant cut (no fade/roll); the swap itself is the beat. → `discrete-text-sequence`
|
||||
- **in-place token cycle** — a fixed line holds and only its variable slot changes, token → token → token. → `discrete-text-sequence`
|
||||
- **per-word staggered reveal** — a phrase assembles word-by-word (or chunk-by-chunk), each landing on its own beat. → `dynamic-content-sequencing`
|
||||
- **kinetic beat-slam** — short phrases slam in on a shared percussive beat array, each with a distinct entrance, resolving on a locked finale; the recipe for "punchy / rhythmic" taglines. → `kinetic-beat-slam`
|
||||
|
||||
## Multi-phase choreography — direct the full shot
|
||||
## Typewriter
|
||||
|
||||
Every non-still frame's timeline is choreographed across its length, not front-loaded into the entrance:
|
||||
- **type-on with caret** — text types in character-by-character behind a blinking caret. → `discrete-text-sequence` (+ `context-sensitive-cursor` for the caret blink / color)
|
||||
- **backspace-and-retype** — the line types, deletes the last word(s), and retypes a new one (typo-correction, reframe). → `discrete-text-sequence` (+ `context-sensitive-cursor`)
|
||||
|
||||
```
|
||||
entrance → development → settle
|
||||
```
|
||||
## Count-up / data
|
||||
|
||||
- **entrance** — the beat's primary content arrives (hero `entry` / `heavy`; groups staggered).
|
||||
- **development (the phase that's usually missing → PPT)** — mid-shot, the content _does something_: a second element reveals, elements rearrange to a new layout, a diagram gains a layer, a count-up runs, an emphasis hit lands on the keyword. This is the motion that separates video from slides.
|
||||
- **settle** — the shot resolves and holds for its read; the camera + idle life continue underneath (never a hard freeze).
|
||||
- **value-scaled counter** — a number counts up and its font size grows with the value, so the climb itself escalates. → `counting-dynamic-scale`
|
||||
- **bars / progress / star wipe** — a number paired with a graphic that fills: bar-height stagger, a progress bar / ring filling, a fractional star-rating wipe. → `stat-bars-and-fills`
|
||||
|
||||
**Architecture:** in hyperframes only the **exit** is forbidden mid-video (the frame unmounts; the harness transition _is_ the exit). Everything _before_ the settle — including rich mid-shot development — is free and seek-safe. Build the development phase; skip only the exit (unless you are the final frame).
|
||||
## Reveal / decode
|
||||
|
||||
When you name a **`blueprint`**, the development phases come from its recipe — write the composition note **shot-by-shot** to match. When you name **no blueprint**, the **≥3 cited effects ARE the phases** — sequence them (one enters, one develops, one emphasizes); **don't fire them all at t=0**.
|
||||
- **3D char flip-decode** — characters flip in 3D and resolve from scrambled glyphs to the real text (decryption feel). → `hacker-flip-3d`
|
||||
- **SVG self-draw** — an outline / icon / ring draws itself stroke-by-stroke. → `svg-path-draw`
|
||||
|
||||
## Spring intent (by role, not curve)
|
||||
## Camera
|
||||
|
||||
| Intent | Feel | Use |
|
||||
| ---------- | ------------------------------------------- | --------------------------------------- |
|
||||
| **entry** | confident slight overshoot, settles quickly | primary element entry (default) |
|
||||
| **gentle** | soft slide-in, no overshoot | background elements, subtle motion |
|
||||
| **snappy** | tight overshoot, nearly instant | small icons, labels, list items |
|
||||
| **heavy** | weighted deceleration | large diagrams, hero visuals |
|
||||
| **slam** | bouncy overshoot, intentionally loud | a coined term landing, an impact moment |
|
||||
- **push / focus / drift** — a sequential camera move on the frame root (pull-back → focus → push) plus continuous micro-drift; the cinematic baseline. → `multi-phase-camera`
|
||||
- **zoom-to-target** — zoom into a non-centered element (scale + counter-translate to keep it framed). → `coordinate-target-zoom`
|
||||
- **pan / focus-lock** — a virtual camera transforming one `.world` wrapper to pan / zoom / lock onto a region. → `viewport-change`
|
||||
- **camera-cursor-tracking** — the viewport locks to a moving focal point (a typing cursor), static framing then focal-locked tracking. → `camera-cursor-tracking`
|
||||
|
||||
**Consistency:** similar elements share one intent (all labels `snappy`, all hero visuals `heavy`). Don't invent a unique ease + duration per element.
|
||||
## Layout motion
|
||||
|
||||
**Forbidden:** `bounce.out` / `elastic.out` (dated; real objects decelerate, they don't bounce — low overshoot for `entry` is fine, high overshoot only for clearly playful moments); a unique ease+duration per element (visual noise).
|
||||
- **cluster→outward expansion** — elements start clustered at center and expand outward to their final positions in lockstep. → `center-outward-expansion`
|
||||
- **orbit** — elements flip in from 3D space and settle into a continuous elliptical orbit (entry flips in-place at the orbital position). → `orbit-3d-entry`
|
||||
- **split-tilt cards** — two cards side-by-side with opposing rotationY tilts, entering from their respective sides (comparison / before-after). → `split-tilt-cards`
|
||||
- **logo/avatar ring + connectors** — avatars or logos on an elliptical ring with SVG connection lines to a center point, staggered entry. → `avatar-cloud-network`
|
||||
|
||||
## Duration intent
|
||||
## Surface / UI
|
||||
|
||||
Reference by **tier** ("instant feedback" / "state change" / "layout change" / "entry animation"); the worker maps concrete ms / frames at 30fps. **A single entry should not exceed ~800ms** — for a longer buildup, use multi-element stagger or a development phase, **not** one long tween.
|
||||
- **3D page-scroll reveal** — a full webpage as a tilted 3D card whose internal content scrolls to reveal specific sections. → `3d-page-scroll`
|
||||
- **cursor click + ripple** — a cursor moves to a target, depresses with it on click, and emits an expanding ripple. → `cursor-click-ripple`
|
||||
- **button press** — a tactile press: compression then spring recovery, optional release burst / glow. → `press-release-spring` (or `physics-press-reaction` for a click that compresses cursor + target together)
|
||||
- **keyword glow** — keywords light up with glow + scale + color on an attack-decay-rest envelope, synced to a word rail. → `asr-keyword-glow`
|
||||
|
||||
**Phase-to-phase within a shot is swift** — when one element makes way for the next (development), the outgoing move runs ~75% of an entry; arrival is deliberate, hand-off is quick. (The between-frame **exit** is the harness's transition, never your within-shot motion.)
|
||||
## Morph / handoff
|
||||
|
||||
## Stagger cap
|
||||
- **scale-swap** — two elements at the same screen center hand off: the outgoing cluster shrinks + fades as the incoming one arrives. → `scale-swap-transition`
|
||||
- **card morph-anchor** — a container morphs apparent size + corner radius + surface between two shots, then fades to reveal the real target beneath (HyperFrames uses uniform `scale`, not `width`/`height`). → `card-morph-anchor`
|
||||
|
||||
When staggering N elements, **total ≤ 500ms** (longer feels dragged):
|
||||
## Seam cuts (worker-built, inside a frame)
|
||||
|
||||
- **3-7 elements** — normal stagger, total 300-700ms.
|
||||
- **8+ elements** — tighten per-item delay, or stagger only the first few and enter the rest with the last.
|
||||
- Never let stagger run past 500ms.
|
||||
The velocity-matched cuts a worker authors between a frame's own Scenes. Name the seam in the shot sequence; the recipe is in the catalog, not a single `../hyperframes-animation/rules/` id.
|
||||
|
||||
## Beat structure across frames (the cross-frame rhythm)
|
||||
- **zoom-through / inverse zoom-through** — a within-scene swap on the Z-axis; forward reads "progressing through", inverse reads "arriving at" (payoff). → `cut-catalog.md`
|
||||
- **cut-the-curve** — a scene-to-scene cut where both sides move the same direction at matched velocity. → `cut-catalog.md`
|
||||
- **waterfall cut** — cut-the-curve at word granularity, a wave across a text-to-text seam. → `cut-catalog.md`
|
||||
|
||||
Rhythmic videos breathe: tension → release → tension → release. A clean reference shape for a ~46s explainer:
|
||||
## Emphasis / marker
|
||||
|
||||
| Phase | Duration | Rhythm | Frame type |
|
||||
| ------------ | -------- | ------------------- | ----------------------------------------- |
|
||||
| Hook + gap | 4-8s | slow build | open the curiosity gap; land the hook |
|
||||
| Concept name | 3-6s | deliberate | name the idea, one breathable beat |
|
||||
| Body build | 12-20s | continuous, layered | the mechanism / steps / items, on a stage |
|
||||
| Landing | 3-5s | still, breathable | the takeaway / principle / CTA |
|
||||
- **highlight / circle / burst / scribble** — a marker-drawn emphasis on a word or element: yellow highlight sweep, hand-drawn circle, radiating burst, scribble, or rough sketch-outline. → `css-marker-patterns`
|
||||
|
||||
Allocate motion by a frame's energy: **high-energy** (hook, a surprising stat) → faster entry, tighter stagger, `snappy`, busier development; **breathable** (concept name, the turn in a story, the landing) → slower entry, `gentle`, longer hold, minimal development; **data / mechanism** (a step, a statistic) → medium rhythm, clean stagger, a count-up or layer-reveal as the development phase.
|
||||
## Aliveness during a hold (use sparingly — see Part 2)
|
||||
|
||||
## Hold time — read time, not freeze time
|
||||
- **subtle jitter** — the sanctioned way to keep a settled frame alive: a small, low-amplitude positional/scale jitter on the held element. The motion-graphics trick that reads "alive" without reading "weak." → `sine-wave-loop` (low-amplitude register)
|
||||
- **live SVG internals** — internal SVG parts move so an icon feels alive (rotating hands, oscillating blades, pulsing dots, dash-flow); fine because it's the subject doing something, not a card breathing. → `svg-icon-enrichment`
|
||||
- **finite bounded ambient** — a single bounded breathe/drift on ONE held hero, only when genuinely needed; de-emphasized — prefer sequential reveal or jitter first. → `sine-wave-loop`
|
||||
|
||||
After an element enters it must stay long enough to read (the worker maps concrete frames). "Hold" means **don't cut early** — the camera + idle life keep playing underneath; it is never a hard freeze.
|
||||
## The added moves — now backed by local rules
|
||||
|
||||
| Content | Minimum hold |
|
||||
| ----------------------------------- | ------------ |
|
||||
| display text (1-3 words) | ~1s |
|
||||
| short sentence | ~1.5s |
|
||||
| data / statistic | ~1.5s |
|
||||
| diagram / formula | ~2s |
|
||||
| complex visual (multi-part diagram) | ~2.5s |
|
||||
| hero / climax word | ~1-1.4s |
|
||||
Five moves the golden corpus needs were added to this skill's `../hyperframes-animation/rules/`, rounding out the vocabulary above:
|
||||
|
||||
Narration shorter than the needed hold → the frame's `duration` should still give the visual its read time.
|
||||
- **depth-of-field / selective-blur** — blur the off-focus subset to spotlight the focal element → `depth-of-field-blur`
|
||||
- **motion-blur streak** — directional velocity blur on a fast fly-in / camera push-through → `motion-blur-streak`
|
||||
- **3D depth scatter-assemble** — glyphs/elements scatter into a tumbling 3D cloud, then reassemble → `depth-scatter-assemble`
|
||||
- **spring-pop entrance** — the canonical entrance pop; default to a smooth long-tail settle, overshoot only when explicitly playful → `spring-pop-entrance`
|
||||
- **ambient glow / bloom** — un-triggered soft glow blooming behind a static hero → `ambient-glow-bloom`
|
||||
|
||||
## Stillness before climax — the marked exception
|
||||
---
|
||||
|
||||
A **0.3-0.75s pause** between the major action and its confirmation / result — the silence builds tension before the landing (the turn in a story, the "aha" after a build). It lands **because the rest of the video is choreographed** — stillness is a contrast against motion, so it only reads when motion is the baseline. **Allocate it to only 2-3 frames per video, named in the `## Video direction` block**, where the narration lands a payoff. Stamped on every frame it becomes a tic and flattens the rhythm. Name `stillness-before-climax` in that frame's motion note; even then the camera move continues (still ≠ frozen).
|
||||
# Part 2 — the motion doctrine (load-bearing)
|
||||
|
||||
## The idle-life budget — what may move during the hold
|
||||
These four rules are the difference between a clip that reads as a serious code-change explainer and one that reads as an agent-made PowerPoint. Follow them as written.
|
||||
|
||||
The 1-2 elements that keep moving _after_ the development settles. This is the layer that, overdone, becomes screensaver — so it is **capped**, not mandated:
|
||||
## 1. Smooth beats bouncy — `power3` is the default
|
||||
|
||||
1. **Camera move** — always present (the macro layer above); it alone keeps everything coherently alive.
|
||||
2. **At most 1-2 secondary live elements** — the ones carrying the beat (hero, the active node). Everything else holds.
|
||||
3. Prefer **macro move + depth parallax** over many independent floats.
|
||||
Elements should use **long-tail decel curves that let them settle smoothly. `power3` is enough in most cases.** No bouncy, no overshoot, no `back.out` / `bounce.out` / `elastic.out` as a default.
|
||||
|
||||
Secondary-slot menu (formulas are the worker's): **multiplicative breathing** (hero — small ±2-5% on final scale) · **glow pulse** (the active element) · **sine float** (one decorative cluster at most) · **rotational drift** (3D cards, hero mark) · **orbit** (surrounding icons; counts as the one decorative cluster) · **halftone breathing** (atmospheric frames).
|
||||
Bouncy is the **#1 instant turn-off** in user-made Remotion / HyperFrames videos, and the agent almost never gets it right — it thinks bouncy adds emphasis, but it buys that emphasis at the cost of cleanliness. The serious motion-design shops feel the same. **Smooth always wins.** Overshoot is demoted to a **rare, explicitly-playful exception** (a consumer/fun logo slam, a deliberate bell-hit) — never the house style. Name the intent as a long-tail settle; the worker maps `power3` (or `expo.out` on a fast arrival). See `../hyperframes-animation/rules/spring-pop-entrance.md` — it now leads with the smooth settle.
|
||||
|
||||
Multiplicative breathing is the signature for a hero **that holds a live slot** — not stamped on every hero. **Minimum amplitude ±6px or ±2-5% scale** — a 3px micro-float doesn't count.
|
||||
## 2. Sequential reveal in the back ~50%, timed to the voiceover
|
||||
|
||||
## Seek-safe motion — intents that don't survive the renderer
|
||||
This is the anti-PowerPoint mechanism — sharper than "put development in the middle."
|
||||
|
||||
The frame is a **paused GSAP timeline seeked frame-by-frame**, so some "continuous" intents from a real-time engine cannot render — **don't name them**:
|
||||
- **Don't dump everything on screen in the first ~25%** of the scene. Rushing all content in up front is exactly what forces the slideshow feel.
|
||||
- **Reveal each piece — a line, a card, even an h1 — when the voiceover mentions it**, sequencing reveals across the **later ~50%** of the scene. Same amount of agent work, but the cut becomes coherent and gains rhythm.
|
||||
- **Less is more.** Fewer things on screen, each arriving on its VO beat, beats a full canvas that animated once and froze.
|
||||
|
||||
- **No infinite / forever motion** — "particles loop endlessly," "logo rotates forever," "marquee scrolls on repeat." Idle life is a **finite tween over the hold** (breathe up then back), never `repeat`/`yoyo`.
|
||||
- **No randomness or wall-clock** — `Math.random` particle fields, `Date.now` drift. Every motion is the same on every render; name deterministic motion only.
|
||||
- **Entrance + development only** (exit = final frame only) — the cross-frame exit is the harness's transition.
|
||||
- Express oscillation/breathing as a **bounded finite move**, not a loop.
|
||||
Practically: a frame's shot sequence front-loads almost nothing — the entrance carries only what the VO is saying at t=0, and the rest of the elements wait in the timeline for their spoken cue. A reveal maps onto a development-class move from Part 1 (`per-word staggered reveal`, `cluster→outward expansion`, a `count-up`, an `asr-keyword-glow` synced to the word rail).
|
||||
|
||||
## Forbidden — both failure modes
|
||||
## 3. No lazy breathing, no bad pan/push — "no motion over bad motion"
|
||||
|
||||
**Slideshow (under-motion):**
|
||||
The agent's two reflexive ways to fake "aliveness" both read cheap:
|
||||
|
||||
- Content animates in, then **freezes** for the rest of the shot (the PPT tell).
|
||||
- Only the entrance is animated; the remaining duration is a frozen hold under a drift.
|
||||
- The ≥3 cited effects **all fire at t=0** instead of sequencing into entrance / development / emphasis.
|
||||
- No mid-shot development on a non-still frame.
|
||||
- **No lazy breathing.** Scaling cards/text up and down in a circular loop to look "alive" is the cheap tell. Don't reach for it.
|
||||
- **No bad slow pan / push in the back half.** A slow pan or push on elements in the later ~50% of a scene **disrupts the viewer's sightline and causes eye discomfort** — it actively makes the frame worse, not better.
|
||||
|
||||
**Screensaver (over-motion):**
|
||||
The fix for both is the same: **stagger element reveals in time with the script** (rule 2). And the governing principle: **"I'd rather have NO motion than BAD motion."** A held, still frame is better than a frame kept "alive" by breathing or a drifting camera. The **only sanctioned aliveness** during a hold is **subtle jitter** — a small low-amplitude jitter that keeps a frame from feeling dead without looking weak (it's in Claude videos now). Everything else holds.
|
||||
|
||||
- **Every element** floating independently; idle motion with no information.
|
||||
- More than 1-2 elements idling at once; scattered sine floats as the "aliveness."
|
||||
- A 3px micro-float standing in for real motion.
|
||||
## 4. Internal seams are velocity-matched cuts
|
||||
|
||||
**Always:**
|
||||
When a frame has an internal seam — a within-scene swap, a Scene-to-Scene cut, a text-to-text line change — make it a **velocity-matched cut**, not a hard slideshow cut: cut at peak velocity, match direction and speed on both sides. The catalog (the four techniques, the blur logic, and which to use when) is `cut-catalog.md`; the moves are listed under **Seam cuts** in Part 1.
|
||||
|
||||
- `bounce.out` / `elastic.out`; a bespoke ease+duration per element; `repeat` / `yoyo`; all elements entering simultaneously (must stagger or sequence).
|
||||
## One-line summary
|
||||
|
||||
## Motion note example
|
||||
Smooth long-tail (`power3`) over bouncy; reveal sequentially in the back ~50% timed to the VO (not dumped in the first 25%); no lazy breathing and no bad slow pan/push — prefer stillness, with subtle jitter as the only aliveness; cut at peak velocity with matched direction/speed (→ `cut-catalog.md`).
|
||||
|
||||
> "Macro: slow dolly-in on the frame root across the whole beat. **Entrance** — the concept word enters `EASE.entry` (heavy); supporting labels snappy-stagger (4 items, ~400ms). **Development** — the diagram gains its second layer, then a count-up runs beneath it. **Stillness-before-climax 0.6s** (allocated frame; only the dolly continues). **Settle** — the takeaway emphasis: text gentle entry + glow; idle hold with the hero word breathing ±3% as the one live element."
|
||||
---
|
||||
|
||||
One line for a single-shot frame; **shot-by-shot when the beat is multi-phase** (always, when you named a `blueprint`). Never concrete ease curves / ms / stagger formulas / JS — the worker writes those.
|
||||
# Part 3 — the seek-safe core (hard rules)
|
||||
|
||||
The frame is a **paused GSAP timeline seeked frame-by-frame**, so some "continuous" intents from a real-time engine can't render — don't name them. These are non-negotiable regardless of doctrine.
|
||||
|
||||
- **No infinite / forever motion** — "particles loop endlessly," "logo rotates forever," "marquee on repeat." Any aliveness (the subtle jitter, a live SVG internal, a needed bounded ambient) is a **finite tween over the hold**, never `repeat` / `yoyo`.
|
||||
- **No randomness or wall-clock** — no `Math.random` particle fields, no `Date.now` drift. Every render must be identical; name deterministic motion only (stagger and any variation derive from the element index).
|
||||
- **Entrances use `fromTo`** — state the from-state explicitly so a seek to `t=0` lands the element correctly; never rely on a CSS-hidden start (it renders visible before the tween claims it, and flickers under seek).
|
||||
- **No CSS `transition` / `@keyframes` for motion** — CSS animation runs on the browser clock, independent of the HF seek clock; it desyncs and flickers. Drive all motion inside the paused GSAP timeline.
|
||||
- **Entrance + sequential reveal only — no mid-video exit.** The frame unmounts via the harness transition; that injected `transition_in` **is** the exit. Exit motion belongs only to the final frame. (Worker-built seam cuts in `cut-catalog.md` are within-frame, not the frame's exit.)
|
||||
|
||||
## Forbidden — the failure modes
|
||||
|
||||
**Slideshow (the primary failure):** everything dumped on screen in the first ~25%; content enters then freezes; nothing revealed on its VO cue. Fix with rule 2 (sequential reveal timed to the VO).
|
||||
|
||||
**Cheap aliveness:** circular breathing as "life"; a slow pan/push in the back half disrupting the eye; many elements floating independently as "motion." Fix with rule 3 (stillness + subtle jitter only).
|
||||
|
||||
**Bouncy:** `back.out` / `bounce.out` / `elastic.out` as the default entrance; hand-keyed overshoot. Fix with rule 1 (`power3` long-tail; overshoot only when explicitly playful).
|
||||
|
||||
**Always:** no `repeat` / `yoyo`; no `Math.random` / `Date.now`; no all-elements-entering-simultaneously (sequence or stagger).
|
||||
|
||||
## Naming motion in a shot — example
|
||||
|
||||
> Scene 1 (0.0–1.0s): solid field; hero headline enters via **per-word staggered reveal** (`dynamic-content-sequencing`) on a smooth long-tail settle (`power3`); slow **push** on the root (`multi-phase-camera`) holds steady — no back-half re-push.
|
||||
> Scene 2 (1.0–3.0s): as the VO names each changed file, five file chips reveal **sequentially** via **cluster→outward expansion** (`center-outward-expansion`), then a **value-scaled counter** (`counting-dynamic-scale`) ticks the +/− line total up beneath them — the back-half reveal, timed to the script, not dumped at t=0.
|
||||
> Scene 3 (3.0–4.2s): hold on the result; **keyword glow** (`asr-keyword-glow`) lands on the payoff word as the VO says it; settles and holds still — at most **subtle jitter** (`sine-wave-loop`, low amplitude) keeps it alive; no breathing, no drift.
|
||||
|
||||
Name the move + its rule id (or `cut-catalog.md` for a seam cut) per scene; let the worker pick curves, ms, and stagger — defaulting to `power3`.
|
||||
|
||||
@@ -111,7 +111,7 @@ This framework builds **one frame per worker** — there is no multi-frame "cont
|
||||
1. **A consistent stage** — consecutive body frames share one composition idea (the same navy code window filling in, the same before|after split, the same counter advancing), stated in each frame's `scene` so Step 4 and the workers keep the stage stable.
|
||||
2. **A consistent transition** — pick one seam type for a run (`crossfade` for a soft code reveal, `push-slide` for the next change item) and repeat it.
|
||||
|
||||
When a single element genuinely _transforms_ between two ideas (the failing test flips green, the old function becomes the new one), keep it **within one frame** as a development beat (entrance → transform → settle) — the worker owns that motion (a `code-diff` or `code-morph` block). Note the intent in `scene` / narrative; Step 4 turns it into the block + `effects`.
|
||||
When a single element genuinely _transforms_ between two ideas (the failing test flips green, the old function becomes the new one), keep it **within one frame** as a development beat (entrance → transform → settle) — the worker owns that motion (a `code-diff` or `code-morph` block). Note the intent in `scene` / narrative; Step 4 wraps it in a time-coded shot sequence around the block (a `code-diff` / `code-morph`).
|
||||
|
||||
## Transitions
|
||||
|
||||
@@ -133,7 +133,7 @@ Code beats live on the **navy code surface** (claude's Code Surface treatment)
|
||||
|
||||
A diff shows **what changed in the code**. It does **not** show **what the change does** — and "what it does" is usually the more memorable, more explanatory beat. The single biggest reason a PR video feels flat is that every body frame is a code surface or a number: it _tells_ (here are the lines, here is the stat) but never _shows_ (here is the request actually recovering).
|
||||
|
||||
A **`mechanism` frame animates the runtime behavior** the PR changes — built as an **invented animated diagram** (SVG / HTML / GSAP on claude's cream ground: hairline-ink nodes / edges / lanes, one coral marker on the active or changed element), where **the build _is_ the teaching** — each part appears on beat, the flow plays out across the shot. It is **not** a code block and **not** a headline. Reach for the `flowchart` / `flowchart-vertical` / `data-chart` registry blocks where they fit; otherwise invent it (composition.md's diagram / abstract-graphics register).
|
||||
A **`mechanism` frame animates the runtime behavior** the PR changes — built as an **invented animated diagram** (SVG / HTML / GSAP on claude's cream ground: hairline-ink nodes / edges / lanes, one coral marker on the active or changed element), where **the build _is_ the teaching** — each part appears on beat, the flow plays out across the shot. It is **not** a code block and **not** a headline. Reach for the `flowchart` / `flowchart-vertical` / `data-chart` registry blocks where they fit; otherwise invent it (visual-design.md's diagram / abstract-graphics register).
|
||||
|
||||
Plan **at least one `mechanism` beat** for any PR with a visible runtime behavior (most feature and fix PRs have one). What to animate, by what the change touches:
|
||||
|
||||
@@ -172,6 +172,8 @@ The largest quality bug in PR videos is **scripts that talk too long**. TTS runs
|
||||
|
||||
Estimate while writing: `duration ≈ ceil(word_count / 2.2)`. 29 words → 13s (trim); 17 words → 8s; 12 words → 6s. Trim techniques: cut the lead-in clause ("Until now, the agent shipped…" → "The agent shipped…"); move numbers off-script onto a counter; split only when the halves carry distinct beats (cause then effect). **Silent frames are allowed and common** — a diff typing on, a before→after morph, a counter running. Set `voiceover` empty, omit from `SCRIPT.md`, and make `narrativeRole` carry it. A complex change does not need a long script; it needs a careful one — if you can't headline the change in 19 words, the headline isn't sharp yet.
|
||||
|
||||
**Write each line as discrete cues, not one run-on breath.** Step 5 reveals each on-screen piece _when the voiceover names it_ (the anti-PowerPoint mechanism). A line with clear phrase boundaries — "Three retries — then it backs off — then it gives up clean" — hands the shot its reveal cadence for free; a single long clause leaves the frame nothing to pace to.
|
||||
|
||||
## Frame template
|
||||
|
||||
```md
|
||||
@@ -186,6 +188,7 @@ Estimate while writing: `duration ≈ ceil(word_count / 2.2)`. 29 words → 13s
|
||||
- type: diff
|
||||
- persuasion: Before/after contrast
|
||||
- beat: comprehension
|
||||
- blueprint: <candidate id from the role→blueprint menu, or omit — a code beat usually omits it (the code-\* block is the shape)>
|
||||
|
||||
narrativeRole: What this frame does in the viewer's understanding (its job, not what's on screen).
|
||||
keyMessage: The one thing the viewer should understand after this frame (one sentence).
|
||||
@@ -199,6 +202,7 @@ The `credits` frame additionally carries an `asset_candidates:` line (see the cr
|
||||
- The opening uses a named hook strategy; you do not read the PR description aloud.
|
||||
- Each frame has one job; the body builds cumulatively, **alternating `diff` (the code) with `mechanism` (the behavior)** + `impact` / `evidence` — not a single isolated body frame, and not an unbroken stack of code surfaces.
|
||||
- Every frame has `type` (PR-native), `persuasion` (a named technique), and `beat` (specific). The emotional arc matches the archetype (fix = frustration → relief; feature = curiosity → confidence).
|
||||
- Each `voiceover` is phrase-segmented into cues (each a piece Step 5 can reveal on), not one run-on clause; a candidate `blueprint:` is tagged from the role→blueprint menu where a proven shape fits (a code beat usually omits it — the `code-*` block is the shape).
|
||||
- **2–4 real diff hunks** featured, each a small legible snippet (not a whole file), each naming its `code-*` block in `scene`.
|
||||
- **At least one `mechanism` beat** animates what the change _does_ at runtime (an invented diagram, or a `flowchart` / `data-chart`), named in its `scene` — unless the PR genuinely has no visible behavior (a pure docs / config bump). The body is not an unbroken run of code surfaces.
|
||||
- Transitions use only registry names and repeat 2–3 types; frame 1 is `cut`.
|
||||
|
||||
@@ -1,106 +1,164 @@
|
||||
# Visual design — PR-to-video per-frame enrichment method
|
||||
# Visual design — PR-to-video per-frame shot method
|
||||
|
||||
> The method behind **Step 4 (Frame visual design)**. You (the orchestrator) read it to **enrich `STORYBOARD.md` frames in place** — story-design wrote the skeleton (each frame's `scene`, `voiceover`, `transition_in`, and the narrative fields); you add how each frame **looks and moves**. Each frame is a **directed shot, not a static slide** — you choreograph it across its whole duration. Because a PR video is **mostly faceless, most visuals are invented** — typography, number-lockups, diagrams — so you describe visual elements rather than place captured assets; the exceptions are **code beats** (a ready-made `code-*` block) and the **credits close** (real contributor avatars), both covered below. You write **no HTML** (that's the frame workers). `frame.md` is your palette/type truth. Composition / motion detail lives in `composition.md` + `motion-language.md`; effect & blueprint **bodies** live in `hyperframes-animation`. Adding palette theory or a generic font rule here? Wrong home — `frame.md` + `hyperframes-creative`.
|
||||
> The method behind **Step 4 (Frame visual design)**. You (the orchestrator) read it to **enrich `STORYBOARD.md` frames in place** — story-design wrote the skeleton (each frame's `scene`, `voiceover`, `transition_in`, the narrative fields, and optionally a candidate blueprint id); you add how each frame **looks and moves**. The unit you write per frame is a **time-coded shot sequence** — a shot directed across its whole duration, not a static slide. You write **no HTML** (that's the frame workers). A PR video is **mostly invented** — typography, number-lockups, mechanism diagrams — so you **design** those elements; the two exceptions are **code beats** (a ready-made `code-*` registry block) and the **credits close** (real contributor avatars), both covered below. `frame.md` is your palette/type truth by role. Layout is a compact vocabulary in this file (the **Layout** section below), stated inline per Scene; motion vocabulary + the motion doctrine + the seek-safe core → `motion-language.md`; the proven shapes → `../hyperframes-animation/blueprints-index.md` + `blueprints/<id>.md`; the `code-*` blocks → `code-vocabulary.md`; concrete rules resolve in Step 5 from this skill's local `../hyperframes-animation/rules/`. Adding palette theory or a generic font rule here? Wrong home — `frame.md` + `hyperframes-creative`.
|
||||
|
||||
## Every frame is a directed shot
|
||||
## The unit is a time-coded shot sequence
|
||||
|
||||
A frame's visual layer is choreographed across its **full duration**, not front-loaded into an entrance. The failure that reads as PowerPoint: content animates in over the first ~0.8s, then **freezes** while a slow drift plays under it. So every frame's metadata + note describe a **shot with phases** — `entrance → development → settle` — where _development_ (a reveal, a rearrange, a morph, an emphasis hit, a count-up) is the mid-shot motion that separates video from slides. The shot model and the choreography-vs-idle budget live in `motion-language.md`; here you **encode it into the frame**: the `effects` / `blueprint` ids are the motion vocabulary, and the **composition note sequences them into phases**.
|
||||
A frame's visual layer is **a sequence of time windows paced to the voiceover**, not a bag of effect tags. The failure that reads as PowerPoint is **front-loading**: the agent rushes the whole canvas on screen in the first ~25%, and then it just sits. A time-coded shot sequence written **against the VO** makes that impossible: each window states what is on screen and what is moving, and **nothing appears before the voiceover reaches it.** In a PR explainer the development often _is_ the reveal — the diff hunk typing in, the before→after morph, the request-retry diagram running, the impact stat landing. Let the build _be_ the message.
|
||||
|
||||
In explainers, _development_ is often the teaching itself — the formula assembling term by term, the diagram gaining a layer, the count-up landing the statistic. Let the build _be_ the message.
|
||||
Write each frame as a handful of windows cued by the spoken line:
|
||||
|
||||
Deliberate **stillness** is the marked exception — the 2-3 climax/breather frames you allocate in `## Video direction`. Every other frame develops; a held frame outside that allocation is just a slide.
|
||||
```
|
||||
Scene 1 (0.0–Xs): only what the VO is saying at t=0 enters — never the whole canvas
|
||||
Scene 2 (Xs–Ys): the next piece reveals as the VO names it (a file chip / the hunk / a node / a stat)
|
||||
… one window per spoken cue — as many or as few as the line calls for
|
||||
Scene N (…–end): content has resolved; hold the read (stillness; subtle jitter at most)
|
||||
```
|
||||
|
||||
- Each `Scene` line names **what's on screen**, **what moves in this window**, and **where it sits** (layout, inline). Times are real seconds across the frame's `duration`.
|
||||
- **Pace reveals to the voiceover; never front-load.** This is the core anti-PowerPoint mechanism (→ `motion-language.md` Part 2 Rule 2). At t=0 show only what the VO is saying then; reveal each further piece — a line, a file chip, the hunk, a stat — **when the VO names it**, spreading reveals across the shot and especially the **back ~50%**. **The window count = the number of spoken cues the line calls for.** There is **no fixed count and no mandatory "middle" act**; the only sin is dumping everything up front.
|
||||
- **End on a held read.** Once the content has resolved it holds and reads — **prefer stillness to bad motion**: no forced camera drift, no lazy breathing, no back-half pan/push; at most a subtle jitter keeps it alive (→ `motion-language.md`). Only the final frame has a real exit; every other frame's exit is the harness transition (story's `transition_in`).
|
||||
- A **deliberately held** frame — content already revealed, now reading still — is legitimate and often right (a climax, a breather). The failure is never "too still"; it is **front-loaded-then-frozen**. Place held beats deliberately for rhythm (allocate them in `## Video direction`).
|
||||
|
||||
## Pick the shape — instantiate a blueprint
|
||||
|
||||
Don't invent each shot from scratch. The frame's **role** (its `type` / `beat`) points to a proven shape:
|
||||
|
||||
1. **Match the role to a blueprint.** Open `../hyperframes-animation/blueprints-index.md`, find the frame's role in the **role→blueprint menu**, and pick the blueprint whose intent fits this beat (story may already have named a candidate id — confirm or override it). Read that `blueprints/<id>.md`: it is a short, domain-agnostic, **time-coded shot template with `[slots]`** and a named **signature move**.
|
||||
|
||||
2. **Instantiate its `[slots]` with THIS frame's content** — three postures:
|
||||
- **Reproduce** — the blueprint fits the beat and your content maps onto its slots cleanly. Fill every `[slot]` and follow its Scene timing.
|
||||
- **Adapt** — the _structure_ fits but the content / surface doesn't. State **what you keep / what you change** in one line, then write the adapted Scene lines. You may never drop the **signature move**, and you keep the reveals **paced to the VO**.
|
||||
- **Compose** — no blueprint fits the beat. Build the shot from the **motion vocabulary** in `motion-language.md`: still pace reveals to the VO. Mark it `blueprint: compose`.
|
||||
|
||||
3. **Keep the signature move.** Whichever posture, the blueprint's signature move is the spine of the shot — carry it through.
|
||||
|
||||
> A **code beat** is the one place you don't pick a blueprint for the centerpiece — the `code-*` block _is_ the shape (see **PR code beats** below). You still write the Scene sequence for the surrounding surface.
|
||||
|
||||
## What you add to each frame
|
||||
|
||||
Story-design's `## Frame N` block already carries the narrative. You append the visual layer as frame metadata + one composition note (story's role/message prose stays):
|
||||
Story-design's `## Frame N` block already carries the narrative. You append the shot. Story's `scene` / `voiceover` / `transition_in` / role fields stay untouched.
|
||||
|
||||
```
|
||||
## Frame 3 — How interest compounds
|
||||
- scene: a snowball rolls downhill, gaining a labeled ring each turn ← refine only if it could read sharper
|
||||
## Frame 4 — The retry fix
|
||||
- scene: the request() retry hunk lands on the navy code surface ← refine only if it could read sharper
|
||||
- voiceover: "…" ← story's; leave it
|
||||
- transition_in: crossfade ← story's; leave it
|
||||
- type: feature_showcase ← story's
|
||||
- persuasion: Concretization + progressive disclosure
|
||||
- beat: comprehension
|
||||
- effects: scale-in, layer-reveal, count-up ← you add: cite effect ids (≥3, sequenced into the phases below)
|
||||
- blueprint: messaging-multi-phase ← you add (optional): one multi-phase blueprint id
|
||||
- focal: the snowball ← you add: which INVENTED element is the hero
|
||||
- roles: snowball = foreground subject; hill = background gradient; ring labels = supporting ← you add: each invented element's role
|
||||
- sfx: whoosh-soft, tick ← you add: the sound the beat wants (fetched + mounted at root; never yours to embed)
|
||||
- type: diff ← story's (PR-native)
|
||||
- persuasion: Show-the-change
|
||||
- beat: clarity
|
||||
- blueprint: compose ← code beats compose the surround; the block owns the code motion
|
||||
- focal: code-diff — the request() retry block, ~6 lines ← you add: the code-* block IS the focal
|
||||
- roles: code surface = foreground subject · file header = supporting · dim grid = background
|
||||
- sfx: keyclack-soft, soft-confirm
|
||||
|
||||
Entrance: the snowball seats upper-left on a dim hill gradient. Development: it rolls down across the beat, gaining one labeled ring per turn (layer-reveal) while a small total ticks up (count-up). Settle: the final ring emphasis holds; only the slow camera drift continues. A dense, left-anchored frame.
|
||||
Scene 1 (0.0–1.0s): the navy Code Surface window seats in (scale-in + soft shadow), file header "client/request.ts" types on — Centered, ~60% of frame. Slow push-in underneath.
|
||||
Scene 2 (1.0–3.2s): the camera settles onto the hunk; the `code-diff` block runs its own before→after on its cadence (the worker fits it to the duration) — you do not re-specify the code motion.
|
||||
Scene 3 (3.2–4.5s): a coral underline draws on the changed line as the VO names it; a `+6/−2` count-up ticks beside the header; settles and holds STILL.
|
||||
```
|
||||
|
||||
- **`effects`** — name atomic effect **ids** from `hyperframes-animation`'s rules index. **Cite ≥3 when you name no `blueprint`** (the worker composes them into the beat; fewer than 3 reads as generic motion); 1+ as accents when a blueprint already carries the choreography. With no blueprint, those **≥3 effects are the shot's phases** — your note must **sequence them** (one enters, one develops, one emphasizes), not list them as a flat set that all fires at entry. You cite; the worker **reads the recipe body and reproduces it** (not a name-guess).
|
||||
- **`blueprint`** — name **one** multi-phase blueprint id from `hyperframes-animation/blueprints-index.md` when a frame's beat wants a proven multi-phase shape. Two postures — both require the worker to read the recipe body first:
|
||||
- **Reproduce** — the blueprint fits the beat cleanly and the frame's content maps onto its slots; write the composition note shot-by-shot to match.
|
||||
- **Adapt** — the blueprint is the right _structure_ but the content / beat doesn't fit its exact form (or you want a fresher surface). Lead the note with a **`Base / Keep / Depart`** line — `Base:` the blueprint id · `Keep:` its **signature** move (never drop this) · `Depart:` what you change and why. Adapt may **extend or vary, never reduce below the shot model** — never flatten a multi-phase blueprint into a single entrance.
|
||||
The lightweight tags:
|
||||
|
||||
Choose **Reproduce** when the shape fits as-is, **Adapt** when the structure fits but the form doesn't; **omit** `blueprint` entirely when none fits — then the cited `effects` (≥3) carry the phases (**Compose**).
|
||||
- **`blueprint:`** — the id you instantiated (with `(Reproduce)` / `(Adapt)`), or `compose`. One id per frame.
|
||||
- **`focal:`** — for a concept/mechanism beat, the **invented** hero (a hero word, a diagram, a number-lockup); for a **code beat**, the **`code-*` block** (name the block + the hunk); for the **credits** close, the avatar row.
|
||||
- **`roles:`** — each element's role: `foreground subject` · `background` (full-bleed, dim 30–50%) · `supporting`. Invented elements you **design**; the only real assets are the credits `assets/<login>.png` avatars (named in story's `asset_candidates`).
|
||||
- **`sfx:`** — name the sound the beat wants; the audio script's `fetch-sfx` retrieves it and the assembler mounts it at root — you only **name** it, never embed `<audio>`.
|
||||
|
||||
- **`focal` / `roles`** — name the **invented** visual elements and their roles. `focal` is the hero element (a hero word, a diagram node, a chart series, a coined-term card). `roles` assigns each element a role: `foreground subject` (the thing the eye lands on, text laid around it), `background` (full-bleed field/gradient/grid, dim 30-50%), `supporting` (labels, secondary shapes, ambient layers). Since there are no captured assets, you are _designing_ these elements, not selecting them — keep them few and load-bearing. A user-supplied `public/<basename>` image, if any, is named in story's `asset_candidates`; treat it as the `focal` cutout or a `background`.
|
||||
- **`sfx`** — name the sound the beat wants (an impact for a slam, a whoosh for a push, a tick for a count). The audio script's `fetch-sfx` pass retrieves it and the assembler mounts it at the root — you only **name** it, never embed an `<audio>` element.
|
||||
- **composition note** — the frame's visual brief: layout, hero, depth layers, the macro move, **and the shot's phases**. **Default to a phased note** — `entrance: … → development: … → settle: …` (mandatory when you named a `blueprint`). A **single still line** is correct only for a deliberately held climax or an allocated stillness frame. Full method → `composition.md` (layout) + `motion-language.md` (phases).
|
||||
**Layout + motion are stated INLINE in each Scene line** — name the template / density / depth as part of "where it sits", and name the move from `motion-language.md`'s vocabulary; let it settle on a long-tail curve (`power3` default). Never write px / scale / ease curves / ms (the worker writes those).
|
||||
|
||||
## PR code beats — name a `code-*` block (the one place you don't invent)
|
||||
## PR code beats — name a `code-*` block
|
||||
|
||||
(Frame `type` values are PR-native — `diff` / `before_after` / `mechanism` / `impact` / `credits` / … from story-design; the enrichment method below is the same regardless of type.)
|
||||
|
||||
For a `diff` / `before_after` / code beat, the frame's centerpiece is a **ready-made `code-*` registry block**, not an invented HTML visual — the one exception to "invent every visual." In that frame:
|
||||
For a `diff` / `before_after` / code beat, the frame's centerpiece is a **ready-made `code-*` registry block**, not an invented HTML visual — the one exception to "invent every visual."
|
||||
|
||||
- **Name the block in `scene` + `focal`.** Pick the one that fits the beat (before→after = `code-diff`; refactor/rename = `code-morph`; new code written on = `code-typing`; spotlight a line = `code-highlight`; walk a long file = `code-scroll`; a hero reveal = `code-3d-extrude` / `code-particle-assemble`). Full map → `code-vocabulary.md`. Name the hunk too ("the `request()` retry block, ~6 lines"). The block is the `focal`; the Step-5 worker installs + fills it with the real diff.
|
||||
- **`effects` choreograph the surrounding chrome, not the code motion.** The block owns the diff/typewriter/morph animation (it _is_ the development beat). Your `effects` / `blueprint` move the claude **Code Surface** around it — the navy window seating in, a `+N/−M` `count-up`, a coral underline drawing on. Cite 1–3 for that chrome; do not re-specify the code animation itself — the worker only fits the block's cadence to the frame's `data-duration` (a long snippet overruns a short frame otherwise).
|
||||
|
||||
Numbers (`+1,204 / −318`, files touched, perf delta) go on an `impact` / `evidence` frame as a `number-lockup` (claude's Number/Impact treatment) — name it the `focal`, with a `count-up`. The **`credits`** close uses the real `assets/<login>.png` avatars (named in story's `asset_candidates`) as the `focal` — an avatar row; the visual phase features non-empty `asset_candidates` like real assets. A **`mechanism`** frame is also invented — but an **animated diagram of the behavior**, not typography (see the next section). Every other frame (`hook` / `change` / `cta`) is invented typography/graphics per the method above.
|
||||
- **The block owns the code animation; your Scenes choreograph the surrounding Code Surface.** The block _is_ the development beat (the diff/typewriter/morph plays on its own cadence — the worker only fits it to the frame's `data-duration` so a long snippet doesn't overrun). Your Scene windows move the claude **Code Surface** around it: the navy window seating in, the file header typing on, the camera settling onto the hunk, a `+N/−M` `count-up`, a coral underline drawing on the landed line. Name those moves inline; **do not re-specify the code animation itself.** A code beat is usually `blueprint: compose` (the block is the shape).
|
||||
|
||||
## PR mechanism beats — invent an animated diagram of the behavior
|
||||
|
||||
A **`mechanism`** frame is the **show-the-behavior** beat — the antidote to a video that only shows code + text. Its `focal` is an **invented animated diagram** that plays out what the change _does_ at runtime (the request retrying, the cache filling, serial→parallel, the race resolved), **not** a `code-*` block and **not** a headline.
|
||||
A **`mechanism`** frame is the **show-the-behavior** beat — the antidote to a video that only shows code + text. Its `focal` is an **invented animated diagram** that plays out what the change _does_ at runtime (the request retrying, the cache filling, serial→parallel, the race resolved) — **not** a `code-*` block and **not** a headline.
|
||||
|
||||
- **Name the behavior + the diagram in `scene` + `focal`.** e.g. `scene: "animate the request lifecycle — fire → 500 → backoff (delay growing) → retry → 200, invented SVG flow"`; `focal: the request-lifecycle flow`. story-design's "what to animate, by what the change touches" table is the menu. Reach for the `flowchart` / `flowchart-vertical` / `data-chart` registry blocks where they fit (name them in `scene` like a `code-*` block so Step 5 pre-installs them); otherwise the worker builds it in SVG / HTML / GSAP from claude's atoms.
|
||||
- **The build _is_ the development beat.** Unlike a code block (which owns its own animation), the diagram is yours to choreograph: cite **≥3 `effects`** (or a `blueprint`) and **sequence them into the phases** — the lanes / nodes draw on (entrance), the flow runs / the lane splits / the front advances (development), the resolved state + one coral emphasis lands (settle). This is exactly `composition.md`'s "diagram / data-viz where the build is the teaching" register — here the mechanism _is_ the teaching, so never let it enter then freeze.
|
||||
- **Stay on claude's cream ground, hairline-ink.** Nodes / edges / lanes in hairline ink on cream; **one coral marker** on the active or changed element (the retry hop, the cache hit, the new lane); mono labels. Not the navy code surface (that's for code), not heavy shapes / bokeh. Plan it into the top ~83% (caption keep-out).
|
||||
- **Name the behavior + the diagram in `scene` + `focal`.** e.g. `scene: "animate the request lifecycle — fire → 500 → backoff → retry → 200, invented SVG flow"`; `focal: the request-lifecycle flow`. Reach for the `flowchart` / `flowchart-vertical` / `data-chart` registry blocks where they fit (name them in `scene` so Step 5 pre-installs them); otherwise the worker builds it in SVG / HTML / GSAP from claude's atoms.
|
||||
- **The build IS the shot sequence.** Unlike a code block (which owns its own animation), the diagram is yours to choreograph across the Scene windows — the lanes / nodes draw on (Scene 1), the flow runs / the lane splits / the front advances as the VO names each step (middle Scenes), the resolved state + one coral emphasis lands (final Scene). Never let it enter then freeze.
|
||||
- **Stay on claude's cream ground, hairline-ink.** Nodes / edges / lanes in hairline ink on cream; **one coral marker** on the active or changed element; mono labels. Not the navy code surface (that's for code), not heavy shapes / bokeh. Plan it into the top ~83% (caption keep-out).
|
||||
|
||||
`focal` / `roles` name the invented diagram and its parts (the lanes = `foreground subject`; a timeline axis = `supporting`; a dim grid = `background`). A `mechanism` frame carries **no** `asset_candidates` (it's invented, like every non-credits frame).
|
||||
A `mechanism` frame carries **no** `asset_candidates` (it's invented, like every non-credits frame).
|
||||
|
||||
## Video direction — write the invariants ONCE
|
||||
## Impact & credits
|
||||
|
||||
The whole video shares one look and one motion grammar. State it **once**, at the top of `STORYBOARD.md` (a `## Video direction` block), so every frame inherits it and per-frame metadata carries only the **delta**:
|
||||
- **Impact / evidence** — numbers (`+1,204 / −318`, files touched, perf delta) go on an `impact` frame as a **`number-lockup`** (claude's Number/Impact treatment): name it the `focal`, reveal it with a `count-up` paced to the VO.
|
||||
- **Credits close** — the optional `credits` frame uses the real `assets/<login>.png` avatars (named in story's `asset_candidates`) as the `focal`: an avatar row that staggers in. This is the one frame with non-empty `asset_candidates` and real assets.
|
||||
|
||||
- **palette system** — from `frame.md`: which roles map to which hues. Never invent.
|
||||
- **motion defaults + shot model** — default eases + the **choreography baseline** (every frame a directed shot: entrance → development → settle) + the **idle-life budget** (what may keep moving during the hold) (→ `motion-language.md`).
|
||||
- **negative list** — what never appears: off-brand textures the pack forbids, **plus both motion failure modes** — slideshow (enter-then-freeze) and screensaver (everything floating independently) (→ `motion-language.md`).
|
||||
- **stillness allocation** — name the 2-3 frames that hold still before a climax; every other frame develops.
|
||||
## Inventing the visual (non-code beats)
|
||||
|
||||
Do **not** repeat these in every frame — each frame's metadata is the delta on top of Video direction.
|
||||
Every non-code, non-credits beat (`hook` / `change` / `cta` / concept) is **designed**, not captured. Three first-class treatments:
|
||||
|
||||
- **Typographic / kinetic type** — a hero word, the PR's headline claim, a stat. Treat type as the subject: full-bleed scale, weight contrast, one emphasized term. Strongest for hooks and the cta.
|
||||
- **Abstract graphics** — shapes / paths / geometry that _embody_ the idea the script names; don't decorate with generic bokeh.
|
||||
- **Diagram / data-viz** — the mechanism diagrams above, a `data-chart` for a perf delta, a number-lockup. The build (each part on beat) is the teaching — design it to assemble across the Scenes.
|
||||
|
||||
Make the invented hero **fill 40–60% of the frame** — big enough to read; don't shrink the one designed element into decoration around empty space.
|
||||
|
||||
## Layout — named inline per Scene
|
||||
|
||||
State each Scene's layout as part of "where it sits." **If the blueprint (or the code-\* block) already implies a composition, that wins** — describe it directly; the vocabulary below is for composing freely. Never write px / scale / shadow (the worker does). One frame's layout can EVOLVE across its Scenes. Use **≥3 different framings per video**; never the same framing twice in a row.
|
||||
|
||||
- **Framing vocabulary** — centered (hero / climax / a single code surface) · rule-of-thirds · split-screen (before/after, two surfaces) · layered-depth (immersive) · asymmetric 60/40 or 70/30 (a code surface + a caption rail) · triptych (three changes at once) · full-width strip (a file list / timeline). Let the beat decide, not a quota.
|
||||
- **Density** — primary visual ≥ 40% of canvas; ≥ 3 depth layers; never a lone small cluster floating in empty space. Openings/closings are prone to emptiness — add environmental layers (a dim grid, low-opacity scanlines, brand-color ambient). Squint test: after blur you can still pick out the #1 element.
|
||||
- **Hierarchy** — combine ≥ 2 of size (3:1) / weight (800 vs 400) / contrast / position (upper-third is golden) / motion, so one element clearly dominates.
|
||||
- **Depth** — layer 2–3 of: size, blur, opacity gradient, overlap, shadow-stack, counter-scale on a push.
|
||||
- **Don't show**: nav bars, footers, scrollbars, real cursors / browser chrome, generic decorative shapes, floating bokeh / purple-blue "AI" gradients (banned). The navy code surface is for code beats only; mechanism diagrams stay on cream.
|
||||
|
||||
## Portrait & square (non-16:9 canvases)
|
||||
|
||||
The zones, density, hierarchy, and depth principles all still apply; the **aspect ratio** changes, and a wide layout doesn't transplant into a tall one — design for the storyboard's `format` from the start.
|
||||
|
||||
- **Stack vertically, not side-by-side** — split-screen / triptych / 60-40 become top/bottom stacks. A code surface runs nearly full-width in portrait with fewer visible lines.
|
||||
- **Vertical center moves with the canvas** — anchor a centered hero around **y ≈ 0.42 × height** (portrait ≈806, square ≈454), not a fixed 540.
|
||||
- **Type runs larger, fewer words per line.** **Travels well to portrait:** Centered, Layered Depth, Full-Width Strip; **avoid** wide Split Screen / Triptych — use stacked equivalents.
|
||||
|
||||
## `## Video direction` — write the invariants ONCE
|
||||
|
||||
The whole video shares one look and one motion grammar. Write a **`## Video direction`** block ONCE at the top of `STORYBOARD.md` so every frame inherits it and per-frame Scene lines carry only the **delta**. This block is load-bearing — **keep it.**
|
||||
|
||||
- **palette system** — from `frame.md` (claude): which roles map to which hues. Never invent.
|
||||
- **motion grammar + reveal model** — long-tail eases (`power3` default, smooth over bouncy) + the **VO-paced reveal** model + what may stay alive during a hold (subtle jitter at most) (→ `motion-language.md`).
|
||||
- **rhythm / held-frame allocation** — name the **held / breather frames** so the video varies its energy.
|
||||
- **negative list** — off-brand textures, **plus both motion failure modes** — slideshow (front-load then freeze) and screensaver (everything floating independently) (→ `motion-language.md`).
|
||||
|
||||
Do **not** repeat these per frame.
|
||||
|
||||
## Palette & type — from `frame.md`, never invented
|
||||
|
||||
- **Palette** — `frame.md` (the adopted pack) is the color truth; apply its roles per frame. Generic basics (one accent, tint neutrals, avoid pure `#000`/`#fff`) → `hyperframes-creative/references/house-style.md`.
|
||||
- **Type** — fonts resolve via `frame.md`'s type tokens; reference them **by role** (display / body / mono / the pack's ramp), never by raw family or px. Typography craft (embedded fonts, dark-bg optical compensation, `tabular-nums`) → `hyperframes-creative/references/typography.md`. In a faceless explainer, **type is often the primary visual** — the hero word, the coined term, the kinetic enumeration — so lean on the type ramp hard.
|
||||
- **Palette** — `frame.md` (claude) is the color truth; apply its roles per frame. Generic basics → `hyperframes-creative/references/house-style.md`.
|
||||
- **Type** — fonts resolve via `frame.md`'s type tokens; reference them **by role** (display / body / mono / the pack's ramp), never by raw family or px. Code surfaces and mechanism labels use the **mono** role. Typography craft → `hyperframes-creative/references/typography.md`.
|
||||
|
||||
## Caption-band keep-out (plan side)
|
||||
|
||||
The bottom ~17% of the canvas is reserved for the caption pill. Plan every frame's content into the **top ~83%** so nothing important lands in the band (the worker enforces the pixel cutoff; you plan the layout). Holds even when captions are disabled — bottom-edge consistency. Geometry detail → `composition.md`.
|
||||
The bottom ~17% of the canvas is reserved for the caption pill. Plan every frame's content into the **top ~83%** (the worker enforces the pixel cutoff). When captions are enabled, primary content caps at the band top, and a centered hero anchors at **y ≈ 0.42 × height** (landscape ≈454, portrait ≈806); background / ambient layers are exempt and may stay full-bleed. Holds even when captions are disabled — bottom-edge consistency.
|
||||
|
||||
## Where the detail lives
|
||||
|
||||
| For… | Read |
|
||||
| ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| composition — zones, density, templates, invented-visual prominence, caption geometry | `composition.md` (local) |
|
||||
| motion — the shot model, phases, idle budget, beat structure, stillness | `motion-language.md` (local) |
|
||||
| effect ids + blueprint ids (vocabulary + recipes) | `../hyperframes-animation/blueprints-index.md` + `../hyperframes-animation/rules-index.md` |
|
||||
| palette + type tokens | the project's `frame.md`; basics → `hyperframes-creative` `house-style.md` / `typography.md` |
|
||||
| transitions | story-design owns `transition_in`; you don't touch it |
|
||||
| For… | Read |
|
||||
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
|
||||
| the proven shapes + role→blueprint menu + how to pick | `../hyperframes-animation/blueprints-index.md` → `blueprints/<id>.md` |
|
||||
| the `code-*` blocks (pick + fill for a code beat) | `code-vocabulary.md` (local) |
|
||||
| motion — shot model, vocabulary, holds, idle budget, stillness, seek-safe | `motion-language.md` (local) |
|
||||
| layout — framing, density, depth, hierarchy, inventing the visual, caption band | the **Layout** + **Inventing the visual** sections in this file |
|
||||
| concrete eases / ms / stagger + rule recipe bodies (Step 5) | local `../hyperframes-animation/rules/` (the frame worker reads it; you don't) |
|
||||
| palette + type tokens | the project's `frame.md` (claude); basics → `hyperframes-creative` |
|
||||
| within-frame cuts / seams (zoom-through · cut-the-curve · waterfall) | `cut-catalog.md` (the worker builds them inside the composition) |
|
||||
| transitions | story-design owns `transition_in`; you don't touch it |
|
||||
|
||||
## Before you finish — checklist
|
||||
|
||||
- Every frame has `effects` (≥1 cited id; **≥3 when no `blueprint`** is named); a `blueprint` where the frame matches one, with a shot-by-shot composition note.
|
||||
- **Every frame's composition note is phased** (entrance → development → settle) — not a single entry that then freezes; the ≥3 effects are **sequenced across phases**, not all fired at t=0.
|
||||
- **Stillness is only the 2-3 frames allocated in Video direction**; every other frame develops mid-shot.
|
||||
- Each frame names its **invented** `focal` + per-element `roles` (foreground / background / supporting), kept few and load-bearing.
|
||||
- A `mechanism` frame's `focal` is an **invented animated diagram of the behavior** (or a `flowchart` / `data-chart`), choreographed across its phases — not a code block, not typography; the body is not an unbroken run of code surfaces.
|
||||
- **Video direction** stated once at the top (palette · shot model + idle budget · negative list incl. both failure modes · stillness allocation); per-frame entries are deltas.
|
||||
- Content planned into the top ~83% (caption band clear).
|
||||
- Palette / type pulled from `frame.md` by role — nothing invented.
|
||||
- **`## Video direction`** written once at the top (palette · motion grammar + shot model + idle budget · stillness allocation · negative list incl. both failure modes); per-frame entries are deltas.
|
||||
- Every frame is a **time-coded shot sequence** with real second windows across its `duration` — not a tag bag.
|
||||
- **No frame front-loads** — at t=0 only what the VO is saying enters; each further piece reveals on its spoken cue, across the back ~50%. Window count follows the VO.
|
||||
- Every frame names a **`blueprint:`** id (Reproduce / Adapt) or `compose`; an Adapt keeps the signature move; nothing collapses to a single front-loaded dump.
|
||||
- **Code beats** name a `code-*` block as the `focal`, let the block own the code animation, and choreograph only the surrounding Code Surface in the Scenes.
|
||||
- **Mechanism beats** name an **invented animated diagram of the behavior** (or a `flowchart` / `data-chart`), choreographed across the Scenes on claude's cream ground with one coral marker — not a code block, not typography; the body is not an unbroken run of code surfaces.
|
||||
- **Impact** uses a `number-lockup` with a `count-up`; the **credits** close uses the real avatars as the `focal`.
|
||||
- Each non-code, non-credits frame names its **invented** `focal` + per-element `roles`, kept few and load-bearing.
|
||||
- Layout + motion named **inline** per Scene (no px / ease curves / ms / JS).
|
||||
- Content planned into the top ~83% (caption band clear); palette / type pulled from `frame.md` by role.
|
||||
- You wrote no HTML.
|
||||
|
||||
Reference in New Issue
Block a user