Skip to content
Content
Skill

/synthetic-ui-demo

Product demo and release-notes videos with no screen recording. Rebuild the app's screens as static React from its source code, then drive them in Remotion with a scripted cursor and camera (lib/components Stage + Cursor). Use when making a product walkthrough, feature demo,

BOOST
From plugin
claude-code-video-toolkit
2.3k14 skills14 commands
Install
$ npx -y skills add digitalsamba/claude-code-video-toolkit --skill synthetic-ui-demo --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/synthetic-ui-demo

Context preview

The summary Claude sees to decide when to auto-load this skill.

Product demo and release-notes videos with no screen recording. Rebuild the app's screens as static React from its source code, then drive them in Remotion with a scripted cursor and camera (lib/components Stage + Cursor). Use when making a product walkthrough, feature demo,

SKILL.md

synthetic-ui-demo.SKILL.md
name: synthetic-ui-demo
description: Product demo and release-notes videos with no screen recording. Rebuild the app's screens as static React from its source code, then drive them in Remotion with a scripted cursor and camera (lib/components Stage + Cursor). Use when making a product walkthrough, feature demo, release-notes or changelog video for an app whose source you can read, or when a Playwright recording would be flaky, need test data, or go stale. Triggers include synthetic demo, rebuild the UI, release video, feature walkthrough, product demo from source, scripted cursor, camera zoom on UI, no screen recording.

Synthetic UI Demos

Nothing is screen-recorded. Claude Code reads the product's repo, rebuilds only the screens a scene shows as static React, and a scripted cursor and camera perform the flow in Remotion. Every click is a frame number, so a scene re-renders identically, never needs a seeded account or a live environment, and is updated by editing code when the product changes.

**Reference builds** (read them alongside this skill; both build without the product repos):

  • `examples/ds-free-schedule-demo`: one 26s flow (schedule a call) with a narrator tile. The simplest complete case.

Its `src/Demo.tsx` is a single timeline with every cursor keyframe, click and camera move.

  • `examples/ds-release-649`: an 80s release-notes video, eight scenes across three apps. `src/Release.tsx` sequences

the scenes, `src/scenes/` has one file per release item, and `src/room/` and `src/ac/` are the screen kits.

When to use this vs. Playwright

| Synthetic (this skill) | Playwright recording (`/record-demo`) | |---|---| | You can read the app's source | You only have the running app | | Release notes and feature tours that get redone every release | One-off capture of real behaviour or real data | | The flow needs data you don't have (a full call, other users, an admin view) | The real thing is easy to reach and looks right as is | | Camera moves, exact click timing, re-renders after a voice change | Long, complex interactions that would be costly to rebuild |

Building blocks (`lib/components`)

import { Stage, typed, cursorAt, near } from '../../../../lib/components';

<Stage
  url="app.example.com/settings"             // address bar; host darker than path
  camera={CAMERA}                             // [{ f, z, x, y }] in canvas px, eased, clamped to the window
  path={PATH}                                 // [{ f, x, y }] cursor keyframes in canvas px
  clicks={CLICKS}                             // frames that squash the cursor and throw a ripple
  aiNote                                      // "People shown are AI-generated" (or pass your own text)
  canvasWidth={1440} canvasHeight={810}       // the defaults
>
  <SettingsScreen field={typed(frame, 'Q4 Product Review', 128)} />
</Stage>
  • `Stage` draws browser chrome around a fixed-size app canvas, applies the camera, and puts the cursor on top at

zIndex 100. At zoom 1 the window is `fit` (0.8625) of the frame width. Keyframes repeat a value to hold it.

  • `Cursor` and `cursorAt` work on their own for a non-browser scene; `near(cursor, target)` drives hover states.
  • Product-specific screen kits (theme, icons, layouts) stay in the project. They are not lib material.

Method

1. Pull a visual spec from the app repo, with subagents

Send one subagent per app or area, in parallel, and have each return a compact spec rather than file dumps:

  • **Theme:** palette, font stack, radii, spacing, shadows (from the theme file or CSS variables).
  • **Strings:** the exact English locale strings for every label, menu item, dialog and toast the scene shows

(`public/locales/en/*.json`, `src/i18n/locales/en/*`). Never paraphrase UI text.

  • **Icons:** if the app uses an icon font, its icomoon/fontello `selection.json` holds each glyph's SVG paths. Extract

the ones you need into a small JSON and render them as `<svg><path d=...>`. Otherwise copy the SVG components.

  • **Layout and behaviour:** component tree for the screens shown, toolbar order, defaults, what each control does.

Read the default branch from the remote (`git show origin/main:path`, or `git fetch` then read `origin/<default>`). **Local checkouts are often stale** and will give you last quarter's UI.

For release notes, trace each item to the commit and component that ship it first. That gives you the exact strings and the default values to show.

2. Rebuild only what a scene shows, on a fixed canvas

  • Lay every element out with absolute positions on a fixed canvas (1440x810 is a good default). Export the rects

that matter as constants (`SAVE_BTN = { x, y, w, h }`), so click targets are arithmetic, not guesses.

  • Build only what the camera sees. A panel that is never in shot can be a flat colour.
  • Keep it static React: no state, no effects. Every visual change is a function of `frame`.
  • Put the kit in its own folder (`src/ui/`, `src/room/`) with a `theme.ts` for constants.

3. Voice first, then put the timeline in frames

  • Write one line per scene and generate per-scene audio first (`voiceover.py --scene-dir ... --json`, add

`--max-wpm 165`). Read the measured durations.

  • Size each scene to its line plus a beat, and keep a header comment listing each line's start and length. That

comment is the source of truth (see "Audio-Anchored Timelines" in CLAUDE.md).

  • Everything is a frame constant at the top of the scene file: cursor keyframes, `CLICKS`, camera keyframes,

UI state switches (`frame >= C.save` shows the dialog). Export the click frames so the parent can place click SFX.

  • Time each click to land on the word that names it.

4. Split dense list lines at their pauses

A line that lists several things ("scheduling, contacts, recordings and transcripts") is too fast for one shot. Split the audio at its pauses into phrase files (`07a`, `07b`, ...), give each phrase its own shot, and place each phrase on its own beat.

Read more
Ships withclaude-code-video-toolkit

Tell Claude Code what video you want — it writes the script, generates the voiceover, music, and visuals, and renders the MP4.

Get the whole plugin

Other skills on claude-code-video-toolkit.