# Skill: Polish a recorded Inkly demo

You have a demo that was already RECORDED (by the image/video or HTML capture skill). Your job is to make it shippable: confirm every step is correct, cut what does not serve the story, sharpen the labels and pacing, and add the annotations, chapters, and cover screens that turn a raw capture into a guided demo. You do NOT re-drive the browser here unless a capture is fundamentally broken.

`demo.config.json` is plain, hand-editable JSON validated by `@inkly/runtime/schema` (`DemoSchema`). Editing it directly is the primary tool — prefer it over re-recording. For exact field shapes (step kinds, annotation types, coordinates, chapters, cover widgets, theme, voiceover), use the `inkly-cli-reference` skill or read `packages/inkly-runtime/src/schema` and `packages/inkly-runtime/src`; the schema is version-dependent, so trust the source over memory.

## What you are working with

A recorded demo is an unpacked folder (also shipped as a ZIP):

- `<slug>/demo.config.json` — the demo definition you edit (top-level `id`, `version: 1`, `title`, `steps[]`, optional `chapters[]`, `theme`, `chrome`, `background`).
- `<slug>/assets.json` — maps each `asset:<id>` (and `publicUrl`) to a file; records `sha256`, `kind`, `contentType`, `viewport`.
- `<slug>/public/<file>` — the captured PNG/WebM bytes (image/video steps).
- `<slug>/snapshots/snap-NNN/index.html` — the captured DOM (HTML steps).

Treat `public/`, `snapshots/`, and the capture-written `assets.json` entries as compiled output: edit `demo.config.json`, not the bytes.

## Building a demo from existing images or videos

You can also ASSEMBLE a demo from media the user already has (screenshots, screen recordings) instead of recording a fresh capture — add one content step per asset. The player's aspect ratio is the thing to get right:

- The player frame is sized ONCE from `demo.aspectRatio` if set, otherwise from the FIRST content step's background `naturalWidth`/`naturalHeight` (cover steps do NOT count). Every other step renders inside that same frame.
- So either (a) use assets that ALL share one aspect ratio, or (b) set an explicit top-level `aspectRatio: { width, height }` to lock the frame — off-ratio steps then fit/letterbox inside it. Prefer matching ratios; reach for `aspectRatio` when the set is mixed or there are no content steps.
- Make the FIRST content step the one whose ratio you want for the whole demo — it is the default driver. Order matters here.
- `naturalWidth`/`naturalHeight` are REQUIRED on every image and video background and must be the asset's real pixel size; they drive both sizing and the locked ratio, and annotation coordinates are normalized over them, so wrong values stretch the frame and misplace callouts.
- Reference each file via `asset:<id>` with a matching `assets.json` entry (`kind: image | video`), or a repo-relative path/URL. Then polish it with the steps below.

## Step 1 — Look at every frame

Automated/console checks do NOT catch the defects that matter — never ship on a clean log. OPEN and look at each step:

- Image/video steps: read each PNG (and video poster) under `<slug>/public/`. Most agent tools render an image you `Read`.
- HTML steps: open each `snapshots/snap-NNN/index.html` (or preview the demo — Step 6) and look at the rendered page.

## Step 2 — Fix correctness, per step

For EACH step confirm:

- POINTER: the click pointer sits on a real, visible element that matches the step's label, and is NOT stuck in the top-left corner. (Pointer/annotation coordinates are normalized 0..1 over the background's natural size — `0.5, 0.5` is dead center.)
- LABEL: a short phrase describing something actually on screen, phrased as an instruction (`Enter your email`, `Open the dashboard`) — not a paragraph, not a bare `Continue`/`Overview`, not a raw URL or placeholder literal. Rewrite weak labels.
- BACKGROUND: the frame is the page the click happened on and shows readable content — not a footer, a mid-animation frame, a hero obscured by an open menu/overlay, or a gated empty state.
- VIDEO steps: more than ~1s of visible smooth motion, and the annotation is legible while the clip plays.
- CONSISTENCY: content steps share a stable aspect ratio unless the user asked for mixed formats; no missing images, clipped pages, stretched video, or wrong logo overrides.

## Step 3 — Edit demo.config.json (it is just JSON)

- TRIM throwaway steps: a leftover cookie/consent dismissal, a login-screen frame when login was only a gate (keep it when the onboarding flow IS the demo), a duplicate frame, or a still that duplicates a video step's end state. Remove the step object from `steps[]` (and its id from any `chapters[].stepIds`). Its now-unused asset in `public/`/`assets.json` is harmless to leave.
- RELABEL: rewrite a step's `label` and any annotation `text` to read as clean, viewer-facing instructions. `text` supports inline markdown (`**bold**`, `*italic*`).
- REORDER: reorder objects in `steps[]` so the arc is value-first (see "Tighten the story").
- NUDGE a pointer/annotation: adjust an annotation's `x`/`y` (normalized 0..1) so the callout points exactly at the element.
- After any edit, the dev server (Step 6) prints schema errors verbatim — keep `demo.config.json` valid.

