retake-demos 0.2.2 → 0.3.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 +10 -0
- package/AGENTS.md +213 -0
- package/README.md +58 -20
- package/demos/example.yaml +1 -1
- package/dist/captions.js +56 -0
- package/dist/cards.js +134 -0
- package/dist/cli.js +114 -6
- package/dist/describe.js +28 -9
- package/dist/dryrun.js +3 -0
- package/dist/env.js +76 -0
- package/dist/manifest.js +111 -6
- package/dist/operator/run.js +4 -0
- package/dist/operator/tools.js +62 -5
- package/dist/pace.js +99 -0
- package/dist/presets.js +12 -12
- package/dist/record.js +36 -4
- package/dist/render.js +179 -48
- package/dist/ui/chat.html +82 -3
- package/dist/ui/guide.html +2 -1
- package/dist/ui/index.html +2 -2
- package/dist/ui/server.js +109 -26
- package/dist/voice.js +36 -0
- package/llms.txt +11 -0
- package/package.json +6 -3
- package/site/index.html +141 -39
- package/site/logos/avexjets.png +0 -0
- package/skill/SKILL.md +124 -6
package/site/index.html
CHANGED
|
@@ -3,10 +3,26 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
-
<title>Retake —
|
|
7
|
-
|
|
6
|
+
<title>Retake — demos that re-record themselves</title>
|
|
7
|
+
<!-- Social card. The domain is stamped by scripts/site-domain.mjs; until
|
|
8
|
+
then these point at the placeholder and a shared link shows no card. -->
|
|
9
|
+
<meta property="og:type" content="website" />
|
|
10
|
+
<meta property="og:site_name" content="Retake" />
|
|
11
|
+
<meta property="og:title" content="Retake — demos that re-record themselves" />
|
|
12
|
+
<meta property="og:description" content="A demo is a small file your coding agent writes. When the UI changes, change one line and run it again." />
|
|
13
|
+
<meta property="og:url" content="https://retake.example.com/" />
|
|
14
|
+
<meta property="og:image" content="https://retake.example.com/og.png" />
|
|
15
|
+
<meta property="og:image:width" content="1200" />
|
|
16
|
+
<meta property="og:image:height" content="630" />
|
|
17
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
18
|
+
<meta name="twitter:title" content="Retake — demos that re-record themselves" />
|
|
19
|
+
<meta name="twitter:description" content="A demo is a small file your coding agent writes. When the UI changes, change one line and run it again." />
|
|
20
|
+
<meta name="twitter:image" content="https://retake.example.com/og.png" />
|
|
21
|
+
<link rel="canonical" href="https://retake.example.com/" />
|
|
22
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB3aWR0aD0iNTEyIiBoZWlnaHQ9IjUxMiIgcm9sZT0iaW1nIiBhcmlhLWxhYmVsPSJSZXRha2UiPiA8cmVjdCB3aWR0aD0iNTEyIiBoZWlnaHQ9IjUxMiIgcng9IjExMiIgZmlsbD0iIzFhMWMxZSIvPiA8ZyBmaWxsPSIjZWNlZWU5Ij4gPHJlY3QgeD0iMTMyIiB5PSIxMTIiIHdpZHRoPSI5NiIgaGVpZ2h0PSI0NiIgcng9IjIzIiBvcGFjaXR5PSIwLjU1Ii8+IDxyZWN0IHg9IjEzMiIgeT0iMTgwIiB3aWR0aD0iMTkyIiBoZWlnaHQ9IjQ2IiByeD0iMjMiIG9wYWNpdHk9IjAuOCIvPiA8cmVjdCB4PSIxMzIiIHk9IjI0OCIgd2lkdGg9IjI4OCIgaGVpZ2h0PSI0NiIgcng9IjIzIiBmaWxsPSIjZThiMDRiIi8+IDxyZWN0IHg9IjEzMiIgeT0iMzE2IiB3aWR0aD0iMTkyIiBoZWlnaHQ9IjQ2IiByeD0iMjMiIG9wYWNpdHk9IjAuOCIvPiA8cmVjdCB4PSIxMzIiIHk9IjM4NCIgd2lkdGg9Ijk2IiBoZWlnaHQ9IjQ2IiByeD0iMjMiIG9wYWNpdHk9IjAuNTUiLz4gPC9nPiA8L3N2Zz4=" />
|
|
23
|
+
<meta name="description" content="A demo is a small file your coding agent writes. When the UI changes, run the file again — nobody re-records anything by hand." />
|
|
8
24
|
<style>
|
|
9
|
-
:root { --paper:#edefe8; --card:#f8f9f5; --ink:#191d19; --muted:#
|
|
25
|
+
:root { --paper:#edefe8; --card:#f8f9f5; --ink:#191d19; --muted:#666e64; --rule:#dbdfd3; --rule2:#c9cec0; --accent:#1a1c1e; --amber:#e8b04b; }
|
|
10
26
|
* { box-sizing:border-box; }
|
|
11
27
|
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
28
|
.top { display:flex; align-items:center; gap:10px; padding:18px 26px; max-width:880px; margin:0 auto; }
|
|
@@ -18,18 +34,21 @@
|
|
|
18
34
|
.top a { color:var(--muted); text-decoration:none; font-size:14px; margin-left:18px; }
|
|
19
35
|
.top a:hover { color:var(--ink); }
|
|
20
36
|
main { max-width:880px; margin:0 auto; padding:30px 26px 90px; }
|
|
21
|
-
.hero { padding:
|
|
37
|
+
.hero { padding:52px 0 34px; }
|
|
38
|
+
.flow { margin:26px 0 0; font:13px ui-monospace, Menlo, monospace; color:var(--muted); letter-spacing:.02em; }
|
|
39
|
+
.flow span { color:var(--rule2); padding:0 2px; }
|
|
40
|
+
.terms { margin:10px 0 0; font-size:12.5px; color:var(--muted); }
|
|
22
41
|
.kicker { font:12px ui-monospace, Menlo, monospace; letter-spacing:.09em; text-transform:uppercase; color:var(--muted); margin:0 0 14px; }
|
|
23
42
|
h1 { font-size:clamp(34px, 6vw, 54px); line-height:1.08; letter-spacing:-.025em; margin:0 0 18px; }
|
|
24
43
|
h1 em { font-style:normal; color:var(--muted); }
|
|
25
44
|
.lede { font-size:19px; color:var(--muted); max-width:620px; margin:0 0 28px; }
|
|
26
45
|
.actions { display:flex; gap:10px; flex-wrap:wrap; }
|
|
27
|
-
.btn { display:inline-block; text-decoration:none; border-radius:
|
|
46
|
+
.btn { display:inline-block; text-decoration:none; border-radius:14px; padding:13px 24px; font-size:15px; letter-spacing:-.01em; }
|
|
28
47
|
.btn.dark { background:var(--accent); color:#eceee9; }
|
|
29
48
|
.btn.dark:hover { opacity:.9; }
|
|
30
49
|
.btn.light { border:1px solid var(--rule2); color:var(--ink); background:#fff; }
|
|
31
50
|
.btn.light:hover { border-color:var(--ink); }
|
|
32
|
-
.say { background:var(--card); border:1px solid var(--rule); border-radius:14px; padding:
|
|
51
|
+
.say { background:var(--card); border:1px solid var(--rule); border-radius:14px; padding:18px 22px; margin:46px 0 10px; font-size:16.5px; box-shadow:0 1px 0 rgba(24,28,24,.03); }
|
|
33
52
|
.say .who { font:11px ui-monospace, Menlo, monospace; letter-spacing:.07em; text-transform:uppercase; color:var(--muted); display:block; margin-bottom:6px; }
|
|
34
53
|
.say i { font-style:normal; }
|
|
35
54
|
.arrow { text-align:center; color:var(--muted); margin:8px 0; }
|
|
@@ -38,10 +57,10 @@
|
|
|
38
57
|
.shot video { width:100%; height:auto; display:block; }
|
|
39
58
|
.shot figcaption { background:var(--card); padding:12px 18px 14px; font-size:14px; color:var(--muted); }
|
|
40
59
|
.shot figcaption b { color:var(--ink); font-weight:600; }
|
|
41
|
-
section { margin-top:
|
|
60
|
+
section { margin-top:84px; }
|
|
42
61
|
h2 { font-size:24px; letter-spacing:-.015em; margin:0 0 8px; }
|
|
43
62
|
.sub { color:var(--muted); margin:0 0 26px; max-width:560px; }
|
|
44
|
-
.grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(
|
|
63
|
+
.grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(300px, 1fr)); gap:14px; }
|
|
45
64
|
.cell { background:var(--card); border:1px solid var(--rule); border-radius:14px; padding:18px 20px; }
|
|
46
65
|
.cell b { display:block; margin-bottom:6px; font-size:15px; }
|
|
47
66
|
.cell p { margin:0; font-size:14px; color:var(--muted); line-height:1.6; }
|
|
@@ -53,6 +72,42 @@
|
|
|
53
72
|
.step p { margin:2px 0 0; color:var(--muted); font-size:14.5px; }
|
|
54
73
|
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
74
|
pre .c { color:var(--muted); }
|
|
75
|
+
.diff { font:13.5px/1.9 ui-monospace, Menlo, monospace; overflow-x:auto; }
|
|
76
|
+
.diff div { white-space:pre; }
|
|
77
|
+
.diff .del { color:#9a4238; } .diff .del::before { content:"− "; opacity:.55; }
|
|
78
|
+
.diff .add { color:#33613f; } .diff .add::before { content:"+ "; opacity:.55; }
|
|
79
|
+
.diff .ctx { color:var(--muted); font-size:12px; margin-bottom:4px; }
|
|
80
|
+
.copyline { display:flex; gap:10px; align-items:stretch; margin-top:0; }
|
|
81
|
+
.copyline .say { flex:1; margin:0; }
|
|
82
|
+
.copybtn { flex:none; border:1px solid var(--rule2); background:#fff; border-radius:14px; padding:0 20px; font:14px/1 inherit; cursor:pointer; transition:border-color .15s; }
|
|
83
|
+
.copybtn:hover { border-color:var(--ink); }
|
|
84
|
+
.vocab { background:var(--card); border:1px solid var(--rule); border-left:3px solid var(--amber); border-radius:14px; padding:18px 22px; font-size:15px; color:var(--muted); line-height:1.8; }
|
|
85
|
+
.vocab b { color:var(--ink); }
|
|
86
|
+
.cases { display:grid; grid-template-columns:repeat(auto-fit, minmax(250px, 1fr)); gap:14px; }
|
|
87
|
+
.case { background:var(--card); border:1px solid var(--rule); border-radius:16px; padding:22px 24px; display:flex; flex-direction:column; box-shadow:0 10px 26px rgba(24,28,24,.06); }
|
|
88
|
+
.wordmark { font-size:24px; font-weight:700; letter-spacing:-.02em; margin-bottom:12px; display:flex; align-items:center; gap:10px; }
|
|
89
|
+
.caselogo { height:28px; width:28px; border-radius:7px; object-fit:contain; }
|
|
90
|
+
.caselogo.wide { height:26px; width:auto; max-width:170px; border-radius:0; }
|
|
91
|
+
.wordmark .serif { font-family:Georgia, "Times New Roman", serif; font-weight:600; letter-spacing:0; }
|
|
92
|
+
.wordmark.tbmark { font-weight:900; letter-spacing:-.03em; gap:1px; }
|
|
93
|
+
.wordmark .avex { color:var(--amber); margin-right:2px; }
|
|
94
|
+
.case .quote { margin:0 0 14px; font-size:14.5px; line-height:1.65; flex:1; }
|
|
95
|
+
.case .meta { margin:0; font-size:12.5px; color:var(--muted); }
|
|
96
|
+
.case .watch { margin:12px 0 0; padding-top:10px; border-top:1px solid var(--rule); font-size:13px; display:flex; gap:8px; align-items:baseline; }
|
|
97
|
+
.case .watch .k { font:10.5px ui-monospace, Menlo, monospace; letter-spacing:.08em; color:var(--muted); flex:none; }
|
|
98
|
+
.case .watch a { color:var(--ink); }
|
|
99
|
+
.case .meta a { color:inherit; }
|
|
100
|
+
@media (max-width: 560px) {
|
|
101
|
+
/* The diff is the page's best proof, so on a phone it wraps rather than
|
|
102
|
+
clipping — it stays the real selector line, not a shortened fake, and
|
|
103
|
+
nothing is hidden off the right edge. */
|
|
104
|
+
.diff { font-size:11.5px; line-height:1.8; }
|
|
105
|
+
.diff div { white-space:pre-wrap; word-break:break-word; }
|
|
106
|
+
/* Keep the − / + markers: colour alone is not a signal everyone gets. */
|
|
107
|
+
.diff .del, .diff .add { padding-left:18px; text-indent:-18px; }
|
|
108
|
+
.copyline { flex-direction:column; }
|
|
109
|
+
.copybtn { padding:12px 20px; }
|
|
110
|
+
}
|
|
56
111
|
.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
112
|
.foot a { color:inherit; }
|
|
58
113
|
</style>
|
|
@@ -66,24 +121,62 @@
|
|
|
66
121
|
</div>
|
|
67
122
|
<main>
|
|
68
123
|
<div class="hero">
|
|
69
|
-
<p class="kicker">
|
|
70
|
-
<h1>
|
|
71
|
-
<p class="lede">
|
|
124
|
+
<p class="kicker">your product changed. your demo is outdated.</p>
|
|
125
|
+
<h1>Demos that<br><em>re-record themselves.</em></h1>
|
|
126
|
+
<p class="lede">A demo is a small file your coding agent writes. When the UI changes, change one line and run it again — the client walkthrough on Tuesday and the launch video on Friday, from the same current take.</p>
|
|
72
127
|
<div class="actions">
|
|
73
|
-
<a class="btn dark" href="#start">
|
|
74
|
-
<a class="btn light" href="#proof">Watch
|
|
128
|
+
<a class="btn dark" href="#start">Copy the setup prompt</a>
|
|
129
|
+
<a class="btn light" href="#proof">Watch the 14-second demo</a>
|
|
75
130
|
</div>
|
|
131
|
+
<p class="flow">one prompt <span>→</span> a YAML demo <span>→</span> dry-run checked <span>→</span> recorded <span>→</span> rerun on the next release</p>
|
|
132
|
+
<p class="terms">MIT licensed · runs on your machine · no account, nothing uploaded</p>
|
|
76
133
|
</div>
|
|
77
134
|
|
|
78
|
-
<div class="say"><span class="who">
|
|
79
|
-
|
|
135
|
+
<div class="say"><span class="who">The release renamed a button. This is the whole fix</span>
|
|
136
|
+
<div class="diff" style="border:0;padding:6px 0 0;background:transparent">
|
|
137
|
+
<div class="ctx">demos/checkout.yaml</div>
|
|
138
|
+
<div class="del">{ action: click, selector: "button:has-text('Buy now')" }</div>
|
|
139
|
+
<div class="add">{ action: click, selector: "button:has-text('Complete purchase')" }</div>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
<p class="arrow" style="font-size:13.5px">one line changed · <code>retake run</code> · a new take of the same demo ↓</p>
|
|
80
143
|
<div class="videos" id="proof" style="scroll-margin-top:20px"></div>
|
|
81
144
|
|
|
145
|
+
<section>
|
|
146
|
+
<h2>Built against three real workflows</h2>
|
|
147
|
+
<p class="sub" style="max-width:640px">Retake was built inside these, not for a landing page. All three are mine — there are no customer quotes here yet, and this page is not going to pretend otherwise.</p>
|
|
148
|
+
<div class="cases">
|
|
149
|
+
<div class="case">
|
|
150
|
+
<div class="wordmark"><span class="serif">capture<span style="color:#2F5D3F">.</span></span></div>
|
|
151
|
+
<p class="quote">A five-video launch set, drafted, corrected and re-cut in one afternoon. Re-doing a take stopped being a decision worth having.</p>
|
|
152
|
+
<p class="meta">Thought-sorting app · <a href="https://capture-playground.vercel.app">capture-playground.vercel.app</a></p>
|
|
153
|
+
<p class="watch"><span class="k">WATCH</span><span>Three of those videos are live on <a href="https://capture-playground.vercel.app">Capture's own page</a>, which credits Retake by name.</span></p>
|
|
154
|
+
</div>
|
|
155
|
+
<div class="case">
|
|
156
|
+
<div class="wordmark"><img src="logos/avexjets.png" alt="AvexJets" class="caselogo wide"></div>
|
|
157
|
+
<p class="quote">One repeatable flow across three portals, replacing a twenty-minute live walkthrough. The proof log catches a broken step before a client ever sees it.</p>
|
|
158
|
+
<p class="meta">Private aviation charter · <a href="https://www.avex-jets.com">avex-jets.com</a></p>
|
|
159
|
+
<p class="watch"><span class="k">SITE</span><span>The walkthrough itself is client-facing; <a href="https://www.avex-jets.com">the product it records is public</a>.</span></p>
|
|
160
|
+
</div>
|
|
161
|
+
<div class="case">
|
|
162
|
+
<div class="wordmark tbmark"><span style="color:#193b92">Tech</span><span style="color:#2C7A7B">Bash</span></div>
|
|
163
|
+
<p class="quote">An agent operates the real Scratch editor, dragging the actual blocks. When a lesson changes, the same file produces the next walkthrough.</p>
|
|
164
|
+
<p class="meta">Coding school for young learners · <a href="https://bash.techtutor.academy">bash.techtutor.academy</a></p>
|
|
165
|
+
<p class="watch"><span class="k">WATCH</span><span><a href="media/scratch-mini-project.mp4">The take, 19 seconds</a> — four blocks dragged into one script, and the cat runs it.</span></p>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
</section>
|
|
169
|
+
|
|
82
170
|
<section id="start">
|
|
83
|
-
<h2>
|
|
84
|
-
<p class="sub">
|
|
85
|
-
<div class="
|
|
86
|
-
|
|
171
|
+
<h2>Give it to your agent</h2>
|
|
172
|
+
<p class="sub">The link is the instruction. The README tells your agent how to install, wire itself up, and open the window for you. You say what to show.</p>
|
|
173
|
+
<div class="copyline">
|
|
174
|
+
<div class="say"><span class="who">In Claude Code, Codex, Cursor — the agent you already use</span><i id="pasteline">“github.com/glebbogachev00/retake — set this up, then record a demo of my app at localhost:3000 showing the checkout flow.”</i></div>
|
|
175
|
+
<button class="copybtn" data-copy="pasteline">Copy</button>
|
|
176
|
+
</div>
|
|
177
|
+
<p class="sub" style="margin:22px 0 10px">Doing it yourself is two commands:</p>
|
|
178
|
+
<pre>npm install -g retake-demos <span class="c"># Node 20+; ffmpeg bundled, Chromium downloads once</span>
|
|
179
|
+
mkdir demos && cd demos && retake install</pre>
|
|
87
180
|
</section>
|
|
88
181
|
|
|
89
182
|
<section id="how">
|
|
@@ -97,46 +190,44 @@
|
|
|
97
190
|
</div>
|
|
98
191
|
</section>
|
|
99
192
|
|
|
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
193
|
<section>
|
|
112
194
|
<h2>What's in the box</h2>
|
|
113
195
|
<p class="sub">Everything required to produce the same clean take again.</p>
|
|
114
196
|
<div class="grid">
|
|
115
|
-
<div class="cell"><b>Scenes with captions</b><p>Captions
|
|
197
|
+
<div class="cell"><b>Scenes with captions</b><p>Captions timed from the actual run, placed under the app — never over it. Every scene also yields a crisp still.</p></div>
|
|
116
198
|
<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>
|
|
118
|
-
<div class="cell"><b>
|
|
119
|
-
<div class="cell"><b>
|
|
120
|
-
<div class="cell"><b>Stubs and seeds</b><p>Stub the backend and reset state so demos stay repeatable.</p></div>
|
|
199
|
+
<div class="cell"><b>Presets that post well</b><p>Landscape, a true square, a true 9:16, docs GIF — the same take, re-rendered. Stubs and seeds keep it repeatable.</p></div>
|
|
200
|
+
<div class="cell"><b>Behind the login, off camera</b><p>The agent asks for a demo account by name; you type it into the window and it stays in one local file. The sign-in runs before recording and is trimmed off. 2FA included.</p></div>
|
|
201
|
+
<div class="cell"><b>Plain, or produced</b><p><code>mode: demo</code> keeps everything but your product out of the frame. <code>mode: launch</code> adds a title card, cuts the waiting, and lets you pick the poster. Demo is the default; your agent never upgrades one on its own.</p></div>
|
|
121
202
|
</div>
|
|
122
203
|
</section>
|
|
123
204
|
|
|
205
|
+
<section>
|
|
206
|
+
<h2>Not a recorder, not a test runner</h2>
|
|
207
|
+
<p class="sub" style="max-width:640px">A screen recording is pixels you can never edit; a browser test is a pass/fail nobody can watch. A Retake demo is both halves: a readable file that proves itself like a test and renders like a film — and reruns when the app changes. And it refuses to become a video editor: if a take needs editing, the file was wrong. Fix the file, run it again.</p>
|
|
208
|
+
</section>
|
|
124
209
|
|
|
210
|
+
<section>
|
|
211
|
+
<h2>Record your first rerunnable demo</h2>
|
|
212
|
+
<p class="sub" style="max-width:620px">The demo outlives the video. When the next release moves a button, the fix is a line in a file — and landscape, square, vertical and the GIF all re-render from the same take.</p>
|
|
213
|
+
<div class="copyline">
|
|
214
|
+
<div class="say"><span class="who">Start with the sentence</span><i id="pasteline2">“github.com/glebbogachev00/retake — set this up, then record a demo of my app at localhost:3000 showing the checkout flow.”</i></div>
|
|
215
|
+
<button class="copybtn" data-copy="pasteline2">Copy</button>
|
|
216
|
+
</div>
|
|
217
|
+
</section>
|
|
125
218
|
|
|
126
219
|
<div class="foot">
|
|
127
220
|
<span>MIT licensed.</span>
|
|
128
221
|
<a href="https://github.com/glebbogachev00/retake">Source</a>
|
|
129
222
|
<span>Built on Playwright, testreel, and ffmpeg.</span>
|
|
130
|
-
<a href="https://github.com/glebbogachev00/retake/issues/new?template=
|
|
223
|
+
<a href="https://github.com/glebbogachev00/retake/issues/new?template=bug.md">Report a bug</a>
|
|
131
224
|
</div>
|
|
132
225
|
</main>
|
|
133
226
|
<script>
|
|
134
227
|
// The proof section fills itself from whatever clean renders exist in
|
|
135
228
|
// site/media/. Committed pages carry no product footage; media is local.
|
|
136
229
|
const CANDIDATES = [
|
|
137
|
-
{ file: '
|
|
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.' },
|
|
230
|
+
{ file: 'capture-two-places', cap: '<b>Capture — the launch pitch.</b> One messy sentence lands as an action and a thread. Drafted, dry-run, recorded, titled and posterised from one YAML file. 14 seconds.' },
|
|
140
231
|
];
|
|
141
232
|
(async () => {
|
|
142
233
|
const host = document.getElementById('proof');
|
|
@@ -151,8 +242,19 @@ const CANDIDATES = [
|
|
|
151
242
|
f.innerHTML = '<video src="' + url + '" poster="' + url.replace('.mp4', '.jpg') + '" controls muted playsinline preload="metadata"></video><figcaption>' + c.cap + '</figcaption>';
|
|
152
243
|
host.appendChild(f);
|
|
153
244
|
}
|
|
245
|
+
if (host.children.length) {
|
|
246
|
+
const more = document.createElement('p');
|
|
247
|
+
more.className = 'sub'; more.style.cssText = 'margin:14px 0 0;font-size:13.5px';
|
|
248
|
+
const base = location.pathname.startsWith('/landing') ? '/landing/media/' : 'media/';
|
|
249
|
+
more.innerHTML = 'Two more launch cuts: <a style="color:inherit" href="' + base + 'scratch-mini-project.mp4">a first Scratch project for TechBash</a> · <a style="color:inherit" href="' + base + 'mark-done.mp4">Capture closing a loop</a>.';
|
|
250
|
+
host.after(more);
|
|
251
|
+
}
|
|
154
252
|
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
253
|
})();
|
|
254
|
+
for (const b of document.querySelectorAll('.copybtn')) b.onclick = async () => {
|
|
255
|
+
const t = document.getElementById(b.dataset.copy).textContent.replace(/^“|”$/g, '');
|
|
256
|
+
try { await navigator.clipboard.writeText(t); b.textContent = 'Copied'; setTimeout(() => (b.textContent = 'Copy'), 1600); } catch {}
|
|
257
|
+
};
|
|
156
258
|
</script>
|
|
157
259
|
</body>
|
|
158
260
|
</html>
|
|
Binary file
|
package/skill/SKILL.md
CHANGED
|
@@ -77,23 +77,141 @@ zooms or caption tone until they have seen one. Two moves instead:
|
|
|
77
77
|
→ landscape, still camera, a hold on the payoff. Skip the question if
|
|
78
78
|
the project's style note already answers it.
|
|
79
79
|
2. **The first take is the menu.** Record the calm default as a preview,
|
|
80
|
-
let them watch it, then
|
|
81
|
-
|
|
82
|
-
Whatever they choose, save it with `style`
|
|
80
|
+
let them watch it, then one line — no list, no questions before it:
|
|
81
|
+
"Want it different? A zoom on the result, cursor off, square for a post —
|
|
82
|
+
say so and I'll re-render." Whatever they choose, save it with `style`
|
|
83
|
+
so it never comes up again in this project. Never ask about zoom or
|
|
84
|
+
cursor before they have seen a take.
|
|
85
|
+
|
|
86
|
+
**Which kind of take is this? Get it from the destination, never from the
|
|
87
|
+
subject.** Write it into the manifest as `mode:`, and default to `demo`.
|
|
88
|
+
|
|
89
|
+
- **`mode: demo`** — it proves how the thing works. A client walkthrough IS
|
|
90
|
+
a demo. So is a PR review, a bug repro, a docs clip, a lesson, "show the
|
|
91
|
+
team", "send it to the customer", "so they can see the flow". Nothing in
|
|
92
|
+
the frame but the product doing the thing. No title card, no music, no
|
|
93
|
+
callouts. Most takes are this.
|
|
94
|
+
- **`mode: launch`** — it presents the product to strangers, in public: a
|
|
95
|
+
launch, a post, an ad, a landing page, Product Hunt, "for X", a trailer.
|
|
96
|
+
Only then are a title card, music, emphasis and a branded ending on the
|
|
97
|
+
table, and each still has to earn its second.
|
|
98
|
+
|
|
99
|
+
The tell is the audience, not the polish: *someone who already wants to
|
|
100
|
+
know how it works* → demo. *Someone who has to be given a reason to care*
|
|
101
|
+
→ launch. If the person has not said, ask the one destination question and
|
|
102
|
+
take `demo` if they shrug. **Never upgrade a demo to a launch on your own**
|
|
103
|
+
— `validate` warns when a demo carries launch furniture, and that warning
|
|
104
|
+
means you guessed.
|
|
105
|
+
|
|
106
|
+
A launch cut ends with THEIR product, never with Retake. Retake branding
|
|
107
|
+
belongs only in a video that presents Retake.
|
|
108
|
+
|
|
109
|
+
**Two kinds of take, one file — and the destination decides.** The default
|
|
110
|
+
is the plain cut: still camera, cursor, captions, nothing else. That is
|
|
111
|
+
correct for PRs, clients, docs, lessons — most takes. When the person's
|
|
112
|
+
answer to "where is this going?" is a launch, a post, or anything public
|
|
113
|
+
and promotional, offer the produced cut in ONE sentence: "Want the launch
|
|
114
|
+
treatment — title card, a callout on the payoff, the waits compressed,
|
|
115
|
+
the captions read aloud, square or vertical for the feed, and music if
|
|
116
|
+
you give me a track?" Never apply it unasked, and
|
|
117
|
+
never ask about its parts one by one.
|
|
118
|
+
|
|
119
|
+
The produced cut, when they say yes (all render-time except typing):
|
|
120
|
+
- `intro: { title, subtitle }` and usually `outro:` (the product name or URL)
|
|
121
|
+
- one `callout` on the payoff moment, not more
|
|
122
|
+
- the destination's shape: `post-square` or `post-vertical`
|
|
123
|
+
- `compressIdle: true` — the app's waits shown as ~1.5s each; the person's
|
|
124
|
+
pacing `wait`s are never touched
|
|
125
|
+
- **voiceover: leave it off.** It needs `script:` (one continuous script,
|
|
126
|
+
synthesized as one performance) AND `approved: true`, which only a person
|
|
127
|
+
who has HEARD it can set. Reading the captions line by line resets prosody
|
|
128
|
+
at every scene — that is a defect in the shape, not the voice. A silent cut
|
|
129
|
+
beats an unapproved synthetic voice. Offer narration only if they ask for
|
|
130
|
+
it, and let them listen before it ships.
|
|
131
|
+
- `typing: brisk` — fast keys, the pauses carry the meaning (re-record)
|
|
132
|
+
- `music: <file>` only if they hand you a file or point at one on disk.
|
|
133
|
+
Retake bundles no tracks (licensing) — say: "give me an mp3 you have the
|
|
134
|
+
rights to; CC0 tracks live at freepd.com or pixabay.com/music". Skip
|
|
135
|
+
music without complaint if they shrug.
|
|
83
136
|
|
|
84
137
|
Anything they would tell a videographer maps to a knob, in plain English:
|
|
85
138
|
|
|
139
|
+
- "add a title card" / "give it a cover" → `intro: { title, subtitle }`
|
|
140
|
+
(and `outro:`) — render-time, and it also writes two poster candidates:
|
|
141
|
+
cover.png (the card) and cover-titled.png (a real frame with the title on
|
|
142
|
+
it, which is what stops a scroll)
|
|
143
|
+
- "the thumbnail is wrong" → they pick the poster themselves in the window
|
|
144
|
+
(any frame, any still, a cover, or their own image). Point them at it
|
|
145
|
+
rather than re-rendering; `outputs.thumbnail: { scene }` only sets the
|
|
146
|
+
starting guess.
|
|
147
|
+
- "point at it" / "highlight the button" → a `callout` step with a label —
|
|
148
|
+
at most one per scene, and only where the caption alone is not enough
|
|
149
|
+
|
|
86
150
|
- "no zooms" / "keep the camera still" → `camera: static` on scenes
|
|
87
151
|
- "hide the cursor" → `cursor: false`
|
|
88
152
|
- "no captions" / "shorter captions" → captions off, or rewrite them
|
|
89
153
|
- "slower" / "hold the ending" → `pauseAfter`, scene `holdMs`, end waits
|
|
90
154
|
- "square" / "vertical" / "for X" → preset `post-square` / `post-vertical`
|
|
91
155
|
|
|
92
|
-
The default is
|
|
156
|
+
The default is calm and real: still camera (`camera: static` is the
|
|
157
|
+
manifest default — write `auto` only when asked), cursor shown, plain
|
|
158
|
+
captions.
|
|
93
159
|
The first time the person expresses taste, save it with the `style` tool
|
|
94
160
|
(or write `demos/style.md`) — every later draft in the project reads it, so
|
|
95
161
|
they never have to say it twice. Their stated taste always beats defaults.
|
|
96
162
|
|
|
163
|
+
## The person may never have seen Retake — walk them
|
|
164
|
+
|
|
165
|
+
Assume a first-timer: your agent installed Retake for them and they know
|
|
166
|
+
nothing about a window, a workspace or a `.env`. So, every time:
|
|
167
|
+
|
|
168
|
+
- **Say where to look, with the link.** At the start of a demo: "I'll record
|
|
169
|
+
this with Retake. You can watch at http://localhost:4310 (run `retake ui`
|
|
170
|
+
if it isn't open) — the video, stills and a step-by-step log land there."
|
|
171
|
+
Never assume the window is open or that they know the address.
|
|
172
|
+
- **One thing at a time, in their words.** When you need them to act (type a
|
|
173
|
+
demo account, log in by hand, start their app), say exactly what to do,
|
|
174
|
+
where, and how you'll know it's done: "…press Save to .env, then tell me
|
|
175
|
+
it's done." Then wait for them to say so. Do not go quiet — a tool that
|
|
176
|
+
waits on them is your cue to speak, not to sit.
|
|
177
|
+
- **Close the loop.** When the take is done: the one-line result, where the
|
|
178
|
+
file is, and the one thing they can change without a re-record (speed,
|
|
179
|
+
captions, format). Offer, don't pile on.
|
|
180
|
+
|
|
181
|
+
## Logins — most real demos start behind one
|
|
182
|
+
|
|
183
|
+
You will never see a password, and you never need to. The whole method:
|
|
184
|
+
|
|
185
|
+
1. **Notice it early.** `read_project` reports sign-in fields; `scout` shows a
|
|
186
|
+
password input; or the person says so. Do not draft a manifest that
|
|
187
|
+
pretends the app is open.
|
|
188
|
+
2. **Call `secrets` with the NAMES** you will use — `APP_USER`, `APP_PASSWORD`,
|
|
189
|
+
and `APP_TOTP_SECRET` if the site asks for an authenticator code — and one
|
|
190
|
+
sentence of why. It returns immediately with the words to say: a form is
|
|
191
|
+
open in the window at a link, or a one-line terminal command. **Relay
|
|
192
|
+
those words in full, link included**, then stop and wait for "done". Call
|
|
193
|
+
`secrets` again; it answers "set" and you carry on. The values went
|
|
194
|
+
straight into the workspace `.env` — you never saw them.
|
|
195
|
+
3. **Write the sign-in under `auth.setup`**, referencing `${APP_USER}` and
|
|
196
|
+
`${APP_PASSWORD}` with `secret: true`, and set `auth.storageState` to
|
|
197
|
+
`.auth/<name>.json`. The login runs before the camera and is trimmed off;
|
|
198
|
+
the session is saved and later takes skip the login entirely. A failed
|
|
199
|
+
sign-in is never saved as a session, so a wrong password stops the take
|
|
200
|
+
instead of recording a logged-out one.
|
|
201
|
+
4. **Authenticator codes:** `text: "${TOTP:APP_TOTP_SECRET}"` — Retake
|
|
202
|
+
computes the six-digit code at the moment it fills the field.
|
|
203
|
+
5. **SMS codes, SSO, captchas, anything only a human can do:** do not try.
|
|
204
|
+
Tell the person: "run `retake signin demos/<name>.yaml` and log in once by
|
|
205
|
+
hand — Retake keeps the session." Then run as normal. The manifest still
|
|
206
|
+
needs `auth.storageState`; `auth.setup` can be empty.
|
|
207
|
+
6. **Firebase-style apps** keep the session in IndexedDB, which a saved
|
|
208
|
+
session cannot restore: put the login under plain `setup` instead, so it
|
|
209
|
+
runs every take (still before the camera, still trimmed).
|
|
210
|
+
|
|
211
|
+
Never ask for a credential in chat. Never write a literal one into a
|
|
212
|
+
manifest. Never invent one. Tell the person to use a demo account — the
|
|
213
|
+
output is a video they may publish.
|
|
214
|
+
|
|
97
215
|
## When a take fails
|
|
98
216
|
|
|
99
217
|
The camera stops at the first failed step, so a failed take is short and
|
|
@@ -136,8 +254,8 @@ up to the end of that scene.
|
|
|
136
254
|
|
|
137
255
|
- Real interactions read as real: type actual text, scroll to what you use,
|
|
138
256
|
hold on the result. No zoom tricks unless asked.
|
|
139
|
-
- Secrets never go in a manifest
|
|
140
|
-
|
|
257
|
+
- Secrets never go in a manifest and never into chat: the `secrets` tool
|
|
258
|
+
gets them into `.env` by name; you reference `${NAME}` with `secret: true`.
|
|
141
259
|
- Never invent selectors — only what scout/read_project returned.
|
|
142
260
|
- If the backend is down, prefer a `stub:` block over giving up.
|
|
143
261
|
- Starting the person's app needs their explicit say-so, every time.
|