Skip to content

Commit 56dc177

Browse files
charliewwdevclaude
andcommitted
feat: make the page move
It was a dark page that sat still. Four things move now, and each one is enhancement over markup that is already complete and already readable — the module turns itself off entirely under prefers-reduced-motion and the page is exactly the page without it. The hero's terminal runs its session. The transcript is in the HTML in full; the script takes it away and gives it back at the speed it happened at, which for a command-line tool is the one piece of motion on the page that is also the product. It waits until it is scrolled to, because a terminal that finished typing before the visitor arrived has only ever shown them a picture. The providers move. Forty-six endpoints that were previously one link — the first question anyone has is whether theirs works, and the answer was a hyperlink. Two rows in opposite directions: one direction reads as a slideshow, two reads as a field. Each track holds its names twice and slides by exactly half its width, so the loop has no seam and needs no JavaScript. Sections arrive as they are scrolled to, and the class stays on — a page that re-animates every time you scroll back up is a page nobody can read twice. A light follows the pointer across the lattice. One listener per grid, and all it writes is two custom properties on the cell under the cursor; the gradient is in the stylesheet, so it never touches layout. Also a faint grid under the hero light, and a monospace index above each statement, which is most of what makes a page like this read as built rather than written. One bug worth naming: the marquee's closing line sat directly on the moving row. sets and is more specific than the rule meant to push it down, so the margin was being silently zeroed. Measured rather than eyeballed — the screenshot only said cramped, the measurement said the gap was exactly 0, which is what pointed at specificity rather than spacing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 6d4c2ef commit 56dc177

4 files changed

Lines changed: 432 additions & 36 deletions

File tree

‎website/index.html‎

Lines changed: 72 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
and holds still for anyone who asked for less motion.
5050
-->
5151
<div class="glow" aria-hidden="true"></div>
52+
<div class="grid-lines" aria-hidden="true"></div>
5253

5354
<div class="wrap">
5455
<a class="badge" href="https://docs.opencli.ai">
@@ -82,23 +83,52 @@ <h1>The agent for the models<br />that <em>do not have one</em></h1>
8283
The session is the model check from the documentation: six rows,
8384
three planted problems, and those are the three.
8485
-->
85-
<div class="terminal" role="img"
86+
<div class="terminal" data-terminal role="img"
8687
aria-label="A terminal running opencli against a six-row invoice file: it reads the rules and the rows, then reports three findings with their row numbers.">
8788
<div class="chrome" aria-hidden="true">
8889
<span class="light"></span><span class="light"></span><span class="light"></span>
8990
<span class="where">~/finance</span>
9091
</div>
91-
<pre aria-hidden="true"><span class="p">$</span> opencli exec <span class="s">"use the spreadsheet-review skill on invoices.csv"</span>
92+
<!-- One span per line and no newlines between them: the lines are
93+
blocks, so a line can be faded in without the ones under it
94+
moving. The transcript is complete in the markup — the script
95+
takes it away and gives it back at the speed it happened at. -->
96+
<pre aria-hidden="true"><span class="cmd"><span class="p">$</span> <span data-type>opencli exec "use the spreadsheet-review skill on invoices.csv"</span><span class="caret"></span></span><span data-line class="gap"></span><span data-line> <span class="t">read</span> rules.md 3 rules</span><span data-line> <span class="t">read</span> invoices.csv 6 rows</span><span data-line class="gap"></span><span data-line> <span class="f">row 2</span> INV-2202 11,800 over 10,000 with no PO number</span><span data-line> <span class="f">row 5</span> INV-2205 — no amount</span><span data-line> <span class="f">row 6</span> INV-2206 2026-13-02 month 13 is not a date</span><span data-line class="gap"></span><span data-line> <span class="d">3 findings in 6 rows.</span></span></pre>
97+
</div>
98+
</div>
99+
</section>
92100

