Minimal team play shell, admin console, and API for a Godot WebGL export embedded in an iframe. See protocol.md for postMessage shapes.
1. API (terminal A):
cd apps/api
cp .env.example .env # edit ADMIN_TOKEN, WEB_ORIGINS
npm install
npm run dev2. Web (terminal B):
cd apps/web
cp .env.example .env.local # optional
npm install
npm run dev3. Game static files: copy your Web export into apps/web/public/game/ so CyberCrime.html is at apps/web/public/game/CyberCrime.html, or set VITE_GAME_URL in apps/web/.env.local to a full URL.
Open http://127.0.0.1:5173/ → enter team name → play page loads the iframe and polls hints.
Admin: http://127.0.0.1:5173/admin.html — paste the same ADMIN_TOKEN as the API.
| Piece | Suggestion |
|---|---|
| API | Fly.io, Railway, or Render. Set ADMIN_TOKEN, WEB_ORIGINS (your shell origin, comma-separated), PORT if required. Persist disk or set SQLITE_PATH to a mounted volume path. |
| Shell | Cloudflare Pages, Vercel, or Netlify from apps/web after npm run build; upload apps/web/dist. |
| Game | Same static host under /game/ or a game. subdomain; set VITE_API_BASE and VITE_GAME_URL at build time for the shell if API/game are on other origins. |
Docker API (from repo root, with Docker running):
docker build -t quest-api .
docker run --rm -p 3001:3001 \
-e ADMIN_TOKEN=your-secret \
-e 'WEB_ORIGINS=https://your-shell.example.com' \
-v quest-data:/app/data \
quest-apiSQLite defaults to ./data/quest.sqlite under the working directory (/app/data with the volume above).
See godot/README.md and godot/QuestBridge.gd. The exported CyberCrime.html includes a small script that queues hint postMessage payloads in window.__questShellInbound.
apps/api— Express + SQLiteapps/web— Vite multi-page shell (/,play.html,admin.html)shared/protocol.ts— shared message validationgodot/— optional autoload bridge for the game project