---
name: wicked-garden-demo
description: |
  Product demo domain: plan, record and review a polished demo video.
  plan — frames the audience, builds the story, picks hero cases and fresh
  alternates, runs a live rehearsal with measured timings, and writes a
  presenter script with a chapter list ready for recording.
  record — records each chapter as its own captioned, chaptered segment via
  Playwright + ffmpeg (DevTools frames at JPEG q95, H.264 CRF 17), then
  stitches them into one MP4 with chapter markers.
  review — generates labelled contact sheets of stills (at chapter slides,
  joins, and the end) and delivers a per-issue verdict: re-encode, re-record
  one segment, or fix the app.

  Use when: "plan a demo", "demo script", "presenter notes", "run of show",
  "rehearse a demo", "record a demo video", "walkthrough video", "feature
  tour", "re-record a segment", "stitch segments", "review the demo video",
  "QA the recording", "contact sheet", "demo workflow", "offline demo".
metadata:
  role: router
  phases: "*"
  archetypes: "*"
---

# Demo

Plan a chapter-by-chapter demo story, record it chapter by chapter with captions
and callouts, then review with contact sheets — three actions, one domain.

## Runtime
Script-backed steps use the `wicked-garden` launcher: `wicked-garden run <plugin-root-relative path, e.g. scripts/…> [args]`. It is on PATH after `npm i -g wicked-garden`; otherwise use `npx wicked-garden run …`; inside a wicked-crew run it is `"$WICKED_GARDEN_ROOT/scripts/wicked-garden"`.
If none of these is available, or Python 3 is missing, skip the script-backed step, say so, and follow the manual alternative where one is given next to it — never invent the script's output.
Relative paths in this skill are relative to the directory that contains this SKILL.md.

## Routing

| Action | When | How |
|--------|------|-----|
| `plan` | No chapter list yet; first time or after a product change | Inline — follow § plan below |
| `record` | Chapter list and case bank exist; recording or re-recording | Script-backed — `wicked-garden run scripts/demo/record.mjs` |
| `review` | A recording exists and needs QA | Script-backed — `wicked-garden run scripts/demo/contact_sheet.py` |

## Action: plan

A good demo is a story the audience can follow, told with cases that behave the same
way every time, and numbers that were actually measured. **Do not write the script
before the rehearsal** — the script describes what the audience will actually see.

Produces: `<product>-demo-script.md` and a chapter list ready for the `record` action.

### 1. Frame it

Establish and write down:

- **Audience**: who watches, what they already know, what decision the demo should help them make.
- **Pitch**: one paragraph — the problem today, what the product does about it, and the guardrail.
- **Use case**: three sentences a listener could repeat (typical request → what the product does → outcome).
- **Capabilities**: a flat list of what the product can show. Each capability that matters to this audience becomes a chapter.

### 2. Build the story

One chapter per capability, ordered so each raises the stakes of the last:

| # | Chapter | Purpose |
|---|---------|---------|
| 1 | Triage / landing | "Here is my day": what needs attention, ranked |
| 2 | Core flow, end to end | One clean case from intake to done |
| 3-4 | Hard cases | Messy input, missing information, exceptions |
| 5 | Learning / governance | How the product gets smarter safely |
| 6 | Knowledge / trust | Where the rules come from, how results trace back |
| 7 | 360 view | Everything about one customer or entity |
| 8 | Wrap-up | Audit trail and measured numbers |

Keep chapters self-contained — each starts from a known page and uses its own cases.
Details and caption voice: `refs/storytelling.md`.

### 3. Choose the cases

- **Truth first**: use scenarios whose expected outcome you know in advance (the finding it
  should raise, the plan it should produce). Seeded or synthetic data with an answer key.
- **One hero case per chapter** plus **fresh alternates** (same story, different names and numbers).
- **Mark state-consuming chapters** (those that analyze, approve, upload, or teach). Prefer read-only.
- Record the case bank as a table: case, story, entity, what it demonstrates, fresh/used, alternates.

### 4. Make it repeatable

Before rehearsing, ensure the demo can be put back exactly as it was:

- A **per-case reset** command that rewinds only the named cases.
- A **fresh/used listing** so the presenter can check readiness in seconds.
- **Deterministic data** (seeded generation, cached model text).
- A **pre-flight checklist**: services and URLs, environment/dataset, business date, persona, fresh cases, files, tabs.
- **Pre-bake** slow steps for live sessions; say so in the script.

If a reset does not exist, build or request it first — it is the difference between a demo and a one-off.

### 5. Rehearse live

Run every chapter the way the UI does it against the real system and log as you go.
Full procedure: `refs/rehearsal.md`.

- **Time every step** (wall clock) and keep the raw numbers.
- **Capture what the audience sees**: exact labels, counts, the key sentence of each result.
- **Log rough edges** with the case key; triage each: fix it, script around it, or drop the chapter.
- **Reset afterwards** and confirm every case is fresh again.

### 6. Keep claims honest