93-
<span class="t">read</span> rules.md 3 rules
94-
<span class="t">read</span> invoices.csv 6 rows
101+
<!--
102+
The providers, moving. This list is the answer to the first question
103+
anybody has — "will it work with mine" — and it was a link. Each of
104+
these was asked for its model list without a key before it went in.
95105
96-
<span class="f">row 2</span> INV-2202 11,800 over 10,000 with no PO number
97-
<span class="f">row 5</span> INV-2205 — no amount
98-
<span class="f">row 6</span> INV-2206 2026-13-02 month 13 is not a date
106+
Two rows in opposite directions: one direction reads as a slideshow,
107+
two reads as a field. The track holds the names twice and slides by
108+
half its width, so the loop has no seam and no JavaScript.
109+
-->
110+
<section class="providers" data-reveal>
111+
<div class="wrap">
112+
<span class="kicker">00 — Reach</span>
113+
<p>
114+
One protocol, not a list of integrations. Anything answering
115+
<code>/v1/chat/completions</code> the way OpenAI does can be pointed at — these were
116+
each asked for their model list, without a key, before they went on this page.
117+
</p>
118+
</div>
99119

100-
<span class="d">3 findings in 6 rows.</span></pre>
101-
</div>
120+
<div class="marquee" aria-hidden="true">
121+
<div class="track"><span>Ollama</span><span>LM Studio</span><span>llama.cpp</span><span>LocalAI</span><span>Jan</span><span>Xinference</span><span>KoboldCpp</span><span>llamafile</span><span>vLLM</span><span>SGLang</span><span>Text Generation Inference</span><span>NVIDIA NIM</span><span>LiteLLM</span><span>Fireworks</span><span>Together</span><span>Groq</span><span>DeepInfra</span><span>Baseten</span><span>Novita</span><span>Hyperbolic</span><span>Nebius</span><span>Cerebras</span><span>SambaNova</span><span>Featherless</span><span>Chutes</span><span>Hugging Face</span><span>OpenRouter</span><span>Vercel AI Gateway</span><span>Perplexity</span><span>Ollama</span><span>LM Studio</span><span>llama.cpp</span><span>LocalAI</span><span>Jan</span><span>Xinference</span><span>KoboldCpp</span><span>llamafile</span><span>vLLM</span><span>SGLang</span><span>Text Generation Inference</span><span>NVIDIA NIM</span><span>LiteLLM</span><span>Fireworks</span><span>Together</span><span>Groq</span><span>DeepInfra</span><span>Baseten</span><span>Novita</span><span>Hyperbolic</span><span>Nebius</span><span>Cerebras</span><span>SambaNova</span><span>Featherless</span><span>Chutes</span><span>Hugging Face</span><span>OpenRouter</span><span>Vercel AI Gateway</span><span>Perplexity</span></div>
122+
</div>
123+
<div class="marquee reverse" aria-hidden="true">
124+
<div class="track"><span>硅基流动</span><span>无问芯穹</span><span>PPIO</span><span>七牛云</span><span>魔搭</span><span>阿里云百炼</span><span>火山方舟 · 豆包</span><span>百度千帆</span><span>讯飞星火</span><span>DeepSeek</span><span>智谱</span><span>月之暗面</span><span>MiniMax</span><span>阶跃星辰</span><span>腾讯混元</span><span>百川</span><span>小米 MiMo</span><span>OpenAI</span><span>Anthropic</span><span>Mistral</span><span>xAI</span><span>硅基流动</span><span>无问芯穹</span><span>PPIO</span><span>七牛云</span><span>魔搭</span><span>阿里云百炼</span><span>火山方舟 · 豆包</span><span>百度千帆</span><span>讯飞星火</span><span>DeepSeek</span><span>智谱</span><span>月之暗面</span><span>MiniMax</span><span>阶跃星辰</span><span>腾讯混元</span><span>百川</span><span>小米 MiMo</span><span>OpenAI</span><span>Anthropic</span><span>Mistral</span><span>xAI</span></div>
125+
</div>
126+
127+
<div class="wrap">
128+
<p class="foot">
129+
<a href="https://docs.opencli.ai/getting-started/providers">The whole list, with what
130+
each one is</a> — including which of them give something away for free.
131+
</p>
102132
</div>
103133
</section>
104134

@@ -110,8 +140,9 @@ <h1>The agent for the models<br />that <em>do not have one</em></h1>
110140
and needs no last-row or last-column special cases.
111141
-->
112142

