Quiz familial multijoueur sur un même écran. Le maître du jeu (MJ) lit les questions et saisit les réponses de chaque joueur. Les questions sont générées à la volée par un LLM OpenAI-compatible, via un proxy qui garde la clé API hors du navigateur.
2 à 6 joueurs. Zéro dépendance runtime, vanilla JS.
session vos joueurs + toutes les parties de la soirée
partie best-of 1, 3, 5 ou 7 manches — gagnée à la majorité
manche course au score cible — les scores repartent de zéro
question
Le score cible termine une manche, pas la partie : en best-of 5, il faut en remporter 3. Le best-of s'arrête dès que la majorité est acquise.
Une session n'a pas de fin : c'est un sac à parties, avec son roster et son historique de questions déjà posées. Elle survit au rechargement de la page et reste consultable dans l'écran Sessions.
- Chronomètre — 30 s à 5 min par question. À zéro, la saisie se verrouille et le MJ garde la main pour révéler.
- −1 point si pas de réponse — sanctionne le silence.
- Mode punisher — −1 point sur une mauvaise réponse, ou −2 sur une question bonus en sévérité ultra.
- Questions bonus ×2, écart de 2 points requis, difficulté et public (kid friendly / tout public / adulte).
Aucun score ne descend sous zéro.
- Node.js ≥ 20 LTS
- Une clé API chez un provider OpenAI-compatible — ou rien du tout, voir la démo offline
npm install
npm run dev # http://localhost:5173Chaque joueur peut renseigner son propre provider (URL, clé, modèle) depuis le panneau Modèle LLM de l'écran de réglages : la clé reste dans son navigateur.
cp .env.example .env
# renseigner LLM_BASE_URL, LLM_API_KEY, LLM_MODEL
npm run devLATENCY_MS=4000 node demo/mock-llm.mjs & # faux LLM local
npm run devnpm run build # génère dist/
npm run preview # prévisualise dist/Le déploiement cible Vercel : vercel.json réécrit /api/* vers la fonction
api/gateway.js, qui joue le rôle de proxy LLM côté serveur et injecte
l'en-tête Authorization. Ne jamais exposer une variable VITE_LLM_API_KEY :
tout ce qui porte le préfixe VITE_ finit dans le bundle client.
Le proxy de
vite.config.jsne sert que le serveur de développement. En production, c'estapi/gateway.jsqui prend le relais — les deux implémentent le même contrat.
Le projet fournit un flake.nix (flakes requis) :
nix develop— environnement de dev (Node.js 24 + npm)nix build .#— compiledist/de façon reproductible, sans nécessiter.envnix flake check— vérifie que le build passe
Le projet est épinglé sur Node.js 24 (LTS) :
engines.nodedanspackage.json, etnodejs_24dans le flake. Le même champ détermine la version utilisée par Vercel, dev et production restent donc alignés. Lepackage-lock.jsonest versionné pour figervite.
| Fichier | Rôle |
|---|---|
src/main.js |
Bootstrap, hydratation, routage des écrans |
src/state.js |
Store global, réducteur, machine à états, session/partie/manche |
src/api.js |
Client HTTP vers /api avec retries |
src/prompt.js |
Construction des prompts LLM |
src/validation.js |
Validation du contrat Question |
src/storage.js |
localStorage — roster, réglages, stats, session active |
src/db.js |
IndexedDB — archive des sessions et parties |
src/themeSwitcher.js |
Thème de couleurs |
src/confetti.js |
Animation de victoire |
src/screens/ |
home · setup · game · victory · sessions |
src/styles/ |
Design system (jetons, mise en page, composants, coquille arcade) |
api/gateway.js |
Proxy LLM serverless (production) |
Le petit état lu au démarrage vit en localStorage (lecture synchrone avant le
premier rendu) ; l'archive, qui grossit sans limite, vit en IndexedDB. Si le
navigateur refuse IndexedDB, le jeu fonctionne normalement — seul l'historique
des sessions est perdu.
Dix apparences au choix, commutables en cours de partie : VS Code, Matrix, Girly,
Windows 98, Jungle, Kids Friendly, Apple, Apple Glass, Paper Quest (défaut),
qui habille le jeu de parchemin et de plaques peintes (public/paper-ui/), et
Mecha, cockpit d'aluminium, de verre fumé et de LED sur fond animé.
Tout passe par des variables CSS : ajouter un thème ne demande qu'une entrée dans
COLOR_THEMES et un bloc de surcharges dans src/styles/theme.css.