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,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Real-time territory snake game — Duel vs AI and Solo modes, PixiJS 2026 renderer + 8-bit classic theme. TypeScript, React, Vitest.
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
▶ Play — https://territory-snake.vercel.app (best on a phone)
A real-time territory game for the mobile browser, with two modes:檢視完整 README ↗▶ Play — https://territory-snake.vercel.app (best on a phone)
A real-time territory game for the mobile browser, with two modes:
In both modes the snake moves on its own; you only steer.
Two looks, switched in the menu (1986 | 2026):
Reduced motion turns effects off in both looks (and makes the 2026 board move cell by cell).
Built as a portfolio project and a game-design experiment: the rules are specified up front, the engine is pure and tested, and the bot is explainable.
https://territory-snake.vercel.app — best on a phone. Add ?perf to the URL to see tick timing, frames per second and board frame time, and copy a performance report from the end screen. If ticks run late on the 2026 board, the game offers to switch to 1986 once.
Auto-deployed from master via Vercel.
npm install
npm run dev # dev server
npm run build # static build in dist/ (relative paths, deployable to any sub-folder)
npm run preview # serve the build locally
Controls: swipe on the board or tap the D-pad on phones; arrow keys or WASD on desktop. Space or P pauses (hiding the tab pauses too). The menu picks the mode (Duel / Solo), the difficulty (Easy / Normal, remembered per mode; for Duel it is the bot) and the speed (Slow 400 ms, Normal 280 ms, Fast 180 ms per tick).
npm test # unit tests, 2000-game invariant stress tests for Duel and Solo, a quick bot smoke match
npm run bench # full bot tournament: win rates, P1/P2 balance, move timing (~1.5 min)
Measured on 2026-09-29 on this repository (npm test, npm run bench, a production build in headless Chromium on an Intel UHD laptop GPU).
Tests: 257 unit and scenario tests in 30 files (npm test).
Stress, Duel: 2000 seeded random-vs-random games; the state invariants are checked after every round — 0 violations.
Stress, Solo: 2000 seeded random-snake games (up to 3000 ticks each); invariants checked after every tick — 0 violations.
Bot benchmark (npm run bench, seed 20260926, sides alternate), Normal bot win rate:
| Normal vs | Games | Wins | Losses | Draws |
|---|---|---|---|---|
| random | 500 | 100.0% | 0.0% | 0.0% |
| safe | 500 | 99.2% | 0.6% | 0.2% |
| easy | 500 | 75.2% | 24.2% | 0.6% |
Normal bot move time: 0.26 ms mean, 0.85 ms p99 over 105,159 moves.
Performance (Fast speed, 180 ms per tick, 375×667, 45 s per run, no CPU throttling): 0 late ticks in Duel and Solo in both looks. 2026 board frame time: 0.81 ms average / 1.6 ms p95 in Solo, 1.03 ms / 1.9 ms in Duel, ~59 FPS; single frames reach ~33 ms.
Bundle (gzip): main JS 74.8 KB; the PixiJS code loaded for the 2026 board, as separate lazy chunks, 119.9 KB (core 81.2 + WebGL 19.7 + render targets 14.9 + 4.1). The 1986 look never downloads it.
src/engine/ — the game rules as pure TypeScript with no UI imports: createInitialState, getLegalMoves, resolveRound → { state, events }, the capture algorithm and runtime invariants.src/engine/solo/ — Solo on top of the same legal moves, trail update and capture: createSoloState, resolveSoloTick → { state, events }, seeded bouncing balls, lives and levels, invariants S1–S6.src/bot/ — computer opponents built only on the public game state: position analysis (distance home, distance to a trail, potential capture), randomBot, safeBot, normalBot (a one-round maximin over a weighted evaluation, weights in NORMAL_CONFIG, choices explained by explainMove) and easyBot on top of it (EASY_CONFIG: slower reactions, mistakes, less caution).src/game/ — the real-time loop without React: a shared tick controller with an injectable clock (countdown, drift-free ticks, pause), the two-press input queue and the wall rule. The Duel match computes bot decisions as generators in small slices between ticks; the Solo match adds short in-game holds (a lost life, a cleared level) before the next countdown.src/render/ — the renderers: the board behind one interface, BoardRenderer (mount / update on each tick / frame(alpha) on each animation frame / resize / destroy). Adapters turn a Duel or Solo state into a neutral RenderSnapshot (land by cell, trails as ordered cell lists, heads, balls). Dom8bitRenderer is the 1986 board; Pixi2026Renderer (PixiJS v8, lazy-loaded chunk, WebGL with a Canvas fallback) draws the 2026 one from pure geometry helpers (body polyline, tail taper, arc-length dashes, interpolation).src/render/pixi2026/ — the 2026 board: land cached in a RenderTexture (only changed cells are redrawn), per-snake render groups, sprite pools for particles, effects played only from engine events.src/ui/ — React + Tailwind screens (menu, how to play, game, pause) that drive the match controller and draw its state and events; no game logic lives here. src/ui26/ holds the 2026 versions of the screens.localStorage ( for Duel, for Solo, for every game) and can be exported as JSON from the menu.The rules are the single source of truth: see GAME_RULES.md for Duel and SOLO_RULES.md for Solo. The 2026 look is specified in VISUAL_2026.md. The original turn-based concept is kept as history in docs/history/PRD-v0.1.md.
computeCapture serves both modes, the bot and the stress tests.explainMove prints the per-term scores, so a surprising move can be traced to a weight. No ML and no LLM; the Easy bot is the same search with slower reactions and deliberate mistakes.state + moves → state + events) with no timers or UI. The real-time loop is a small controller with an injectable clock (countdown, drift-free ticks, pause, input queue), so tick timing is unit-tested with fake clocks and the same engine plays the 2,700-game bot tournament headless in about 36 s.BoardRenderer (mount / update per tick / frame(alpha) per animation frame) has a DOM implementation for 1986 and a PixiJS one for 2026, fed by a neutral snapshot built from engine state. The budget was set first (0 late ticks at Fast, frame ≤ 16 ms); profiling drove the fixes: land cached in a RenderTexture with per-cell redraws, straight moving segments as stretched sprites, alpha instead of visible toggles, per-snake render groups, and a warm-up during the countdown. After the renderer refactor the 1986 screens were checked pixel-for-pixel against the previous build.Development followed specifications written in Markdown before the code: the rules (GAME_RULES.md, SOLO_RULES.md) with numbered test scenarios, the visual spec (VISUAL_2026.md) and the original product brief (docs/history/PRD-v0.1.md). Work went in short sessions, each with a written task, per-step commits and a report with measurements (stress tests, frame and tick timing, bundle size, pixel comparison of the 1986 screens).
The code was written with Claude Code.
2026:
| Menu | How to play | Duel | Capture wave | Trail in danger |
|---|---|---|---|---|
| Solo | Ball hit | Level clear | Game over | Pause |
|---|---|---|---|---|
1986 board, Duel:
| Menu | How to play | Game | End screen |
|---|---|---|---|
1986 board, Solo:
| How to play | Game | Ball hit | Level clear | End screen |
|---|---|---|---|---|
ts_statsts_solots_games