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
Stances, the weapon triangle, and a thirty-battle campaign. Seven paths, seven endings, twenty-one painted characters — the full campaign, free, in your browser. Published by Pencat Games.
GamesTypeScript · JavaScriptGitHub @seykafuOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
After a failed coup d'état—the player character, Amar, must recruit a new squad of allies and feign amnesia to hide their skill from the monitoring King's agent, all while secretly preparing to conquer the true colonial ruler, the dark lord King Archbold, and become the land's first non-monarch leader.
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
A tactical RPG vertical slice — nineteen battles per run (eighteen shared + one of seven path-opener finales) from a 30-battle story about Amar, the man who tried to take a country and now has to learn to deserve it.
Built with Phaser 3 + TypeScript + Vite. All sprites, portraits, and backdrops are generated procedurally at runtime via offscreen Canvas. All sound effects are synthesized via WebAudio. The only external assets are the music tracks in public/audio/ and the named-character portraits in public/assets/portraits/.Read the full README ↗A tactical RPG vertical slice — nineteen battles per run (eighteen shared + one of seven path-opener finales) from a 30-battle story about Amar, the man who tried to take a country and now has to learn to deserve it.
Built with Phaser 3 + TypeScript + Vite. All sprites, portraits, and backdrops are generated procedurally at runtime via offscreen Canvas. All sound effects are synthesized via WebAudio. The only external assets are the music tracks in public/audio/ and the named-character portraits in public/assets/portraits/.
Eighteen playable battles closing out the first half of the campaign and opening the second — squad assembly, the bandit / monastery / Orinhal arc, the cliff exit to Madame Dawn's ship, the empire's welcome at the Grude harbor, the rebellion strike where Rose pays the cost, the night Amar learns whose child he really is, the mole inside Dawn's own house, the King's Knife on the river bridge, the break with Dawn when her lie comes whole, and the empire's last boarding party on the open sea before Amar chooses his path from the Seven Names:
| # | Title | Music |
|---|---|---|
| 1 | The Palace Coup | Entering the Stronghold |
| 2 | Bandits in the Farmland | Danger |
| 3 | Madame Dawn's Bandits | Spine of the World — Battle |
| 4 | Ambush in the Swamp | Spine of the World — Battle 2 |
| 5 | The Mountain Bandits — Ndari (first boss) | Stronghold of Memories |
| 6 | The Caravan | Spine of the World — Battle |
| 7 | The Ghost from Para (Selene the Swordmaster) | Spine of the World — Battle 2 |
| 8 | The Town of Orinhal (the choice in the square) | Danger |
| 9 | The Price of Doubt (Fergus's trap, Maya's reveal) | Danger |
| 10 | Leaving Thuling (Kian's blockade) | Stronghold of Memories |
| 11 | The Cliffs (Kian's truth, Lucian's farewell) | Stronghold of Memories |
| 12 | The Ravage (Grude harbor, the colony reveal lands) | Grude Battle 1 |
| 13 | Madame Dawn's Rebellion (Rose dies for the captain) | Spine of the World — Battle 2 |
| 14 | The Origin (Amar's parentage; the empire comes for the heir) | Spine of the World — Battle 2 |
| 15 | A Coup Within a Coup (Coyne the mole; Ndara falls) | Spine of the World — Battle 2 |
| 16 | Dawn's Proposal (the throne offer; the King's Knife) | Spine of the World — Battle 2 |
| 17 | Dawn's Lie (Khione's truth; the break with Dawn) | Spine of the World — Battle 2 |
| 18 | Seven Names, One Choice (the empire's last boarding party; the path fork) | GrudeBattle1 |
After B18's victory the Seven Paths choice (ChoiceScene) forks the campaign — the player commits Amar to one of seven philosophies, which is persisted to the save and gates the path-specific chapters to come.
Battle 19 is the Seven Paths payoff: all seven path openers are playable — Vengeance (kill Lord Castor on the canyon road), Restoration (hold the road at Khonu's village), Revolution (burn the border granary), Duty (hold the frontier bridge for six rounds), Exile (Amar alone against a kill team in the snow), Mercy (subdue the holdout captain of a fort that wants to surrender), and Forgetting (a fisherman with a soldier's hands, alone on the beach). Each run plays exactly one, chosen at B18, each with its own epilogue and credits. Battles 20–30 remain data stubs for the full campaign.
Requires Node 18+.
npm install
npm run dev # http://localhost:5173
npm run build # tsc -b && vite build → dist/
npm run preview # preview the built bundle on :4173
knight, dactyl_rider) get +2 movement above their base stat.Names from the full script not yet in the slice —
Dawn(Boss Fighter),Kian(Destruct) — will get their abilities wired when their data entries are added.
The full 21-battle script and design docs live separately at C:\Users\kasey\Documents\Ravage Scripts\ (Word .docx). The slice was built directly from those documents — any divergence between the game and the script should be treated as a bug in the slice, not the script.
Key documents:
Ravage_script_v2_Official.md — the full battle-by-battle scriptRavage_combat_system.md — combat rules (this implementation)Ravage_strategic_layer.md — between-battle hub design (Phase 1/2/3) — not yet implementedRavage_dawn_arc.md, Ravage_leo_arc.md, Ravage_maya_arc.md — character arc setupsEverything the strategic-layer doc describes:
Ravage_maya_arc.mdThe vertical slice is the foundation those systems will sit on top of. Combat is in. Initiative is in. Save/unlock is in. Story scenes plug into a generic StoryScene that can carry the bond conversations later. The world map (OverworldScene) already shows all 21 nodes — the unplayable ones are visibly locked.
src/
scenes/
BootScene.ts asset preload
TitleScene.ts New Game / Continue
StoryScene.ts dialog beats with portrait, typewriter reveal
OverworldScene.ts 21-node world map
BattlePrepScene.ts pre-battle briefing + deploy
BattleScene.ts the actual combat — initiative, AP, stances, AI
EndScene.ts victory / defeat resolution
CreditsScene.ts slice-end credits roll
combat/ pure logic — Grid, Damage, Stances, AI, Initiative
data/ battles, maps, units (the 21 BattleNodes)
art/ procedural sprite/portrait/backdrop/tile generators
audio/ Music manager (crossfade) + WebAudio sfx
story/ dialog beats + arc graph
ui/ Button, Panel
util/ constants, save (local slots), Rng, math
Ravage is a fully local game. There is no account, no sign-in, and no
server: everything the player earns lives in their own browser's
localStorage, on their own machine.
ravage:save:v1:slot{1,2,3}.localStorage["ravage:save:v1"] is the active mirror of the currently
selected slot — the gameplay code reads and writes this one.ravage:current_slot:v1 records which slot is active.Because saves are browser storage, clearing site data for the origin (or playing in a different browser / private window) starts a player fresh. The slot picker says as much on screen.