## Step 4 — Tighten the story

The demo should make ONE point. State the sentence a viewer should believe by the end, then make every step earn its place:

- Lead with value — the first step should land on the core capability or signature interaction, not chrome.
- One idea per step; cut any step that does not change what the viewer understands. A tight 5-7 step arc beats a flat 12-step tour.
- Sequence: hook -> core capability in action -> a differentiator -> a supporting feature -> payoff. Pricing/sign-up late. End on the moment you want remembered.
- If the recording cannot tell a coherent story even after editing, re-record (see the capture skill) — do not ship a weak demo.

## Step 5 — Enrich with schema features

Raw captures are bare backgrounds + a pointer. These DemoSchema features turn them into a guided demo (see `inkly-cli-reference` for exact fields):

- ANNOTATIONS on a content step's `annotations[]`:
  - `message` (the workhorse) with `variant: pointer | callout | area` — a pulsing dot, a pinned card, or a clickable region at normalized `(x, y)` (area also needs `w, h`). `text` is markdown; `anchor` picks the card edge. On HTML steps a message can pin to a captured element via `target: { type: 'html-element', alphaId: '<data-inkly-id>' }` instead of `x/y`.
  - `blur` `{ x, y, w, h, intensity }` to mask PII or unreleased UI.
  - `text` `{ x, y, text, fontSize, color }` for a free-floating label.
- ZOOM/PAN: a content step's `transform: { zoom, x, y }` (focal point normalized 0..1) zooms into the detail that matters. Capture also auto-applies click zoom; tune or remove it here.
- CHAPTERS: `chapters: [{ id, title, stepIds: [...] }]` group steps into a navigable outline. Every `stepId` must exist in `steps[]`.
- COVER steps (`kind: 'cover'`) for an intro/outro: a single `headline` widget (title, description, `cta` with `action` like `{ type: 'next' }`, `{ type: 'url', href }`, `{ type: 'restart' }`) or a `form` widget for lead capture. Add a hook intro and a payoff/CTA outro.
- PRESENTATION: `background` (page canvas behind the player), `theme` (per-demo `preset`/`tokens`/`brand`), `chrome` (`hideHeader`, `controls`, `showHubBreadcrumb`, `autoplay`), and `aspectRatio` to lock the frame.
- NARRATION (optional): per-step `script` (text) + `voiceover` (TTS audio) + `captions` — see "Add voiceover" below.

## Add voiceover (optional)

When the user wants a narrated demo, add per-step audio. Three related step fields:

- `script` — the narration TEXT for the step (you author it; it persists independently of the audio so it survives later edits).
- `voiceover` — `{ src, duration? }`, the generated clip. `src` is an audio asset: an `asset:<id>` (preferred), a repo-relative path under `public/`, or an `https://` URL. `duration` is the clip length in ms.
- `captions` — `[{ id, text, start?, end? }]` (ms). With `voiceover` present, cues track the audio clock; without it they track step-elapsed time. Omit `start`/`end` to hold a caption for the whole step.

Workflow:

1. Write a tight `script` for each step — one or two sentences that match what is on screen.
2. Synthesize audio with a TTS API. ElevenLabs (11labs) is a good default; any TTS that returns an audio file works (OpenAI, Google, Azure, PlayHT). Use ONE consistent voice across steps. The user supplies the API key via env — never hardcode or print it.
3. Save each clip under `<slug>/public/` (e.g. `public/vo-<stepId>.mp3`), add an `assets.json` entry with `kind: 'audio'`, and set that step's `voiceover.src` to the new `asset:<id>` (plus `duration` in ms if known).
4. Optionally add `captions` derived from the script for accessibility; keep cues short.
5. Preview (next step) WITH sound and confirm the audio matches each step and its pacing.

## Step 6 — Preview with inkly dev

Render the real thing and click through it:

- Put the demo in a hub: from an existing hub, copy the `<slug>/` folder into its `demos/` directory and add the slug to a collection in `inkly.json`. To make a throwaway hub: `inkly init preview-hub`, then copy `<slug>/` into `preview-hub/demos/` and reference it.
- `inkly dev` — serves the hub at `http://localhost:3000`; each demo is at `/<slug>`. It watches the files and live-reloads, and prints schema errors verbatim.
- Click through EVERY step: re-confirm the Step 2 checklist in motion (pointers land, annotations are legible and well-anchored, video plays, chapters/CTA navigate correctly, no clipped or empty frames).

## When to re-record instead of edit

Editing fixes labels, trims, reorders, annotations, pacing, and presentation. Re-record (capture skill) only when the underlying capture is wrong: a mismatched/blank background, a broken top-left pointer, missing video motion, or a step that landed on the wrong page. Do not try to repaint a broken frame in JSON.

## Return

Report what you changed (steps trimmed, relabeled, annotations/chapters/cover/voiceover added, aspect ratio locked), the final step count, the demo folder path, and the preview URL if you started `inkly dev`.
