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,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
A two-player, turn-based tactical battler in the spirit of Heroes of Might & Magic 3,
set in a Slavic dark-fantasy world.
Send a friend a link → you both pick a castle → you each spend a gold budget recruiting
an army → the two armies fight on a hex battlefield until one side is wiped.
There is no adventure map, no hero and no spellbook. The battlefield phase is the
whole game.查看完整 README ↗A two-player, turn-based tactical battler in the spirit of Heroes of Might & Magic 3, set in a Slavic dark-fantasy world.
Send a friend a link → you both pick a castle → you each spend a gold budget recruiting an army → the two armies fight on a hex battlefield until one side is wiped.
There is no adventure map, no hero and no spellbook. The battlefield phase is the whole game.
| Side | Castle | Flavour |
|---|---|---|
| Явь | Kitezh | The sunken city's druzhina. Human steel, shield walls, discipline. |
| Явь | Borovina | Leshy's old forest. Wolves, wood-wights, things wearing bark. |
| Явь | Gromoboy | Perun's thunder-host. Fast, fragile, hits like a storm. |
| Навь | Kostyanoy Dvor | Koshchei's bone court. Slow, relentless, hard to finish. |
| Навь | Topyla | Vodyanoy's drowned mire. Rusalki, bolotniks, drag-you-under tricks. |
| Навь | Yagaya Pushcha | Baba Yaga's wildwood. Witches, hexes, the hut on chicken legs. |
Full stat tables live in docs/factions.md.
npm install
npm run dev
| Script | What it does |
|---|---|
npm run dev | Vite dev server |
npm run build | Typecheck and build to dist/ |
npm run typecheck | TypeScript only |
npm run lint | oxlint |
npm run test | Vitest unit tests |
npm run e2e | Playwright end-to-end tests |
Cross-device multiplayer works out of the box, no account needed: it connects the two
browsers directly over WebRTC, using a free public broker only to make the initial
introduction. For a connection that does not depend on either player's network (some
restrictive corporate/campus networks block direct peer-to-peer), copy .env.example to
.env, fill in Supabase credentials, and that real server relay is used instead whenever
it's configured.
src/
hex/ axial coordinates, neighbours, pixel<->hex, A* pathfinding
engine/ rule-agnostic core: seeded RNG, Result<T>, pure action reducer
rules/ HoMM3 combat: initiative queue, retaliation, damage, victory
content/ factions, units, battlefield dimensions, balance numbers
net/ rooms, the sync protocol, and its transports (WebRTC, Supabase, BroadcastChannel)
ui/ screens, battle components, theme tokens
Two invariants hold the whole thing together:
Action handlers are pure and total. Same state plus same action always produces the
same result, with no clocks, no Math.random, and no I/O. Every die roll goes through
the seeded RNG in src/engine/rng.ts, whose cursor is part of serialized state.
Nothing outside src/ui/theme/tokens.css hardcodes a colour. Every colour, spacing
step and animation duration is a custom property, so a change to the visual direction
stays in one file.
The match is host-authoritative with verification. The guest sends action
requests; the host resolves them — including every random draw — and broadcasts
{action, rngDraws, stateHash}. The guest replays the action using the host's draws,
then compares its own hash against the host's.
Pure lockstep determinism would also work, and would be more elegant, but it fails silently: one difference in iteration order and the two players are playing subtly different games with no indication anything is wrong. Resolving randomness once and checksumming after every action means a desync is caught immediately and can be reported honestly.
Known limitation: the host's browser is the authority, so if the host closes their tab, the match ends. A guest who drops can reconnect and the host will re-send state, but a host who drops cannot be recovered — there is no database behind this, by design.
There is also no anti-cheat, and there cannot be one without a real server. Play with people you like.
Pushes to main deploy to Vercel automatically; other branches get preview URLs.
CI (typecheck, lint, test, build) runs on every push and pull request.