diff --git a/CLAUDE.md b/CLAUDE.md index 4c8b6990a..9297b98d0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -67,4 +67,4 @@ will not match CI. Use it only for local-only experimentation. ## Skills -Composition authoring (not repo development) is guided by skills installed via `npx skills add heygen-com/hyperframes`. See `skills/` for source. Invoke `/hyperframes`, `/hyperframes-cli`, `/hyperframes-registry`, `/tailwind`, or `/gsap` when authoring compositions. Use `/tailwind` for projects created with `hyperframes init --tailwind` so agents follow the pinned Tailwind v4 browser-runtime contract instead of Studio's Tailwind v3 setup. Use `/animejs`, `/css-animations`, `/lottie`, `/three`, or `/waapi` when a composition uses those first-party runtime adapters. Invoke `/hyperframes-media` for asset preprocessing (TTS narration, audio/video transcription, background removal for transparent overlays) — these commands have their own skill so the CLI skill stays focused on the dev loop. When a user provides a website URL and wants a video, invoke `/website-to-hyperframes` — it runs the full 7-step capture-to-video pipeline. +Composition authoring (not repo development) is guided by skills installed via `npx skills add heygen-com/hyperframes`. See `skills/` for source. Invoke `/hyperframes`, `/hyperframes-cli`, `/hyperframes-registry`, `/tailwind`, or `/gsap` when authoring compositions. Use `/tailwind` for projects created with `hyperframes init --tailwind` so agents follow the pinned Tailwind v4 browser-runtime contract instead of Studio's Tailwind v3 setup. Use `/animejs`, `/css-animations`, `/lottie`, `/three`, or `/waapi` when a composition uses those first-party runtime adapters. Invoke `/hyperframes-media` for asset preprocessing (TTS narration, audio/video transcription, background removal for transparent overlays) — these commands have their own skill so the CLI skill stays focused on the dev loop. When a user provides a website URL and wants a video, invoke `/website-to-hyperframes` — it runs the full 7-step capture-to-video pipeline. Use `/hyperframes-promo-video` when the user wants to generate a rendered promotional video (mp4 + poster) from a PR, feature, or product change — it drives the full 7-phase pipeline from discovery through narrative planning, scaffold, preview iteration, and render. diff --git a/packages/producer/node_modules/.bin/esbuild b/packages/producer/node_modules/.bin/esbuild index 00d2d93cd..bc39eee32 120000 --- a/packages/producer/node_modules/.bin/esbuild +++ b/packages/producer/node_modules/.bin/esbuild @@ -1 +1 @@ -../../../../node_modules/.bun/@esbuild+darwin-arm64@0.27.7/node_modules/@esbuild/darwin-arm64/bin/esbuild \ No newline at end of file +../../../../node_modules/.bun/@esbuild+darwin-arm64@0.25.12/node_modules/@esbuild/darwin-arm64/bin/esbuild \ No newline at end of file diff --git a/packages/producer/node_modules/@types/node b/packages/producer/node_modules/@types/node index 454f1340f..a8c1741d9 120000 --- a/packages/producer/node_modules/@types/node +++ b/packages/producer/node_modules/@types/node @@ -1 +1 @@ -../../../../node_modules/.bun/@types+node@22.19.19/node_modules/@types/node \ No newline at end of file +../../../../node_modules/.bun/@types+node@25.7.0/node_modules/@types/node \ No newline at end of file diff --git a/packages/producer/node_modules/esbuild b/packages/producer/node_modules/esbuild index 2bb1f6fa5..6fa394cb1 120000 --- a/packages/producer/node_modules/esbuild +++ b/packages/producer/node_modules/esbuild @@ -1 +1 @@ -../../../node_modules/.bun/esbuild@0.27.7/node_modules/esbuild \ No newline at end of file +../../../node_modules/.bun/esbuild@0.25.12/node_modules/esbuild \ No newline at end of file diff --git a/skills/hyperframes-promo-video/README.md b/skills/hyperframes-promo-video/README.md new file mode 100644 index 000000000..941f88ea6 --- /dev/null +++ b/skills/hyperframes-promo-video/README.md @@ -0,0 +1,81 @@ +# hyperframes-promo-video + +Generate an actual rendered `mp4` + poster image from a PR, feature, or product change — using [HyperFrames](https://hyperframes.dev) (HTML/CSS/GSAP-based video). + +Same workflow shape as `remotion-video` and the same storytelling rules, but built on HyperFrames instead of React/Remotion. For people who'd rather author scenes in HTML/CSS than JSX. Iterates with `npx hyperframes preview`, then renders `video.mp4` + `poster.jpg`. + +This skill produces a _video file_. If you want a textual script instead, use `video-script`. + +## Companion skills (HyperFrames ecosystem) + +This skill only carries the promo-video-from-PR logic — input resolution, narrative planning, motif derivation, hook enforcement, scene-plan auditing, render-time gates. The mechanics of the HyperFrames stack live in separate skills (install them for best results): + +- **`hyperframes`** — composition authoring rules: DESIGN.md gate, Layout Before Animation, palettes, transitions, typography, motion principles, captions, audio, TTS +- **`hyperframes-cli`** — every `npx hyperframes ` (init, lint, preview, render, transcribe, tts, doctor, etc.) +- **`gsap`** — GSAP timeline patterns, easing, stagger, performance, position parameter, labels, nesting +- **`hyperframes-registry`** — registry blocks/components and `hyperframes add` + +Without those installed, the skill still works but emits a warning that quality may be reduced. + +## Inputs + +In resolution order: + +1. Path to a marketing brief (`.md` containing "Executive Summary" or "Key Messages") +2. Path to a blog post +3. Path to a changelog +4. GitHub PR URL or `#1234` +5. Git ref range — `v1.0...v2.0` +6. File or directory path +7. Freeform text + +## Invoke + +``` +/hyperframes-promo-video #1234 +/hyperframes-promo-video .tmp/marketing-brief.md +``` + +Or trigger by description: + +> "Render a HyperFrames video for #1234." +> "Make a 30-second promo video using HyperFrames." + +## Output + +- `video.mp4` — the rendered video (default 30s, 16:9) +- `poster.jpg` — first-frame poster +- The HyperFrames project directory (HTML composition) for further hand-editing + +Default location: `marketing//hyperframes/` or wherever `marketing-pipeline` directs shared output. + +## How it works + +Seven phases: discovery, configuration (duration, aspect ratio, project location, brand scanning), narrative planning (motif, hook, scene plan), scaffold the composition, first draft + iterate via `npx hyperframes preview` (freeform loop), render with pre-render audits, cleanup. Phases 1, 3, 5, and 7 have explicit approval gates. + +### "Use sane defaults" mode + +The skill recognizes phrases like _"use sane defaults"_, _"don't ask questions"_, _"non-interactive"_, _"just ship it"_ and skips the configuration prompts (defaults to 30s / 16:9 / `marketing//hyperframes/`). + +But it does **not** skip: + +- Brand color/font/logo scanning — hardcoding from training-data assumptions is forbidden +- The `npx hyperframes preview` step — you must see the studio URL before render +- Phase 6 pre-render audits (storytelling, hook rules, motif presence, pacing variance, value-prop timing, contrast) +- The cleanup question + +These exist to prevent shipping a generic video. + +## Files + +- [`SKILL.md`](./SKILL.md) — the skill itself +- [`brand-detection.md`](./brand-detection.md) — how the skill scans for brand assets +- [`patterns/`](./patterns) — reusable scene patterns +- [`templates/`](./templates) — starter compositions +- [`hooks/`](./hooks) — pre-render audit hooks +- [`references/`](./references) — supporting documentation + +## Credits + +Originally authored by [Alem Tuzlak (@AlemTuzlak)](https://github.com/AlemTuzlak) as `hyperframes-video`. +Integrated into the HyperFrames skill catalog with permission. diff --git a/skills/hyperframes-promo-video/SKILL.md b/skills/hyperframes-promo-video/SKILL.md new file mode 100644 index 000000000..f7b22b640 --- /dev/null +++ b/skills/hyperframes-promo-video/SKILL.md @@ -0,0 +1,1299 @@ +--- +name: hyperframes-promo-video +description: Use when the user wants to generate a rendered promotional video (not just a script) for a PR, feature, or product change — produces a HyperFrames HTML composition, iterates with `npx hyperframes preview`, and outputs mp4 + poster for X/LinkedIn/social. +author: Alem Tuzlak (@AlemTuzlak) +--- + +# HyperFrames Video + +Turn a PR into a rendered short-form promo video with a hook, code moments, and CTA, using HyperFrames. Iterate with live preview via `npx hyperframes preview`, then render `video.mp4` and `poster.jpg` for X/LinkedIn/social. + +Unlike `/video-script` (which produces a textual script), this skill produces the actual video file. Counterpart to the `remotion-video` skill — same workflow shape, same storytelling rules, but built on the HyperFrames stack instead of Remotion. + +## Triggers + +Invoke when the user says: "make a video for this PR", "hyperframes video", "render a promo video", "video for X/LinkedIn", or when selected from `/marketing-pipeline`. + +## How this skill relates to the hyperframes ecosystem + +This skill carries only the promo-video-from-PR logic: input resolution, narrative planning, motif derivation, hook enforcement, scene-plan auditing, render-time gates. The mechanics of authoring HyperFrames compositions, running the CLI, animating with GSAP, and installing registry components are owned by separate skills you should invoke when their topic comes up: + +- **`hyperframes`** — composition authoring rules: DESIGN.md gate, Layout Before Animation, palettes, transitions, typography, motion principles, captions, audio, TTS. +- **`hyperframes-cli`** — every `npx hyperframes ` (init, lint, inspect, preview, render, transcribe, tts, doctor, browser, info, upgrade, compositions, docs, benchmark). +- **`gsap`** — GSAP timeline patterns, easing, stagger, performance, position parameter, labels, nesting, playback. +- **`hyperframes-registry`** — registry blocks/components and how to wire them via `hyperframes add`. + +When this skill needs to do something covered by one of those skills, defer to that skill's instructions rather than re-deriving them here. + +## Process Flow + +``` +Resolve input + → Phase 1: Discovery + → Phase 2: Configuration + → Phase 3: Narrative planning + → Phase 4: Scaffold + → Phase 5: First draft + iterate + → Phase 6: Render + → Phase 7: Cleanup +``` + +Phases 1, 3, 5, and 7 have explicit approval gates. Phase 2 is an interactive Q&A. Phase 5 is a freeform iteration loop that can run many rounds. + +## "Use Sane Defaults" / "Don't Ask Questions" — What It Does and Doesn't Override + +When the user invokes the skill with phrasing like _"use sane defaults"_, _"don't ask questions"_, _"non-interactive"_, _"just ship it"_, or any equivalent — interpret it precisely: + +**It DOES override (skip the prompt, pick the default):** + +- Q2.1 duration → derive from scope using the ladder in Q2.1 (still in the 15–60s window); pick the midpoint of the matched scope band and proceed without asking +- Q2.2 aspect ratio → 16:9 landscape +- Q2.3 project location → `marketing//hyperframes/` +- Q2.4 brand _confirmation_ (the "use these / customize / provide your own?" question) +- Phase 1.4 scope confirmation +- Phase 3.0 motif confirmation +- Phase 3.1 story-pattern confirmation +- Phase 3.3 scene-plan approval +- Phase 5 freeform iteration loop (the "what would you like to change?" prompt) + +**It does NOT override (must always run regardless):** + +- Brand color/font/logo **scanning** (Q2.4 detection — see HARD-GATE in Q2.4). Hardcoding colors from training-data assumptions about a project is a forbidden shortcut. +- Phase 5 **preview** (HARD-GATE in Phase 5). Even in fully unattended mode, `npx hyperframes preview` must start and the studio URL must be opened in the browser before the render runs. The user can interrupt; the agent must not pre-decide for them. +- Phase 6 pre-render audits (storytelling, hook rules, motif presence, pacing variance, value-prop timing, contrast). These exist to prevent shipping a generic video. +- Phase 7 cleanup question (the user owns project disposition). + +If you're tempted to skip a HARD-GATE because the user "said no questions" — re-read this section. The user said no _questions_, not no _gates_. + +## Input Resolution + +Resolve the argument (if provided) in this order: + +1. Path to a marketing brief (`.md` containing "Executive Summary" or "Key Messages") → **marketing brief** +2. Path to a blog post (`.md` with blog post structure) → **blog post** +3. Path to a changelog → **changelog** +4. GitHub PR URL or `#\d+` pattern → **PR** +5. Matches `..` or `...` (alphanumeric + `/`, `_`, `.`, `-` on each side) → **git ref range** +6. Resolves to an existing file/directory → **codebase feature** +7. Otherwise → **freeform text** + +If no argument is provided, ask: "What should the video be about? You can provide a PR URL/number, marketing brief, blog post, changelog, git ref range, file/directory path, or just describe the feature." + +When invoked from the pipeline with a PR _and_ upstream marketing-brief/blog-post paths, read both: PR for technical accuracy, upstream content for positioning/tone. + +(Detailed phase specs begin below — see Phase 1.) + +## Phase 1: Discovery + +### Step 1.1 — Check hyperframes skills availability + +Attempt to invoke the `hyperframes` and `hyperframes-cli` skills via the Skill tool. If either is unavailable, present: + +> "The `hyperframes` / `hyperframes-cli` skills aren't installed. Options: +> a) proceed with baseline knowledge (quality may be reduced) +> b) wait while you install them +> c) cancel" + +If the user picks (a), emit a warning in the final summary noting reduced quality. + +### Step 1.2 — Analyze input + +| Input type | What to read | +| --------------- | ---------------------------------------------------------------------------------------------------- | +| Marketing brief | positioning, key messages, audience | +| Blog post | headline, narrative, examples | +| Changelog | highest-impact entry | +| PR | `gh pr view --json title,body,files,labels`, diff (`gh pr diff`), commit messages, linked issues | +| Git refs | `git diff ` + `git log --oneline` | +| Codebase path | read the specified files/directories | +| Freeform | parse the user's description | + +For PRs with 20+ files, filter to user-facing changes only — skip `tests/`, `ci/`, `.github/`, lockfile changes, dep bumps. + +**Error handling:** + +- `gh` not available → tell the user, ask for an alternative (diff file, freeform description) +- Invalid PR/ref → ask user to verify +- File not found → ask for the correct path + +### Step 1.2a — PR deep analysis (when input is a PR) + +When the input is a PR, the brief table in Step 1.2 is not enough. PR bodies are routinely vague, outdated, or focused on implementation rather than user value, and a video built off the body alone tends to overclaim or miss the headline angle entirely. Before continuing to Step 1.3, run this structured analysis and produce a written **PR analysis block** that becomes the source of truth for Steps 1.4 (scope confirmation), Q2.1 (duration ladder), and Phase 3 (narrative planning). + +**Mandatory steps — do all of them:** + +1. **Pull metadata and identify the base branch.** + + ``` + gh pr view --json number,title,body,baseRefName,headRefName,files,labels,commits,additions,deletions + ``` + + Record `baseRefName` (usually `main` / `master` / `develop`) — that is the diff reference. `gh pr diff ` automatically compares the PR head against this base. + +2. **Pull the full diff against the base.** + + ``` + gh pr diff + ``` + + For very large PRs (>500 lines or >20 files), also list changed files via `gh pr view --json files`. + +3. **Filter to user-facing surfaces.** Ignore (do not let these shape the headline angle): `tests/`, `__tests__/`, `*.test.*`, `*.spec.*`, `__mocks__/`, `ci/`, `.github/`, lockfiles, dep bumps without behavior change, generated/build artifacts (`dist/`, `build/`, `.next/`), and formatting-only diffs. What remains is the user-facing surface of the PR. + +4. **Enumerate the public-API delta.** From the filtered diff, list every change a user could observe or write code against: + - New, renamed, or removed `export`s (functions, types, components, hooks, classes, constants) + - New CLI commands, flags, or environment variables + - New routes, endpoints, or event names + - New config keys or schema fields + - Changed default values for existing public surfaces + - Changed error messages, log shapes, or response shapes the user could rely on + + Grep the diff for added lines beginning with `export `, new top-level `function`/`class`/`const` in `src/` / `lib/` / `packages/*/src/`, new files in those trees, and changes to public type signatures. **If you cannot point at a line in the diff for a claimed API, the claim is wrong — drop it.** + +5. **Enumerate the behavior delta.** Beyond API surfaces, list user-visible behavior changes: UI elements added/changed (with file references), CLI / network output that looks different, side effects firing under new conditions, removed limitations, performance characteristics that changed. + +6. **Write the before / after value statement.** Exactly two sentences, both grounded in concrete diff evidence: + - **Before:** _"Before this PR, a user who wanted to *** had to ***."_ + - **After:** _"After this PR, the same user can \_\_\_."_ + + The "had to" half must be a real prior workflow you can describe — copy-pasting an adapter from the docs, installing a second package, writing boilerplate, hitting an error, switching to a different tool. If the honest "Before" sentence is _"they could already do this"_, the PR has no user-visible value delta — see step 8. + +7. **Cross-check the PR body against the diff.** Walk the body's claims and the diff side-by-side: + - **Body claims a feature → does the diff confirm?** If the body says "added X" and the diff has no public surface for X (only tests, only docs, only internal helpers), flag it: _"PR body claims X but the diff doesn't expose X to users — should I shift the angle to ?"_ + - **Diff shows multiple distinct features → body emphasizes one?** Flag the others as candidate angles: _"The body emphasizes A, but the diff also adds B and C. Which is the headline angle?"_ + - **Body is empty / boilerplate / `[BLANK]`?** Infer from the diff; make the inferred angle explicit and confirm with the user at Step 1.4. + - **List "surprises"** — anything in the diff _not_ mentioned in the body that affects user-visible behavior. Surprises are often the real story. + +8. **Bail-out check: is this PR actually user-visible?** If after steps 4–6 you cannot name a single new thing the user can do or observe, the PR is not video-worthy as a feature launch. **Stop and ask the user:** + + > "This PR looks like an internal refactor / test-only / dep-bump PR — I can't find a user-visible value delta. Options: + > a) shift to a performance / DX / cleanup angle if numbers support it + > b) pick a different PR or input + > c) cancel" + + Do not invent a feature angle to fill the gap. A confabulated angle wastes a full iteration round and destroys user trust on the very first draft. + +9. **Produce the PR analysis block.** Write the result as a short structured block before continuing to Step 1.3. This block — not the PR body — is the source of truth for everything downstream: + + ``` + PR analysis — #1234 "Add fromZodSchema support" + Base: main · Head: feature/zod-schema · Author: + User-facing files: 3 (packages/core/src/index.ts, packages/core/src/zod.ts, packages/core/src/types.ts) + Filtered out: 5 test files, 2 doc files, lockfile + + Public-API delta: + + export function fromZodSchema(schema: ZodSchema): StandardSchema + + export type ZodCompatibleSchema + ~ default error code for ZodError changed: 'invalid_type' → 'STANDARD/type' + + Behavior delta: + - Users importing zod schemas no longer need a manual adapter. + - Error messages from zod paths now use the StandardError shape. + + Before / after: + Before: copy a 15-line adapter from the docs into every project that mixes zod with this library. + After: one import + one call. + + Surprises (in diff but not in PR body): + - Default error shape change (above) — could be the headline angle for migration-aware audiences. + + Headline angle: "drop the 15-line adapter — one import, one call" + Scope band for Q2.1: one idea (15–25s) + ``` + + The "Headline angle" line feeds Phase 3.0's motif derivation and Phase 3.3's hook copy. The "Scope band" line feeds Q2.1's scope-derived duration proposal. + +10. **Forbidden shortcuts** (each is a fast path to a wrong video): + - Writing the analysis block from the PR title alone — **fail**; you must read the diff. + - Skipping the cross-check because the body "looks complete" — bodies often look complete and are wrong. + - Treating the PR body as truth when it conflicts with the diff — **the diff wins**. + - Filling in a plausible "Before" sentence when the diff doesn't support one — run the bail-out check instead. + - Collapsing two genuinely distinct user-visible features into one "feature X" bullet to make the scope band look smaller — record both and pick a headline angle at Step 1.4. + +**For git-ref-range and codebase-path inputs**, apply the same structure with the diff coming from `git diff ` / direct file reads in place of `gh pr diff`. Steps 4–9 (public-API delta → analysis block) are not PR-specific. + +### Step 1.3 — Read product context + +Read if they exist: `README.md`, `docs/`, `package.json`. If nothing found, ask: "Can you briefly describe the product and who it's for?" + +### Step 1.4 — Present understanding + get scope confirmation + +**For PR inputs**, the bullets and the compelling angle below **must** be derived from the PR analysis block written in Step 1.2a — not from the PR title or body. Quote the "Headline angle" line directly as the proposed story seed; turn the public-API delta and the before/after statement into the bullets. If the user added clarifying context after Step 1.2a, fold it in here. + +**For non-PR inputs**, derive the bullets from the relevant entry in Step 1.2 (marketing brief positioning, blog headline, changelog highlight, codebase reading, freeform description). + +Present: + +> "Here's what I'll base the video on: +> +> - [feature summary bullet 1 — concrete, grounded in the diff / source] +> - [feature summary bullet 2 — the before → after value, in one line] +> +> The compelling angle: [proposed story seed — for PRs, the "Headline angle" from the analysis block] +> +> Anything to add, remove, or correct?" + +**Do not proceed until the user confirms.** + +### Step 1.5 — Sensitive content scan + +Before continuing, scan for: security patches, internal pricing, credentials, unreleased roadmap items, content marked confidential. Flag anything questionable to the user. + +## Phase 2: Configuration + +Ask these questions one at a time, in order. + +### Q2.1 — Duration (derived from scope, never offered as a menu) + +**Do not ask the user to pick a fixed length from a menu.** (This restriction is specific to duration; other questions like aspect ratio use a numbered menu.) A fixed number becomes a constraint, and the dominant failure mode is padding — freeze-frames, repeated beats, black or empty trailing frames, or filler bullets added solely to reach the chosen target. Instead, derive a duration from the _scope of the change_ and present it as a proposal the user can confirm or override. + +**Allowed range: 15–60 seconds.** Anything outside this window is wrong by default. Going under 15s means the story can't breathe; going over 60s means it's two videos. + +**Scope → duration ladder:** + +| Scope of the PR / feature | Distinct payoff beats | Target | +| -------------------------------------------------------------------------------------------------------------- | ------------------------- | ---------- | +| One idea (single API addition, single bug fix, one QoL win) | hook + 1 delivery + CTA | **15–25s** | +| Typical PR-sized feature (problem → solution → proof, or a multi-chapter code walk) | hook + 2–3 delivery + CTA | **25–40s** | +| Multi-faceted release (multiple distinct sub-features, or comparison needing problem + solution + proof beats) | hook + 3–4 delivery + CTA | **40–60s** | + +A _distinct payoff beat_ is one new thing the viewer learns. Two scenes whose payoff sentences (see Phase 3.3 item 1) reduce to the same idea are one beat, not two. + +**Sanity check before proposing — do this silently first:** + +1. List the distinct payoff beats the video must contain. +2. Estimate: hook ≈ 3s, CTA ≈ 5–7s, each delivery beat ≈ 6–10s (longer if it contains a code chapter ladder). +3. Sum the floor and the ceiling. If the floor is under 15s, you're padding the beat list — cut beats or shrink the scope claim. If the ceiling is over 60s, you have two videos — pick one angle. + +**Propose to the user (no menu, no fixed lengths):** + +> "Based on the scope of this PR, I'm targeting **~Xs** (range Ys–Zs). Beats: . Confirm, or override with a different length anywhere in 15–60s." + +**Hard rule — story sets duration, never the other way around.** If at any later phase a scene needs to be stretched, held on a static frame, repeated, backed by black/empty frames, or filled with filler bullets to reach the chosen target — **stop**, shorten the target, re-confirm with the user, and ship the shorter video. Padding to hit a number is the single behavior this rule exists to forbid. If a 30s scope honestly tells in 18s, ship 18s. + +**Breathing-room constraint.** Whatever duration is chosen, it must allow every on-screen text element to (a) finish animating in, (b) dwell long enough to be read, and (c) settle for at least ~0.4s before the next scene begins. Cutting to a new scene the instant a line of text finishes appearing is forbidden. See Phase 3.3 (item 3) and the Phase 6 audit for the concrete dwell-time table. + +### Q2.2 — Aspect ratio + +> "Which aspect ratio? +> +> 1. **16:9 landscape** (1920×1080, default) — desktop X/LinkedIn +> 2. **1:1 square** (1080×1080) — mobile-friendly feed +> 3. **9:16 vertical** (1080×1920) — Reels/Shorts/TikTok +> 4. **Multi-format** — render all three from the same story" + +Frame rate is fixed at 30fps. + +### Q2.3 — HyperFrames project location + +> "Where should the HyperFrames project live? +> Default: `marketing//hyperframes/` (fresh per-video) +> Override: specify a path." + +### Q2.4 — Brand assets (auto-detect → confirm) + + +**The brand scan is mandatory. It is not skippable under any user instruction — including "use sane defaults", "don't ask questions", "just ship it", or "non-interactive". Those instructions affect interactive *confirmation*; they do NOT affect *detection*.** + +You MUST run the heuristics in `brand-detection.md` against the actual target repository — the source code that owns the feature, not the `marketing/` output directory — before selecting any color, font, or logo. + +**Forbidden shortcuts (these produce wrong colors and waste an iteration):** + +- "I know this project — TanStack uses amber, Vercel uses black/white, Stripe uses purple" → **No.** Run the scan. Recall is unreliable; brand details drift between training data and now. +- "It's a dev tool, dark + neon green is fine" → **No.** Generic vibes ≠ this product's brand. +- "User said no questions, so I'll skip detection" → **No.** Detection is silent. Confirmation is what the "no questions" instruction skips. +- Picking from a palette in your head because it "fits the topic" → **No.** Read the repo's CSS/Tailwind/theme files. + +**The scan must produce a written record before any composition file is written.** Output a short block listing, for each field: the source file checked, the value found (or `not found`), and the final value used. Example: + +``` +Brand scan — TanStack/ai + Primary : checked tailwind.config.* (none) · packages/*/styles.css (--brand: #0a3d2e) → #0a3d2e + Accent : checked theme.json (none) · brand.json (none) · derived from primary → #14b870 + Logo : checked public/logo.svg → media/header_ai.png + Font : checked next/font (none) · @fontsource (none) · README ref → Inter (fallback) +``` + +If the scan finds nothing for a field, fall through to the neutral defaults below — but **only after** the scan ran and is recorded. Skipping the scan and going straight to defaults is the failure mode this gate exists to prevent. + +In interactive mode, present findings (the block above) and ask for confirmation. In non-interactive / "use sane defaults" mode, print the same block and proceed without asking — the _record_ is required either way. + + +Present findings as: + +> "I found: +> +> - Logo: `media/header_ai.png` (copied from `public/logo.svg`) +> - Primary: `#0066ff` (from `tailwind.config.js`) +> - Font: `Inter` (from `next/font`) +> +> Use these, customize some, or provide your own?" + +**Persistence:** write chosen brand to `.marketing/brand.json` (relative to repo root) and to a generated `DESIGN.md` inside the project (the file the `hyperframes` skill's Visual Identity Gate requires). On subsequent runs, ask: + +> "I loaded brand settings from `.marketing/brand.json`. Use saved, or re-detect?" + +**Fallback when nothing detected:** ask explicitly with these neutral defaults. These are intentionally neutral — auto-detection of the project's actual brand is always preferred, and these values should only appear when detection turns up nothing. + +- Primary: `#3B82F6` (neutral blue) +- Accent: `#8B5CF6` (neutral violet) +- Background: `#0A0A0A` (near-black, dark mode) +- Text: `#FFFFFF` (white) +- Muted: `#9CA3AF` +- Success: `#22C55E` +- Danger: `#EF4444` +- Font: `Geist` (loaded via Google Fonts `` in `index.html`) +- Logo: none + +Confirm with the user before scaffolding. + +**Note on fonts:** The default scaffold loads **Geist** via a `` to `https://fonts.googleapis.com/css2?family=Geist:wght@400;600;700;900&display=swap`. To use a different Google Font, edit `DESIGN.md`, update `.marketing/brand.json`, and the skill regenerates `index.html` and `styles.css` accordingly. Non-Google fonts require manual self-hosting. + +## Phase 3: Narrative Planning + +### Step 3.0 — Derive the signature motif from context + +Before picking a story pattern, identify the **signature visual motif** that will carry the narrative across scenes. This is the single most important call for not looking generic. + +1. **Finish this sentence in one verb**: "This feature lets developers \_\_\_ something." + - Examples: _compose_ music, _sync_ state, _validate_ inputs, _secure_ tokens, _deploy_ functions, _route_ requests. +2. **Translate the verb into a physical / spatial metaphor**: a waveform for audio composition, packets traveling edges for sync, squiggle underlines for type validation, a padlock for auth, a rocket/checkpoint line for deploy, a switchboard for routing. +3. **Pick the state-change axis**: the motif must visibly change between Problem and Solution scenes (broken ↔ unified, empty ↔ full, disconnected ↔ connected). Pick ONE axis and hold it across the video. +4. **Look up the motif** in `references/visual-motifs.md` — the catalog maps 20+ common verbs to motifs, state axes, and example custom elements. If the verb isn't listed, apply the heuristic in that file. + +**Confirm with user:** + +> "The core verb is **compose music**, so I'll use an **animated waveform** as the signature motif — smooth/clean in the hook and solution, jagged/red in the problem. This thread will appear in scenes 1, 2, and 4. Approve, pick a different motif, or let me propose alternatives?" + +Do NOT skip this step. A video without a derived motif defaults to generic bullet-list storytelling and fails the generic test (Storytelling Rule 10). + +### Step 3.1 — Detect story pattern + +Scan the PR/input for signals and pick one of 5 patterns. See the detection signals table in `patterns/README.md` — that file is the single source of truth. + +Load the matching pattern spec from `patterns/.md`. + +**Confirm with user:** + +> "This looks like an **[API/Library feature]** PR. I'll use that story template. Override? Options: api-library / ui / performance / bugfix / generic / describe a custom pattern" + +### Step 3.2 — Decide code sourcing (hybrid) + +Per pattern: + +- **api-library-feature** → **synthesize** realistic usage examples that show how developers will actually use the feature +- **ui-feature** → **screenshots / mock components** (no code block scenes) +- **performance-win** → metric cards + optional code +- **bug-fix** → before (broken) + after (working) snippets, synthesized if raw diff is noisy +- **generic-fallback** → bullet benefits, no code + +Offer user override: + +> "For code snippets, I'll **synthesize realistic usage examples** rather than paste raw diff. Override: use-diff / synthesize / mix" + +### Step 3.2b — Ground synthesized code in the real library + +Before synthesizing usage code for a PR, verify the library's actual public API. Do **not** invent method names, argument shapes, or import paths. + +For each snippet the skill plans to include: + +1. Locate the real library code locally (e.g., `packages//src/index.ts`, docs examples in `docs/`, test fixtures in `tests/`). +2. Confirm every imported name exists as exported. +3. Confirm every method/function signature matches (argument names, shape, async vs sync). +4. Prefer patterns from the library's own docs over inferred shapes. + +If the library isn't available locally and the skill can't verify, **ask the user** before synthesizing. A wrong API in the first draft destroys user trust and wastes a full iteration round. + +### Step 3.3 — Self-improve the draft, then present for approval + +This step has two parts: a **silent self-improvement loop** that you run before the user sees anything, and the **user-facing approval gate** that follows. + +**Do not show the user the first thing you wrote.** The first version of a scene plan is almost always weaker than the second. The agent's job here is to hand the user the _strongest_ plan it can build given the rules in this skill, not the first draft. + +#### Self-improvement loop (silent — run before presenting) + +After drafting an initial scene plan, run a deliberate improvement pass against the rule sections listed below. Iterate **at least twice**. Stop only when one full pass produces zero further changes — the draft has stabilized. + +**On every pass, for each scene and for the plan as a whole, ask:** _"Does this satisfy this rule? If not, can I rewrite, merge, drop, split, or reorder a scene to fix it?"_ Apply the fix in-place, then continue the pass. + +The five **Core checks** below must be satisfied — every plan, no exceptions. On top of those, scan against the broader rule sections at the end of this step. + +**Core checks (every plan must satisfy all five):** + +1. **Per-scene payoff**: for each scene, write one sentence of the form _"The new thing a viewer knows at the end of this scene is \_\_\_."_ If two scenes produce the same sentence, one is redundant — merge or cut. If a scene's sentence is vague (e.g., _"the product is good"_), the scene is filler — redesign. +2. **Pacing variance**: scene durations must reflect cognitive load, not a uniform slice. Reference shape for a **30s** target — **scale proportionally** for shorter (15–25s) or longer (40–60s) videos: + - Hook: ~10–12% of total (≈3s @ 30s; ≈1.8s @ 15s; ≈6s @ 60s) — a single punch + - Problem / setup: ~15–20% (≈5s @ 30s) — enough to land one concrete claim + - Delivery (code / swap / comparison): ~45–55%, with internal chapters if the beat exceeds ~8s + - CTA: ~18–25%, **never below 4s** regardless of total — the CTA always breathes and never rushes + + Reject plans where the shortest and longest scene differ by less than ~2×. Equal-slice plans are the single strongest "AI-generated" tell. Reject plans where the CTA is under 4s — a rushed CTA destroys the conversion the rest of the video bought. + +3. **Breathing room (no rush-cuts on text)**: a scene must not transition out while a text element is still being read. Minimum on-screen dwell time, measured from the moment the element _finishes_ animating in to the moment the scene _begins_ transitioning out: + + | Element | Minimum dwell | + | --------------------------------------------- | ------------- | + | Short headline / one phrase (≤6 words) | ≥ 1.5s | + | Long headline / single sentence (7–14 words) | ≥ 2.5s | + | Two-line text / short paragraph (15–30 words) | ≥ 3.5s | + | Code chapter (per chapter, after focus lands) | ≥ 3s | + | CTA URL / handle (must be clearly readable) | ≥ 3s | + + Every scene must also include a **~0.4s settle hold** between the last animation completing and the transition starting. Cutting on the same frame an animation finishes is forbidden — the eye needs a beat to confirm what it saw, and transitions that arrive on the resolve-frame feel cluttered and amateur. If the proposed scene durations cannot accommodate these minima, **shorten the beat list, do not shrink the dwell times**. + +4. **Value prop by ~t=8s** (or by ~25–30% of total duration, whichever is earlier): by the end of scene 2, the viewer must know what the feature does, who it's for, and why it matters. If that's not true with the current plan, restructure before scaffolding. Do NOT bury the value in the delivery scene. +5. **Motif presence and state-change**: the signature motif chosen in Phase 3.0 must appear in at least 2 scenes (typically 3: hook + problem + CTA) and visibly change state between at least one adjacent pair (e.g., clean → glitchy → clean again). + +**Broader rule sections to scan on every improvement pass.** Search this file (or the linked file) for each section heading and walk it against the current draft: + +- **Hook enforcement** (`hooks/hook-rules.md`) — applied to the HookTitle scene. If it fails any check, rewrite the headline; don't just record the failure. +- **Storytelling & Visual Uniqueness Rules** (the numbered "Rule N" sections later in this file) — generic-test, no plain bullet lists, signature motif as load-bearing element, anti-clickbait, side-by-side contrasts, insight tagline, counter-expectation beat, pattern-interrupt vs information, first-10s value prop, et al. +- **Code Scene Rules** — chapters mandatory for ≥5s code beats, synchronized per-chapter narration, per-chapter dwell (~3s), line-length per scene type, diagnostic-comment color, elide unimportant config with `/*…*/`, pre-break long imports. +- **Layout Rules** — single alignment per scene, foreground readability over decoration, no accidental overlap, hero-text size on aspect changes. +- **Visual Cognition Rules** — ≤4 visual chunks per frame, one pre-attentive cue per focal element, reading-flow matched to scene type, reading-saccade limits. +- **Anti-padding rule** (Q2.1) — if any scene exists solely to fill time, **cut it and shorten the target**. Do not carry it forward. +- **Pattern spec** loaded in Step 3.1 (`patterns/.md`) — the scene sequence and payoffs should be coherent with the template; deviations must have a clear justification. +- **Step 3.0 motif & Step 3.2b grounded code** — verify motif state-change still applies and any synthesized code still maps to real exports/signatures after the rewrites. + +**Improvements you may apply silently during the loop (no user question needed):** + +- Rewrite headlines, payoff sentences, captions, and CTA copy for stronger hook discipline and clearer payoff +- Merge two scenes whose payoff sentences collapse to the same idea +- Drop a scene whose only function is to fill time, and shorten the target accordingly +- Split a delivery scene into chaptered sub-beats when a single block exceeds ~8s +- Re-assign motif state per scene to produce a visible state-change between at least one adjacent pair +- Reorder scenes to move the value prop earlier +- Adjust per-scene durations to satisfy pacing variance and breathing-room minima — only by **trimming**, never by stretching or padding +- Replace generic bullets with concrete artifacts (real API shapes, real error messages, real metrics) drawn from the input + +**Changes that must wait for the user — flag them, do not apply silently:** + +- Moving the target duration outside the ±20% band confirmed at Q2.1 +- Changing the signature motif chosen at Step 3.0 +- Changing the story pattern chosen at Step 3.1 +- Adding or removing major scenes that alter the headline narrative claim + +**Stop condition.** End the loop when one full pass over all rule sections (Core checks + broader sections) produces zero changes. If you hit five passes without stabilizing, you have a structural problem the loop can't fix — stop and ask the user for guidance instead of churning. + +#### Present the (already-improved) scene plan for approval + +When presenting to the user, include a brief **"Self-review notes"** line near the top of the response so the user can see the improvement work was actually done. List the 2–5 most material changes the loop applied. Example: + +> _Self-review notes: tightened the hook line from "Add validation easily" to "Swap validation libs with one line"; merged a redundant "why it matters" scene into the problem setup; trimmed delivery 14s → 11s so the CTA dwells ≥4s._ + +If the loop produced no material changes (rare — usually means the first draft was already strong, or the agent isn't pushing hard enough), say so explicitly: _"Self-review notes: draft was stable on first pass; no rewrites needed."_ + +Example output: + +> "Here's the plan (30s target): +> +> 1. **HookTitle** (0–3s, 90f) — `"Swap validation libs with one line"` +> — _payoff: there's one line that replaces N SDKs_ +> 2. **ProblemSetup** (3–8s, 150f) — three evidence cards with concrete conflicting API shapes +> — _payoff: viewer sees the real API-shape conflict they live with today_ +> 3. **LibrarySwap** (8–22s, 420f) — shared Standard Schema code, import line cycles zod → valibot → arktype +> — _payoff: viewer sees the "one line change" literally happen on screen_ +> 4. **CTAEndScreen** (22–30s, 240f) — `"Ship it"` + link to standardschema.dev +> — _payoff: viewer knows exactly where to go next_ +> +> Pacing: hook 3s / problem 5s / delivery 14s / CTA 8s (ratio ~4.7×) — passes variance check. +> Motif: schema-interop glyph (interlocking rings) appears in scenes 1, 2, 4; rings are disconnected in scene 2, unified in 1 and 4. +> +> Approve or adjust any section?" + +**Do not scaffold until the user approves the scene plan.** + +See `patterns/README.md` for how patterns map to scene plans. + +### Step 3.4 — Plan scene transitions (match-cuts) + +Hard cuts between scenes are acceptable; **match-cuts are what make a video feel crafted**. When the signature motif (Phase 3.0) appears in adjacent scenes, the motif must carry over as a match-cut, not restart from zero. + +Rules: + +1. When the same motif component appears in scene N and scene N+1, render it in the last ~8 frames of scene N with the entering state of scene N+1 already beginning. The motif's position, scale, and core geometry must be continuous across the cut — only its _state_ (color, amplitude, opacity, shape) changes. +2. When adjacent scenes use different motifs, a text/background element may bridge them: e.g., the last word of scene N's tagline becomes the first word of scene N+1's caption, kept at the same position during the transition. +3. When scenes have NO common element, use a directional motion cue — a brand-primary bar sweeping left-to-right that covers the cut — never a generic fade-to-black. +4. The `data-bg` variant must change between adjacent scenes (no two adjacent scenes share a variant). This is enforced at pre-render. + +Write the planned transitions into the scene plan before scaffolding: + +> Transition 1→2: waveform carries over at the same position; color fades from brand.primary → brand.danger; amplitude jitters from smooth to glitchy over 8 frames. +> Transition 2→3: glitch waveform contracts into a flat line → that line becomes the top border of the code card in scene 3. +> Transition 3→4: active-provider pill in scene 3 slides down and morphs into the URL pill of the CTA. + +### Step 3.5 — UI moment (when a UI surface exists) + +If the feature has a visible UI surface — a generated image, a rendered audio player, a dashboard, a settings toggle, a diff view — the video must include at least one beat that shows that surface. Research on product-launch video is consistent: "show the product in action" is the strongest single predictor of viewer recall. + +Options (in order of preference): + +1. **Real screen capture**: a short 2–3s clip of the feature running in the example app. Embedded via `