Roo Code logo

Skill

feature-demo

produce product feature demo videos

Covers Content Creation Marketing Video

Description

Produce a polished demo video of a product feature — recorded live in the sandbox browser with cursor effects, captions, and optional voice-over narration.

SKILL.md

You produce short, polished feature-demo videos: a real recording of the product driven live in the browser, narrated as a flowing story. The page moves by scrolling, with cursor movement and click ripples showing interactions. Captions carry the narration on screen, and when the deployment has narration configured, a voice-over speaks each line as its visual arrives.

Use this skill when the user asks for a demo video, walkthrough recording, or promo clip of a feature. It is NOT for verification screencasts of a code change — that is capture-visual-proof.

The narrative drives the visuals. The demo is planned as a spoken story first; narration is synthesized (or, captions-only, each line's speaking time is estimated) BEFORE capture, and the capture runner conducts the browser to it — each beat holds for exactly as long as its line takes to speak, and clip start times are stamped as each visual arrives. The runner also logs, on the same clock, where the cursor is, when clicks land, and the resolved rectangle of every interaction target, so effects stay aligned and nothing needs retiming afterwards.

Pipeline: plan the narrative → author script → narrate → capture (browser, delegated, paced to the narrative) → trim opening → render → verify → upload.

The bundled render/ project is a reference template, not a fixed pipeline stage: copy it to the work dir and adapt the copy freely (branding, caption styling, layout, extra presets) when the demo calls for it. The timeline JSON is the stable contract between capture and render — keep the copy consuming it and any adaptation stays in sync with the recording.

All work happens under /tmp/feature-demo/work (the work dir). Nothing from this pipeline is ever committed to the repository.

Scope and plan the demo (advisor)Delegate the creative plan to the `advisor` subagent with the Task tool — it runs the planning model at deeper reasoning and can read the repository to study the feature. Give it a complete brief: the user's request, the surface to record (URL), the relevant source paths for the feature's UI, the beat vocabulary and cinematography rules from step 2 verbatim, and the narration style rules. Ask it to write the NARRATION FIRST — a flowing spoken story of 4-7 conversational lines (roughly 8-20 words each) that a founder might say while walking a friend through the feature: open with why it matters, walk the what and how, land on the payoff. Then, for each line, the visual that accompanies it: the element to scroll into view (with a proposed resilient CSS selector from source) or, only where the story calls for actually clicking or typing, the interaction. Return that plus which preset(s) fit. A good demo is 25-45 seconds; the narration should carry it — sparse label-style narration makes a hollow video.Treat the advisor's plan as internal guidance, not finished work: the advisor cannot run commands or see the live page, so its selectors are educated guesses from source. You own verification (step 2) and every artifact. If the advisor returns empty output, retry once with a tighter brief, then plan directly yourself.Pick presets: `wide` (1920x1080) is the default; add `vertical` (1080x1920) only when the user wants a social/short-form cut.If the surface needs the app running, make sure the environment is up first (dev server reachable) before capturing.Author the demo scriptWrite `/tmp/feature-demo/demo-script.json`: `{ "url": string, "viewport": { "w": 1280, "h": 800 }, "beats": [...] }`. Beat actions: - `{ "a": "show", "sel": css, "caption": "..." }` — THE DEFAULT NARRATED MOVE: scroll the subject into view and speak over it, camera wide. No cursor. - `{ "a": "wait", "ms": n }` / `{ "a": "hold", "ms": n }` — let the page settle / linger. - `{ "a": "scrollTo", "sel": css, "ms": n }` — plain scroll with no narration attached. - `{ "a": "click", "sel": css, "holdMs": ~300 }` — real click with ripple. - `{ "a": "type", "sel": css, "text": "...", "moveMs": ~450 }` — glide the cursor to the field, then type.Cinematography: MOVE BY SCROLLING — that is how a person actually reads a page. Use cursor movement and click ripples to draw attention to interactions, and author scripts using only the beat actions listed above.Keep the opening tight: one short `wait` for page load, then get moving. Dead opening seconds are trimmed automatically, but do not rely on it.Captions ARE the narration, verbatim — what the viewer reads is exactly what the voice says, and narrated demos highlight each word as it is spoken. Write them as full conversational sentences (roughly 8-20 words): contractions are good, symbols and clause pileups are not. They appear on screen while spoken and wrap to two lines.Caption display can be tuned declaratively with a top-level `"captionStyle"` object in the demo script — `{ "position": "top"|"bottom", "accent": cssColor, "pill": boolean, "sizeScale": number }` — controlling placement, the active-word highlight color, the pill background (off = bare text with a drop shadow), and a font-size multiplier. Use it for brand-fit requests ("captions on top", "highlight in our green"); deeper caption redesigns go through the render-template adaptation path in step 6.Selectors must be resilient: prefer ids, stable data attributes, or unique semantic tags over deep CSS chains. How you gain confidence before capture depends on the surface: - Repository-backed surface (the app's own UI): grep the component/template source for each proposed selector and confirm it exists — cheap and worth doing every time. - External public page named by the user: there is no local source to grep, and the browser is reachable only through the single capture delegation (the `proof-runner` takes one brief per task and keeps its configured surface, so a separate pre-flight is not available). Author best-effort resilient selectors — landmark roles, headings, obvious ids the advisor inferred; avoid deep chains — and rely on capture's own validation: the runner resolves every selector live and fails loudly naming any that do not resolve. Use that named failure to correct the script and re-capture within the one allowed retry (step 3).Narrate first (the narrative drives the visuals)Synthesize the narration BEFORE capture: `SCRIPT=/tmp/feature-demo/demo-script.json node "$HOME/.agents/skills/feature-demo/scripts/build-narration.mjs"`. This posts the caption lines to the Roomote control plane, which holds the TTS credentials — no provider key exists in this sandbox, and you must never ask for one. It writes `/tmp/feature-demo/vo/*.mp3` and `/tmp/feature-demo/narration.json` with each line's measured duration and per-word timings (used by the renderer to highlight the word being spoken); during capture, each beat then holds exactly as long as its line takes to speak, and clip start times are stamped as the visuals land. No retiming happens afterwards.Exit code 3 means narration is not configured on this deployment: proceed captions-only — capture paces each captioned beat from the caption's estimated speaking time instead, so the demo still reads at narrative pace. Mention in the final report that voice-over is available if an admin connects ElevenLabs under Settings → Integrations.Capture (delegated browser work)Stage the capture runner where the delegated runtime can see it — home-directory paths do not survive the delegation boundary, so always copy first:

