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
A two-player euchre variant where each player controls two hands, playing them alternately from memory.
Translation pending
GamesTypeScript · PythonGitHub @WillPaz16OnlineOwner 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
Four-hand euchre for two players: you play both hands of your partnership. Pixel-art cabin, solo vs a bot or online with a friend. React + TypeScript on Cloudflare Durable Objects.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
The euchre you know and love, for when you only have one other friend.
▶ Play it: doublehand.willpaz16.workers.dev, solo against a bot or online with a friend.
A pixel-art cabin, a crackling fire, and a variant of euchre we invented so two people can play
the four-handed game. Each of you plays both hands of a partnership: one you picked without
looking, and one you only see when it's that hand's turn.
Standard 24-card euchre, first to 10, with two twists that change everything:Read the full README ↗The euchre you know and love, for when you only have one other friend.
▶ Play it: doublehand.willpaz16.workers.dev, solo against a bot or online with a friend.
A pixel-art cabin, a crackling fire, and a variant of euchre we invented so two people can play the four-handed game. Each of you plays both hands of a partnership: one you picked without looking, and one you only see when it's that hand's turn.
Standard 24-card euchre, first to 10, with two twists that change everything:
The established two-handed variants deal one playable hand per player, so this isn't one of them. The full spec is in RULES.md.
flowchart LR
subgraph Browser
UI["React UI<br/>(src/)"]
Engine1["Rules engine<br/>(shared/engine)"]
UI -- solo --> Engine1
end
subgraph Cloudflare["Cloudflare edge"]
Worker["Worker<br/>assets + routing"]
DO["Durable Object<br/>one per room code"]
Engine2["Rules engine<br/>(shared/engine)"]
Worker -- "/ws?code=XXXX" --> DO
DO --> Engine2
end
UI -- "WebSocket (online)" --> Worker
One rules engine, two homes. shared/engine is a pure TypeScript reducer with no DOM and no
network, seeded so every deal is reproducible. Solo play runs it in the browser; online play runs
the same code on the server, so the two modes can't disagree about the rules.
The server is authoritative. Clients send intentions. The room checks each one against the engine's legal moves for that connection's seat, and sends every player a view redacted for their eyes only. A modified client can't see hidden cards or play out of turn, because the move simply isn't in its legal list.
One Durable Object per room. The room code is the object's identity, so Cloudflare guarantees exactly one instance of each game worldwide: no single server to outgrow and no split-brain. Sockets use the Hibernation API, so an idle game costs nothing, and the whole thing runs on Cloudflare's free tier.
Art and audio are generated by code. Every card, character, and piece of the cabin is drawn
by a deterministic Python generator (art/generate_art.py), and every
sound is synthesized from waveform math (art/generate_audio.py). There
are no hand-painted or model-generated asset files, and regenerating is pixel-identical.
Every pull request and every push to dev or main runs these in CI. Nothing deploys unless all
of them pass.
| Check | What it guards |
|---|---|
| 200+ unit & component tests (Vitest) | rules, scoring, room logic, multiplayer protocol, UI behavior, crash and storage fallbacks |
| 10,000-deal fuzz | random legal play under random rule settings never reaches an illegal state |
| Layout audit (Playwright) | 11 screen sizes: whole-pixel art scaling, UI/scenery collisions, edge anchoring, hand-fan spacing |
| Art checks | two generator runs are pixel-identical, card art is unchanged, sprites have no holes |
| Production build | the app and the Worker both type-check and build |
| Multiplayer smoke test | two real WebSocket clients against the Worker under wrangler dev: seating, hidden cards, turn enforcement, reconnect, a full hand |
| Post-deploy smoke test | the same test against the live URL right after each deploy |
| Client | React 19, TypeScript, Vite, vite-plugin-pwa |
| Server | Cloudflare Workers, Durable Objects (SQLite storage), Hibernatable WebSockets |
| Testing | Vitest, Testing Library, Playwright |
| Assets | Python + Pillow (sprites), stdlib wave (audio) |
| CI/CD | GitHub Actions → Wrangler; dev and main deploy to separate staging and production Workers |
Requires Node 22+.
npm install
npm run dev # the game with hot reload, http://localhost:5173
npm run worker # multiplayer server on :8787 (run `npm run build` once first)
Solo play needs only npm run dev. Other useful scripts:
npm test # unit and component tests
npm run fuzz # 10,000 random deals
npm run audit # layout audit across 11 screen sizes
npm run typecheck && npm run typecheck:worker
To regenerate art or audio (Python 3.11+):
pip install -r art/requirements.txt
python3 art/generate_art.py && npm run art:check
python3 art/generate_audio.py
When editing the characters, python3 art/check_avatar_posture.py compares the sprites against
the last commit.
src/ React app: screens, table, hooks, styles
shared/engine/ pure rules engine (deal, bidding, loners, tricks, scoring, redaction)
shared/net/ room logic and wire protocol, shared by client and server
shared/bot/ the solo opponent
worker/ Cloudflare Worker and the per-room Durable Object
tests/ Vitest suite
scripts/ fuzz, layout audit, multiplayer smoke test, bot balance
art/ asset generators, checks, and the art spec (ASSETS.md)
public/ generated sprites and audio
docs/ README screenshots
| File | What's in it |
|---|---|
| RULES.md | The complete rules, and the reference the engine is built from. Starts with a summary for people who already know euchre. |
| art/ASSETS.md | How every sprite is drawn by code, and the rules that keep it all crisp and consistent. |
| DEPLOY.md | Environments, the deploy pipeline, and running it locally. |
Reading the code? shared/engine/ is the best place to start: it's pure
TypeScript with no DOM and no network, so the whole game is legible without a browser.
shared/net/room.ts is the multiplayer rules on top of it, and
worker/room-object.ts is the server that holds one room.
Pushing to dev deploys the staging site, and merging to main deploys production, both only
after every check passes. Environments, setup, and manual deploys are in DEPLOY.md.
MIT © 2026 Will Paz