* refactor(product-launch-video): restructure onto script-driven architecture Move product-launch-video onto the shared script-driven authoring flow: build-frame remixes a hyperframes-creative preset onto brand tokens, audio routes through the shared hyperframes-media engine, per-preset caption skins, and every frame is authored as a directed shot. Removes the old bespoke scripts (captions/validate/prep/hoist/…) in favour of the shared lib. assemble-index.mjs keeps upstream #1629's blank/partial scene-file guard (reject an empty or markup-less scene file at assembly, before emitting data-composition-src, and re-dispatch) carried onto the restructured reader. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(pr-to-video): restructure onto script-driven architecture Move pr-to-video onto the shared script-driven authoring flow: ingest.mjs folds the gh PR artifacts into the synthetic capture package the shared backend (build-frame / captions / assemble-index) reads, add the mechanism beat, route audio through hyperframes-media, and remix a hyperframes-creative preset onto brand tokens via the shared lib. - Fix skill name: pr-to-video-refactor -> pr-to-video (match directory). - Drop a stale faceless-explainer-refactor reference in an ingest.mjs comment. - assemble-index.mjs keeps upstream #1629's blank/partial scene-file guard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(faceless-explainer): restructure onto script-driven architecture Move faceless-explainer onto the shared script-driven authoring flow: every visual is invented (typography / abstract graphics / diagram / data-viz) and authored through the shared backend (build-frame remixes a hyperframes-creative preset onto tokens, audio via hyperframes-media, assemble-index builds the standalone index.html) using the shared lib. - Fix skill name: faceless-explainer-refactor -> faceless-explainer (match directory). - assemble-index.mjs keeps upstream #1629's blank/partial scene-file guard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(skills): refresh test-skills-fresh.sh workflow roster Update the install-and-verify harness to the current surface: 10 workflows (adds website-to-video, embedded-captions, graphic-overlays, slideshow; drops the removed footage-recut) and refreshed example prompts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * style(product-launch-video): oxfmt storyboard.mjs Run oxfmt over lib/storyboard.mjs — formatting only, no logic change. Fixes the Format / Preflight CI check. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(studio): import commitGsapPositionFromDrag from its actual module The function was split out into gsapDragPositionCommit.ts in #1605, but the test kept importing it from ./gsapDragCommit, which no longer exports it — yielding 'is not a function' at runtime. Import from the correct module. Inherited main breakage (same fix as #1631); fixes the Test CI check on this branch independently of merge order. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(hyperframes): refine router skill metadata tags Update the entry router's metadata tags (video / animation / router focus); oxfmt collapses the now-shorter metadata to a single line. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(skills): tighten caption comment-strip + document audio --only merge Review follow-ups (#1635): - captions.mjs (x3): the HTML-comment strip used a single global replace, which CodeQL flags as incomplete multi-character sanitization (a nested/partial pair can re-form a marker the single pass misses). Strip in a fixpoint loop instead. Input is preset-library content, not user-controlled, so this is lint- cleanliness, not XSS defense. - audio.mjs (x3): document that fetch-sfx (--only sfx) MERGES into the neutral audio_engine_meta.json sidecar — the engine reads prev and recomputes only the sfx section, so voices/bgm from the generate pass are preserved (review Q). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(skills): remove existsSync->write TOCTOU in workflow scripts Clears the 9 js/file-system-race CodeQL alerts (captions/audio/transitions x3). Each was an existsSync precheck followed by a later write of the same path: - captions.mjs: caption-overrides shim -> atomic writeFileSync({ flag: 'wx' }). - audio.mjs (sync-durations) + transitions.mjs (inject): drop the existsSync precheck and read directly, surfacing the same friendly error from a try/catch on readFileSync — no check->write gap. Behavior is unchanged (same error messages); these are local single-process deterministic scripts so the race was never a real risk, but this clears the gate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(skills): paint root composition ground color in assemble-index Per-frame roots carry data-start/data-duration and get clip-gated against the global timeline at render, so only the first frame's window overlaps global 0 — a frame's own full-bleed background can't serve as the video ground, and every frame after the first renders on the bare body color (black). Paint the ground on the always-present root composition using the project's frame.md canvas color (the same role the caption skin maps to --cap-canvas); fall back to the body letterbox color when frame.md is absent or has no resolvable ground. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(hyperframes): drop router-tag edit (moved to the foundation PR) The entry SKILL.md is rewritten wholesale by the frame-presets/media foundation PR (#1632); editing it here too guaranteed a merge conflict. Restore this file to main and let the router-tag tweak live with the rewrite in #1632, so the two PRs no longer both touch it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
11 KiB
Story design — product launch video
Use this reference in Step 3 to write STORYBOARD.md and SCRIPT.md for a product launch, promo, feature reveal, or marketing video.
This file defines the story: what the video says, in what order, and why each frame exists. It does not define layout, visual effects, animation, or final markdown schemas. For exact file syntax, follow ../hyperframes-core/references/storyboard-format.md and ../hyperframes-core/references/script-format.md.
Read first
Read these inputs before writing:
hyperframes.json— locked brief: angle, length, aspect ratio, language.frame.md— tone, mood, design system, and brand register.capture/extracted/visible-text.txt— product facts, page copy, positioning, proof, CTA.capture/extracted/asset-descriptions.md— the only source for captured asset inventory.user_script.txtandVO_MODE, when present.
Do not inspect capture/assets/, contact sheets, screenshots, or raw captured files during Step 3. Treat asset-descriptions.md as the canonical asset list. Do not invent asset filenames.
Output
Create two files:
STORYBOARD.md— the narrative plan, one frame per beat.SCRIPT.md— the locked narration, only for spoken frames.
Every storyboard frame must include the required fields from the storyboard format reference, plus the narrative metadata below.
Core rule
A website is an information layout. A video is an emotional sequence.
Do not follow page order. Reorder, merge, omit, and reshape captured content into a clear launch story.
Step 3 method
1. Extract the product truth
From the brief and captured text, identify:
- Audience — who the video is speaking to.
- Pain or desire — what the viewer already wants fixed or achieved.
- Promise — the one-line thesis of the video.
- Product role — what the product does in the story.
- Proof — features, UI moments, metrics, logos, examples, or demos.
- CTA — what the viewer should do next.
Write the storyboard around the promise, not around a list of features.
2. Match the register to frame.md
Use frame.md as a soft guide:
frame.md signal |
Story effect |
|---|---|
| restrained, editorial, B2B | plain, confident, low-hype script |
| bold, kinetic, launch-like | short hooks, punchier beats |
| warm, human, playful | friendly direct address, lighter phrasing |
| premium, cinematic, spectacle | aspirational framing, fewer words |
The product truth decides the arc. The visual system tunes the voice.
3. Choose one outer arc
Pick one primary arc. Use a compound only when useful, e.g. PAS with feature-benefit progression.
| Arc | Use when | Beat order | Reveal timing |
|---|---|---|---|
PAS |
The pain is known and urgent. Best for broken B2B workflows. | hook → pain → agitation → solution tease → product intro → proof/demo → CTA | late |
Future Pacing |
The product sells a new future, category, or paradigm. | imagine → name product → remove pain → show mechanism → show outcome → CTA | early |
Demo Loop |
The UI is self-explanatory and the product is best shown working. | question → product intro → demo cycle 1 → demo cycle 2 → trust/benefit → CTA | early |
BAB |
The product bridges an old workflow to a better one. | before → after tease → bridge/product → step 1 → step 2 → step 3/wow → CTA | early-mid |
Feature-Benefit Cascade |
The product is feature-rich or desire/status-driven. | product/category hook → feature → benefit → feature → benefit → climax → CTA | frame 1 |
Use feature-benefit rhythm inside any arc when the video has many capabilities. Do not stack several features without translating them into viewer value.
4. Build the frame sequence
Each frame needs one clear job. Avoid frames that only say “more benefits” or “another feature.”
Use these frame types:
hook | pain_point | product_intro | feature_showcase | benefit_highlight | social_proof | branding | cta
For every frame, define:
type— one of the allowed frame types.persuasion— the specific persuasion move.beat— the viewer emotion.scene— a one-line visual idea, not detailed composition.voiceover— spoken guide text, or empty for silent frames.asset_candidates— real captured assets that could support the frame.
The prose under each frame should state:
narrativeRole— why this frame exists in the story.keyMessage— the one idea the viewer should remember.
Hook strategy
Pick one opening strategy for the first 3-5 seconds:
| Strategy | Use when |
|---|---|
| Shocking statistic | A credible number proves the pain. |
| Pain validation | The audience already knows the problem. |
| Rhetorical question | You need curiosity and speed. |
| Direct address | The audience is clear and specific. |
| Imagine / future pacing | The product introduces a new future. |
| Category announcement | The product is the category or launch headline. |
| Visual spectacle | The aesthetic is part of the pitch. |
| Trend positioning | The product rides a timely market shift. |
The hook must create tension, curiosity, or desire. Do not open with generic company description.
Persuasion labels
Use concrete labels. Do not write generic labels like “show benefit.”
Good labels include:
- Pain agitation
- Cognitive overload
- Negative contrast
- Friction reduction
- Simplification
- Show-don’t-tell proof
- Demonstration of capability
- Feature-to-benefit translation
- Statistical proof
- Authority by association
- Social proof
- Risk reversal
- Future pacing
- Value stacking
- Empowerment and control
- Rule of three
- Scarcity / urgency
- Status seeking
When no label fits, create one and explain the mechanism in the frame prose.
Emotional beats
Use specific emotions:
- Negative:
anxiety,frustration,overwhelm,tension,urgency,skepticism,FOMO - Pivot:
relief,curiosity,clarity,intrigue,aspiration - Build:
trust,confidence,control,ease,power,awe,excitement,belonging,reassurance - Close:
triumph,motivation,urgency-to-act,peace of mind,inevitability
Compound beats are allowed, e.g. relief + control.
Asset candidates
asset_candidates is the handoff from Step 3 to visual design and frame building.
Rules:
- Read only
capture/extracted/asset-descriptions.mdto know what assets exist. - Use only filenames listed there.
- Write candidates as
assets/<basename>, where<basename>is the captured file basename. - Put all candidates on one line.
- Separate candidates with semicolons.
- Add a short description after
—. - Prefer
[video]assets when motion proves the product better than a still. - Use content assets: UI, screenshots, product photos, charts, diagrams, demos.
- Skip tiny icons, favicons, badges, decorative chrome, and repeated logo variants unless the frame needs them.
- Pure typography frames may use an empty asset list.
Example:
- asset_candidates: assets/dashboard-hero.png — main analytics UI, dark dashboard, wide screenshot; assets/demo-loop.mp4 — product interaction clip, query to result flow
Do not use nested lists for assets. The parser expects a single metadata line.
UI demos
A UI demo should usually be a sequence, not one isolated frame.
Use 3 or more consecutive feature_showcase / benefit_highlight frames on the same product surface when the product value depends on workflow or interaction.
Good demo rhythm:
- Input or user action.
- Product response.
- Result, insight, automation, or saved effort.
- Benefit or trust proof.
Use consistent transitions across the sequence so it feels like one flow.
Script rules
If there is no pasted script
Write tight per-frame narration:
- 1-2 sentences per spoken frame.
- Usually 6-20 words per frame.
- Concrete and human.
- Say what the product does for a person.
- Prefer active verbs.
Avoid:
- “Seamless experience.”
- “Unlock the power of...”
- “Streamline your workflow.”
- Long noun-phrase lists.
- A whole frame with only “Or...” or another filler bridge.
Silent frames are allowed when the visual proves the point. Leave them out of SCRIPT.md.
If VO_MODE = restructure
Treat user_script.txt as source material. Rewrite, reorder, merge, or omit to fit the chosen arc and target length.
If VO_MODE = verbatim
Do not rewrite the user’s words. Segment the script into frame-sized chunks at sentence or paragraph boundaries. You may split a long sentence at a natural clause boundary, but do not change words. The final duration follows the provided script.
Transitions
Use only registry transition names:
cut | crossfade | blur-crossfade | push-slide LEFT | push-slide RIGHT | push-slide UP | push-slide DOWN | zoom-through | squeeze
Pick 2-3 transition types for the whole video and repeat them. Frame 1 can use cut as a placeholder.
Frame template
Use the exact fields required by the core storyboard format. This is the narrative shape each frame should satisfy:
## Frame N — Short name
- scene: one clear visual idea
- voiceover: "spoken guide text, or empty"
- duration: rough estimate in seconds
- transition_in: cut
- status: outline
- src: compositions/frames/NN-short-name.html
- type: hook
- persuasion: Pain validation
- beat: urgency
- asset_candidates: assets/example.png — short asset description
narrativeRole: What this frame does in the viewer journey.
keyMessage: The one idea the viewer should remember.
Final checklist
Before asking for user approval, verify:
- The arc is named and consistent.
- The sequence is narrative-driven, not page-order-driven.
- The opening uses a clear hook strategy.
- Each frame has one job.
- Every frame has
type,persuasion, andbeat. - Every visual frame has suitable
asset_candidates, unless intentionally typography-only. - Asset filenames come only from
capture/extracted/asset-descriptions.md. - UI/product demos use a multi-frame sequence when needed.
- Transitions use only registry names and repeat 2-3 types.
SCRIPT.mdcontains only locked spoken narration.- Silent frames are intentional and omitted from
SCRIPT.md.