Underground 2 Revived
Play Need for Speed: Underground 2 (2004) in Chrome and Firefox with WebGPU graphics, Web Audio, up to 120 fps widescreen, controller support, free roam and Online races with friends. Fan project, not
Créez une table, partagez un code de quatre lettres, et jouez en temps réel depuis n’importe quel écran.
Translation pending
GamesTypeScript · CSSGitHub @falmonmickael260-commitsOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
🃏 Jeux de cartes en ligne — Rami & Le Président Deux véritables tables de jeu numériques, multijoueur en temps réel, serveur autoritaire, cartes entièrement vectorielles et motion design soigné. Aucun compte, aucune installation : on crée une salle, on partage un code de 4 caractères, et on joue. La racine / propose le choix du jeu. Rien d'autre à configurer. Le serveur Next.js héberge l'état des parties en mémoire et diffuse les mises à jour en temps réel.Read the full README ↗
Deux véritables tables de jeu numériques, multijoueur en temps réel, serveur autoritaire, cartes entièrement vectorielles et motion design soigné.
Aucun compte, aucune installation : on crée une salle, on partage un code de 4 caractères, et on joue.
| Jeu | Joueurs | Objectif | Accueil |
|---|---|---|---|
| Rami | 2 à 4 (1v1 · 1v1v1 · 2v2) | Ne pas atteindre 401 / 601 points | /rami |
| Le Président | 3 à 8 | Se débarrasser de ses cartes | /president |
La racine / propose le choix du jeu.
npm install
npm run dev # http://localhost:3000
Rien d'autre à configurer. Le serveur Next.js héberge l'état des parties en mémoire et diffuse les mises à jour en temps réel.
npm run verify # typecheck + tests + build
npm run test # moteurs de règles (Vitest)
npm run build && npm start
Depuis le salon, l'hôte peut ajouter des bots. Ils passent par les mêmes actions et la même validation que les joueurs humains : ils ne voient jamais que leur propre main.
La variante implémentée est décrite intégralement — exemples compris — dans REGLES-RAMI.md, qui fait référence. En résumé :
| Sujet | Règle |
|---|---|
| Paquet | 2 jeux de 52 cartes + 4 jokers = 108 cartes |
| Distribution | 14 cartes, 15 au donneur — il ne pioche pas et jette sa quinzième |
| Tour | Piocher ou reprendre la défausse → poser → jeter (obligatoire) |
| Reprise | Une carte reprise dans la défausse doit servir immédiatement |
| Tierce | 3 cartes consécutives ou plus, même signe |
| Brelan / carré | 3 ou 4 cartes de même valeur, signes différents |
| Jokers | 1 par combinaison, compté à la valeur de la carte représentée |
| Ouverture | 71 points, dont une tierce de trois vraies cartes |
| Surenchère | L'équipe suivante doit dépasser : 71 → 72, 119 → 120 |
| Partenaire | En 2 vs 2, il lui suffit d'une tierce |
| Joker dans une tierce | Se récupère avec la carte exacte |
| Joker dans un brelan | Se récupère avec toutes les cartes manquantes |
| Table | On ne réorganise jamais : on complète seulement |
| Fin de manche | Il faut toujours une carte à jeter |
| Score | Gagnant 0 · jamais posé 100 · sinon les cartes restantes |
| Cible | 401 en 1 vs 1, 601 sinon — l'atteindre fait perdre |
Les points d'interprétation assumés — ce que le cahier des charges ne tranchait
pas — sont listés à la fin de REGLES-RAMI.md, avec l'endroit du code où les
modifier.
| Sujet | Règle |
|---|---|
| Paquet | 52 cartes, ordre 3 … A, 2 |
| Combinaisons | 1 à 4 cartes de même valeur |
| Ouverture | Manche 1 : le porteur de la Dame de pique commence |
| Carré | Ferme le pli immédiatement |
| Classement | 👑 Président · 🥈 Vice-Président · … · 💩 Trou du Cul |
| Échange | Trou du Cul → Président : 2 meilleures cartes, retour au choix |
src/
├─ rami/ Moteur du Rami — pur, sans React, réseau ni DOM
│ ├─ cards.ts 108 cartes, valeurs, As 1/11, tri
│ ├─ melds.ts Tierces, brelans, carrés, jokers, compléments
│ ├─ scoring.ts Seuils d'ouverture, points de manche, fin de partie
│ ├─ moves.ts Validation centrale, messages destinés au joueur
│ ├─ engine.ts Machine d'état (distribution → tours → manches)
│ ├─ solver.ts Recherche de combinaisons (bots + aide d'interface)
│ ├─ view.ts Projection par joueur (frontière de confidentialité)
│ ├─ bot.ts Stratégie des bots
│ └─ *.test.ts Tous les cas du cahier des charges
│
├─ game/ Moteur du Président (même principes)
│
├─ server/
│ ├─ roomStore.ts Plomberie des salles, **commune aux deux jeux**
│ ├─ games/ Un adaptateur par jeu
│ ├─ persistence.ts Supabase optionnel, une table par jeu
│ └─ input.ts Validation défensive des entrées client
│
├─ app/
│ ├─ page.tsx Choix du jeu
│ ├─ rami/ … Accueil, salle, règlement
│ ├─ president/ salle/ Accueil et salle du Président
│ └─ api/ REST + flux SSE, un espace par jeu
│
├─ components/
│ ├─ card/ Cartes du Président, géométrie et éventail partagés
│ ├─ ramicard/ Faces du Rami (As → Roi) et joker vectoriel
│ ├─ rami/ Table, tapis, main, plan de travail, règlement
│ ├─ game/ Table du Président, ancres, couche de vol
│ └─ ui/ lobby/ home/
│
└─ hooks/
├─ useGameRoom Connexion temps réel, commune aux deux jeux
├─ useRamiTurn Sélection, préparation des combinaisons
└─ useRamiDirector Événements serveur → trajectoires, sons, annonces
Les deux jeux partagent la plomberie : salles, jetons, présence, chrono, bots, flux temps réel, géométrie des cartes, calcul de l'éventail, couche de vol, composants d'interface de base.
Ils ne partagent aucune règle : les valeurs, l'ordre et les combinaisons diffèrent, et les mélanger produirait des cartes illisibles. La couche de vol est donc générique sur le type de carte, et chaque jeu fournit son rendu.
{ pseudo, avatar, nombre de cartes, statut }, et la pioche à un compteur.Le flux passe par SSE. À chaque mutation, le serveur pousse à chaque abonné une vue personnalisée plus la liste des événements à animer.
Ce choix est délibéré : chaque joueur doit recevoir un état différent. Diffuser les lignes brutes d'une table — via Supabase Realtime par exemple — exposerait les mains adverses à tous les abonnés du canal.
La reconnexion est triviale : le client garde son jeton en localStorage,
EventSource se reconnecte avec un repli exponentiel, et la première vue reçue
fait autorité. Rafraîchir la page, changer de réseau ou mettre le téléphone en
veille ne fait pas perdre la partie.
Les jeux fonctionnent sans. En configurant les variables ci-dessous, les salles survivent à un redémarrage du serveur :
NEXT_PUBLIC_SUPABASE_URL=...
SUPABASE_SERVICE_ROLE_KEY=...
Appliquez alors supabase/schema.sql. Les tables restent inaccessibles depuis
le navigateur (RLS sans policy publique) : elles contiennent les mains.
feTurbulence, pas par une image.Le point délicat est l'ouverture : il faut souvent plusieurs combinaisons comptées ensemble pour atteindre 71 points. Plutôt que de le deviner, le joueur les prépare sur un plan de travail, voit le total monter, et ne pose que lorsque le compte y est — comme on aligne ses cartes devant soi sur une vraie table.
Le solveur propose une ouverture quand il en trouve une, mais ne l'impose jamais : c'est un bouton, pas un coup joué.
Chaque animation sert la lisibilité :
prefers-reduced-motion est respecté : les trajectoires sont remplacées par des
fondus courts, sans jamais désactiver de fonctionnalité.
P piocher, R reprendre la défausse, Entrée
préparer/poser/jeter, Échap annuler, T trier la main par signe ou par
valeur. Ils sont listés dans le menu de la partie.prefers-contrast: more.Toutes les animations portent sur transform et opacity. Le chrono s'écrit
directement dans le DOM en requestAnimationFrame : aucun rendu React par
frame. Le solveur est borné par un budget de nœuds : une main tordue ne peut
pas faire tourner le serveur en rond.
Voir DEPLOY.md. En résumé : le serveur doit tourner en un seul processus persistant (Render, Fly.io, Railway, Docker) — les plateformes serverless ne conviennent ni à l'état en mémoire ni aux flux SSE.
Projet privé.