113-
<section class="statement">
143+
<section class="statement" data-reveal>
114144
<div class="wrap">
145+
<span class="kicker">01 — Shapes</span>
115146
<h2>The same agent in <em>three shapes</em></h2>
116147
<p>
117148
A terminal program, a desktop app, and a local web UI. All three run on your machine
@@ -121,26 +152,27 @@ <h2>The same agent in <em>three shapes</em></h2>
121152
</section>
122153

123154
<div class="lattice two">
124-
<div class="cell">
155+
<div class="cell" data-reveal>
125156
<h3>Bring your own model</h3>
126157
<p>Ollama, LM Studio, vLLM, llama.cpp, or any hosted endpoint that speaks the OpenAI API. Declare it in one config file and it appears in the picker.</p>
127158
</div>
128-
<div class="cell">
159+
<div class="cell" data-reveal>
129160
<h3>Nothing phones home</h3>
130161
<p>No built-in gateway, no telemetry account, no key baked into the binary. What it talks to is what you configured.</p>
131162
</div>
132-
<div class="cell">
163+
<div class="cell" data-reveal>
133164
<h3>It asks before it acts</h3>
134165
<p>Commands and file writes are shown before they run, with a sandbox underneath. You choose how much it may do unattended.</p>
135166
</div>
136-
<div class="cell">
167+
<div class="cell" data-reveal>
137168
<h3>Organised like an office</h3>
138169
<p>A <em>department</em> is a directory with standing instructions. A <em>bot</em> is a chat inside one, with a job. A <em>duty</em> comes round on its own and asks you when it is stuck.</p>
139170
</div>
140171
</div>
141172

142-
<section class="statement">
173+
<section class="statement" data-reveal>
143174
<div class="wrap">
175+
<span class="kicker">02 — Departments</span>
144176
<h2>It is not only <em>for code</em></h2>
145177
<p>
146178
The agent reads files, runs commands and edits things. That is as true of a folder of
@@ -152,39 +184,39 @@ <h2>It is not only <em>for code</em></h2>
152184
</section>
153185

154186
<div class="lattice three compact">
155-
<div class="cell">
187+
<div class="cell" data-reveal>
156188
<h3>Finance</h3>
157189
<p>Reconcile <code>ledger.csv</code> against <code>statement.csv</code>; chase what is overdue</p>
158190
</div>
159-
<div class="cell">
191+
<div class="cell" data-reveal>
160192
<h3>Support</h3>
161193
<p>Answer what came in; group questions by what they are really about</p>
162194
</div>
163-
<div class="cell">
195+
<div class="cell" data-reveal>
164196
<h3>Operations</h3>
165197
<p>List every order still unshipped, and how long it has waited</p>
166198
</div>
167-
<div class="cell">
199+
<div class="cell" data-reveal>
168200
<h3>Marketing</h3>
169201
<p>Turn notes into a week of posts; group contacts by what they bought</p>
170202
</div>
171-
<div class="cell">
203+
<div class="cell" data-reveal>
172204
<h3>People &amp; admin</h3>
173205
<p>Read applicants against a role; pull decisions and owners out of notes</p>
174206
</div>
175-
<div class="cell">
207+
<div class="cell" data-reveal>
176208
<h3>Legal</h3>
177209
<p>Compare their draft against our terms, clause by clause, quoting both</p>
178210
</div>
179-
<div class="cell">
211+
<div class="cell" data-reveal>
180212
<h3>Research</h3>
181213
<p>Where studies agree, where they conflict, and why</p>
182214
</div>
183-
<div class="cell">
215+
<div class="cell" data-reveal>
184216
<h3>Clinical records</h3>
185217
<p>What is recorded, and what a clinician should look at, quoted</p>
186218
</div>
187-
<div class="cell">
219+
<div class="cell" data-reveal>
188220
<h3>Engineering</h3>
189221
<p>Read a service and report what would give a wrong answer</p>
190222
</div>
@@ -201,8 +233,9 @@ <h3>Engineering</h3>
201233
</div>
202234
</section>
203235

