🍝 Chaos Diner RPG

Un'innocua cena al ristorante che si trasforma in un'arena di caos multiplayer in tempo reale, alimentata dall'AI Cameriere (Gemini).

👉 Gioca subito: https://chaos-diner.val.run

🎮 Come si gioca

  1. Lobby — un giocatore apre la stanza e condivide il codice con gli amici (ognuno entra da un proprio tab con "Entra").
  2. Ordinazione — l'AI Cameriere ti dà il benvenuto e raccoglie l'ordine di ogni commensale, scritto in linguaggio naturale (es. "Cotoletta con patatine e una bibita").
  3. Servizio — il Cameriere va in cucina, genera l'immagine del piatto per ogni commensale e torna con le pietanze impilate una sopra l'altra, distribuendole a ognuno in base a ciò che ha ordinato.
  4. La scelta — a ogni giocatore compare la forchetta con 🍴 Mangia Tranquillo oppure 🍝 Lancia il Cibo.
  5. Food Fight & Fuga — lanciare il cibo fa partire lo scratch del vinile e la traccia Heavy Metal. Bersaglia un commensale o il Cameriere: ogni lancio alimenta la sua rabbia (0-100). Sopra la soglia, il Cameriere va in RAGE e parte la fase di fuga: nasconditi, scappa, lancia una sedia… chi viene beccato è eliminato e passa in modalità Spettatore. Sopravvive solo il più scaltro.

🔧 Architettura (Val.town)

index.ts        ← server Hono: HTML + API
lib/
  game.ts       ← macchina a stati (LOBBY→ORDERING→SERVING→CHILL→CHASE→ENDED), rabbia, fuga
  ai.ts         ← Cameriere AI (chat) + generazione immagini piatti (Gemini)
  db.ts         ← SQLite (val-scoped): stanze + log eventi
  types.ts      ← tipi condivisi client/server
frontend/
  root.tsx      ← HTML shell
  audio.ts      ← motore audio (scratch/metalli via Web Audio)
  api.ts        ← client API + sessione (localStorage)
  components/   ← Lobby, GameScreen (tavolo, servizio, food fight, fuga)
  • Real-time: polling (~1.2s) su GET /api/room/:id?since=… con eventi incrementali — serverless-friendly (niente WebSocket).
  • Immagini piatti: embeddate come data-URL negli eventi (SERVING), servite a ogni client; il polling resta leggero.
  • Audio: scratch del vinile e riff Heavy Metal generati in Web Audio (nessun asset esterno). Se vuoi colonne reali, punta due URL in frontend/audio.tssetPlaylist(lofiUrl, metalUrl).

⚙️ Configurazione

La chiave Gemini vive nella env var GEMINI_API_KEY (mai nel codice). Modelli usati:

  • Chat (Cameriere): gemini-3.5-flash — attivo.
  • Immagini (piatti): gemini-2.5-flash-image — richiede quota sull'account (limite 0 sul piano free). Se non disponibile, il gioco usa un piatto segnaposto SVG come fallback.