- **Measured** means timed in a rehearsal or recording on this system; say where and when.
- **Estimate** means a manual-baseline guess; label it "estimate, team to validate" every time.
- Say plainly which systems are **simulated** and that the data is **synthetic**.
- Show the guardrail every time you show automation: who approved, what was refused and why.

### 7. Write the presenter script

Use the templates in `refs/templates.md`:
- The **presenter-script template** provides the overall document structure (pitch, setup, run of show,
  case bank, recovery tips, Q&A).
- The **segment block template** covers each chapter (case, click, say, audience sees, under the hood,
  speed-up, rough-edge note).

Style: skimmable. Tables and short bullets, exact UI labels in **bold**, quotes in *italics*, one idea per line.

### 8. Keep it in sync, then hand off to record

- **Keep the script in sync with rehearsal changes**: after any fix lands, update the affected segment and add a
  **Changes since the rehearsal** block at the top of the script — what changed, whether it was seen in a browser,
  and which timings predate it.
- Re-rehearse chapters whose behaviour changed; replace numbers only with new measurements.

For each chapter write:
- **Key**: `NN-slug` (`01-dashboard`) — stable, used for files and re-recording.
- **Title**: 2-6 words, sentence case.
- **Blurb**: one sentence that states what the chapter proves.
- **Tags**: 2-5 capability chips.
- **Resets**: the cases it changes.

That list becomes the `segments` array in the storyline file for the `record` action.

### Checklist (acceptance gate)

`plan` is done only when every item is checked:

- [ ] Audience, pitch, three-sentence use case written
- [ ] Capabilities listed; one chapter each, ordered as a story
- [ ] Hero case + fresh alternates per chapter; state-consuming chapters marked
- [ ] Per-case reset and fresh/used listing work; pre-flight written
- [ ] Every chapter rehearsed live; timings and audience-visible results logged; rough edges triaged
- [ ] Script written from the template; measured vs estimate labelled everywhere
- [ ] Cases reset and confirmed fresh after rehearsal
- [ ] Chapter list ready for recording (keys, titles, blurbs, tags, resets)

---

## Action: record

Turn the chapter list into a captioned, chaptered MP4 that looks produced rather than screen-grabbed.
Requires: Node.js ≥ 20, ffmpeg and ffprobe on PATH (or `FFMPEG=/path/to/ffmpeg`),
and the web app running and reachable.

### Install (once per machine)

```sh
wicked-garden run scripts/demo/setup.mjs
```

Confirm: `ffmpeg -version` and `ffprobe -version` both work.

### Write the storyline

Copy `assets/example-storyline.mjs` next to your project (e.g. `demo/storyline.mjs`) and
replace the segments. Keep each segment self-contained: it starts from `startPath`, resets its
own data in `beforeSegment`, and never relies on another segment's state.

Full module shape and the `ctx` API: `refs/storyline-api.md`.
Visual system (stage layout, captions, callouts, chapter slides, time-lapse): `refs/stage-design.md`.

### Probe selectors (read-only)

Before writing `run()` bodies, load each page without clicking to confirm every locator:

```sh
wicked-garden run scripts/demo/probe.mjs <baseUrl> /page1 /page2
```

Saves a screenshot and lists headings, sections, buttons with ARIA roles, inputs and links.

### Record

```sh
wicked-garden run scripts/demo/record.mjs <storyline.mjs>              # record missing segments, then stitch
wicked-garden run scripts/demo/record.mjs <storyline.mjs> 03-search    # (re)record one segment, restitch
wicked-garden run scripts/demo/record.mjs <storyline.mjs> --all        # re-record everything
wicked-garden run scripts/demo/record.mjs <storyline.mjs> --stitch     # stitch existing segments only
wicked-garden run scripts/demo/record.mjs <storyline.mjs> --reencode   # rebuild from saved frames, restitch
wicked-garden run scripts/demo/record.mjs <storyline.mjs> --list       # which segments are recorded
```

Options: `--out <dir>` (default `demo-video/` next to the storyline).
Environment: `FFMPEG`, `DEMO_BASE_URL`, `DEMO_HEADFUL=1`, `DEMO_ALLOW_WRITES=1`.

**Read-only by default.** While it records, the browser sends no writes: every request that is not
GET, HEAD or OPTIONS is aborted, and so is every WebSocket frame the page sends (frames the server pushes
still arrive). The segment fails `side_effect_blocked`, naming each request. A failed take deletes that
segment's old `segment.mp4`, and while any segment's last take was blocked, `--reencode` and `--stitch`
refuse to run: re-record it (or remove its directory) first. Service workers are blocked while recording.
So a recording can never launch, approve, create or delete anything on the app it films. Show a control
without pressing it. `DEMO_ALLOW_WRITES=1` lifts the guard, but only for a disposable target you started
for the demo (a fixture server or a scratch database), never for a live system. `recording.json` records
how each stitched segment was recorded.

Record one segment first, review its stills with the `review` action, then record the rest.

### Restore the app

