···11-# Atmosphere VODs
11+# Streamplace VOD Client
2233-Atmosphere VODs is a minimalist glassy PWA for browsing ATmosphereConf 2026 talks from the
44-Streamplace AT Protocol VOD beta API.
33+Streamplace VOD Client is a minimalist glassy PWA for browsing `place.stream.video` records
44+across discovered AT Protocol repos, with a dedicated AtmosphereConf 2026 page.
55+66+Production URL: https://vods.j4ck.xyz
5768## What it includes
79810- React + Vite + TypeScript app with Tailwind + shadcn-style UI primitives
99-- PDS-aware data fetching: resolves the repo DID in PLC directory, then fetches records from that PDS
1111+- Relay + PDS-aware fetch flow:
1212+ - discovers repos via `com.atproto.sync.listReposByCollection` on `bsky.network`
1313+ - resolves each DID to its PDS via `plc.directory`
1414+ - fetches `place.stream.video` records from each repo using `com.atproto.repo.listRecords`
1015- HLS playback via `hls.js` with native controls and mobile swipe-down dismiss
1111-- Search by title + AI-generated tags/topics with `/tag/{tag}` routes
1616+- Search across all discovered videos, with semantic ranking via Cloudflare Pages Function (`/api/search`)
1717+- AtmosphereConf-specific tag/topic enrichment from OpenRouter taxonomy for stronger conference query matching
1818+- `/atmosphereconf-2026` route with official conference videos only
1219- Mobile-first navigation: bottom tabs on mobile, sidebar on desktop
1320- PWA setup with `vite-plugin-pwa` and Workbox runtime caching
1421···27342835## Generate AI taxonomy (one-time or refresh)
29363030-The app can enrich talks with tags/topics generated through OpenRouter.
3737+The app can enrich AtmosphereConf talks with tags/topics generated through OpenRouter.
313832391. Put your key in `.env` as `OPENROUTER_API_KEY=...`.
33402. Run:
···38453946This updates `src/lib/video-taxonomy.json`, which is bundled into the app and used by search + tag routes.
40474848+## Generate semantic embeddings index (for `/api/search`)
4949+5050+To support cheap server-assisted semantic search on Cloudflare Pages, generate a static embedding index:
5151+5252+```bash
5353+npm run embeddings:generate
5454+```
5555+5656+This updates `public/video-embeddings.json`.
5757+5858+### Required env vars for embeddings generation
5959+6060+- `OPENROUTER_API_KEY`
6161+- optional: `OPENROUTER_EMBEDDING_MODEL` (defaults to `openai/text-embedding-3-small`)
6262+6363+## Cloudflare Pages function search backend
6464+6565+`functions/api/search.ts` provides semantic ranking using:
6666+6767+- static embedding index from `public/video-embeddings.json`
6868+- OpenRouter query embeddings at request time
6969+- live repo discovery overlay so newly uploaded videos are included immediately
7070+- lexical + recency fallback for any videos not yet embedded
7171+7272+Set this env var in Cloudflare Pages project settings for semantic mode:
7373+7474+- `OPENROUTER_API_KEY`
7575+- optional: `OPENROUTER_EMBEDDING_MODEL`
7676+7777+If the key is not set, search falls back gracefully to lexical title ranking.
7878+7979+### Freshness behavior
8080+8181+- Newly uploaded VODs appear immediately in results because the search function overlays a live catalog
8282+ from relay + PDS APIs.
8383+- Those fresh videos are lexical-ranked until you refresh `public/video-embeddings.json`.
8484+- The UI shows index snapshot time and how many videos are currently embedded.
8585+4186## Deploy to Vercel
428743881. Push this repo to GitHub.
44892. In Vercel, import the repository.
45903. Deploy with defaults, or run `vercel deploy` from your terminal.
46914747-No environment variables are required because all APIs are public.
9292+For semantic `/api/search`, set `OPENROUTER_API_KEY` in Cloudflare Pages.
48934994## License
5095