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
Six flavors of chess played browser-to-browser over WebRTC, with voice chat. No accounts, no server in the middle of your game.
GamesTypeScript · CSSGitHub @maxlbchungOnlineOwner 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
chess with voice chat
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗Eight flavors of chess, played peer-to-peer with optional voice chat. Moves and audio travel directly between browsers over WebRTC. Identity is a local Ed25519 keypair, ratings are computed from cryptographically-signed game records stored in your browser, and the central infrastructure is kept minimal: a small Cloudflare Worker that pairs peers in a queue, a TURN relay for cross-NAT voice, and the public PeerJS broker for WebRTC signaling. None of those services see your moves.
VCC ships with eight variants. Each one is playable solo in free-play (with full history scrubbing and branching) or online via the matchmaker. Every mode has the same three time controls: 5 min, 10 min, and +1 min / move.
| Mode | What's different |
|---|---|
| Normal | Standard chess. chess.js for rules. |
| Merge | Capture your own R/B/N/Q to fuse — combined pieces inherit both movement patterns (chancellor = R+N, archbishop = B+N, amazon = R+B+N). Kings and pawns can't merge. |
| Guerilla | A back-rank rethink: Queen moves 1 square like a king · Bishop slides 1–2 squares diagonally · Knight jumps over any adjacent piece checkers-style (captures both the hopped piece and the landed-on piece) · Rook moves 1 square orthogonally and can push a friendly chain. Pawn/King are standard. No castling. |
| Cash Money | Start with 8 pawns + a king — no other pieces. Gain 1 gold every turn; pushing a pawn to the opposing back rank cashes it in for +10 gold. Buy upgrades at the shop (Knight 3g, Bishop 3g, Rook 5g, Queen 9g) — each buy replaces one of your pawns and uses your turn. Multi-queen is legal. No castling. |
| Hero | Standard chess plus your king has an ability, picked at game start: Frost (freeze a piece) · Warlord (destroy an enemy piece adjacent to your king) · Necromancer (spawn a pawn next to your king) · Flight (fly any of your pieces to any empty square) · Harem (bishops + rooks start as queens) · Mutation (fuse B/R/Q with knight movement) · ICBM (delayed-strike missile) · Goofball (force up to two opponent moves) · Twin-Jutsu (your pieces masquerade as kings) · Kamakaze (arm your own pieces as chain-reacting explosives). Full rules + cooldowns in hero.md. No castling. |
| Setup | Bring your own opening: both players get 60 simultaneous seconds to arrange their standard army anywhere on their own half (pawns off the back rank), hidden from the opponent. The halves merge and a normal game begins — no castling, and an exposed king may simply be captured, ending the game at once. In free play / sandbox you place both sides yourself, untimed. |
| Secret Queen | Before move one, each side secretly crowns one of its 8 pawns. The fake moves like a queen from ply 1 but renders as an ordinary pawn to the opponent for as long as it also moves like one — single steps, the home-rank double-step, diagonal captures, even en passant (in both directions: it can capture ep and be ep-captured). The moment it makes a move a pawn couldn't (or gives a non-pawn check, or reaches the last rank, or is captured) the disguise drops for good. In free play / sandbox you pick both fakes and see them both, marked with the owner-shadow pawn. |
| Chesssweeper | Standard chess over a hidden minefield: 4 landmines are buried at random in the middle two ranks (4 and 5). Landing a piece on a square reveals how many live mines touch it (the 8 surrounding squares) — land on a mine and it detonates, destroying the piece that stepped on it. Each mine fires once and leaves a crater. Blow up your own king — or let the blast leave it hanging — and you lose on the spot. A panel beside the board shows one bomb per buried mine (spent ones fade to a shadow) and toggles flag mode, where right-click marks squares you suspect instead of drawing annotation arrows — your own private note, never sent to the opponent. Both players derive the same minefield from the shared game ID, so the layout never crosses the wire. |
| Piece | How |
|---|---|
| Identity | Ed25519 keypair generated in your browser, stored in IndexedDB. Exportable as a string. No accounts, no email, no password. |
| Move transport | Direct WebRTC data channel between the two players. No server sees the moves. |
| Voice chat | WebRTC audio between the two peers (separate from the move channel, same PeerJS session). No server sees the audio — TURN, when used, only relays encrypted DTLS-SRTP. |
| Game records | Every move is signed by the mover and verified by the opponent on receipt. At game end each side independently saves the record signed with its own key only — there's no mutual sign-off exchange yet. |
| Rating | Computed locally from your signed game history (standard ELO, K=32 → 24 after 30 games). |
| Matchmaking | A Cloudflare Worker backed by a D1 (SQLite) database holds the per-time-control wait queue and emits a pairing when two peers arrive. It sees peer IDs, handles, public keys, and ratings — never moves, audio, or game results. |
| WebRTC signaling | Uses the public PeerJS broker (0.peerjs.com) to bootstrap the connection between peers. The broker sees peer IDs and SDP offers, not move payloads — once the data channel is up, the broker is out of the loop. Swappable for a self-hosted PeerJS server. |
Trust model in plain words: if you trust your opponent's signed move records, you can verify everything they claim happened. The matchmaker can't lie about game results because it never sees them. The TURN server (when needed for NAT traversal) sees encrypted DTLS-SRTP packets, not plaintext audio.
npm install
npm run dev # local dev with in-memory matchmaker
Open in two browser tabs (or two devices on the same network), pick the same mode + time control on both, hit Play. Allow mic permission when the voice button is clicked. Or click Free play and play either color yourself.
The front end is a static Vite build hosted on Cloudflare Pages; the matchmaker is a separate Cloudflare Worker with a D1 (SQLite) database. D1 was chosen over a Durable Object so the whole stack fits on the Workers free plan.
npm run deploy # builds and pushes the front end to Pages (project: chess-vc)
npm run deploy:worker # deploys the matchmaker Worker (worker/wrangler.toml)
The Worker needs a D1 database. Run these once before the first deploy:worker:
npm run d1:create # creates the chess-matchmaker D1 db; copy the printed database_id
# into worker/wrangler.toml under [[d1_databases]]
npm run d1:schema # applies worker/schema.sql (waiting / matched / queue_log tables)
npm run deploy:worker # deploy
Production uses Cloudflare Realtime TURN. The matchmaker Worker mints short-lived (24h) ICE credentials via the CF TURN API; the browser fetches them at session start. No long-lived TURN secret ships in the client bundle.
# 1. Create a TURN token in the Cloudflare dashboard:
# Cloudflare Realtime → TURN → Create TURN Token
# Copy the Token ID and the API token.
# 2. Bind them as Worker secrets:
npx wrangler secret put TURN_KEY_ID --config worker/wrangler.toml
npx wrangler secret put TURN_KEY_API_TOKEN --config worker/wrangler.toml
# 3. Redeploy the worker:
npm run deploy:worker
If you'd rather not use Cloudflare TURN, ship static credentials via env:
VITE_TURN_URL="turn:your-turn.example.com:3478"
VITE_TURN_USER="user"
VITE_TURN_PASS="pass"
Used only when the Worker's TURN endpoint isn't reachable.
# docker-compose.yml example
services:
turn:
image: coturn/coturn
network_mode: host
command: >
-n --log-file=stdout
--realm=your-domain.example.com
--user=youruser:yourpass
--no-tls --no-dtls
src/
lib/
identity.ts # keypair, sign, verify
timeControls.ts # variant × time-control matrix
elo.ts # ELO math
peer.ts # PeerJS / WebRTC session
voice.ts # getUserMedia helpers
matchmaking.ts # client for the Worker queue
iceConfig.ts # fetches ephemeral TURN credentials
gameRecord.ts # canonical signing format
storage.ts # IndexedDB for rating + history
mergeChess.ts # Merge variant engine
chess2.ts # Two variant engine
cashChess.ts # Cash Money variant engine + economy
heroChess.ts # Hero variant engine + abilities
sweeperChess.ts # Chesssweeper engine — minefield + reveal on top of chess.js
components/
MergeBoard.tsx # custom board — drag/drop, highlights, ability anims
CashShop.tsx # shop UI for Cash Money
HeroAbilities.tsx # ability buttons + cooldown display
Clock.tsx, TimeModeSelector.tsx, VoiceControls.tsx, Layout.tsx, ...
pages/
Home.tsx # lobby + free play (all variants)
GameRoute.tsx # dispatches to the right Game* page per variant
Game.tsx, MergeGame.tsx, TwoGame.tsx, CashGame.tsx, HeroGame.tsx, SweeperGame.tsx
Join.tsx, Profile.tsx, Settings.tsx
store/ # zustand identity store + lobby handoff
worker/
src/index.ts # matchmaker Worker (D1-backed) + TURN credential minter
schema.sql # D1 schema — waiting / matched / queue_log tables
wrangler.toml # Worker config (D1 binding)
vite.config.ts # dev-mode in-memory matchmaker plugin
The board component (MergeBoard) is custom-built — react-chessboard was dropped so all eight variants could share one render path that supports drag-drop, last-move highlights, frozen-piece overlays (Hero/Frost), and ability animations.
TBD — see the discussion in LICENSE once it's added. The intent is non-commercial: source-available so anyone can fork, learn, and self-host, but the custom modes (Merge, Two, Cash Money, Hero, Chesssweeper) shouldn't be lifted and monetized. Game rules aren't copyrightable, but the implementation and assets are.