Reset whatever the recording consumed (run the per-case reset for every segment's `resets`) so the live demo
starts fresh, and confirm the cases list as fresh again.

Deliverable: `<out>/<slug>.mp4` (stitched), `chapters.md`, `timings.json`, `recording.json`, `segments/<key>/`.

Hard-won failure modes and fixes: `refs/gotchas.md`.

### Before you call it done (acceptance gate)

`record` is done only when every item is checked:

- [ ] Every segment probed read-only, then recorded without errors; `--list` shows all recorded.
- [ ] Stills reviewed: opening slides, each caption against its picture, callouts on target, joins, closing card.
- [ ] No caption claims something the video doesn't show; waits are badged; the closing card shows measured numbers.
- [ ] Simulated systems and synthetic data are labelled where the audience could mistake them for real.
- [ ] Recorded read-only (`recording.json` says `"readOnly": true`), unless the target is disposable.
- [ ] The app's data is reset afterwards; services you didn't start are still running.
- [ ] The MP4 plays from start to end with chapters (`ffprobe -show_chapters <file>`).

---

## Action: review

Review a recording by looking at stills, not by watching the whole video. A few targeted
contact sheets catch almost every defect in minutes and give exact timestamps to report.

### Contact sheets

```sh
wicked-garden run scripts/demo/contact_sheet.py <video.mp4> --chapters        # ~2 s into every chapter
wicked-garden run scripts/demo/contact_sheet.py <video.mp4> --chapters --offset 8  # first content of each chapter
wicked-garden run scripts/demo/contact_sheet.py <video.mp4> --joins           # just before + after every boundary
wicked-garden run scripts/demo/contact_sheet.py <video.mp4> --end             # last seconds: closing card held?
wicked-garden run scripts/demo/contact_sheet.py <video.mp4> --every 20 --cols 4    # survey
wicked-garden run scripts/demo/contact_sheet.py <video.mp4> --at 1:02,1:05   # zoom in on a moment
wicked-garden run scripts/demo/contact_sheet.py segments/05/segment.mp4 --every 8  # one segment alone
```

Options: `--offset` (seconds into each chapter, default 2), `--join-gap` (seconds either side of a boundary for
`--joins`, default 0.6), `--end-span` (seconds before the end for `--end`, default 6), `--cols` (tiles per row,
default 3), `--width` (tile width in px, default 640), `--out` (output PNG; default `<video>-sheet.png` next to the
video). Full list: `wicked-garden run scripts/demo/contact_sheet.py --help`.

Also check format: `ffprobe -v error -show_entries format=duration:stream=codec_name,width,height,r_frame_rate -show_chapters <video.mp4>`.

### Review passes (in this order)

1. **Structure** (`--chapters`, ffprobe): every chapter present, in order, titled, 1920x1080 H.264.
2. **Joins** (`--joins`): plain background → next chapter slide, no setup flash.
3. **The end** (`--end`): closing card present and **held** for its full duration.
4. **Survey** (`--every 20`, then `--at` around anything odd): caption sync, callouts, cursor, waits, state.
5. **Numbers**: timings on the closing card match `timings.json` and what the app shows.

Full per-item checklist with causes and fixes: `refs/review-checklist.md`.

### Verdicts

Classify every finding before fixing anything:

| Verdict | When | Fix |
|---------|------|-----|
| **Re-encode** | Timing, trimming, speed-up, frame rate, chapter metadata, missing end hold | Rebuild from saved raw capture — no re-recording (`--reencode`) |
| **Re-record one segment** | Wrong caption, callout, stale data, wrong persona, unannotated wait | Fix the storyline for that segment, reset its data, record only it, restitch |
| **Fix the app** | Errors, crashes, stale UI, wrong numbers, confusing copy | Fix and rebuild, then re-record affected segments. Report to the product owner too |

Report findings as: `timestamp · chapter · what's wrong · verdict`.
Re-review only the changed segments plus the joins on either side, then run `--end` again.

Deliverable: contact-sheet PNGs + findings table with verdicts.

### Checklist (acceptance gate)

`review` is done only when every item is checked:

- [ ] All five review passes run, in order, on the final file.
- [ ] Every finding reported as `timestamp · chapter · what's wrong · verdict`.
- [ ] After fixes: changed segments and the joins on either side re-reviewed, and `--end` run again.

---

## References

- `refs/storytelling.md` — chapter design, ordering, metadata (keys, blurbs, tags), caption voice, honest claims
- `refs/rehearsal.md` — rehearsal procedure: how to drive it, what to log, rough-edge triage, post-rehearsal
- `refs/templates.md` — presenter-script template and per-segment block template
- `refs/stage-design.md` — the visual system: layout, typography, captions, callouts, chapter slides, time-lapse badge
- `refs/storyline-api.md` — storyline module shape, all `ctx` methods, rules of thumb
- `refs/gotchas.md` — failure modes and fixes: capture, clicking, scrolling, timing, environment
- `refs/review-checklist.md` — full QA checklist with symptom → cause → fix → verdict per item
