Skip to content

Commit 601ecb6

Browse files
committed
feat(web,readme): hide broken demo, swap Fig labels for SVG icons, add logo
- Remove the HammerDemo section from the landing page and delete the component. The demo POSTs to localhost:3001, so on the hosted site it is dead weight and worse UX than not showing it at all. It will come back when the hosted API ships. - Replace the "Fig 1 / Fig 2 / Fig 3" placeholders in the metrics cards with actual SVG icons that encode each stat: parallel lines converging into an ordered stream (1000 concurrent writes), shield with check (0 race conditions), lightning bolt (<100ms p50 read). - Add a static apps/web/public/logo.svg — same 3-fading-bars-to-1 visual as the favicon — and embed it at the top of the README. - Drop hammer-demo references from the README (CTA badge, status table, dashboard-experience bullet, dedicated section, roadmap), and move the demo to V1 behind the hosted API.
1 parent 3b7617e commit 601ecb6

4 files changed

Lines changed: 96 additions & 259 deletions

File tree

README.md

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
<br />
44

5+
<img src="apps/web/public/logo.svg" alt="sheetforge" width="120" height="120" />
6+
57
# sheetforge
68

79
### Google Sheets as a backend that actually behaves like one.
@@ -21,8 +23,6 @@ Serialized writes. Idempotent retries. Typed TypeScript SDKs, generated live fro
2123

