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,即可驗證所有權並自行管理介紹。
一分鐘完成驗證The world's largest online jigsaw puzzle. One million pieces on a single shared board.
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
A community-built online jigsaw puzzle: 1,000,000 pieces on a single shared canvas, all shuffled from the start, solved together in real time. A long-form, non-commercial, open-source event with no time limit.
v1.4.2 is out: production serves the 1,000,000-piece earth-mosaic board ahead of the public event. Work is tracked in ROADMAP.md.檢視完整 README ↗A community-built online jigsaw puzzle: 1,000,000 pieces on a single shared canvas, all shuffled from the start, solved together in real time. A long-form, non-commercial, open-source event with no time limit.
Play at app.millionpiecepuzzle.com
v1.4.2 is out: production serves the 1,000,000-piece earth-mosaic board ahead of the public event. Work is tracked in ROADMAP.md.
Every player, guest or signed in, connects over a single WebSocket path. Past a global connection cap an admission queue holds new arrivals in a first-in-first-out wait, so the server sheds load into an orderly queue instead of accepting connections until it falls over.
A restart is announced rather than suffered: the server tells every connected player it is going down before it drops the sockets, and the app switches to a maintenance screen (served by Cloudflare Pages, so it survives the backend being gone) that reloads itself back into the board once the server answers again.
Piece events are tiered by cost:
| Event | Scope |
|---|---|
| Drag | Broadcast to viewport-neighbor clients, never persisted |
| Drop | Redis write, viewport broadcast |
| Snap | Redis write, Mongo log, global broadcast |
Pieces belong to clusters. Every piece starts as its own cluster; when two pieces of compatible neighboring positions meet at the correct relative offset, their clusters merge and their relative positions freeze. Grabbing any piece grabs its whole cluster, and the wire format carries one absolute position plus a group id rather than N piece positions.
The puzzle frame is the anchor. A cluster locks permanently when a human drop brings its origin within snap tolerance of the frame origin, or when it merges with an already locked cluster. Locked pieces never move again: no undo, no griefing.
Piece geometry is neither stored nor sent. Bezier silhouettes and canonical offsets derive from a server-only generation seed and are baked into each pre-masked tile by the slicer. The client renders from those tiles plus per-piece offsets, so it never holds anything a solver could use.
The source image carries no AI-generated content, a community commitment.
@auth/express, Google), database sessions, internal per-IP login rate limitingpackages/
shared/ # Shared TypeScript types (WS messages, piece and user schemas)
frontend/ # Vue + PixiJS + OpenSeadragon
server/ # Node + WebSocket + Redis/Mongo handlers
load-test/ # WS load/soak harness (bots + admission gate)
git clone https://github.com/MillionPiecePuzzle/million-piece-puzzle.git
cd million-piece-puzzle
npm install
cp .env.example .env
docker compose up --build -d
Frontend on http://localhost:5173, WebSocket server on ws://localhost:8080/, anonymous landing data on http://localhost:8080/landing, http://localhost:8080/live and http://localhost:8080/interested.
.env is gitignored and never committed. Fill it in before bringing the stack up:
AUTH_SECRET, a 32+ character random string, e.g. openssl rand -hex 32. Without it the /auth routes fail, so the SPA cannot read its session back and mints a fresh guest on every visit.AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET, from a Google OAuth client whose authorized redirect URI is http://localhost:8080/auth/callback/google. Without them the server still runs and guest play works end to end; only Google sign-in and guest claiming are unavailable.The non-secret auth config (AUTH_URL, AUTH_COOKIE_DOMAIN, MPP_APP_ORIGIN) has local defaults.
| Command | Purpose |
|---|---|
npm run build | Build shared, then server, then frontend |
npm run typecheck | Typecheck every workspace |
npm test | Run the Vitest suite |
npm run lint | ESLint over the monorepo |
npm run format | Prettier write |
npm run dev:frontend | Vite dev server, outside Docker |
npm run dev:server | Server in watch mode, outside Docker |
The image pipeline carries its own scripts (slice, mosaic, upload, validate:generation); see package.json.
The wire protocol (v10), schema, and gameplay are frozen for the public event. Code contributions are welcome, but please open an issue first to discuss the change before sending a pull request.
CLAUDE.md holds the working conventions, ROADMAP.md the tasks and their exit criteria, and DECISIONS.md the non-obvious trade-offs along with what would make each worth revisiting.
Bug reports and feedback go to GitHub Issues or the Discord.
MIT. See LICENSE.