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
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Achetez et vendez des cryptomonnaies au prix réel du marché avec 10 000 $ fictifs, suivez vos plus-values et comparez-vous aux autres joueurs. Aucun argent réel. Je voulais m'entraîner sur Next.js et m'amuser sur un sujet qui m'intéresse : la finance. Un simulateur de trading réunit les deux, avec des données en temps réel et des calculs où l'exactitude compte, même quand l'argent est fictif.README 전문 보기 ↗
Achetez et vendez des cryptomonnaies au prix réel du marché avec 10 000 $ fictifs, suivez vos plus-values et comparez-vous aux autres joueurs. Aucun argent réel.
Démo : https://papertrade-five-peach.vercel.app
Je voulais m'entraîner sur Next.js et m'amuser sur un sujet qui m'intéresse : la finance. Un simulateur de trading réunit les deux, avec des données en temps réel et des calculs où l'exactitude compte, même quand l'argent est fictif.
BTC puis Entrée, ⌘K pour y accéder) et
touches de fonction F1 à F3 pour changer d'écran| Domaine | Outils |
|---|---|
| Framework | Next.js 16 (App Router, Server Components, Server Actions), React 19, TypeScript strict |
| Interface | Tailwind CSS 4, Lightweight Charts, IBM Plex Mono |
| Données | PostgreSQL, Drizzle ORM, Zod |
| Auth | Better Auth (compte invité, OAuth GitHub) |
| Qualité | Vitest (tests unitaires et d'intégration sur Postgres), ESLint, GitHub Actions |
| Hébergement | Vercel + Neon (offres gratuites) |
Une interface de terminal de marché plutôt que d'application grand public : une seule police à
chasse fixe (IBM Plex Mono), des noirs neutres, l'ambre pour tout ce qui est interactif, le vert et
le rouge réservés aux variations. Pas d'arrondis ni d'ombres : des panneaux séparés par des filets.
Les choix et leurs raisons sont dans
design-system/papertrade/MASTER.md.
aria-sort, confirmations dans un <dialog> natif. Aucun raccourci à
touche unique (WCAG 2.1.4).Le formulaire n'envoie que l'actif, le sens et la quantité. La Server Action
(src/app/actions.ts) identifie l'utilisateur par sa session, valide
l'entrée avec Zod puis relit le prix chez Binance, sans cache, avant d'exécuter l'ordre. Modifier
la requête à la main ne permet donc pas d'acheter moins cher.
Chaque ordre s'exécute dans une transaction qui verrouille le portefeuille et la position
(SELECT … FOR UPDATE, voir src/lib/data/portfolio.ts). Le test
d'intégration envoie 10 achats simultanés de 2 000 $ avec 10 000 $ : exactement 5 passent.
Sans le verrou, les 10 passent (vérifié en le retirant). Des contraintes CHECK en base
(liquidités ≥ 0, quantité > 0) servent de dernier filet de sécurité.
En JavaScript, 0.1 + 0.2 !== 0.3. Les montants sont donc stockés en numeric(28, 8) et calculés
avec decimal.js (src/lib/trading.ts). Les arrondis se font au détriment du
joueur (coût d'achat arrondi au-dessus, produit de vente en dessous), comme sur une vraie
plateforme. Ces règles sont couvertes par des tests unitaires.
Toute l'application partage une connexion WebSocket
(src/lib/price-store.ts). Elle s'ouvre quand un composant en a besoin,
se ferme quand plus personne ne l'écoute et se reconnecte avec une attente exponentielle. Les
mises à jour sont regroupées toutes les 500 ms et lues via useSyncExternalStore : un composant
ne se re-rend que si le prix de son actif a changé.
Les réponses de l'API Binance sont validées avec Zod avant usage, et mises en cache côté serveur (10 s pour les prix, 30 s pour l'historique). Les prix servis par le serveur s'affichent dès le premier rendu, puis le flux temps réel prend le relais.
Un invité qui se déconnecte est supprimé. Une tâche planifiée Vercel
(src/app/api/cron/cleanup/route.ts) efface chaque nuit les
invités dont toutes les sessions ont expiré.
Prérequis : Node.js 24 ou plus, et Docker.
npm install
cp .env.example .env.local # puis renseigner BETTER_AUTH_SECRET (openssl rand -base64 32)
docker compose up -d # Postgres sur le port 5433
npm run db:migrate
npm run dev # http://localhost:3000
| Commande | Rôle |
|---|---|
npm run dev | Serveur de développement |
npm test | Tests unitaires et d'intégration (base Docker requise) |
npm run lint | ESLint |
npm run typecheck | Vérification TypeScript |
npm run db:generate | Génère une migration après modification du schéma |
npm run db:migrate | Applique les migrations |
npm run db:studio | Explore la base dans Drizzle Studio |
DATABASE_URL est ajoutée automatiquement.BETTER_AUTH_SECRET : générée avec openssl rand -base64 32CRON_SECRET : générée avec openssl rand -hex 16Pour activer la connexion GitHub (optionnel) :
https://<votre-projet>.vercel.app/api/auth/callback/github.BETTER_AUTH_URL (l'URL publique, pour que l'adresse de retour
envoyée à GitHub soit toujours la même), GITHUB_CLIENT_ID et GITHUB_CLIENT_SECRET (en
« Sensitive »).Une OAuth App n'accepte qu'une adresse de retour : la connexion GitHub fonctionne en production, pas sur les prévisualisations des pull requests.
Bon à savoir :
vercel.json place les fonctions à Francfort (fra1), près de la base.src/
├── app/ Pages, Server Actions (actions.ts) et routes API
├── components/ Composants partagés : prix en direct, en-tête, historique…
└── lib/
├── trading.ts Règles de calcul des ordres (tests unitaires)
├── data/ Accès aux données : ordres, portefeuille, classement
├── db/ Schéma Drizzle et connexion Postgres
├── binance.ts API REST Binance (serveur)
├── price-store.ts Flux WebSocket des prix (navigateur)
└── auth.ts Configuration Better Auth
design-system/ Design system (tokens, typographie, règles d'accessibilité)
drizzle/ Migrations SQL générées
scripts/migrate.mts Application des migrations (lancé au build)
Projet éducatif : aucune transaction réelle n'est effectuée et rien ici ne constitue un conseil en investissement. Données de marché fournies par Binance (prix en USDT, assimilés au dollar).