demo-director
Turn a SaaS web app into a polished 60-90s marketing demo video — explore the app with Playwright, extract its brand, write a playbook-driven script, narrate…
Skill by baldiga
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/baldiga-demo-director
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: design, frontend, testing, writing
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/demo-director
What's inside
- Skill name
demo-director- Description
- Turn a SaaS web app into a polished 60-90s marketing demo video — explore the app with Playwright, extract its brand, write a playbook-driven script, narrate with local Kokoro TTS, capture real footage, and render with Remotion. Use when the user asks for a product demo video, marketing video, or promo video of a web app.
- License
- MIT
- Instructions
- 128 lines in SKILL.md · view on GitHub
Files (4)
- SKILL.md
- demo-playbook.md · references/
- storyboard-spec.md · references/
- troubleshooting.md · references/
SKILL.md (first lines)
# DemoDirector
You are directing a marketing demo video of a real SaaS app. CLI scripts do the mechanics; you do the judgment. All commands run from the repo root; all artifacts live in `jobs/<slug>/`. Read `references/demo-playbook.md` BEFORE writing any script or storyboard, and follow it mechanically. When anything breaks, check `references/troubleshooting.md` first.
## Stage 0 — Brief
1. Run `npm run doctor` (= `npx tsx scripts/doctor.ts`). If anything is MISS, give the user the printed install hints and stop until resolved. espeak-ng showing WARN is fine — TTS bundles espeak via espeakng-loader. If `uv` is MISS only because the shell predates a fresh install, set `$env:UV` to the full uv.exe path and use it in Stage 4 instead of `uv` (see troubleshooting).
2. Ask the user (one message, all questions): app URL; login needed? (offer: manual login in a headed browser / .env credentials / none); preset (default **narrated-75s**); target audience; any features they insist on including; optional music file path.
3. Create `jobs/<slug>/project.json` matching `ProjectSchema` (see `src/schemas.ts`). Slug: lowercase-kebab from app name.
## Stage 1 — Explore
1. If login is needed: `npx tsx scripts/explore.ts <url> jobs/<slug>/discovery --profile jobs/<slug>/browser-profile --login` — a headed browser opens at the app and stays open; tell the user to log in there, then press Enter in the terminal to save the profile. Then continue with the full explore.
2. Run `npx tsx scripts/explore.ts <url> jobs/<slug>/discovery --profile jobs/<slug>/browser-profile --max 15`.
3. **SPA fallback:** if fewer than 3 screens come back, read the first screen's ariaSnapshot, derive the app's main routes from its nav, and re-run with `--routes /route1,/route2,...`. For apps that navigate only by clicking (no route URLs), capture the missing screens later with tiny shot-only playbooks via capture.ts (`record: false`, click steps, a final `shot`).
4. Read `discovery/raw-screens.json`; view each screenshot; read each ariaSnapshot.
5. Write `jobs/<slug>/discovery/feature-map.json` (FeatureMapSchema): name each screen, its purpose, a 1-5 marketingScore (5 = shows the aha moment), and keyActions with **a11y targets you saw in the snapshots — never invent UI labels**.
## Stage 2 — Brand
1. Run `npx tsx scripts/brand.ts <url> jobs/<slug>/brand`.
2. Read `brand/brand-raw.json`. Curate `brand/brand.json` (BrandSchema): pick primary/accent/background/text (prefer css-var > theme-color > manifest > vibrant), choose the best logo candidate (view the images), set fonts from computed values, record `sources`. Logo paths must be `brand/<file>` (public-dir relative).
### GATE A
Show the user: the feature map (table: screen, purpose, score) and the brand kit (palette swatches as hex, logo file, fonts). Ask: "Demo will focus on the top-scored features: <list 3>. Brand kit look right?" Adjust per feedback before continuing.
## Stage 3 — Creative
1. Re-read BOTH `references/demo-playbook.md` AND `references/storyboard-spec.md` before writing anything. Write `jobs/<slug>/script.md`: narration per beat (hook / problem / solution / 3 features / proof / cta), word counts per the WPM budget (seconds × 2.5), hook from the playbook formulas, benefit-first lines, exactly one CTA.
2. Write `jobs/<slug>/storyboard.json` (StoryboardSchema) and one capture playbook YAML per clip/still scene in `jobs/<slug>/playbooks/` (exact contracts + a worked example of each: `references/storyboard-spec.md`). Targets MUST come from feature-map keyActions. Every click needs a `done`. Vary transitions and scene rhythm; zoom only on trigger+payoff.
- **Caption placeholder rule:** write `"captions": []` for every scene that will get captions. Do NOT invent `atMs` values at this stage — they must come from `timing.json` word timestamps produced in Stage 4. See the caption-authoring step below.
**v2 composition rules (apply to every storyboard from template v2 onward):**
- **Prefer `component` scenes for hero moments.** One billboard-scale recreated UI element per beat beats a full-page clip every time. Use `kinetic`, `clip`, or `still` for context-setting and transitions; use `component` for the beats where you need the viewer to feel "oh, that's the product."
- **Kinetic punch for hook and problem.** The cold-open hook and the problem beat should almost always be `kinetic` with `layout: "punch"` — one short claim per line, emphasis words in the brand accent, no footage needed.
- **Hard-cut budget: ≤1 per 10s.** Everything else transitions via `"fade"` plus camera moves and element fly-ins over a persistent background. Back-to-back `"cut"` transitions are a machine-generated tell. Reserve `"cut"` for chapter boundaries only.
- **Set `musicBpm` when music is known.** Add `"musicBpm"` to `project.json` whenever you have a track — compose will snap all scene durations to the beat grid automatically. Do not hand-pad `minDurationMs` to approximate beats.
- **Camera variety across consecutive scenes.** Never assign the same `camera` preset to two consecutive `component` or `clip`/`still` scenes. A sequence like `tiltIn → floatSlow → pushIn` reads as intentional; `floatSlow → floatSlow → floatSlow` reads as a default dump.
- **Real data only in component props.** Every prop you pass to a `component` scene must come from what you actually saw in the app (snapshots, screenshots, feature map). The default props in each component are ZOOQ-specific and must be overridden for any other product.
3. **Capture physics:** the screencast only emits frames when pixels change — a flow that should breathe on screen needs explicit `wait` steps (they extend the last frame's encoded duration; idle without them adds nothing). Place waits where the viewer must absorb the UI.
4. Pick `fit` per clip scene: **speed-fit** for flows longer than their narration, **hold** for payoff moments that should freeze on the result, **trim** rarely.
5. Validate: every storyboard playbook file exists; each playbook's `scene:` equals its storyboard scene id; narration word counts fit scene durations; ≤3 feature beats.
### GATE B
Show the user script.md (full text) and a scene-by-scene storyboard summary (beat, visual, narration line, planned zooms/overlays). Iterate until approved.
## Stage 4 — Narrate
### Pronunciation respelling rule
Brand names, initialisms, and unusual proper nouns must be respelled phonetically **in the narration text only** — on-screen text (overlays, kinetic lines, captions, component props) always keeps the correct spelling.
| correct spelling | narration respelling | rationale |
|---|---|---|
| ZOOQ | Zuke | TTS would otherwise say "Zoo-cue" or "Zok" |
| JSON | Jason | TTS says "Jay-son" for the respelling; Jayson → natural |
| SQL | sequel | standard dev pronunciation |
| API | A-P-I | read letter by letter; no respelling needed (TTS handles it) |
| MCP | M-C-P | same — letter-by-letter is correct |
**General technique:** test a respelling by running TTS on just that word/phrase, listen to the output, adjust the spelling until the pronunciation is natural, then use it throughout the narration. Keep narration and on-screen visuals decoupled — the viewer reads "JSON" on screen while hearing "Jason" in the audio; they are the same word to the viewer.
The zooq-v3 project shows both in action — `project.json` `userNotes` documents the respellings used, narration says "Zuke" and "Jason", while the on-screen title card and terminal component show "ZOOQ" and "JSON".
### Voice and speed guidance
- **`af_bella` @ speed 1.15–1.2** — punchy launch cuts, energetic tone. Use for 20–45s social/teaser formats. Speed 1.2 is the sweet spot for keeping energy high without sounding rushed. At 1.2 speed, target ≈ **duration_target_seconds × 2.4 words** for VO (not the base 2.5 — the speedup buys ~4%).
- **`am_michael` @ speed 1.0** — calm technical walkthroughs, enterprise audience. Measured pace, clear enunciation. Target the base 2.5 words/second budget.
- Set `"voice"` in `project.json` once; all TTS calls pick it up automatically.
### Running TTS
```
uv run --project scripts/tts scripts/tts/speak.py --text "<narration>" --out jobs/<slug>/audio/<sceneId> --scene <sceneId> --voice <project.voice>
```
(If `uv` isn't on PATH, substitute the full path: `& $env:UV run --project scripts/tts ...`.)
Writes `audio/<sceneId>.wav` + `.timing.json` and prints `{"durationMs":...,"words":...}` on stdout. Check durationMs against the scene's word budget; if a scene runs >15% long, tighten the line and regenerate. First run downloads the ~300MB model — be patient.
### Caption authoring step (after TTS)
Captions need `timing.json` word timestamps — this step cannot happen before TTS.
For each scene with captions planned:
1. Read `jobs/<slug>/audio/<sceneId>.timing.json` (the `words[]` array: `{ word, startMs, endMs }`).
2. Find the `startMs` of each keyword you want to caption.
3. Set `atMs` in the storyboard caption to that `startMs` (±100ms for feel).
4. Ensure consecutive captions don't overlap: `atMs[i+1] ≥ atMs[i] + durationMs[i]`.
5. Edit `storyboard.json` to fill the previously-empty `captions` arrays.
Only then run Stage 5 (capture) and Stage 6 (compose).
## Stage 5 — Capture
For each clip/still scene:
```
npx tsx scripts/capture.ts jobs/<slug>/playbooks/<scene>.yaml <baseUrl> jobs/<slug>/footage/<sceneId> --profile jobs/<slug>/browser-profile
```
The out dir MUST be `footage/<sceneId>` — compose joins footage to scenes by id. If a step fails, the error names the step and the scene's footage dir gets `failure-step-<i>.png` + `failure-step-<i>.aria.yml` + a partial `events.json` — view them, fix the playbook target/done, re-run **that scene only**. Spot-check each clip.mp4 and shot png.
## Stage 6 — Compose
1. `npx tsx scripts/compose.ts <slug>` → `render/preview.mp4` (HALF resolution, narration only — music joins only at `--final`; use `npm run studio` when iterating on look rather than content).
2. Self-critique against BOTH checklists in `references/demo-playbook.md` (scriptwriting + visual): extract stills with `ffmpeg -i jobs/<slug>/render/preview.mp4 -vf fps=1/10 jobs/<slug>/render/review-%02d.png` (≈6-8 stills on a 60-90s video; adjust the rate to length), view them, and verify pacing variance, overlay word counts, zoom restraint, brand colors, narration sync (listen at least once). Fix and re-compose until clean.
### GATE C
Send the user the preview path + your self-critique. Iterate on their notes (storyboard edits → re-run only affected stages).
## Stage 7 — Deliver
`npx tsx scripts/compose.ts <slug> --final` → `render/final.mp4` (full-res master, loudness-normalized to −14 LUFS / −1 dBTP; if `project.musicPath` is set, music is mixed in with true sidechain ducking under the narration) + `render/captions.srt`. Summarize what was produced and where.
## RulesFrom baldiga/headless-studio, MIT.
More from baldiga/headless-studio
- 0.543score
avatar-ad-director
baldiga
Turn a SaaS project's brand + screenshots into a ≤60s 9:16 UGC-style ad — one HeyGen realistic-avatar clip as the spine, composited in Remotion with…
SkillCFreshness: C★ 11Claude Code +9 - 0.294score
headless-studio
baldiga
No description from the publisher yet.
SkillCFreshness: C★ 11Claude Code +9
Signals
- Stars
- 11
- Forks
- 6
- Open issues
- 0
- Last commit (this folder)
- Jun 29, 2026 (4 months ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/baldiga/headless-studio
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from baldiga
- 0.543score
avatar-ad-director
baldiga
Turn a SaaS project's brand + screenshots into a ≤60s 9:16 UGC-style ad — one HeyGen realistic-avatar clip as the spine, composited in Remotion with…
SkillCFreshness: C★ 11Claude Code +9 - 0.468score
ZOOQ - LinkedIn Data for AI Agents
baldiga
Live LinkedIn data for AI agents: profiles, companies, jobs, posts, email finding.
ConnectorBFreshness: BRemoteRead-onlyClaude Code +3
Cite this page
demo-director skill. Agent Mart. https://agentmart.dev/skills/baldiga-demo-director (last updated 2026-10-24)