retake-demos 0.3.0 → 0.4.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/AGENTS.md +64 -0
- package/README.md +14 -11
- package/dist/captions.js +9 -10
- package/dist/cards.js +57 -14
- package/dist/cli.js +197 -20
- package/dist/describe.js +2 -1
- package/dist/dryrun.js +182 -2
- package/dist/manifest.js +67 -4
- package/dist/operator/tools.js +50 -9
- package/dist/presets.js +13 -13
- package/dist/record.js +440 -43
- package/dist/render.js +255 -23
- package/dist/tidy.js +103 -0
- package/dist/ui/chat.html +233 -54
- package/dist/ui/server.js +63 -10
- package/package.json +2 -3
- package/site/releases.json +45 -0
- package/skill/SKILL.md +148 -2
- package/demos/example.yaml +0 -65
- package/dist/ui/index.html +0 -724
- package/site/index.html +0 -260
- package/site/logos/avexjets.png +0 -0
package/site/index.html
DELETED
|
@@ -1,260 +0,0 @@
|
|
|
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 — 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." />
|
|
24
|
-
<style>
|
|
25
|
-
:root { --paper:#edefe8; --card:#f8f9f5; --ink:#191d19; --muted:#666e64; --rule:#dbdfd3; --rule2:#c9cec0; --accent:#1a1c1e; --amber:#e8b04b; }
|
|
26
|
-
* { box-sizing:border-box; }
|
|
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; }
|
|
28
|
-
.top { display:flex; align-items:center; gap:10px; padding:18px 26px; max-width:880px; margin:0 auto; }
|
|
29
|
-
.mark { width:26px; height:26px; border-radius:8px; background:var(--accent); position:relative; flex:none; }
|
|
30
|
-
.mark i { position:absolute; left:6.5px; height:3px; border-radius:2px; background:#eceee9; }
|
|
31
|
-
.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}
|
|
32
|
-
.top b { font-size:17px; letter-spacing:-.01em; }
|
|
33
|
-
.top .sp { flex:1; }
|
|
34
|
-
.top a { color:var(--muted); text-decoration:none; font-size:14px; margin-left:18px; }
|
|
35
|
-
.top a:hover { color:var(--ink); }
|
|
36
|
-
main { max-width:880px; margin:0 auto; padding:30px 26px 90px; }
|
|
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); }
|
|
41
|
-
.kicker { font:12px ui-monospace, Menlo, monospace; letter-spacing:.09em; text-transform:uppercase; color:var(--muted); margin:0 0 14px; }
|
|
42
|
-
h1 { font-size:clamp(34px, 6vw, 54px); line-height:1.08; letter-spacing:-.025em; margin:0 0 18px; }
|
|
43
|
-
h1 em { font-style:normal; color:var(--muted); }
|
|
44
|
-
.lede { font-size:19px; color:var(--muted); max-width:620px; margin:0 0 28px; }
|
|
45
|
-
.actions { display:flex; gap:10px; flex-wrap:wrap; }
|
|
46
|
-
.btn { display:inline-block; text-decoration:none; border-radius:14px; padding:13px 24px; font-size:15px; letter-spacing:-.01em; }
|
|
47
|
-
.btn.dark { background:var(--accent); color:#eceee9; }
|
|
48
|
-
.btn.dark:hover { opacity:.9; }
|
|
49
|
-
.btn.light { border:1px solid var(--rule2); color:var(--ink); background:#fff; }
|
|
50
|
-
.btn.light:hover { border-color:var(--ink); }
|
|
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); }
|
|
52
|
-
.say .who { font:11px ui-monospace, Menlo, monospace; letter-spacing:.07em; text-transform:uppercase; color:var(--muted); display:block; margin-bottom:6px; }
|
|
53
|
-
.say i { font-style:normal; }
|
|
54
|
-
.arrow { text-align:center; color:var(--muted); margin:8px 0; }
|
|
55
|
-
.videos { display:grid; gap:26px; margin:14px 0 0; }
|
|
56
|
-
.shot { border:1px solid var(--rule2); border-radius:14px; overflow:hidden; background:#111; box-shadow:0 14px 40px rgba(24,28,24,.12); }
|
|
57
|
-
.shot video { width:100%; height:auto; display:block; }
|
|
58
|
-
.shot figcaption { background:var(--card); padding:12px 18px 14px; font-size:14px; color:var(--muted); }
|
|
59
|
-
.shot figcaption b { color:var(--ink); font-weight:600; }
|
|
60
|
-
section { margin-top:84px; }
|
|
61
|
-
h2 { font-size:24px; letter-spacing:-.015em; margin:0 0 8px; }
|
|
62
|
-
.sub { color:var(--muted); margin:0 0 26px; max-width:560px; }
|
|
63
|
-
.grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(300px, 1fr)); gap:14px; }
|
|
64
|
-
.cell { background:var(--card); border:1px solid var(--rule); border-radius:14px; padding:18px 20px; }
|
|
65
|
-
.cell b { display:block; margin-bottom:6px; font-size:15px; }
|
|
66
|
-
.cell p { margin:0; font-size:14px; color:var(--muted); line-height:1.6; }
|
|
67
|
-
.how { counter-reset:step; }
|
|
68
|
-
.step { display:flex; gap:16px; padding:14px 0; border-bottom:1px solid var(--rule); }
|
|
69
|
-
.step:last-child { border-bottom:0; }
|
|
70
|
-
.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; }
|
|
71
|
-
.step b { display:block; }
|
|
72
|
-
.step p { margin:2px 0 0; color:var(--muted); font-size:14.5px; }
|
|
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; }
|
|
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
|
-
}
|
|
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; }
|
|
112
|
-
.foot a { color:inherit; }
|
|
113
|
-
</style>
|
|
114
|
-
</head>
|
|
115
|
-
<body>
|
|
116
|
-
<div class="top">
|
|
117
|
-
<div class="mark"><i></i><i></i><i></i><i></i></div>
|
|
118
|
-
<b>Retake</b>
|
|
119
|
-
<span class="sp"></span>
|
|
120
|
-
<a href="https://github.com/glebbogachev00/retake">GitHub</a>
|
|
121
|
-
</div>
|
|
122
|
-
<main>
|
|
123
|
-
<div class="hero">
|
|
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>
|
|
127
|
-
<div class="actions">
|
|
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>
|
|
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>
|
|
133
|
-
</div>
|
|
134
|
-
|
|
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>
|
|
143
|
-
<div class="videos" id="proof" style="scroll-margin-top:20px"></div>
|
|
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
|
-
|
|
170
|
-
<section id="start">
|
|
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>
|
|
180
|
-
</section>
|
|
181
|
-
|
|
182
|
-
<section id="how">
|
|
183
|
-
<h2>How it works</h2>
|
|
184
|
-
<p class="sub">You provide intent. The agent writes the flow. Retake verifies, records, and renders it.</p>
|
|
185
|
-
<div class="how">
|
|
186
|
-
<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>
|
|
187
|
-
<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>
|
|
188
|
-
<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>
|
|
189
|
-
<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>
|
|
190
|
-
</div>
|
|
191
|
-
</section>
|
|
192
|
-
|
|
193
|
-
<section>
|
|
194
|
-
<h2>What's in the box</h2>
|
|
195
|
-
<p class="sub">Everything required to produce the same clean take again.</p>
|
|
196
|
-
<div class="grid">
|
|
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>
|
|
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>
|
|
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>
|
|
202
|
-
</div>
|
|
203
|
-
</section>
|
|
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>
|
|
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>
|
|
218
|
-
|
|
219
|
-
<div class="foot">
|
|
220
|
-
<span>MIT licensed.</span>
|
|
221
|
-
<a href="https://github.com/glebbogachev00/retake">Source</a>
|
|
222
|
-
<span>Built on Playwright, testreel, and ffmpeg.</span>
|
|
223
|
-
<a href="https://github.com/glebbogachev00/retake/issues/new?template=bug.md">Report a bug</a>
|
|
224
|
-
</div>
|
|
225
|
-
</main>
|
|
226
|
-
<script>
|
|
227
|
-
// The proof section fills itself from whatever clean renders exist in
|
|
228
|
-
// site/media/. Committed pages carry no product footage; media is local.
|
|
229
|
-
const CANDIDATES = [
|
|
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.' },
|
|
231
|
-
];
|
|
232
|
-
(async () => {
|
|
233
|
-
const host = document.getElementById('proof');
|
|
234
|
-
for (const c of CANDIDATES) {
|
|
235
|
-
const url = (location.pathname.startsWith('/landing') ? '/landing/media/' : 'media/') + c.file + '.mp4';
|
|
236
|
-
try {
|
|
237
|
-
const r = await fetch(url, { method: 'HEAD' });
|
|
238
|
-
if (!r.ok) continue;
|
|
239
|
-
} catch { continue; }
|
|
240
|
-
const f = document.createElement('figure');
|
|
241
|
-
f.className = 'shot'; f.style.margin = 0;
|
|
242
|
-
f.innerHTML = '<video src="' + url + '" poster="' + url.replace('.mp4', '.jpg') + '" controls muted playsinline preload="metadata"></video><figcaption>' + c.cap + '</figcaption>';
|
|
243
|
-
host.appendChild(f);
|
|
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
|
-
}
|
|
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>';
|
|
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
|
-
};
|
|
258
|
-
</script>
|
|
259
|
-
</body>
|
|
260
|
-
</html>
|
package/site/logos/avexjets.png
DELETED
|
Binary file
|