diff --git a/README.md b/README.md index a97d2d3..1976cbc 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,72 @@ -# newbury-nights +# Newbury Nights -Fan-made AR ghost-hunting web app — tribute to LEGO Hidden Side AR mechanics. Node/Express + SQLite + Three.js. Not affiliated with the LEGO Group. \ No newline at end of file +A fan-made AR ghost-hunting web app — a tribute to the AR mechanics of the LEGO® Hidden Side™ app. The focus is the **Hunter Mode** AR loop: raise your phone as a ghost detector, scan the colour wheel to uncover gloom, lock on, and blast ghosts down before your battery dies. + +> Fan-made tribute. Not affiliated with, sponsored by, or endorsed by the LEGO Group. LEGO® and Hidden Side™ are trademarks of the LEGO Group. + +## What's inside + +- **Backend** — Node + Express 5, SQLite via `better-sqlite3`, bcrypt password hashing, JWT auth (8h), multer image uploads. +- **Frontend** — Three.js (ES module import maps via CDN), `getUserMedia` camera passthrough with `DeviceOrientation` gyro look (iOS Safari friendly), `BarcodeDetector` QR scanning with a manual code fallback. +- **Ghost rendering** — animated-GIF billboards (texture pumped via `texture.needsUpdate` each frame) when a ghost has an uploaded image; procedural Three.js wisp meshes otherwise. +- **Spawning** — rarity-weighted: ★ common down to ★★★★ legendary. +- **Admin panel** (`/admin`) — JWT-gated. Upload / enable / disable / delete ghost images, create sets with scan codes linked to ghost rosters (many-to-many via `set_ghosts`). +- **Public endpoint** — `GET /api/scan/:code` requires no auth and returns a set's ghost roster. + +## Data + +The ghost roster, stats, abilities, and boss→set references are seeded from `data/*.json`, which are generated from the source spreadsheet by `scripts/extract_ghosts.py`. Three ghost types (red / yellow / blue) and four rarity tiers drive the colour-wheel and damage mechanics. + +To regenerate the JSON from a spreadsheet: + +```bash +python3 scripts/extract_ghosts.py path/to/Ghost_Data.xlsx data +``` + +## Setup + +Requires Node 18+ and `build-essential` on Ubuntu (so `better-sqlite3` can compile its native module): + +```bash +sudo apt-get install -y build-essential +npm install +cp .env.example .env # then edit JWT_SECRET and admin creds +npm run seed # creates the DB, seeds ghosts/sets, bootstraps admin +npm start +``` + +The app listens on `PORT` (default 3000) over plain HTTP — **nginx terminates HTTPS in front of it**. `app.set('trust proxy', 1)` is set so secure cookies work behind the proxy. + +Re-running `npm run seed` is safe: it only seeds ghost/set data when the `ghosts` table is empty, so it won't clobber admin edits. It always ensures an admin user exists. + +## nginx + +See `deploy/nginx.conf.example` for a reverse-proxy block. Camera and gyro APIs require a secure context, so the site must be served over HTTPS (which nginx already handles for you). + +## API quick reference + +Public: +- `GET /api/scan/:code` — set roster + boss for a scan code +- `GET /api/freehunt?n=&type=` — rarity-weighted random spawns +- `GET /api/ghosts?type=&rarity=&boss=` — public ghost index (enabled only) +- `GET /api/abilities` — ability reference + +Auth: +- `POST /auth/login` · `POST /auth/logout` · `GET /auth/me` · `POST /auth/change-password` + +Admin (JWT required): +- `GET/POST /api/admin/ghosts`, `PATCH/DELETE /api/admin/ghosts/:id`, `POST /api/admin/ghosts/:id/image` +- `GET/POST /api/admin/sets`, `PATCH/DELETE /api/admin/sets/:id`, `PUT /api/admin/sets/:id/roster` + +## Project layout + +``` +server.js Express app + static hosting +db/index.js SQLite schema + connection +routes/ auth, public api, admin api, auth middleware +scripts/extract_ghosts.py xlsx -> data/*.json +scripts/seed.js seed DB from data/*.json + bootstrap admin +data/ ghosts.json, abilities.json, sets.json +public/ index.html (game), admin.html, css/, js/ +uploads/ uploaded ghost billboards (gitignored) +```