# UI Demo Video

> Use after UI work that can be verified visually, such as a new element, layout change, or user flow in a web app whose dev server a browser can drive. Not for API-only or non-visual changes, and not a test suite.

- Skill: `giostriquer/ui-demo-video` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add giostriquer/ui-demo-video`
- Raw SKILL.md: https://api.skillmd.com/api/skills/giostriquer/ui-demo-video/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: giostriquer (https://skillmd.com/u/giostriquer)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/giostriquer/ui-demo-video

---


# UI Demo Video

Record a Playwright-driven walkthrough of the running app into a shareable video,
emitting a PNG frame per scene. **The frames are the point for the model**: Read
them after recording to visually verify the UI state, and iterate (fix code or
scenario, re-record) until the frames show the expected result. The video is the
human-shareable artifact (GitHub PR descriptions accept mp4 drag-drop).

## When to use

After UI work that a video can verify: a new element, layout change, or flow.
Use proportionate visual feedback with existing tooling. Record a video when
requested, required by the repo, or useful within the authorized UI task; a small
visual check does not require installing a recording toolchain.
Not for API-only or non-visual changes, and not as a test suite: scenes
demonstrate and verify visually, they do not assert.

## Prerequisites

- The app runs locally. Find the project's documented run path: a project run
  skill, README, package scripts, and use that; do not invent a launch command.
- Playwright is installed **in the project** (`@playwright/test` or
  `playwright`) with a Chromium browser available. If absent, use an available
  browser tool for visual checks and report the video prerequisite. Install a new
  persistent dependency/browser only when that setup is in the authorized scope,
  using the repository's package manager and documented setup. Do not silently
  modify package or lockfiles just to record a demo.
- `ffmpeg` on PATH for mp4 conversion (optional: the webm is always produced).

## Workflow

1. **App running first.** Start the dev server via the documented run path, in
   the background, and health-check it before anything else. If booting can
   reseed or migrate a local dev database, back that file up first. Seed the
   data the scenes need through the app's **real surface**: a fixture/seed
   endpoint, the REST/RPC API, a documented CLI seeder, never direct DB
   writes: seeded state must pass the same validation real usage does.
2. **Copy the harness, then write a scenario file next to it.** Copy
   `scripts/harness.mjs` from this skill's directory into the project's `tmp/`
   folder: the harness must live inside the project so Node resolves the
   project's own Playwright install: then write `tmp/<scenario>.mjs` beside it
   (example below). Scenes should be short and named for what they prove. Use
   `highlight()` to draw the eye to the element under test. List every route
   the scenario visits in `prewarm` so dev-compile skeletons stay out of frame.
3. **Run it:** `node tmp/<scenario>.mjs`. Outputs land in `tmp/<name>/`:
   per-scene PNGs, `<name>.webm` + `<name>.mp4`, `manifest.json`. A scenario
   failure still saves the video and a `scene-FAIL.png`; those are debugging
   evidence, not garbage.
4. **Feedback loop (mandatory):** Read every `scene-*.png` with the Read tool
   and check the UI is actually correct: the element present, states right, no
   hidden runtime errors or half-loaded skeletons. Inspect unfiltered UI/error
   evidence first; overlay suppression is presentation-only and must not conceal
   a verification failure. Wrong → fix in scope and re-record. Only
   a frame-verified recording counts as evidence.
5. **Cleanup:** delete the demo entities you seeded (through the same real
   surface you created them with), stop any dev server you started, and confirm
   the port is closed.
6. **Delivery:** provide the local recording and frames. Attach them to a PR or
   tracker only when existing authorization explicitly covers that external write.
   When authorized, use the host's supported attachment mechanism; do not turn
   local verification into an implicit publication step.

## Scenario example

```js
import { recordUiDemo } from "./harness.mjs";

const BASE = "http://localhost:3000";

await recordUiDemo(
  {
    name: "my-feature-demo",
    baseUrl: BASE,
    prewarm: ["/items", "/items/42"],
  },
  async ({ page, scene, highlight }) => {
    await scene("list shows the new item", async () => {
      await page.goto(`${BASE}/items`, { waitUntil: "networkidle" });
      await page.getByText("Quarterly report").first().click();
    });
    await scene("detail dialog renders the new action", async () => {
      await page.getByRole("button", { name: "Share" }).click();
      await highlight(page.getByRole("dialog").getByRole("link", { name: "Copy link" }));
    });
  },
);
```

## Notes

- The harness leaves overlays visible by default. After inspecting and preserving
  unfiltered failure evidence, an optional presentation recording may set
  `hideNextDevOverlay: true` or explicit `hideSelectors`. Those frames alone do
  not establish that no runtime error occurred.
- Realistic demo data reads better than test slugs: name seeded entities like
  a user would ("Sprint review"), not "TEST-1234 probe".
- Viewport defaults to 1280×720; override via `viewport` if the surface needs it.
- mp4 conversion needs `ffmpeg` on PATH; without it the webm is still produced.
- The app under test must be the working tree you changed: the dev server
  compiles from source, so a stale server proves old code; restart when in doubt.