mkdir -p /tmp/feature-demo && cp "$HOME/.agents/skills/feature-demo/capture/capture.mjs" /tmp/feature-demo/capture.mjs

The runner also reads /tmp/feature-demo/narration.json (written in step 3) on its own; captions-only runs simply will not have one. Browser automation is the proof-runner subagent's exclusive surface — do not load agent-browser or run the capture yourself. Delegate with the Task tool to proof-runner, telling it the script path (/tmp/feature-demo/demo-script.json), the output dir (/tmp/feature-demo/work), and the staged runner path (/tmp/feature-demo/capture.mjs), and to report the runner's printed summary plus ls -la /tmp/feature-demo/work. The staged runner is proof-runner's one sanctioned script exception — an agent-browser orchestrator that shells the agent-browser CLI for every browser action — and its own instructions define the exact integrity-verified command it must use to execute it. Do not dictate the node invocation yourself; the proof-runner owns that.If the harness has no proof-runner registered, report a blocker (proof runtime unavailable) instead of driving the browser from this skill.Expected outputs: /tmp/feature-demo/work/recording.mp4 and /tmp/feature-demo/work/timeline.json. Verify both exist and that ffprobe reports a duration close to the timeline's durationSeconds (the runner itself fails loudly when the recording is much shorter than the interaction). One retry on failure; then report blocked with the runner's error.The runner records headless with an imperceptible frame ticker, which is deterministic and captures at wall-clock rate on ordinary pages. It stops any existing agent-browser daemon first so the beats and the recorder share one page.If a recording comes back much shorter than the interaction, the runner fails loudly. GPU-backed surfaces (WebGL/WebGPU, 3D, games) do not present frames to the headless compositor and cannot be recorded here — report webgl surface stalls recording naming the surface rather than retrying. If record stop itself reports an ffmpeg error, the sandbox is likely a stale snapshot with an outdated runtime ffmpeg (stale sandbox runtime).

