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,即可验证所有权并自行管理介绍。
一分钟完成验证🐶 A maze-chase game with zero art assets — every character, texture and sound is generated at runtime. three.js + TypeScript, installable as a PWA, with a Hono/Postgres API that validates every score.
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
A maze-chase game where every single pixel is drawn in code.
No 3D models. No texture files. No audio files. Just TypeScript, three.js and a lot of maths.
Guide a beagle around a maze, eat every biscuit to clear the map, and chomp a golden bone
to turn the enemies scared and edible. It installs to your phone as a PWA, plays with
swipe, thumbstick, D-pad or keyboard, and keeps a server-validated leaderboard.查看完整 README ↗Guide a hungry beagle through the maze, eat every biscuit, and chomp the bone to turn the tables.
Works on phones, tablets and desktops · install it to your home screen like an app · no download store needed
Eat every biscuit to clear the map. The bugs (and, later, a walking pizza slice) are chasing you. Grab the golden bone and the tables turn: for a few seconds they are scared, and you can chomp them for big points.
Controls: swipe, a thumbstick or an on-screen D-pad on touch screens (your pick, in Account), and the arrow keys or WASD on a keyboard.
| 🗺️ 36 mazes | An endless Classic mode of 30-map cycles in six stages, each closed by a bonus level. |
| 🏝️ The Journey | 40 hand-tuned levels: a grand tour of every maze, then ten that bend the rules. |
| 🏆 114 challenges | Goals with coin rewards, like "collect 30 bones in one run". Your progress fills in from games you have already played. |
| 🐶 5 beagles, each with a power | A shield every map, an extra life, double coins, bonus fruit… the shop sells dogs, not skins. |
| 🐛 11 enemies | From a flea and a crab to sushi, a pizza slice and a stacked hamburger. |
| 🌍 8 worlds | A garden, a deep forest, a beach, a park, two cities, a pirate island, and a neon arcade throwback. |
| 🔊 A sound for every world | Birdsong, surf, forest wind, distant traffic: generated live, never a recording. |
| 📊 A real leaderboard | Every score is checked by the server against what the game can actually produce. |
This is also a portfolio piece about procedural content. Beyond five subset web fonts, the logo and the app icons, the repository ships no assets at all: no 3D models, no texture images, no audio files. The beagle, the eleven enemies, the eight worlds, the neighbourhood you can see past the maze walls, every surface texture, every sound effect and every ambient soundscape are generated at runtime from TypeScript.
Characters are sculpted, not modelled. They are built from swept solids, revolved
profiles and per-triangle material groups (beagleSculpt.ts),
measured off reference images by an image-to-three.js pipeline and then hand-tuned until
they read at the size a player actually sees them.
Surfaces are painted at runtime. Walls and floors are drawn to a canvas and tile
seamlessly (wallTexture.ts, floorTexture.ts).
The park's gravel walks and the city's road markings follow the real corridors of
whichever maze you are on.
Sound is synthesis. About 1,600 lines of hand-written Web Audio (sound.ts,
ambience.ts). Each world's ambient bed is deliberately pitched outside
the frequency band of the biscuit chomp, so the two can never mask each other.
The game logic has no idea three.js exists. src/game/* is pure TypeScript (grid,
tile-stepping movement, enemy AI, the state machine) with a hard rule that it never imports
three. That is what lets npm run test run the real modules in Node, with a
pathfinding bot that has to clear all 36 boards to 100% before the suite passes.
Draw calls are the budget, not triangles. The whole maze is one InstancedMesh. The
neighbourhood around it (hundreds of houses, hedges, trees and flower beds) is merged by
material into ~14 draw calls and culled to the camera's actual ground footprint, which cuts
a phone's surround geometry by about 65%.
It ships with its own 3D editor. npm run editor opens a dev-only workbench over the
real meshes: part tree, transform gizmo, multi-select, animation timeline, undo, glTF
import/export, and it writes changes back into the source files as three.js code. It
never ships to players.
Frontend: three.js r169 (WebGL) · TypeScript (strict) · Vite · vite-plugin-pwa
Backend: Hono · Node 22 · Postgres (pg, no ORM) · argon2id · zod
Tests: 50+ suites, pure logic ones that run in Node plus Playwright ones that drive the real app
Hosting: Cloudflare Pages (frontend) · Docker (API)
No physics engine, no post-processing, no asset loader. Movement is tile-stepping on a grid; 1 world unit = 1 maze tile.
npm install
npm run dev # the game at localhost:5173
npm run test # the headless logic suites (no browser, no database)
npm run build # typecheck + production build
The game requires sign-in, so npm run dev alone will stop at the login screen. For the
full stack:
cp .env.example .env # VITE_API_URL=http://localhost:3001
docker compose up db api # Postgres + the API (migrations run on start)
npm run dev # in a second terminal
Everything in Docker instead: docker compose --profile full up.
See server/README.md for the API on its own.
| Page | What it is |
|---|---|
/editor/ | The mesh, theme, prop and balance workbench (npm run editor). |
None of them are build inputs, so none of them ship.
npm run test # the pure suites: maze validation, the sim, and the rest
npm run validate # maze connectivity and reachability
npm run sim # a pathfinding bot must clear all 36 boards
npm run test:editor # the editor suites (Playwright)
npm run test:menu-ui # one of the suites that drives the real app
Anything touching src/game/{grid,movement,ghostAI}.ts or the maze data has to pass
npm run test before it counts as done. Changing config.ts, mazes.json, journey.ts
or challenges.ts also means npm run sync inside server/: the score validator's
constants are generated from the real game modules, and drift means honest runs start
getting rejected.
src/game/ pure logic, never imports three. Grid, movement, AI, state, config,
36 mazes, cosmetics, themes, the Journey ladder, 114 challenges
src/render/ three.js: scene, board, characters, props, surround, the art direction
src/ui/ DOM chrome: HUD, shop, leaderboard, challenges, sound + ambience
src/input/ keyboard · swipe · D-pad · thumbstick
src/editor/ the dev-only workbench (nothing in the game imports from it)
server/ the API: Hono + Postgres + argon2id, own Dockerfile and migrations
admin/ the metrics portal (its own build, its own Pages project)
scripts/ the test suites plus ~100 measuring instruments and review sheets
docs/ architecture, game design, the brand kit and the README media
docs/ARCHITECTURE.md: the layer rules, the coordinate system, the editor, the render pipelinedocs/GAME_DESIGN.md: entities, scoring, AI, progression, the economydocs/brand/BRAND_GUIDELINES.md: the logo, its lockups, colours and how (not) to use themserver/README.md: the API, its migrations, its observabilityThis whole game was built in collaboration with Claude Code.
The code is MIT. Use it, learn from it, build on it.
Two things are not covered by it:
docs/brand/, public/brand/, the app icons) are the
game's identity. Please don't use them for your own project..img2threejs/ is gitignored). No pixel
of any of them is used as colour or texture. Every mesh here is original geometry.