--- name: product-launch-video description: > Use when the user wants a product launch, SaaS promo, feature reveal, app/company/site marketing video, or a script/brief turned into a product-focused video. Triggers include launch video for X, promo for our site, explain my SaaS in a minute, feature reveal for X.com, and turn this script into a 60s promo. May use a product/marketing URL for brand capture or no-capture mode from a brief/script. Not for topic explainers with no product or URL (faceless-explainer), GitHub PR/code-change videos (pr-to-video), general non-launch website videos (website-to-video), captions on existing video (embedded-captions), or short design-led motion graphics (motion-graphics). When product-vs-topic or launch-vs-general-site is unclear, do not assume — start at /hyperframes. metadata: { "tags": "orchestrator, pipeline, product-launch" } --- # product-launch-video - dispatch entry > **Confirm the route before Step 0.** This skill makes a video for a **product being marketed / launched / promoted**. If it's really a **general (non-launch) site → video** (site tour / showcase, not selling a product) → `/website-to-video`; a **topic / concept with no product** → `/faceless-explainer`; a **GitHub PR** → `/pr-to-video`; an **existing video to caption / package** → `/embedded-captions` · `/graphic-overlays`. **Out of scope** (decline, don't fake): live / at-render-time data (every value is baked in at author time), or footage / screenshots / an avatar that doesn't exist yet (HyperFrames can't record or capture). Routed here on a vague "make a video", or unsure product-vs-topic / launch-vs-general-site? **Read `/hyperframes` first.** All artifacts are written to `PROJECT_DIR = videos//` (created in Step 0). Paths below are relative to `PROJECT_DIR`. You (the orchestrator) run the Bash steps and dispatch the subagents; per-phase details live in the linked guides/agents/scripts — do not expand them here. Dispatch is harness-portable: before the first subagent dispatch, read `/../hyperframes-core/references/subagent-dispatch.md` once — it maps the dispatch verbs (parallel fan-out / background / wait) to your harness's primitives; a concurrency cap below N means waves of the cap size, never fewer scenes. **This file is a binding runbook, not background reading**: execute the steps in order and produce every phase artifact with its designated script or agent role — do not substitute a freestyle pipeline (hand-written narration, ad-hoc TTS calls, one hand-authored composition), and do not skip a pause step because the request seems clear. A step you cannot perform → stop and report; improvising past it breaks every downstream contract. | Phase | Execution | Primary artifact | Detailed flow | | ------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------- | ----------------------------------------- | | init | Bash directly | `hyperframes.json` | Step 0 (this file) | | capture | Bash directly (`hyperframes capture`) | `capture/extracted/tokens.json` | `phases/capture/guide.md` | | design-system | subagent | `design-system/design.html` + `chunks/` | `agents/design-system.md` | | story-design | subagent | `narrator_scripts.json` | `agents/story-design.md` | | audio | Bash directly (`audio.mjs`) | `audio_meta.json` | `phases/audio/guide.md` | | visual-design | subagent | `section_plan.md` | `agents/visual-design.md` | | prep | Bash directly (`prep.mjs`) | `group_spec.json` | `scripts/prep.mjs` header | | captions | Bash directly (`captions.mjs group` -> `html`) | `caption_groups.json` + `compositions/captions.html` | `scripts/captions.mjs` header | | scenes | N x subagent (parallel, one scene each) | `compositions/scene_*.html` | `agents/hyperframes-scene.md` | | finalize | Bash prelude (wait-bgm + assemble + transitions + hoist + sfx-verify) -> finalize subagent | `renders/video.mp4` | Step 7 / `agents/hyperframes-finalize.md` | ## Prerequisites (install before first run) macOS Apple Silicon or Linux x64: ```bash brew install python@3.11 node ffmpeg # On Linux, use the apt/dnf equivalent npx hyperframes doctor # One-time check that Chrome / dependencies are ready ``` - `python@3.11` — **Homebrew Python, not system `/usr/bin/python3`** (PEP 668 blocks `pip install` otherwise); used by the MusicGen fallback - `node >= 18` + `ffmpeg` (`audio.mjs` uses `ffprobe`) - Chrome downloads automatically on first `npx hyperframes capture`. `hoist-videos.mjs` (Step 7, runs only when a scene declares footage) reuses that cached Chrome; if it reports deps missing, run `node /scripts/hoist-videos.mjs --ensure-deps` once (~5s) Optional API keys (unset -> local fallbacks; injection in Step 0.5; `GEMINI_API_KEY` ≡ `GOOGLE_API_KEY`): | Key | Used for | Default voice / fallback | | ---------------------------------------------- | ---------------------------------------------- | --------------------------------------------------------------------------------------------- | | `HEYGEN_API_KEY` (or `hyperframes auth login`) | TTS (cloud, with word-level timestamps) | voice: auto (first English starfish voice; override `--voice`) | | `ELEVENLABS_API_KEY` | TTS (cloud; requires `pip install elevenlabs`) | voice `21m00Tcm4TlvDq8ikWAM` (Rachel) | | Neither, and not logged in | TTS | local Kokoro, voice `am_michael` (for non-English, pass `--voice`) | | `GEMINI_API_KEY` (one key for both uses) | Capture vision caption + Lyria BGM | unset -> captions use DOM context only; BGM uses local MusicGen (first run downloads ~300 MB) | ## Flow ### Step 0.0 - Confirm the brief (one round, then build) Before Step 0, in **one** message confirm only what materially shapes the launch video and you can't infer — lead with a recommended default, skip anything the user already gave: the **angle / focus** (the product overall, a headline feature, an offer / CTA), **length** (default ~30-90s; up to ~3 min), and — if `/hyperframes` did not already set them — **aspect** (default 16:9; 9:16 for vertical / social) and **language**. The preset is derived from brand capture, not asked. For a fully specified request, skip this and build. ### Step 0 - Initialize the video project cwd is the agent workspace root; all video artifacts go in `PROJECT_DIR = videos//`. **Naming ``**: an explicit user-given directory wins; otherwise choose a short kebab-case name like `-promo` (**never** the workspace basename or a timestamp). From a URL, derive it from the domain/page title; the name is fixed once `capture/` is written. **Initialization** (only when `$PROJECT_DIR/hyperframes.json` does not exist): ```bash PROJECT_DIR="${LAUNCH_VIDEO_DIR:-videos/}" mkdir -p "$(dirname "$PROJECT_DIR")" npx hyperframes init "$PROJECT_DIR" --non-interactive --skip-skills --example=blank ``` > `hyperframes init` drops a generic `AGENTS.md` / `CLAUDE.md` into `$PROJECT_DIR`; leave them in place but do not treat their generic guidance as run-time constraints — this skill is the source of truth. **Constraints** (each violation breaks later phases): - Do not run `hyperframes init` (or generate `AGENTS.md` / `CLAUDE.md`) in the workspace root; do not create a `hyperframes/` subproject inside `PROJECT_DIR`. - Every subagent dispatch context contains a `PROJECT_DIR: ` line; the subagent treats it as the project root. - **cwd discipline (master too)**: every Bash command runs as a `(cd "$PROJECT_DIR" && ...)` subshell — never bare `cd "$PROJECT_DIR" && ...` (persistent cwd drift makes later relative paths wrong). ### Step 0.5 - API key guidance **Skip when** `$PROJECT_DIR/.env` exists or `context.log` is non-empty. Otherwise detect what's configured (HeyGen TTS = `$HEYGEN_API_KEY` / `$HYPERFRAMES_API_KEY` / `~/.heygen/credentials`; ElevenLabs / Gemini = their env keys), then **always pause and ask — do not proceed on your own, even when a workable config is detected**: > Detected: . Cloud keys are optional — without them, unconfigured providers fall back locally (TTS -> Kokoro unless HeyGen is configured; BGM -> MusicGen). Reply with: > > - paste keys -> I will write them to `$PROJECT_DIR/.env` > - "go" -> proceed with what is configured now > - "skip" -> proceed with local fallbacks for anything unconfigured Pasted keys -> Write/Edit `$PROJECT_DIR/.env`, one `KEY=value` per line (overwrite same-name keys, do not judge values). "go" / "skip" -> Step 1. ### Step 1 - Capture (Phase 1) 1. Resolve `SKILL_DIR` and any explicit `TARGET_URL` from the prompt; ensure Step 0 ran. 2. Read `$PROJECT_DIR/context.log` if it exists and use the Resume table below to skip completed phases. 3. **Classify the input** (Step 1.0) to set `CAPTURE` and `VO_MODE`, then run the matching path. Both paths share the same downstream commands. #### Step 1.0 - Classify the input (set CAPTURE + VO_MODE) | Input shape | What to do | | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Explicit URL in the prompt** | `TARGET_URL` = that URL; `CAPTURE=yes`; no voice-over question (narration comes from the captured site). Path (A). | | **User pasted / pointed at a script or brief** | (1) Save the verbatim text to `$PROJECT_DIR/user_script.txt`. (2) **Ask the voice-over question once** (below) → set `VO_MODE`. (3) **Resolve a capture target from the script** (below) → set `CAPTURE`. | | **A topic / brief with no script prose, no product** | `CAPTURE=no`; no voice-over question. Path (B). | **Voice-over question** (only when the user supplied actual script prose) — ask one short line and wait: > Should I use your script **verbatim** as the voice-over, or **restructure** it into more screen-ready scene narration? > > - Verbatim — keep the original wording; I only split scenes and pair visuals. Duration follows the script. > - Restructure — treat it as a brief and rewrite tighter narration, 1-2 sentences per scene. `VO_MODE = verbatim | restructure` (default `restructure`); threaded to story-design in Step 2. **Resolve a capture target from the script** — default to finding and crawling a site (real brand tokens beat preset fallbacks); skip only when the user opted out ("no web / text-only / no capture"). In order: (1) explicit `http(s)://` URL in the script → use it, announce, `CAPTURE=yes`; (2) clear brand/product name → `WebSearch` for the official site, **confirm the resolved URL with the user in one line** before crawling (decline / nothing credible → `CAPTURE=no`); (3) nothing derivable → `CAPTURE=no`. > **Capture + user script coexist**: the crawl supplies only brand tokens + assets + visual register; the narration spine stays `user_script.txt` (honored via `VO_MODE`), never the site's own copy. **(A) Capture path (`CAPTURE=yes`)**: ```bash (cd "$PROJECT_DIR" && npx hyperframes capture "" -o ./capture) ``` **(B) No-capture path (`CAPTURE=no`)** — synthesize a minimal capture package; downstream is identical. **You (master) choose the preset** (no site to infer from; pick from the 19 presets per user intent, or ask one short question). The full script/brief goes into `visible-text.txt`; `colors:[]` triggers the preset-palette fallback (fill `colors` only if the user named brand colors): ```bash (cd "$PROJECT_DIR" && mkdir -p capture/extracted capture/assets) (cd "$PROJECT_DIR" && cat > capture/extracted/tokens.json <<'JSON' { "title": "", "description": "", "colors": [], "fonts": [], "headings": [], "sections": [], "ctas": [], "svgs": [], "cssVariables": {} } JSON ) (cd "$PROJECT_DIR" && echo '{}' > capture/extracted/design-styles.json) (cd "$PROJECT_DIR" && printf '%s\n' "" > capture/extracted/visible-text.txt) ``` > If the user already has a final `narrator_scripts.json`, place it in `$PROJECT_DIR/`; the Resume table skips story-design. **Shared downstream for both paths** (Path B appends `--style ` to build-design; Path A omits it for auto-inference): ```bash (cd "$PROJECT_DIR" && node /scripts/derive-context-pack.mjs --capture ./capture) (cd "$PROJECT_DIR" && node /phases/design-system/scripts/build-design.mjs ./design-system --no-emit) # Path B: append --style ``` Validation (stop and report if anything is missing; if `capture/BLOCKED.md` exists, the site blocked the crawl — follow the instructions inside it): ```bash [ -s "$PROJECT_DIR/capture/extracted/tokens.json" ] && \ [ -s "$PROJECT_DIR/capture/extracted/design-styles.json" ] && \ [ -s "$PROJECT_DIR/capture/context_pack.md" ] && \ [ -s "$PROJECT_DIR/design-system/inference.json" ] && \ [ -d "$PROJECT_DIR/capture/assets" ] && echo ok || echo missing ``` ### Step 1b + Step 2 - design-system ∥ story-design (parallel fork) Both subagents depend only on Step 1 artifacts and do not read each other's output — after capture validates, start them **in parallel** (two concurrent background dispatches, per the dispatch adapter); do not serialize: - **design-system**: prompt = full `agents/design-system.md` + `## Dispatch context` with `SKILL_DIR` / `PROJECT_DIR` / `Target URL` + the full text of `design-system/inference.json` inlined via `cat` (~2-4 KB, saves the subagent one Read). - **story-design**: prompt = full `agents/story-design.md` + `## Dispatch context`: ``` SKILL_DIR: PROJECT_DIR: