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.