2224
[![Self-host in 60s](https://img.shields.io/badge/Self--host%20in%2060s%20→-0c0c0e?style=for-the-badge&labelColor=22c55e)](#quickstart)
2325
&nbsp;
24-
[![Try the hammer demo](https://img.shields.io/badge/Try%20the%20hammer%20demo%20→-22c55e?style=for-the-badge&labelColor=0c0c0e)](#the-hammer-demo)
25-
&nbsp;
2626
[![How it works](https://img.shields.io/badge/How%20it%20works%20→-bbf7d0?style=for-the-badge&labelColor=0c0c0e)](#how-the-queue-actually-works)
2727

2828
<br />
@@ -83,32 +83,14 @@ await Promise.all([
8383
| Surface | Status |
8484
| :-- | :-- |
8585
| Landing site (marketing only) | ✅ live at [sheetforge.dev](https://sheetforge.dev) |
86-
| Dashboard + API (write-queue, SDK codegen, hammer demo) | 🟢 runs locally via `pnpm dev` |
86+
| Dashboard + API (write-queue, SDK codegen) | 🟢 runs locally via `pnpm dev` |
8787
| Hosted SaaS (sign up, skip local infra) | ⏳ planned after V1 stabilizes |
8888
| OSS core (`packages/queue`, `packages/codegen`, `packages/sdk-ts`) | ✅ MIT, free forever |
8989

90-
**What this means for you.** If you land on the marketing site today and hit "Sign in", that flow only works against an API *you* run — the hosted endpoint isn't up yet. To try the product, clone this repo, follow the [quickstart](#quickstart), and the dashboard at `http://localhost:3000` gives you the whole experience (OAuth, sheet connect, typed SDK download, hammer demo).
90+
**What this means for you.** If you land on the marketing site today and hit "Sign in", that flow only works against an API *you* run — the hosted endpoint isn't up yet. To try the product, clone this repo, follow the [quickstart](#quickstart), and the dashboard at `http://localhost:3000` gives you the whole experience (OAuth, sheet connect, typed SDK download).
9191

9292
I'll update this section the moment the hosted API is live. Star the repo to get notified.
9393

94-
## The hammer demo
95-
96-
There's a button on the landing page labeled **fire 50 parallel writes**. Once you have the stack running locally, it fires 50 concurrent POSTs at a synthetic sheet, polls the status endpoint, and paints a 50-tile grid as writes land. Try breaking it.
97-
98-
```
99-
$ pnpm dev
100-
▸ web http://localhost:3000
101-
▸ api http://localhost:3001
102-
103-
fire 50 parallel writes
104-
██████████████████████████████████████████ 50 / 50
105-
ordered · idempotent · 1.2s end-to-end
106-
```
107-
108-
Zero dropped rows. Zero duplicates on replay. Grid order matches enqueue order because the advisory lock serializes the tail. The same hammer hits a raw Sheets API sample and reliably drops 3 to 8 rows per run.
109-
110-
> The demo button on the **hosted** landing page intentionally points at `localhost:3001` — it's here to show the pipeline, not to be a SaaS. When the hosted API ships, it'll be swapped to the public endpoint.
111-
11294
## Quickstart
11395

11496
```bash
@@ -309,7 +291,7 @@ slices/ feature slices. barrel is the only public API
309291
write-queue/ submitWrite, processNext, advisory-lock fencing
310292
rest-api/ Hono routes, CORS, idempotency, error boundary
311293
sdk-codegen/ schema to TypeScript client
312-
demo/ the hammer demo (public, rate-limited)
294+
demo/ local-only hammer demo (hidden until hosted API ships)
313295
314296
packages/ MIT, npm-publishable, no shared/ imports
315297
queue/ generic Redis-Streams consumer
@@ -335,9 +317,9 @@ Slice internals stay private. Cross-slice imports fail CI. `packages/*` stays OS
335317
- [x] Idempotency by key, partial unique index
336318
- [x] Upstash REST adapter (Workers-ready)
337319
- [x] TypeScript SDK download
338-
- [x] Hammer demo on the landing page
339320

340321
**V1**
322+
- [ ] Hammer demo on the hosted landing page (requires hosted API)
341323
- [ ] Dedicated worker process (currently inline with API)
342324
- [ ] Python SDK generator
343325
- [ ] Write-status webhooks

apps/web/public/logo.svg

Lines changed: 7 additions & 0 deletions
Loading

apps/web/src/app/page.tsx

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use client';
22

3-
import { HammerDemo } from '@/components/HammerDemo';
43
import { ChevronDownIcon, CopyIcon, OpenCodeLogo } from '@/components/icons';
54
import { useState } from 'react';
65

@@ -342,10 +341,48 @@ function StatsSection() {
342341
</p>
343342
<div className="grid grid-cols-3 gap-6">
344343
<div
345-
className="border rounded p-6"
344+
className="border rounded p-6 flex flex-col gap-3"
346345
style={{ borderColor: '#3d3838' }}
347346
>
348-
<p className="text-[#7f7a7a] text-sm mb-2">Fig 1.</p>
347+
<svg
348+
width="40"
349+
height="40"
350+
viewBox="0 0 40 40"
351+
fill="none"
352+
aria-hidden="true"
353+
>
354+
<title>Parallel writes converging into an ordered stream</title>
355+
<path
356+
d="M4 10 L18 10 L24 20"
357+
stroke="#22c55e"
358+
strokeOpacity="0.45"
359+
strokeWidth="2"
360+
strokeLinecap="round"
361+
strokeLinejoin="round"
362+
/>
363+
<path
364+
d="M4 20 L18 20 L24 20"
365+
stroke="#22c55e"
366+
strokeOpacity="0.7"
367+
strokeWidth="2"
368+
strokeLinecap="round"
369+
strokeLinejoin="round"
370+
/>
371+
<path
372+
d="M4 30 L18 30 L24 20"
373+
stroke="#22c55e"
374+
strokeOpacity="0.45"
375+
strokeWidth="2"
376+
strokeLinecap="round"
377+
strokeLinejoin="round"
378+
/>
379+
<path
380+
d="M24 20 L36 20"
381+
stroke="#22c55e"
382+
strokeWidth="3"
383+
strokeLinecap="round"
384+
/>
385+
</svg>
349386
<p
350387
className="text-2xl font-bold"
351388
style={{ color: '#22c55e' }}
@@ -355,10 +392,33 @@ function StatsSection() {
355392
<p className="text-[#b8b2b2] text-sm">Concurrent writes, in order</p>
356393
</div>
357394
<div
358-
className="border rounded p-6"
395+
className="border rounded p-6 flex flex-col gap-3"
359396
style={{ borderColor: '#3d3838' }}
360397
>
361-
<p className="text-[#7f7a7a] text-sm mb-2">Fig 2.</p>
398+
<svg
399+
width="40"
400+
height="40"
401+
viewBox="0 0 40 40"
402+
fill="none"
403+
aria-hidden="true"
404+
>
405+
<title>Shielded queue — no race conditions</title>
406+
<path
407+
d="M20 4 L6 9 V20 C6 28 12 34 20 37 C28 34 34 28 34 20 V9 Z"
408+
stroke="#22c55e"
409+
strokeWidth="2"
410+
strokeLinejoin="round"
411+
fill="#22c55e"
412+
fillOpacity="0.08"
413+
/>
414+
<path
415+
d="M14 20 L18 24 L26 15"
416+
stroke="#22c55e"
417+
strokeWidth="2.5"
418+
strokeLinecap="round"
419+
strokeLinejoin="round"
420+
/>
421+
</svg>
362422
<p
363423
className="text-2xl font-bold"
364424
style={{ color: '#22c55e' }}
@@ -368,10 +428,26 @@ function StatsSection() {
368428
<p className="text-[#b8b2b2] text-sm">Race conditions</p>
369429
</div>
370430
<div
371-
className="border rounded p-6"
431+
className="border rounded p-6 flex flex-col gap-3"
372432
style={{ borderColor: '#3d3838' }}
373433
>
374-
<p className="text-[#7f7a7a] text-sm mb-2">Fig 3.</p>
434+
<svg
435+
width="40"
436+
height="40"
437+
viewBox="0 0 40 40"
438+
fill="none"
439+
aria-hidden="true"
440+
>
441+
<title>Edge-cached read — sub-100ms latency bolt</title>
442+
<path
443+
d="M22 3 L8 22 H18 L16 37 L32 16 H22 L24 3 Z"
444+
stroke="#22c55e"
445+
strokeWidth="2"
446+
strokeLinejoin="round"
447+
fill="#22c55e"
448+
fillOpacity="0.15"
449+
/>
450+
</svg>
375451
<p
376452
className="text-2xl font-bold"
377453
style={{ color: '#22c55e' }}
@@ -513,7 +589,6 @@ export default function Home() {
513589
<Header />
514590
<SelfHostBanner />
515591
<HeroSection />
516-
<HammerDemo />
517592
<FeaturesSection />
518593
<StatsSection />
519594
<PrivacySection />

0 commit comments

Comments
 (0)