The living map of your real circle. Hard cap of twelve.
See who is free, drop a Pulse, hang when you are nearby.
There is no public feed, no followers, no For You, no ads.
Needs Node 20+ (LTS).
npm install
npm run db:seed
npm run devOpen http://127.0.0.1:45621. On a laptop the app sits in a phone frame. /pitch is full-width.
npm run db:seed resets SQLite and rebuilds Riverside Hall. npm run build / npm test also work.
Password for all three: riverside
| Who | What you see | |
|---|---|---|
| Maya Chen | maya@riverside.kith |
Default demo. Jordan is nearby. Two unopened Pulses. |
| Jordan Hale | jordan@riverside.kith |
The other side of the hang and the rooftop Pulse. |
| Priya Nair | priya@riverside.kith |
Busy in the library. Accepted hang with Wren. |
Or tap Enter Riverside Hall — no typing.
From You → Present as, switch Maya / Jordan / Priya without signing out.
- Open
/pitch. One breath on the story: twelve is the product, not a feature Meta can bolt onto Reels. - Open the live demo → Enter Riverside Hall. The map should already be alive: breathing orbs, amber rings, a voice pip on Jordan.
- Tap Jordan’s glowing orb. Rooftop Pulse, dual still, voice. Leave a sticker or a voice. Ring drains because you opened it.
- The hang sheet is up — he is in the courtyard. 5 min?.
- Center shutter. Capture or upload a Pulse. The lock badge is honest: solid if in-app camera, dashed if file upload. Not C2PA.
- Chapters — this week’s filmstrip, letterboxed, date ticks.
- Circle — 12/12, tokens you cannot spend because the cap is real. Press a token onto Kai on floor 3; the API refuses.
- You → Present as Jordan. See Maya’s new Pulse and the hang you sent.
The metric this is designed to show: a stranger enters a dense circle and posts a Pulse in session one.
- MapLibre + OSM/CARTO dark tiles. No Google billing.
- Pulses persist to
public/uploads(swappable storage helper inlib/storage.ts). - Presence: free breathes, busy freezes, ghost desaturates and hides exact coordinates.
- Quiet hours, location precision (off / fuzzy / exact), block, report.
- Invite tokens are scarce; circle cap is enforced in API and UI.
- PWA: manifest, icons, theme color, service worker, apple-mobile-web-app.
- Realtime via SSE (
/api/events). Short polling fallback is the same payload on/api/me.
npm testCovers circle cap, invite tokens, ghost location privacy, and auth sessions.
Next.js App Router, TypeScript, Tailwind v4, Prisma, SQLite, MapLibre GL, httpOnly JWT cookies.
The full Next+Prisma app cannot run on Pages. static-demo/ is a client-only Vite walkthrough of Riverside Hall.
npm run build:pagesPublic URL after Pages is enabled: https://amineux.github.io/kith/
Pitch and auth load without MapLibre. The map library is an async chunk, fetched only when the map screen mounts.
Enable: GitHub repo Settings → Pages → Source: GitHub Actions. The workflow .github/workflows/pages.yml deploys on push to main.
Set AUTH_SECRET on the project (see .env.example). Leave DATABASE_URL as file:./dev.db for build — npm run build seeds Riverside Hall into prisma/dev.db. On Vercel the app copies that file to /tmp on cold start so SQLite can write; it will not persist across instances. Seed images in public/ are fine.