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/.env.example +19 -0
- package/LICENSE +21 -0
- package/README.md +183 -0
- package/assets/icon-192.png +0 -0
- package/assets/icon-512.png +0 -0
- package/assets/logo.svg +13 -0
- package/demos/example.yaml +65 -0
- package/dist/appserver.js +316 -0
- package/dist/cli.js +467 -0
- package/dist/describe.js +377 -0
- package/dist/digest.js +197 -0
- package/dist/dryrun.js +196 -0
- package/dist/edits.js +229 -0
- package/dist/manifest.js +358 -0
- package/dist/operator/run.js +231 -0
- package/dist/operator/tools.js +412 -0
- package/dist/paths.js +39 -0
- package/dist/presets.js +75 -0
- package/dist/record.js +814 -0
- package/dist/render.js +661 -0
- package/dist/ui/chat.html +385 -0
- package/dist/ui/guide.html +85 -0
- package/dist/ui/index.html +722 -0
- package/dist/ui/server.js +1112 -0
- package/package.json +67 -0
- package/site/index.html +158 -0
- package/skill/SKILL.md +154 -0
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
|
+
}
|
package/site/index.html
ADDED
|
@@ -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>` |
|