diff --git a/skills-manifest.json b/skills-manifest.json index d8591b9eb6..acb94dd4a1 100644 --- a/skills-manifest.json +++ b/skills-manifest.json @@ -6,7 +6,7 @@ "files": 144 }, "faceless-explainer": { - "hash": "8f89def06adfe745", + "hash": "b94e52c77d04c1ea", "files": 17 }, "general-video": { @@ -54,7 +54,7 @@ "files": 132 }, "pr-to-video": { - "hash": "f2014a51c7a052bd", + "hash": "85a7577aee41bb82", "files": 21 }, "product-launch-video": { diff --git a/skills/faceless-explainer/SKILL.md b/skills/faceless-explainer/SKILL.md index 28b84de747..30667133a6 100644 --- a/skills/faceless-explainer/SKILL.md +++ b/skills/faceless-explainer/SKILL.md @@ -1,6 +1,6 @@ --- name: faceless-explainer -description: "turn arbitrary text — an article, notes, a topic, a brief — into a faceless explainer video, up to ~3 min (sweet spot 30-90s), where every visual is invented (typography, abstract graphics, diagrams, data-viz) rather than captured. There is no URL, no website capture, and no real assets. Use this skill for topic explainers, concept breakdowns, how-tos, listicles, and narrative explainers. Do not use it for a product launch/promo (use /product-launch-video), a tour of a real website (use /website-to-video), a GitHub PR (use /pr-to-video), captions on existing footage (use /embedded-captions), or a short unnarrated motion graphic (use /motion-graphics). If the intent is unclear, route through /hyperframes first." +description: "turn arbitrary text — an article, notes, a topic, a brief — into a faceless explainer video, up to ~3 min (sweet spot 30-90s), where every visual is invented (typography, abstract graphics, diagrams, data-viz) rather than captured. There is no URL, no website capture, and no real assets. Use this skill for topic explainers, concept breakdowns, how-tos, listicles, and narrative explainers. Do not use it for a product launch/promo (use /product-launch-video), a tour of a real website (use /website-to-video), a GitHub PR (use /pr-to-video), captions on existing footage (use /embedded-captions), or a short unnarrated motion graphic (use /motion-graphics). If the intent is unclear, route through /hyperframes first. This is the shot-sequence architecture: every frame is authored as a time-coded shot sequence picked from a menu of golden blueprints, so frames develop over their full duration instead of freezing after entrance." --- > **media-use**: Before sourcing audio/images, call `/media-use` to resolve BGM/SFX/images from the HeyGen catalog. Run `--adopt` first to register existing assets. See `/media-use` skill. @@ -11,7 +11,7 @@ Use this skill to turn a body of text into an explainer video: pick a design sys > **Confirm the route before Step 0.** You are the orchestrator. Run each step, verify its gate, and only then continue. This skill is for **explaining a topic from text, with no product and no website to capture**. Route other intents elsewhere: a product launch/promo → `/product-launch-video`; a tour of a real site → `/website-to-video`; a GitHub PR → `/pr-to-video`; captions on existing footage → `/embedded-captions`; a short unnarrated motion graphic → `/motion-graphics`. If the user says only "make a video" or the route is uncertain, read `/hyperframes` first. -You are the orchestrator. Work in `videos//`. Run steps in order and pass each gate before continuing. User-gated steps are Step 0, Step 3, and Step 6. Do every step yourself except Step 5, where you dispatch one sub-agent per frame. Do not put design or motion rules here; those live in the frame-worker sub-agent, `hyperframes-creative`, and `hyperframes-animation`. +You are the orchestrator. Work in `videos//`. Run steps in order and pass each gate before continuing. User-gated steps are Step 0, Step 3, and Step 6. Do every step yourself except Step 5, where you dispatch one sub-agent per frame. Do not put design or motion rules here; those live in the frame-worker sub-agent, this skill's local `../hyperframes-animation/rules/` + `../hyperframes-animation/blueprints/`, and `hyperframes-creative`. Workflow: Step 0 setup → `hyperframes.json`; Step 1 brief → `capture/extracted/`; Step 2 design system → `frame.md`; Step 3 storyboard/script → `STORYBOARD.md` and `SCRIPT.md`; Step 3.1 audio → `audio_meta.json`; Step 4 visual design → enriched `STORYBOARD.md`; Step 5 frames → `compositions/frames/NN-*.html` and `index.html`; Step 6 final render → `renders/video.mp4`. @@ -40,6 +40,8 @@ Save the user's full input verbatim, then create the synthetic capture package b - `capture/extracted/visible-text.txt` — the full article / notes / topic / brief, verbatim. This is the source of **information**, not a story template (Step 3 reshapes it). - `capture/extracted/tokens.json` — `{ "title": "", "description": "", "colors": [], "fonts": [] }`. Fill `title`/`description` from the brief. Leave `colors`/`fonts` empty unless the user explicitly gave brand colors or fonts — then add them (the design preset supplies a complete palette regardless). +If the user pasted a script or wants their wording kept, save it verbatim as `user_script.txt`, ask once "use it verbatim or restructure?", and store the answer as `VO_MODE` for Step 3. + Do **not** run `npx hyperframes capture` (there is no URL). Do not create `asset-descriptions.md` or populate `capture/assets/` — faceless visuals are invented in Steps 4-5, not captured. The one exception: if the user supplied a real image, place it under `public/` and note it for Step 3. **Gate:** `capture/extracted/visible-text.txt` and `capture/extracted/tokens.json` exist; you can state the explainer's topic and audience in one clear sentence. @@ -68,9 +70,9 @@ A faceless explainer usually has **no brand colors/fonts** (`tokens.json` colors Goal: Turn the text into an approved frame-by-frame teaching plan. -Read `references/story-design.md`, `../hyperframes-core/references/storyboard-format.md`, and `../hyperframes-core/references/script-format.md`. Use them to write `STORYBOARD.md` and, when narration is needed, `SCRIPT.md`. +Read `references/story-design.md`, `../hyperframes-animation/blueprints-index.md`, `../hyperframes-core/references/storyboard-format.md`, and `../hyperframes-core/references/script-format.md`. Use them to write `STORYBOARD.md` and, when narration is needed, `SCRIPT.md`. -Use `story-design.md` for the explainer structure (concept / how-to / listicle / story), hook strategy, clarity techniques, emotional beats, the type-enum mapping, and `VO_MODE`. The video's sequence comes from **narrative design, not the input text's paragraph order** — reorder, merge, omit, compress. Faceless visuals are invented downstream, so frames do **not** carry an asset inventory: leave `asset_candidates` empty unless the user supplied a real `public/` image. Use the exact required fields from the storyboard and script references. +Use `story-design.md` for the explainer structure (concept / how-to / listicle / story), hook strategy, clarity techniques, emotional beats, the type-enum mapping, and `VO_MODE`. The video's sequence comes from **narrative design, not the input text's paragraph order** — reorder, merge, omit, compress. As a **soft guide**, consult the role→blueprint menu in `../hyperframes-animation/blueprints-index.md`: for each beat, write the voiceover in the shape its candidate blueprint implies and tag that candidate `blueprint:` id when one fits. Teaching truth still decides which beats exist — never force a beat to fit a blueprint, and never invent a beat just because a proven shape is available. Faceless visuals are invented downstream, so frames do **not** carry an asset inventory: leave `asset_candidates` empty unless the user supplied a real `public/` image. Use the exact required fields from the storyboard and script references. After drafting, show a frame-by-frame summary. In that same message ask the user two things: (a) to approve or request changes, and (b) whether they want a live preview of the storyboard scaffold (`npx hyperframes preview`) — open it only on a yes. Iterate until approved, and carry the preview choice to Step 6. @@ -98,15 +100,15 @@ If there is no narration and no `SCRIPT.md`, skip voice generation. BGM may stil Goal: Add the visual direction, layout intent, and motion choices to each storyboard frame. -Edit `STORYBOARD.md` in place. Do not create another storyboard. Use `frame.md` as the source of truth for color, type, layout feel, and style. +Edit `STORYBOARD.md` in place. Do not create another storyboard. Use `frame.md` as source of truth for color, type, layout feel, and style. -Read `references/visual-design.md`, `references/composition.md`, `references/motion-language.md`, and `../hyperframes-animation/`. Use `visual-design.md` for required frame fields and the required `## Video direction` block. Use `composition.md` for layout, hierarchy, focal points, and the invented-visual treatment. Use `motion-language.md` and `../hyperframes-animation/` for valid effects and blueprint IDs. Do not invent effect names or blueprint IDs. +Read `references/visual-design.md`, `../hyperframes-animation/blueprints-index.md`, `references/motion-language.md`, and `../hyperframes-animation/rules-index.md`. Use `visual-design.md` for the method (the time-coded shot sequence, the inline Layout vocabulary, and the invented-visual treatment), plus the required `## Video direction` block. Use `../hyperframes-animation/blueprints-index.md` to pick each frame's shot shape. Use `motion-language.md` (the motion vocabulary + the motion doctrine) and `../hyperframes-animation/rules-index.md` (valid rule names) for motion — do not invent motion names. -For every frame, add required visual and motion fields, including `effects` and `focal` and/or `roles`. Because the explainer is faceless, `focal`/`roles` describe **invented visual elements** (a hero word, a diagram node, a data-viz series), not captured assets. Add one video-wide `## Video direction` block for overall visual direction, motion style, pacing, and design rules. +For every frame, write a **time-coded shot sequence** into `STORYBOARD.md` per `visual-design.md`'s method: pick the frame's blueprint (or compose), instantiate it with THIS frame's **invented** content, and pace each Scene's reveal to the voiceover so the frame develops across its full duration instead of front-loading then freezing. Because the explainer is faceless, `focal`/`roles` name the **invented visual elements** (a hero word, a diagram node, a data-viz series) — you are designing them, not selecting captured assets. State layout and motion **inline** per Scene (vocabularies in `visual-design.md` and `motion-language.md`). Add one video-wide `## Video direction` block. Do not change story, script, `transition_in`, or the source text. Do not write HTML in this step. There is **no asset-staging step** — faceless visuals are built by the workers in Step 5. If the user supplied a real `public/` image, reference it by path in the relevant frame's `focal`/`roles`; otherwise nothing to stage. -**Gate:** every frame has `effects` plus `focal` and/or `roles`; `## Video direction` exists. +**Gate:** every frame has a time-coded shot sequence whose reveals are paced to the voiceover (no front-loading); each frame names its invented `focal` and/or `roles`; `## Video direction` exists. --- @@ -124,7 +126,7 @@ Duration sync is mechanical: real voice duration wins; silent frames keep estima Before dispatch, read `sub-agents/frame-worker.md` and `../hyperframes-core/references/subagent-dispatch.md`. Dispatch one sub-agent per frame, in parallel if possible; otherwise run workers in waves. Each worker gets exactly one frame. -Each worker context must include `PROJECT_DIR`, `frame_id`, canvas size, caption status and keep-out band if captions are enabled, and `ANIM_DIR` as the absolute path to `../hyperframes-animation/`. Each worker reads `frame.md`, its own `## Frame N` block from `STORYBOARD.md`, and the recipe body for each cited effect or blueprint ID. Each worker writes only `compositions/frames/NN-*.html`. Workers must never edit `STORYBOARD.md`. +Each worker context must include `PROJECT_DIR`, `frame_id`, canvas size, caption status and keep-out band if captions are enabled, and `RULES_DIR` as the absolute path to this skill's `../hyperframes-animation/rules/`. Each worker reads `frame.md`, its own `## Frame N` block from `STORYBOARD.md`, the local rule recipe (`../hyperframes-animation/rules/.md`) for each cited motion, and the frame's blueprint template (`../hyperframes-animation/blueprints/.md`). Each worker writes only `compositions/frames/NN-*.html`. Workers must never edit `STORYBOARD.md`. As each worker returns, the orchestrator marks that frame as `animated` in `STORYBOARD.md`. @@ -186,17 +188,20 @@ Do not rerun `lint`, `validate`, `inspect`, or `snapshot` after rendering unless **Background scripts:** the workflow ships only these under `scripts/`: `build-frame` for adopting + brand-remixing a frame preset into `frame.md` (+ caption skin); `audio` for TTS, transcription, BGM, SFX, and duration syncing; `captions`; `transitions` for inject and verify; and `assemble-index`. Everything else is the `hyperframes` CLI. -| Read | When | -| ------------------------------------------------------------------------------------------------------------ | --------------------------------------------- | -| `[../hyperframes-creative/frame-presets/](../hyperframes-creative/frame-presets/)` | Step 2: choose and adopt a frame preset. | -| `[../hyperframes-creative/references/design-spec.md](../hyperframes-creative/references/design-spec.md)` | Step 2: apply brand tokens correctly. | -| `[references/story-design.md](references/story-design.md)` | Step 3: plan the explainer story. | -| `[../hyperframes-core/references/storyboard-format.md](../hyperframes-core/references/storyboard-format.md)` | Step 3: write `STORYBOARD.md`. | -| `[../hyperframes-core/references/script-format.md](../hyperframes-core/references/script-format.md)` | Step 3: write `SCRIPT.md`. | -| `[../hyperframes-media/references/tts.md](../hyperframes-media/references/tts.md)` | Step 3.1: choose or understand TTS providers. | -| `[references/visual-design.md](references/visual-design.md)` | Step 4: enrich the storyboard visually. | -| `[references/composition.md](references/composition.md)` | Step 4: judge composition. | -| `[references/motion-language.md](references/motion-language.md)` | Step 4: judge motion language. | -| `[../hyperframes-animation/](../hyperframes-animation/)` | Step 4: cite effect and blueprint IDs. | -| `[sub-agents/frame-worker.md](sub-agents/frame-worker.md)` | Step 5: dispatch per-frame workers. | -| `[../hyperframes-core/references/subagent-dispatch.md](../hyperframes-core/references/subagent-dispatch.md)` | Step 5: dispatch sub-agents safely. | +The reusable, domain-agnostic shot shapes live in `../hyperframes-animation/blueprints/` (indexed by `../hyperframes-animation/blueprints-index.md`). + +| Read | When | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | +| `[../hyperframes-creative/frame-presets/](../hyperframes-creative/frame-presets/)` | Step 2: choose and adopt a frame preset. | +| `[../hyperframes-creative/references/design-spec.md](../hyperframes-creative/references/design-spec.md)` | Step 2: apply brand tokens correctly. | +| `[references/story-design.md](references/story-design.md)` | Step 3: plan the explainer story. | +| `[../hyperframes-animation/blueprints-index.md](../hyperframes-animation/blueprints-index.md)` | Step 3: role→blueprint menu. Step 4: pick the shot shape. | +| `[../hyperframes-core/references/storyboard-format.md](../hyperframes-core/references/storyboard-format.md)` | Step 3: write `STORYBOARD.md`. | +| `[../hyperframes-core/references/script-format.md](../hyperframes-core/references/script-format.md)` | Step 3: write `SCRIPT.md`. | +| `[../hyperframes-media/references/tts.md](../hyperframes-media/references/tts.md)` | Step 3.1: choose or understand TTS providers and voices. | +| `[references/visual-design.md](references/visual-design.md)` | Step 4: write the frame's shot sequence (+ Layout vocabulary). | +| `[references/motion-language.md](references/motion-language.md)` | Step 4: the motion vocabulary + the motion doctrine. | +| `[references/cut-catalog.md](references/cut-catalog.md)` | Step 4-5: the cut catalog (worker builds within-frame seams). | +| `[../hyperframes-animation/rules-index.md](../hyperframes-animation/rules-index.md)` + `[../hyperframes-animation/rules/](../hyperframes-animation/rules/)` | Step 5: local rule recipe bodies for the cited motions. | +| `[sub-agents/frame-worker.md](sub-agents/frame-worker.md)` | Step 5: dispatch per-frame workers. | +| `[../hyperframes-core/references/subagent-dispatch.md](../hyperframes-core/references/subagent-dispatch.md)` | Step 5: dispatch sub-agents safely. | diff --git a/skills/faceless-explainer/references/composition.md b/skills/faceless-explainer/references/composition.md deleted file mode 100644 index 2bd694fb54..0000000000 --- a/skills/faceless-explainer/references/composition.md +++ /dev/null @@ -1,123 +0,0 @@ -# Composition — faceless-explainer 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). diff --git a/skills/faceless-explainer/references/cut-catalog.md b/skills/faceless-explainer/references/cut-catalog.md new file mode 100644 index 0000000000..9aef70e408 --- /dev/null +++ b/skills/faceless-explainer/references/cut-catalog.md @@ -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 | diff --git a/skills/faceless-explainer/references/motion-language.md b/skills/faceless-explainer/references/motion-language.md index bcb8268bd5..e1ec693462 100644 --- a/skills/faceless-explainer/references/motion-language.md +++ b/skills/faceless-explainer/references/motion-language.md @@ -1,141 +1,156 @@ -# Motion language — faceless-explainer 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/.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 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 an explainer the development _is_ the teaching: the formula assembling, the diagram gaining a layer, the count-up 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 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 step, five mechanism nodes reveal **sequentially** via **cluster→outward expansion** (`center-outward-expansion`), then a **value-scaled counter** (`counting-dynamic-scale`) ticks 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`. diff --git a/skills/faceless-explainer/references/story-design.md b/skills/faceless-explainer/references/story-design.md index fc90611396..b22a97e862 100644 --- a/skills/faceless-explainer/references/story-design.md +++ b/skills/faceless-explainer/references/story-design.md @@ -85,6 +85,7 @@ For every frame, define (use the storyboard format's fields, with these narrativ - `scene` — a one-line visual idea, not detailed composition. - `voiceover` — spoken guide text, or empty for silent frames. - `transition_in` — a registry transition name (see Transitions). +- `blueprint` _(optional candidate)_ — consult the role→blueprint menu in `../hyperframes-animation/blueprints-index.md`; when a proven shape fits this beat, tag its id (a tag, not a commitment — Step 4 confirms or overrides). Then **write the `voiceover` in the shape that blueprint implies**, so the line is reveal-ready before Step 4 ever runs. Teaching truth still decides which beats exist — never invent, drop, or bend a beat just to fit a shape; omit `blueprint` and write the line plainly when none fits. In the prose under each frame, state: @@ -93,7 +94,7 @@ In the prose under each frame, state: ### Type-enum repurposing (shared enum → explainer roles) -The enum is shared with the product-launch visual layer; map your explainer roles onto it so downstream pacing matches the frame's job: +The enum is shared with the downstream visual layer; map your explainer roles onto it so downstream pacing matches the frame's job: | Explainer role you want | Use `type` | Why this value | | -------------------------------- | ------------------- | -------------------------------------------------------------------- | @@ -168,7 +169,7 @@ This framework builds **one frame per worker** — there is no "continue run" th 1. **A consistent stage** — consecutive body frames share the same composition idea (same diagram growing, same number line, same desk), 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 sequence (usually `push-slide ` for ordered steps, `crossfade` for a soft layer reveal) and repeat it across the run, so the frames feel like one flow rather than separate slides. -When a single element genuinely _transforms_ between two ideas (a diagram node becomes a chart bar, a formula becomes its result), keep it within **one frame** as a development beat (entrance → the transform → settle) rather than splitting it across a seam — the worker owns that motion. Note the intent in the frame's `scene` / narrative; Step 4 turns it into `effects` / `blueprint`. +When a single element genuinely _transforms_ between two ideas (a diagram node becomes a chart bar, a formula becomes its result), keep it within **one frame** as a development beat (entrance → the transform → settle) rather than splitting it across a seam — the worker owns that motion. Note the intent in the frame's `scene` / narrative; Step 4 turns it into a time-coded shot sequence (instantiating the candidate `blueprint`). ## Transitions @@ -193,6 +194,7 @@ Write tight per-frame narration: - 1-2 sentences per spoken frame; usually 6-20 words. - Concrete and human; teach, don't read the article aloud. +- **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 — "First the snowball — then the hill — then the speed" — hands the shot its reveal cadence for free; a single long clause leaves the frame nothing to pace to. - **Strong** (concretization): "Compound interest isn't addition, it's a snowball — every turn picks up the snow from the last, then more." - **Weak** (article-paraphrase): "The study, published in 2019, examined three cohorts and found that…" — that is reading, not explaining. @@ -224,6 +226,7 @@ Use the exact fields required by the core storyboard format. This is the narrati - type: feature_showcase - persuasion: Progressive disclosure - beat: comprehension +- blueprint: messaging-multi-phase — candidate shape from the role→blueprint menu; omit when none fits narrativeRole: What this frame does in the viewer's understanding. keyMessage: The one idea the viewer should remember. @@ -237,6 +240,7 @@ Before asking for user approval, verify: - The opening uses a named hook strategy. - Each frame has one job; the body builds cumulatively (a run of `feature_showcase` / `benefit_highlight` / `product_intro`), not a single isolated body frame. - Every frame has `type`, `persuasion` (a named technique from the catalog), and `beat` (specific, not generic). +- 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 wherever a proven shape fits, and omitted where none does. - The emotional arc has meaningful variation matching the structure. - Transitions use only registry names and repeat 2-3 types; frame 1 is `cut`. - A consistent stage + consistent transition carry any multi-frame sequence; a genuine element transform stays inside one frame. diff --git a/skills/faceless-explainer/references/visual-design.md b/skills/faceless-explainer/references/visual-design.md index 6533caa46b..9c65b20827 100644 --- a/skills/faceless-explainer/references/visual-design.md +++ b/skills/faceless-explainer/references/visual-design.md @@ -1,18 +1,43 @@ -# Visual design — faceless-explainer per-frame enrichment method +# Visual design — faceless-explainer 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 the explainer is **faceless, every visual is invented** — typography, abstract graphics, diagrams, data-viz — so you describe the visual elements rather than place captured assets. 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). Because the explainer is **faceless, every visual is invented** — typography, abstract graphics, diagrams, data-viz — so you **design** the visual elements rather than select captured assets (there is no `capture/` to read). `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/.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 an explainer the development _is_ the teaching — the formula assembling term by term, the diagram gaining a layer, the count-up landing the statistic. 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 line / layer / node / 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 layer, even an h1 — **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** — a two-beat line is two windows, a five-item enumeration is five or six. There is **no fixed count and no mandatory "middle" act**; the only sin is dumping everything up front. (A **silent** frame — a diagram assembling itself, a worked example animating — paces its reveals to the beat instead of the VO; same discipline, no spoken cue.) +- **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`). On a short shot the final reveal and the hold are the **same window** — the hold is not a separate mandatory act. 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, a beat of held tension before a turn). The failure is never "too still"; it is **front-loaded-then-frozen** (everything dumped by ~25%, nothing cued to the VO). Place held beats deliberately for rhythm so the video isn't uniformly busy (allocate them in `## Video direction`). Reveal pacing + holds + the idle budget → `motion-language.md`. + +## 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/.md`: it is a short, domain-agnostic, **time-coded shot template with `[slots]`** and a named **signature move** (the thing that makes the shape itself — the SVG ring, the push-THROUGH, the in-place token swap). + +2. **Instantiate its `[slots]` with THIS frame's invented content** — three postures: + - **Reproduce** — the blueprint fits the beat and your content maps onto its slots cleanly. Fill every `[slot]` with this frame's word / shape / stat and follow its Scene timing. Write the resulting Scene lines. + - **Adapt** — the _structure_ fits but the content / element-count / surface doesn't (or you want a fresher surface to avoid templating). State **what you keep / what you change** in one line, then write the adapted Scene lines. You may extend or vary; you may **never** drop the **signature move** (drop it and you picked the wrong blueprint), and you keep the reveals **paced to the VO** — never collapse the shape to a single front-loaded dump. + - **Compose** — no blueprint fits the beat. Build the shot from the **motion vocabulary** in `motion-language.md`: still pace the reveals to the VO across the shot, never fire everything at t=0. Mark it `blueprint: compose`. + +3. **Keep the signature move.** Whichever posture, the blueprint's signature move (named in its file) is the spine of the shot — it usually lands on the shot's key reveal. Carry it through. + +The blueprint's own Scene lines, motion vocabulary, and `rule mapping` are your raw material; you are choosing a shape and casting this frame's invented content into it, not copying an engineering spec. ## 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 @@ -22,63 +47,100 @@ Story-design's `## Frame N` block already carries the narrative. You append the - 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) - -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. +- blueprint: dataviz-countup (Adapt) ← you add: the id you instantiated (or "compose") +- focal: the snowball ← you add: the INVENTED hero element of this beat +- roles: snowball = foreground subject · hill = background gradient (dim ~40%) · ring labels = supporting ← you add: role per invented element +- sfx: whoosh-soft, tick ← you add: the sound the beat wants (fetched + mounted at root; never yours to embed) + +Adapt: keep the count-up-ring signature; the trend chart becomes the snowball's labeled rings climbing. +Scene 1 (0.0–1.2s): solid hill gradient (dim ~40%); the snowball seats upper-left, a circular progress ring + bold center number anchor it — Centered template, ~50% of frame. Slow push-in runs underneath. +Scene 2 (1.2–3.4s): as the VO names each turn, the snowball rolls down and gains one labeled ring per turn (layer-reveal); a small total ticks up beside it (the count-up reveals on its spoken cue, not at t=0). Asymmetric 60/40, 3 depth layers. +Scene 3 (3.4–5.0s): land the final ring emphasis dead-center, accent glow blooms behind it and holds; the total reads clean and STILL — no continuing push, no breathing (a held beat beats bad motion). The stillness reads against the prior motion. ``` -- **`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: + +- **`blueprint:`** — the id you instantiated (with `(Reproduce)` / `(Adapt)`), or `compose`. One id per frame. +- **`focal:`** — which **invented** element is the hero of this beat (a hero word, a diagram node, a chart series, a coined-term card). +- **`roles:`** — each invented element's 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/` image, if any (named in story's `asset_candidates`), is treated 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 `