A single-page personal bookshelf: a typed heading, two 3D shelves, natural-language search, and visitor recommendations.
The main shelf is Diana’s Goodreads export (goodreads_library_export.csv), imported into src/data/books.ts. Wishlist (to-read) rows are skipped. Covers and blurbs are resolved from Open Library (Google Books fallback) — nothing is invented.
Visitor recommendations are real Open Library titles, stored in .data/recommendations.json (created at runtime, not committed).
npm install
cp .env.example .env # optional — set AI_API_KEY, ANTHROPIC_API_KEY, or CLAUDE_API_KEY
npm run devDev server: http://127.0.0.1:4731
POST /api/search runs on the Vite server so the API key never reaches the client.
- With
AI_API_KEY,ANTHROPIC_API_KEY, orCLAUDE_API_KEYin.env(first match wins): the server calls Anthropic Claude and returns matching catalog ids. - Without a key: keyword matching over the imported catalog.
Do not use a VITE_ prefix on the key. Leave .env uncommitted. Never commit or paste the key.
npm run import:goodreadsReads goodreads_library_export.csv from the repo root and rewrites src/data/books.ts. Exclusive shelf to-read is skipped; remaining rows are newest-first by Date Added. Rows without a verified cover still import.
Vite + React + TypeScript + Tailwind. Design fonts and motion values from the original guide were not attached; the walnut/brass room (Fraunces + Figtree) is a stand-in until that spec arrives.