204-
<section class="statement">
236+
<section class="statement" data-reveal>
205237
<div class="wrap">
238+
<span class="kicker">03 — Models</span>
206239
<h2>Which models <em>actually work</em></h2>
207240
<p>
208241
The question nobody else answers. Calling tools is what separates a model that can do
@@ -211,7 +244,7 @@ <h2>Which models <em>actually work</em></h2>
211244
</div>
212245
</section>
213246

214-
<section class="tight">
247+
<section class="tight" data-reveal>
215248
<div class="wrap">
216249
<p>
217250
One fixed task: a six-row invoice file with three planted problems — an amount over the
@@ -247,44 +280,46 @@ <h2>Which models <em>actually work</em></h2>
247280
</div>
248281
</section>
249282

250-
<section class="statement">
283+
<section class="statement" data-reveal>
251284
<div class="wrap">
285+
<span class="kicker">04 — Limits</span>
252286
<h2>What it <em>cannot do</em></h2>
253287
<p>Said here rather than discovered later.</p>
254288
</div>
255289
</section>
256290

257291
<div class="lattice two">
258-
<div class="cell">
292+
<div class="cell" data-reveal>
259293
<h3>Open models reach for <code>grep</code></h3>
260294
<p>Given a structured way to read a file, a model not trained towards agentic work will shell out anyway. That is a gap in the models, and no interface closes it.</p>
261295
</div>
262-
<div class="cell">
296+
<div class="cell" data-reveal>
263297
<h3>The builds are not signed</h3>
264298
<p>No Apple or Microsoft certificate. Your operating system will warn you, and it is right to — it cannot tell who built them. The <a href="/download.html">download page</a> says what to do.</p>
265299
</div>
266-
<div class="cell">
300+
<div class="cell" data-reveal>
267301
<h3>Scheduled work needs the app open</h3>
268302
<p>This is a local agent, not a server. Anything that must fire while the machine sleeps belongs in the operating system's scheduler.</p>
269303
</div>
270-
<div class="cell">
304+
<div class="cell" data-reveal>
271305
<h3>Token counts are estimated</h3>
272306
<p>The tokenizer belongs to the model, and this runs models it has never seen. Everything downstream of the count is approximate.</p>
273307
</div>
274-
<div class="cell wide">
308+
<div class="cell wide" data-reveal>
275309
<h3>A run may write anywhere inside its directory</h3>
276310
<p>The sandbox's writable root <em>is</em> that directory — which is why a conversation opens in a workspace rather than your home folder, and why runs outside a department's directory are held until you allow the place by name.</p>
277311
</div>
278312
</div>
279313

280-
<section class="statement">
314+
<section class="statement" data-reveal>
281315
<div class="wrap">
316+
<span class="kicker">05 — Compared</span>
282317
<h2>How it <em>compares</em></h2>
283318
<p>Not a scorecard. These are different tools, and the row that matters is the first one.</p>
284319
</div>
285320
</section>
286321

287-
<section class="tight">
322+
<section class="tight" data-reveal>
288323
<div class="wrap">
289324
<table>
290325
<thead>
@@ -343,8 +378,9 @@ <h2>How it <em>compares</em></h2>
343378
</div>
344379
</section>
345380

346-
<section class="statement" id="cli">
381+
<section class="statement" id="cli" data-reveal>
347382
<div class="wrap">
383+
<span class="kicker">06 — Install</span>
348384
<h2>One binary, <em>one line</em></h2>
349385
<p>macOS and Linux:</p>
350386
<div class="oneline">
@@ -358,7 +394,7 @@ <h2>One binary, <em>one line</em></h2>
358394
</div>
359395
</section>
360396

361-
<section class="tight">
397+
<section class="tight" data-reveal>
362398
<div class="wrap">
363399
<p>
364400
Then point it at a model. A local Ollama, for example, needs nothing but this in

‎website/src/main.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212

1313
import { mountHeroShader } from "./hero-gl";
14+
import { startMotion } from "./motion";
1415

1516
const REPO = "ai-dashboad/opencli";
1617

@@ -144,3 +145,9 @@ if (hero) {
144145
// No WebGL, or a driver that refused. The CSS gradient is still there.
145146
}
146147
}
148+
149+
try {
150+
startMotion();
151+
} catch {
152+
// Everything it touches is already visible and already readable.
153+
}

0 commit comments

Comments
 (0)