retake-demos 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "retake-demos",
3
+ "version": "0.2.0",
4
+ "description": "Demo-as-code for coding agents: a YAML manifest in, a product walkthrough video out. Rerun the demo instead of re-recording it.",
5
+ "keywords": [
6
+ "demo",
7
+ "screen-recording",
8
+ "playwright",
9
+ "mcp",
10
+ "claude-code",
11
+ "codex",
12
+ "video",
13
+ "documentation",
14
+ "agent"
15
+ ],
16
+ "homepage": "https://github.com/glebbogachev00/retake#readme",
17
+ "bugs": {
18
+ "url": "https://github.com/glebbogachev00/retake/issues"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/glebbogachev00/retake.git"
23
+ },
24
+ "license": "MIT",
25
+ "author": "Gleb Bogachev",
26
+ "type": "module",
27
+ "bin": {
28
+ "retake": "dist/cli.js"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "skill",
33
+ "site/index.html",
34
+ "assets/logo.svg",
35
+ "assets/icon-192.png",
36
+ "assets/icon-512.png",
37
+ "demos/example.yaml",
38
+ ".env.example",
39
+ "README.md",
40
+ "LICENSE"
41
+ ],
42
+ "scripts": {
43
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && mkdir -p dist/ui && cp src/ui/*.html dist/ui/ && chmod +x dist/cli.js",
44
+ "prepare": "npm run build",
45
+ "prepublishOnly": "npm run typecheck && npm test",
46
+ "retake": "tsx src/cli.ts",
47
+ "ui": "tsx src/cli.ts ui",
48
+ "typecheck": "tsc --noEmit",
49
+ "test": "tsx --test test/*.test.ts"
50
+ },
51
+ "dependencies": {
52
+ "@modelcontextprotocol/sdk": "^1.30.0",
53
+ "commander": "^14.0.3",
54
+ "playwright": "^1.58.2",
55
+ "testreel": "^0.2.0",
56
+ "yaml": "^2.8.3",
57
+ "zod": "^4.4.3"
58
+ },
59
+ "devDependencies": {
60
+ "@types/node": "^22",
61
+ "tsx": "^4.20.0",
62
+ "typescript": "^5.9.0"
63
+ },
64
+ "engines": {
65
+ "node": ">=20"
66
+ }
67
+ }
@@ -0,0 +1,158 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Retake — rerun the demo, don't re-record it</title>
7
+ <meta name="description" content="Retake turns a plain-English walkthrough into a repeatable video of your real app. Your agent writes the flow; Retake checks it, records it, and keeps it rerunnable." />
8
+ <style>
9
+ :root { --paper:#edefe8; --card:#f8f9f5; --ink:#191d19; --muted:#767e74; --rule:#dbdfd3; --rule2:#c9cec0; --accent:#1a1c1e; --amber:#e8b04b; }
10
+ * { box-sizing:border-box; }
11
+ body { margin:0; background:var(--paper); color:var(--ink); font:16px/1.7 -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", Inter, Arial, sans-serif; -webkit-font-smoothing:antialiased; }
12
+ .top { display:flex; align-items:center; gap:10px; padding:18px 26px; max-width:880px; margin:0 auto; }
13
+ .mark { width:26px; height:26px; border-radius:8px; background:var(--accent); position:relative; flex:none; }
14
+ .mark i { position:absolute; left:6.5px; height:3px; border-radius:2px; background:#eceee9; }
15
+ .mark i:nth-child(1){top:5px;width:5px;opacity:.55} .mark i:nth-child(2){top:10px;width:8px;opacity:.8} .mark i:nth-child(3){top:15px;width:13px;background:var(--amber)} .mark i:nth-child(4){top:20px;width:8px;opacity:.8}
16
+ .top b { font-size:17px; letter-spacing:-.01em; }
17
+ .top .sp { flex:1; }
18
+ .top a { color:var(--muted); text-decoration:none; font-size:14px; margin-left:18px; }
19
+ .top a:hover { color:var(--ink); }
20
+ main { max-width:880px; margin:0 auto; padding:30px 26px 90px; }
21
+ .hero { padding:40px 0 30px; }
22
+ .kicker { font:12px ui-monospace, Menlo, monospace; letter-spacing:.09em; text-transform:uppercase; color:var(--muted); margin:0 0 14px; }
23
+ h1 { font-size:clamp(34px, 6vw, 54px); line-height:1.08; letter-spacing:-.025em; margin:0 0 18px; }
24
+ h1 em { font-style:normal; color:var(--muted); }
25
+ .lede { font-size:19px; color:var(--muted); max-width:620px; margin:0 0 28px; }
26
+ .actions { display:flex; gap:10px; flex-wrap:wrap; }
27
+ .btn { display:inline-block; text-decoration:none; border-radius:12px; padding:12px 22px; font-size:15px; }
28
+ .btn.dark { background:var(--accent); color:#eceee9; }
29
+ .btn.dark:hover { opacity:.9; }
30
+ .btn.light { border:1px solid var(--rule2); color:var(--ink); background:#fff; }
31
+ .btn.light:hover { border-color:var(--ink); }
32
+ .say { background:var(--card); border:1px solid var(--rule); border-radius:14px; padding:16px 20px; margin:46px 0 10px; font-size:17px; }
33
+ .say .who { font:11px ui-monospace, Menlo, monospace; letter-spacing:.07em; text-transform:uppercase; color:var(--muted); display:block; margin-bottom:6px; }
34
+ .say i { font-style:normal; }
35
+ .arrow { text-align:center; color:var(--muted); margin:8px 0; }
36
+ .videos { display:grid; gap:26px; margin:14px 0 0; }
37
+ .shot { border:1px solid var(--rule2); border-radius:14px; overflow:hidden; background:#111; box-shadow:0 14px 40px rgba(24,28,24,.12); }
38
+ .shot video { width:100%; height:auto; display:block; }
39
+ .shot figcaption { background:var(--card); padding:12px 18px 14px; font-size:14px; color:var(--muted); }
40
+ .shot figcaption b { color:var(--ink); font-weight:600; }
41
+ section { margin-top:72px; }
42
+ h2 { font-size:24px; letter-spacing:-.015em; margin:0 0 8px; }
43
+ .sub { color:var(--muted); margin:0 0 26px; max-width:560px; }
44
+ .grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(240px, 1fr)); gap:14px; }
45
+ .cell { background:var(--card); border:1px solid var(--rule); border-radius:14px; padding:18px 20px; }
46
+ .cell b { display:block; margin-bottom:6px; font-size:15px; }
47
+ .cell p { margin:0; font-size:14px; color:var(--muted); line-height:1.6; }
48
+ .how { counter-reset:step; }
49
+ .step { display:flex; gap:16px; padding:14px 0; border-bottom:1px solid var(--rule); }
50
+ .step:last-child { border-bottom:0; }
51
+ .step::before { counter-increment:step; content:counter(step); flex:none; width:28px; height:28px; border-radius:50%; background:var(--accent); color:#eceee9; display:flex; align-items:center; justify-content:center; font-size:13px; margin-top:2px; }
52
+ .step b { display:block; }
53
+ .step p { margin:2px 0 0; color:var(--muted); font-size:14.5px; }
54
+ pre { background:var(--card); border:1px solid var(--rule); border-radius:12px; padding:16px 20px; overflow-x:auto; font:14px/1.8 ui-monospace, Menlo, monospace; }
55
+ pre .c { color:var(--muted); }
56
+ .foot { margin-top:80px; padding-top:22px; border-top:1px solid var(--rule); color:var(--muted); font-size:13.5px; display:flex; gap:18px; flex-wrap:wrap; }
57
+ .foot a { color:inherit; }
58
+ </style>
59
+ </head>
60
+ <body>
61
+ <div class="top">
62
+ <div class="mark"><i></i><i></i><i></i><i></i></div>
63
+ <b>Retake</b>
64
+ <span class="sp"></span>
65
+ <a href="https://github.com/glebbogachev00/retake">GitHub</a>
66
+ </div>
67
+ <main>
68
+ <div class="hero">
69
+ <p class="kicker">Product demos, as code</p>
70
+ <h1>Rerun the demo.<br><em>Don't re-record it.</em></h1>
71
+ <p class="lede">Retake turns a plain-English walkthrough into a repeatable video of your real app. Your coding agent writes the flow. Retake checks it, drives the browser, records in 1080p, and lets you rerun the same demo when the UI changes.</p>
72
+ <div class="actions">
73
+ <a class="btn dark" href="#start">Paste the prompt</a>
74
+ <a class="btn light" href="#proof">Watch a demo</a>
75
+ </div>
76
+ </div>
77
+
78
+ <div class="say"><span class="who">You, to the agent you already use</span><i>“Record a demo of my app at localhost:3000 showing the sign-up flow.”</i></div>
79
+ <p class="arrow">↓</p>
80
+ <div class="videos" id="proof" style="scroll-margin-top:20px"></div>
81
+
82
+ <section id="start">
83
+ <h2>Paste this to your agent</h2>
84
+ <p class="sub">Ask from the coding agent you already use. It installs Retake, registers the tools, and produces the first take. Or do the two commands yourself and just ask for the demo.</p>
85
+ <div class="say" style="margin-top:0"><span class="who">In Claude Code, Codex, Hermes, or another coding agent</span><i>“Install retake-demos from npm (npm i -g retake-demos, then retake install in a new folder), then record a demo of my app at localhost:3000 showing the checkout flow.”</i></div>
86
+ <p class="sub" style="margin:14px 0 0">After setup, each demo starts as a sentence and ends as files you can inspect, rerender, or rerun.</p>
87
+ </section>
88
+
89
+ <section id="how">
90
+ <h2>How it works</h2>
91
+ <p class="sub">You provide intent. The agent writes the flow. Retake verifies, records, and renders it.</p>
92
+ <div class="how">
93
+ <div class="step"><div><b>You ask</b><p>"Record a demo of checkout." That sentence is the brief for the agent you already use.</p></div></div>
94
+ <div class="step"><div><b>Your agent builds and checks the flow</b><p>It reads your app, writes a small YAML demo, and dry-runs every selector and wait. Nothing records until the walkthrough works.</p></div></div>
95
+ <div class="step"><div><b>Retake records the real interaction</b><p>Real typing, real clicks, real waits. The result is demo.mp4, a still for each scene, and a proof log of what happened.</p></div></div>
96
+ <div class="step"><div><b>You revise without starting over</b><p>Change captions, zoom, layout, or format in seconds. When the UI changes, rerun the same flow instead of recording by hand.</p></div></div>
97
+ </div>
98
+ </section>
99
+
100
+ <section>
101
+ <h2>What people record</h2>
102
+ <p class="sub">One engine, different audiences. Because the demo is a file, each version is a rerun, not a fresh recording session.</p>
103
+ <div class="grid">
104
+ <div class="cell"><b>Client walkthroughs</b><p>Show the flow they asked about without booking a call. When the question changes, adjust the file and send a fresh take.</p></div>
105
+ <div class="cell"><b>Launches and social</b><p>Render the same interaction as landscape, square, or vertical. Ship the feature, then post the 20 seconds that show it.</p></div>
106
+ <div class="cell"><b>Docs and onboarding</b><p>README GIFs, first-run walkthroughs, and help-page clips can be regenerated when the UI changes.</p></div>
107
+ <div class="cell"><b>Regression proof</b><p>The dry run walks every step in seconds. A demo that fails when your app breaks is both a visible repro and a useful check.</p></div>
108
+ </div>
109
+ </section>
110
+
111
+ <section>
112
+ <h2>What's in the box</h2>
113
+ <p class="sub">Everything required to produce the same clean take again.</p>
114
+ <div class="grid">
115
+ <div class="cell"><b>Scenes with captions</b><p>Captions are timed from the actual run and placed outside the product frame.</p></div>
116
+ <div class="cell"><b>Render-time camera</b><p>Zoom and framing applied after recording. Change your mind in seconds, no browser involved.</p></div>
117
+ <div class="cell"><b>Presets that post well</b><p>1080p landscape, square, vertical, docs GIF. Pick the publishing format, not the browser window.</p></div>
118
+ <div class="cell"><b>A still for every scene</b><p>Each scene yields a crisp PNG. A video usually ships with a picture next to it.</p></div>
119
+ <div class="cell"><b>Secrets stay secret</b><p>Credentials live in .env, redacted from logs, warned about if they'd appear on camera.</p></div>
120
+ <div class="cell"><b>Stubs and seeds</b><p>Stub the backend and reset state so demos stay repeatable.</p></div>
121
+ </div>
122
+ </section>
123
+
124
+
125
+
126
+ <div class="foot">
127
+ <span>MIT licensed.</span>
128
+ <a href="https://github.com/glebbogachev00/retake">Source</a>
129
+ <span>Built on Playwright, testreel, and ffmpeg.</span>
130
+ <a href="https://github.com/glebbogachev00/retake/issues/new?template=gremlin.md">Report a bug</a>
131
+ </div>
132
+ </main>
133
+ <script>
134
+ // The proof section fills itself from whatever clean renders exist in
135
+ // site/media/. Committed pages carry no product footage; media is local.
136
+ const CANDIDATES = [
137
+ { file: 'todo-basics', cap: '<b>Written by an agent, performed by a browser.</b> Real typing, real clicks, captions timed from the actual run — 22 seconds, every step passed.' },
138
+ { file: 'store-checkout', cap: '<b>The login is handled properly.</b> Credentials from .env, marked secret, signed in before the camera rolls — then a checkout, end to end.' },
139
+ { file: 'distill-messy', cap: '<b>A conversation, recorded end to end.</b> Drafted, dry-run, and performed by an agent against a live model — 33 seconds.' },
140
+ ];
141
+ (async () => {
142
+ const host = document.getElementById('proof');
143
+ for (const c of CANDIDATES) {
144
+ const url = (location.pathname.startsWith('/landing') ? '/landing/media/' : 'media/') + c.file + '.mp4';
145
+ try {
146
+ const r = await fetch(url, { method: 'HEAD' });
147
+ if (!r.ok) continue;
148
+ } catch { continue; }
149
+ const f = document.createElement('figure');
150
+ f.className = 'shot'; f.style.margin = 0;
151
+ f.innerHTML = '<video src="' + url + '" poster="' + url.replace('.mp4', '.jpg') + '" controls muted playsinline preload="metadata"></video><figcaption>' + c.cap + '</figcaption>';
152
+ host.appendChild(f);
153
+ }
154
+ if (!host.children.length) host.innerHTML = '<div class="say" style="margin-top:0"><span class="who">Proof pending</span>Record a demo and drop its render into <code>site/media/</code> — this section fills itself.</div>';
155
+ })();
156
+ </script>
157
+ </body>
158
+ </html>
package/skill/SKILL.md ADDED
@@ -0,0 +1,154 @@
1
+ ---
2
+ name: recording-product-demos
3
+ description: Record a silent product demo video of a web app with Retake. Use when the user asks for a demo video, screen recording, or product walkthrough of an app — or asks what demos would be worth recording. Works through Retake's MCP tools (preferred) or its CLI.
4
+ ---
5
+
6
+ # Recording product demos with Retake
7
+
8
+ Retake turns a small YAML manifest into a 1080p silent demo video (MP4 +
9
+ one still per scene + a proof log). The demo lives as code, so when the UI
10
+ changes you edit one line and re-run — nobody re-records by hand.
11
+
12
+ You drive it; the person watches at http://localhost:4310 if the Retake
13
+ window is open. Prefer the MCP tools (`retake` server). If they are not
14
+ available, the CLI equivalents are in the table at the end.
15
+
16
+ ## If the person asks what Retake is or how to use it
17
+
18
+ Explain it from this file, briefly, in their language — do not send them to
19
+ docs. The short version: "Describe the demo in a sentence and I'll record it
20
+ as a real browser walkthrough — video plus a still per scene. You can direct
21
+ it like a videographer: no zooms, hide the cursor, shorter captions, square
22
+ for X. Say it once and I'll remember it for this project." Then offer the
23
+ first concrete step: suggest ideas from their app, or record the flow they
24
+ name.
25
+
26
+ ## You have Retake's tools and nothing else
27
+
28
+ When you are driving Retake you usually have no shell, no file reader, no
29
+ grep. Do not reach for them — every call to a tool you do not have is a
30
+ wasted turn. `scout` and `read_project` are your eyes on the app; `receipts`
31
+ and `look` are your eyes on the take; `ask` only works when a Retake window
32
+ is open, and `start_app` needs the person's say-so. If you are truly stuck,
33
+ say so in one line and stop.
34
+
35
+ ## The order that wins
36
+
37
+ 1. **`read_project`** (if you have the source folder) — routes, start
38
+ command, sign-in fields, stable selectors, things that animate forever.
39
+ 2. **`scout <url>`** — what is really on the page: unique selectors, text.
40
+ If the URL refuses, check `ports`; dev servers often sit one port over.
41
+ Do not start the app yourself unless the person says to.
42
+ 3. **What to record?** If the person asked for suggestions, call `ideas` —
43
+ do not invent ideas blind. Show them the list in the chat, numbered, and
44
+ **stop**: they pick, drop, or reword before anything is recorded. Only
45
+ then `plan_set` their choices and `plan_mark` each item as you go; an
46
+ unfinished plan survives into the next session (`plan` shows it).
47
+ 4. **`draft`** the manifest from the person's sentence, then read it and fix
48
+ the obvious with `edit`: wait for results instead of timers, unique
49
+ selectors, logins under `auth.setup` with `${ENV}` placeholders and
50
+ `secret: true`, `reducedMotion: true` if things animate forever, scrolls
51
+ before anything below the fold.
52
+ 5. **`dry`** — ALWAYS before `run`. Seconds, no camera, strict; failures
53
+ include what was on screen. Fix and repeat until it passes. Never record
54
+ a manifest whose dry run fails.
55
+ 6. **While iterating, record at `--preset draft`** (CLI) — same layout as the
56
+ final at a quarter of the pixels, so a take costs ~real time instead of
57
+ real time plus an encoder. Switch to a post preset only for the take you
58
+ intend to keep.
59
+ 7. **`run` with `preview=true`**, then read the `receipts` AND `look` at
60
+ the take. Receipts say what happened; `look` shows how it looks — one
61
+ image per scene. Judge it like a viewer would: is the thing the caption
62
+ names actually on screen? Anything in shot that shouldn't be (dev
63
+ badges, leftover data, cut-off text)? Wrong story or failed step →
64
+ `edit`, run again. More than four rounds → ask the person.
65
+ 8. When it is right: `run` with `preview=false` once (full quality), then
66
+ `done` with one sentence. Outputs: `demo.mp4`, `stills/` (one PNG per
67
+ scene), `proof-log.md`.
68
+
69
+ ## Style — how the person wants their videos to look
70
+
71
+ Do not ask about knobs before the first take — nobody has opinions about
72
+ zooms or caption tone until they have seen one. Two moves instead:
73
+
74
+ 1. **One question, about the destination:** "Where is this going — a
75
+ post, docs, or a client?" Post → `post-square` or `post-vertical`,
76
+ short captions. Docs → landscape or `docs-gif`, plain captions. Client
77
+ → landscape, still camera, a hold on the payoff. Skip the question if
78
+ the project's style note already answers it.
79
+ 2. **The first take is the menu.** Record the calm default as a preview,
80
+ let them watch it, then offer two or three concrete alternatives as
81
+ sentences ("Square for a post? Captions off? Zoom on the result?").
82
+ Whatever they choose, save it with `style` so it never comes up again.
83
+
84
+ Anything they would tell a videographer maps to a knob, in plain English:
85
+
86
+ - "no zooms" / "keep the camera still" → `camera: static` on scenes
87
+ - "hide the cursor" → `cursor: false`
88
+ - "no captions" / "shorter captions" → captions off, or rewrite them
89
+ - "slower" / "hold the ending" → `pauseAfter`, scene `holdMs`, end waits
90
+ - "square" / "vertical" / "for X" → preset `post-square` / `post-vertical`
91
+
92
+ The default is already calm: still camera, cursor shown, plain captions.
93
+ The first time the person expresses taste, save it with the `style` tool
94
+ (or write `demos/style.md`) — every later draft in the project reads it, so
95
+ they never have to say it twice. Their stated taste always beats defaults.
96
+
97
+ ## When a take fails
98
+
99
+ The camera stops at the first failed step, so a failed take is short and
100
+ its receipts name the step, the error, and what was on screen. **Fix from
101
+ that text** — usually a selector or a missing wait — then `dry` and `run`
102
+ again. Do not `look` at a failed take; images cost, and the text already
103
+ says what went wrong. Never call `done` on a take with a failed step.
104
+ Four rounds without a passing take → stop and ask the person.
105
+
106
+ ## Two footguns worth knowing
107
+
108
+ - **Wait for durable state, not its announcement.** Toasts and banners clear
109
+ themselves; wait for the row, the count, the heading that persists.
110
+ - **A one-line `script:` with braces is YAML, not JS** — use a block
111
+ (`script: |`). Retake's validation error now says so too.
112
+
113
+ ## When Retake itself breaks — stop, don't patch
114
+
115
+ A failed *step* is yours to fix (selector, wait, state). A failed *tool* is
116
+ not: a render error, an ffmpeg message, a crash, a cap you did not set.
117
+ Do not work around it, do not read Retake's or testreel's source, do not
118
+ try variations hoping one sticks. Say in one line what failed and which
119
+ demo, and stop. The person files it (the Bug? button) and it gets fixed
120
+ once, for everyone — an agent patching the tool is the most expensive
121
+ outcome there is.
122
+
123
+ ## Long demos: split, and record up to the beat you are fixing
124
+
125
+ Hard limit to know: the cursor overlay cannot survive more than ~45 cursor
126
+ moves in one take (an ffmpeg expression-depth limit in testreel). `validate`
127
+ warns, `check` fails if it happened. Past that, split — or `cursor: false`.
128
+
129
+ A take is real time: a six-minute walkthrough costs six minutes per
130
+ attempt and nobody watches six minutes. Above ~40 steps, split the story
131
+ into several 30–60s demos — each fails fast and re-records in a minute.
132
+ While iterating on one beat, `run` with `until: <scene label>` records only
133
+ up to the end of that scene.
134
+
135
+ ## Rules
136
+
137
+ - Real interactions read as real: type actual text, scroll to what you use,
138
+ hold on the result. No zoom tricks unless asked.
139
+ - Secrets never go in a manifest. `${ENV_VAR}` + `secret: true`, and tell
140
+ the person which variable to set.
141
+ - Never invent selectors — only what scout/read_project returned.
142
+ - If the backend is down, prefer a `stub:` block over giving up.
143
+ - Starting the person's app needs their explicit say-so, every time.
144
+
145
+ ## CLI fallback
146
+
147
+ | MCP tool | CLI |
148
+ |---|---|
149
+ | draft | `retake describe <name> <url> "<story>" -P <folder>` |
150
+ | dry | `retake dry demos/<name>.yaml` |
151
+ | run | `retake run demos/<name>.yaml` (`--preset preview-fast` for previews, `--until <scene>`) |
152
+ | render | `retake render outputs/<name>` |
153
+ | receipts | read `outputs/<name>/proof-log.md` |
154
+ | ideas | `retake ideas <url> -P <folder>` |