一键导入
record-demo
Record feature demo walkthrough with Playwright, generate commentary subtitles, produce final video with ffmpeg
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Record feature demo walkthrough with Playwright, generate commentary subtitles, produce final video with ffmpeg
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Session-after-session product perfection loop. The strongest available model (Fable) directs — it walks the repo's context map context-by-context, proposes 5 challenged, high-value directions per context (features, design elevations, significant optimizations), gates them with the user until 10 are accepted, then orchestrates one Opus builder subagent per context in isolated worktrees while making every review/merge decision itself. All state lives in a linked Obsidian vault so any future session resumes the loop exactly where the last one stopped. Invoke with `/perfect [init|propose|build|status|reflect] [context-name]`.
Generate images with OpenAI gpt-image-2 (primary) or Leonardo AI (fallback), remove backgrounds, analyze with Gemini vision, and write SVG. For brand assets, UI illustrations, backgrounds, and icons.
Upgrade a generic UI icon or loading/empty state into a traced, motion-animated SVG. Generates flat trace-friendly art (via /leonardo tools), validates with Qwen vision, vectorizes to a clean multi-path SVG, and emits a Motion (framer-motion) reveal component. For icon + loading-state visual upgrades — NOT raw image generation (use /leonardo for that).
Hunts the highest-value surface of an LLM-powered app — the LLM call sites themselves — and drives them to their potential across three lenses. (1) Code quality of the AI plumbing (wrapping/chokepoint, logging/telemetry, caching/dedupe, schema+validation+self-repair). (2) Business value, by reusing the UAT Character method (representative users with jobs-to-be-done + a senior-quality bar + time-saved) but TESTING ONLY THE LLM PIECES — does each prompt's grounding and output clear the bar. (3) Model optimization as an alternative scenario — benchmark the same character inputs across models × thinking levels to find quality degradation/upgrade vs cost/latency. Everything is memorized in a linked **Obsidian vault** (one note per call site / character / model / session) so each scan builds on the last. Stack-agnostic engine; per-app specifics live in the repo's `tiger/` overlay (which IS the vault). Invoke with `/tiger init|scan|run|benchmark|recall|backlog [args]`.
Simulated User Acceptance Testing for the Personas desktop app, driven by Characters (representative users with jobs-to-be-done) rather than feature/code coverage. A capable LLM verifies each user journey in two chronological certification levels — L1 theoretical (over a code-derived surface model, cheap + mass-parallel) then L2 empirical (the LIVE app driven through the test-automation harness, serial) — judging through each Character's own consistent lens (time saved vs the manual way, and senior-in-role quality). Personas-specific: L1 reads context-map.json + the React/Rust source; L2 drives the running app via the test-automation server on :17320 (NOT a browser). Per-run specifics live in the repo's uat/ overlay. Invoke with `/uat init|update|run|promote [args]`.
Iteratively prototype a UI component through directional variants behind a tab switcher, then consolidate and refactor the winner. Use when the user wants to improve a component they consider a pillar of the app (visual appeal, creativity, UX clarity).
| name | record-demo |
| description | Record feature demo walkthrough with Playwright, generate commentary subtitles, produce final video with ffmpeg |
| allowed-tools | Read, Write, Edit, Glob, Grep, Bash, Agent |
| argument-hint | <feature to demo, e.g. "template adoption wizard" or "sidebar navigation"> |
Record a polished demo video of a feature in the Personas desktop (Tauri) app. Pipeline: analyze the codebase → plan the shots → script the walkthrough → capture video → write commentary subtitles → burn a final MP4 with ffmpeg → verify the artifacts play.
recordings/ in project root (create if missing)This is a Tauri desktop app. The Vite dev server (:1420) serves HTML only — stores populate from Rust IPC, so Playwright pointed at http://localhost:1420 renders a dead shell. Never script against :1420.
Primary path (reliable): drive the real app through the test-automation HTTP server on http://127.0.0.1:17320, started via npm run tauri:dev:test (lite features + test-automation; tauri:dev:test:full if the demo needs ML/P2P). Capture video with ffmpeg gdigrab of the app window.
Alternative (only if a WebView remote-debugging port is already configured): Playwright chromium.connectOverCDP() to the running WebView gives native recordVideo and selectors. Do not add debugging-port config yourself just for a demo — prefer the harness path.
Navigation is section-based, not URL routes. POST /navigate {"section":"<id>"} switches the sidebar section (ids from SidebarSection — home, overview, personas, templates, settings, …). There are no /templates-style URLs to goto.
/eval for interactions. The /eval queue silently drops scripts mid-session — a demo dies halfway with no error. Use the semantic routes instead: /navigate, /click-testid ({"testId":"…"}), /fill-field, /click, /type, /wait ({"selector","timeoutMs"}), /wait-toast, /select-agent, /open-editor-tab, /open-settings-tab, /search-agents, /adopt-template, /execute-persona./eval — it returns only {success:true}. Read the DOM via POST /query, POST /find-text, GET /state, GET /snapshot, GET /list-interactive.netstat -ano | findstr :17320) and stop it unless you know it's current. After boot: GET /health proves a server is up, not yours — additionally assert something known-new (a testid or /state field that exists in the current build). Bridge-wait logic adopts the FIRST responder on the port.data-testid (1,000+ exist across src/features/), pick the real testid, and use /click-testid. If none exists nearby, fall back to /find-text + /click with a selector read from the component source./screenshot ({"saveDir","filename","maxWidth?","windowTitle?"}) saves a PNG of the app window — use it to verify visual state between beats without touching the recording.Use the argument if provided; otherwise ask:
What feature would you like to demo? (e.g., "template adoption from gallery to persona creation") Any specifics? Viewport/window size, speed (slow/normal/fast), required app state (e.g., "5 pending reviews").
Defaults: window ~1280x800, speed normal (1500ms between beats; slow 2500ms, fast 800ms), output recordings/.
Understand the flow before scripting anything.
src/features/<area>/; read the entry component and its container to learn which sidebar section + subtab hosts it.data-testid attributes. Never guess selectors; every anchor in the script must be traceable to a line of source. Selector preference: data-testid → visible text (/find-text) → CSS selector from source (last resort).GET /state, GET /agent-cards, or POST /overview-counts once the app is up. If seeding is needed, note it in the plan and ask the user first./wait-toast).Before writing code, list the beats — one line per shot — and get user confirmation:
Shot Plan: [Feature Name]
=========================
1. [0:00] Land on Templates section — gallery grid (HOLD 2.5s: orientation)
2. [0:03] Click template card "Dev Clone" (testid: template-card-dev-clone) — detail opens
3. [0:06] Click "Adopt" — wizard step 1 (HOLD 3s: PAYOFF — the 5-step rail)
...
Estimated duration: ~[N]s · [N] beats
Pacing rules:
PAYOFF in the plan.Write a standalone Node driver to recordings/_walkthrough.mjs that calls the :17320 harness (plain fetch, no deps). One clearly commented section per beat; log a timestamp per beat (subtitle alignment depends on these logs).
// recordings/_walkthrough.mjs — drives the LIVE app via the test-automation server
const BASE = 'http://127.0.0.1:17320';
const DELAY = 1500; // per speed setting
const t0 = Date.now();
const log = (msg) => console.log(`[${((Date.now() - t0) / 1000).toFixed(1)}s] ${msg}`);
const wait = (ms = DELAY) => new Promise(r => setTimeout(r, ms));
const post = async (route, body = {}) => {
const res = await fetch(BASE + route, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });
if (!res.ok) throw new Error(`${route} → ${res.status}: ${await res.text()}`);
return res.text();
};
// ── Beat 1: Land on Templates ────────────────────────────────
await post('/navigate', { section: 'templates' });
await post('/wait', { selector: '[data-testid="template-gallery"]', timeoutMs: 10000 });
log('beat 1: templates gallery');
await wait(2500); // orientation hold
// ── Beat 2: Open a template ─────────────────────────────────
await post('/click-testid', { testId: 'template-card-dev-clone' });
await post('/wait', { selector: '[data-testid="template-detail"]', timeoutMs: 8000 });
log('beat 2: template detail');
await wait();
// … one section per beat …
log('done'); await wait(2500); // final hold
Script rules:
/wait on a source-verified selector before every interaction — never click blind./query or /find-text that the expected result is on screen — do not trust {success:true}.log() are the subtitle timeline — keep them accurate.(CDP variant: if a debugging port exists, the same beats become a Playwright script with connectOverCDP + recordVideo; interaction and verification rules are identical.)
npm run tauri:dev:test in another terminal (do NOT start it yourself — it blocks), or confirm a current instance is already up.curl -s http://127.0.0.1:17320/health returns {"status":"ok",...} and a known-current probe passes (e.g. /wait on a testid you read from today's source).ffmpeg -y -f gdigrab -framerate 24 -i title=Personas -c:v libx264 -crf 23 -pix_fmt yuv420p recordings/_take.mp4
(If the window title doesn't match, capture -i desktop with the window maximized.) Run it via a background Bash call; stop it after the driver finishes (send q / kill the ffmpeg PID).node recordings/_walkthrough.mjs._walkthrough.mjs, and re-record the whole take (max 3 takes; then report the blocker to the user).Write recordings/_subtitles.srt — one cue per beat, timed from the driver's logged timestamps (not estimates), offset by when capture started relative to the driver.
1
00:00:00,000 --> 00:00:02,500
Browsing the template gallery
2
00:00:02,500 --> 00:00:05,500
Opening the Dev Clone template
Subtitle style contract:
ffmpeg -y -i recordings/_take.mp4 \
-vf "subtitles=recordings/_subtitles.srt:force_style='FontSize=22,FontName=Arial,PrimaryColour=&H00FFFFFF&,OutlineColour=&H00000000&,Outline=2,Shadow=1,MarginV=35'" \
-c:v libx264 -crf 23 -preset fast \
"recordings/demo-[feature-name].mp4"
White text, black outline, bottom margin so subtitles don't cover UI. If the burn fails, deliver _take.mp4 + _subtitles.srt and say so.
Do not declare done until both artifacts verify:
ffprobe -v error -show_entries format=duration:stream=codec_name -of default=nw=1 "recordings/demo-[feature].mp4"
_subtitles.srt exists, is non-empty, and its last cue ends within the video duration.ffmpeg -ss <mid> -i demo.mp4 -frames:v 1 recordings/_check.png) and Read it — confirm the app UI (not a black/desktop frame) and legible subtitles. Delete _check.png after.Cleanup: delete _take.mp4; keep _walkthrough.mjs and _subtitles.srt for re-recording.
Report:
Demo recorded and verified.
Video: recordings/demo-[feature].mp4 (~[N]s, [N] beats, subtitles burned in)
Script: recordings/_walkthrough.mjs (re-runnable against :17320)
Subtitles: recordings/_subtitles.srt
To re-record: fix the script, restart capture (Step 6), re-run Steps 7-9.
src/features/
agents/ — persona detail, executions, lab overview/ — dashboard, events, reviews
templates/ — gallery, adoption wizard vault/ — credentials, connectors
shared/ — components + chrome (sidebar) plugins/ — dev-tools, companion, …
src/features/shared/chrome/sidebar/ — SidebarLevel1.tsx (sections), SidebarSubNav.tsx (subtabs). Drive via /navigate sections, not clicks, unless the navigation itself is the demo.BaseModal (src/features/shared/components/modals/) — wait for [role="dialog"]./wait-toast to sync on success feedback.