Trim the openingRun `WORK_DIR=/tmp/feature-demo/work node "$HOME/.agents/skills/feature-demo/scripts/fit-timing.mjs"`. Because capture was paced to the narrative, there is nothing to retime — this only cuts the dead opening hold (page-load settle) so the demo starts immediately, shifting timeline, captions, and clip starts together. Check its printed line schedule for sanity.RenderAssemble the render project in the work dir: - `cp -R "$HOME/.agents/skills/feature-demo/render" /tmp/feature-demo/render` - `cp /tmp/feature-demo/work/timeline.json /tmp/feature-demo/work/narration.json /tmp/feature-demo/render/props/` (skip narration.json if captions-only; the checked-in placeholder `{ "clips": [] }` is already correct) - `mkdir -p /tmp/feature-demo/render/public && cp /tmp/feature-demo/work/recording.mp4 /tmp/feature-demo/render/public/` - `cp -R /tmp/feature-demo/vo /tmp/feature-demo/render/public/vo` (narrated demos only; the mp3s were written next to the script in step 3)Adapt the copied composition when the default look does not fit the request — different backdrop, caption treatment, brand colors, an extra preset, a layout change. Before writing Remotion code, install just the Remotion agent skills relevant to editing an existing composition and read them for current API guidance: `cd /tmp/feature-demo/render && npx -y skills add remotion-dev/skills --skill remotion-markup --skill remotion-render --skill remotion-docs --yes` (markup, render, and doc lookup — not the full bundle, which also carries create/maps/saas/upgrade skills you do not need here). Preserve the cursor, click ripples, captions, and timeline-driven keyframe interpolation.Provide the dependencies. The image pre-installs the render project's node_modules (Remotion + React) at `/opt/feature-demo/render/node_modules`, keyed off this same pinned `package.json`, so normally you reuse them with no network install: `cp -R /opt/feature-demo/render/node_modules /tmp/feature-demo/render/node_modules`. Then run `cd /tmp/feature-demo/render && npm install` only if you adapted the composition to add dependencies (it reconciles just the delta), or if the baked modules are absent (older sandbox snapshot), in which case it does a full install.Render with the image's baked headless shell:

npx remotion render src/index.ts Demo-wide out/demo-wide.mp4 --browser-executable="${REMOTION_HEADLESS_SHELL_PATH:-/opt/remotion/headless-shell}" --log=error

Run this with a GENEROUS command timeout (10 minutes) on the first attempt: a narrative-length cut is 750+ frames rendering in software on a small container, which routinely exceeds the default two-minute command window — a timeout there is wasted work, not a render failure. If the binary does not exist (older sandbox snapshot), run npx remotion browser ensure once and render without the flag. Repeat for Demo-vertical when the vertical preset was requested.

Verify honestly`ffprobe` the output: sane duration, a video stream, and an audio stream when narration was generated.Extract 3-4 spread frames (`ffmpeg -ss -i out/demo-wide.mp4 -frames:v 1 frame.png`) and review each whole frame: cursor and click ripples align with their targets, captions are legible and correctly timed, and no broken page state appears in shot.A defect in the video is a blocker to report, not something to ship quietly. One recapture/re-render attempt; then report blocked with what failed and the frames that show it.DeliverUpload the mp4 via `manage_artifacts` (`action: upload`, `type: general`) plus one representative keyframe PNG. Treat only the returned `artifactId`/`viewUrl`/`rawUrl` values as canonical — never invent URLs.In a PR body, embed under `## Screencasts` using the existing convention: the keyframe image (its signed `rawUrl`) hyperlinked to the video's `viewUrl`, with a one-line caption. In chat replies, share the keyframe via image attachment and the video `viewUrl` as a link (video files cannot be attached inline).End with a sharing note: what the demo shows, which presets were rendered, and whether it is narrated or captions-only.
Never load or invoke `agent-browser` (or any other browser automation) from this skill — capture is always delegated to the `proof-runner` subagent.Never ask for, read, or handle TTS provider keys. Narration goes through the control-plane endpoint with the run token; a 404 there means captions-only.All intermediate files live under `/tmp/feature-demo`. Never commit recordings, renders, node_modules, or props into the repository.Author demo scripts using only the beat actions listed in step 2.Adapt the work-dir copy of the render template, never the installed skill sources under `~/.agents/skills/feature-demo`. The timeline JSON schema is the stable contract: adaptations change how it is rendered, not what it means.Report blockers honestly: a missing selector, a failed render, or a visibly broken frame is a blocker with evidence, not a reason to narrow the claim or ship a degraded video silently.Voice, wording, and pacing choices belong to the user when they express them; defaults are: wide preset, captions as narration lines, conversational tone.

© 2026 YourAI.tools. Every skill from an identity-verified publisher.

Independent catalog. Not affiliated with, endorsed by, or sponsored by Anthropic or any listed publisher. All trademarks belong to their respective owners.