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 mobile-first archaeological adventure, played entirely in first person. You
walk real ground, sweep a metal detector, dig carefully, and find out what has
been down there — or notice it lying in plain sight without digging at all.
Most of what comes up is rubbish. Occasionally it is the first piece of
something much bigger — a shard that turns out to be one of three, a symbol
that keeps recurring on finds made in different places, a clue that opens up
ground you had no reason to go looking at before.
Play it: https://scottyfncodes.github.io/UNEARTH/ — best on a phone, with
sound on.查看完整 README ↗An 8-bit archaeological mystery starring CK, the Curious Kitten.
Dad pops out one morning — "twenty minutes, back before you know it!" — and CK, batting a book off the shelf, finds a note: "Back soon — followed a lead out past the old ruins." So CK follows the trail. Out through the Meadow, into the Forgotten Temple, down the Old Well into the Sunken Crypt, and through a crack no person could ever fit through, to the Hollow at the bottom of it all.
It is a real adventure. It is also, on a second read of every clue, a very funny one: the note was twenty years old, and Dad just went to the store.
Play it: https://scottyfncodes.github.io/UNEARTH/ — best on a phone, with sound on.
This repository is the cat game and nothing else. An early first-person metal-detecting prototype once shared the name; it now lives in its own repository (DETECTOR) and none of its code, saves or assets remain here.
NOTICE → INVESTIGATE → INTERPRET → LOCATE → DIG → DISCOVER
| Where | What happens | |
|---|---|---|
| Prologue | Home — Twenty Minutes | Dad leaves. A vase falls (a shiny rolls out). A book falls (the note falls out). |
| The Meadow | Old Shellby the tortoise, who remembers everything slightly wrong. A magpie who buried her best bottlecap and forgot which side of the stump. Molehills (always moles). Three roads. | |
| Dad's Old Dig Site (optional) | Dad's abandoned camp: a neat grid of trenches, every one empty; a dig log pointing at the one find he never came back for; junk everywhere; Mortimer the Mole, who explains the collar with contempt; and a tarp that isn't holding anything up — down into The Old Trench. | |
| Chapter I | The Forgotten Temple (3 rooms) | Follow the guardian's stare to half a bronze key; squeeze behind it for the other half. A strip of slightly-wrong bricks across a corridor, a frieze of a small figure leaping them, and a loose pebble to find out for sure. Grit from a loose ceiling. Push a block into a pit for a secret lever. Lift the Sunstone — and run from the boulder. |
| The Old Well | The way down — pitch black until CK carries the Sunstone. | |
| Chapter II | The Sunken Crypt (5 rooms + the Last Passage) | Dark rooms lit only by CK's glow. Pip the bat teaches CK to mew into the dark and listen. Ceilings that trickle before they drop. The Crumbling Span: a bridge that holds just long enough, with gaps to hop. Pip the bat. A weighted-plate door and a floor of spikes with a heartbeat. Three pieces of the Moon Seal, the last one buried among the keepers' decoy moons. Dad's hat, thick with dust. The Hush (optional): so black the Sunstone barely reaches past CK's whiskers, and a causeway of loose stones that forks over a pit. Dad turned back here. |
| Chapter III | The Hollow | Where Dad had to stop — and where CK doesn't. |
Along the way: 17 shinies to hoard, 5 pages of Dad's field notes, 9 secret nooks, nearly twenty things CK simply notices, and a Curiosity rating on the ending screen, from Mildly Interested to Keeper of the Hollow.
npm install
npm run dev # http://localhost:5173 — open it on a phone on your network
npm run build # typecheck + production build
npm run preview # serve the build on :4173
npm test # unit tests (engine, content)
npm run e2e # end-to-end smoke test at a phone viewport
Everything is rendered on a <canvas> at runtime — no image or audio assets,
no engine dependency. The whole game is React + a hand-rolled 2D tile
renderer; gzipped the bundle is about 120 kB.
Rooms are zoomed to fill a phone's play area top to bottom (between nine and eleven tiles across), the camera leads a little in the direction CK is facing, and footsteps sound like the ground they land on.
src/
game/ pure, framework-free engine logic — unit-testable without a browser
types.ts GameMap, Entity, GameState, Action, GameEvent
mapBuilder.ts turns ASCII terrain rows + an optional ASCII props layer into a GameMap
world.ts read-only queries: what's at a tile, is it blocked, is a door open
movement.ts stepping, turning on the spot and hopping, sharing one arrival rule
(items, nooks, curios, trigger strips, crumbling stone, exits)
dig.ts dig the soft tile ahead: a find, junk, dirt, or somebody's old hole
collar.ts the directional collar: proximity, aim, walls, lock-on, junk vs. treasure
affordance.ts what each button would do right now — Paw's verb, whether Hop goes
anywhere, whether Dig is "hot" — without doing it
hazards.ts time: delayed strikes, crumbling floors, spike rhythms, rolling boulders
interact.ts the one contextual action: talk, unlock, pull, read, inspect
artifacts.ts fragment → artifact assembly recipes
inventory.ts small state helpers: add item, add clue, set flag
engine.ts reduce(state, action) -> { state, events } — the single dispatch point
save.ts minimal localStorage save/load
content/ pure data — maps, items, clues, recipes
maps.ts all eleven screens, as ASCII rows + entities
items.ts fragments, artifacts, relics, treats and the 12 shinies
clues.ts Dad's field-note pages and everything CK noticed
recipes.ts the bronze key and the Moon Seal
progress.ts shinies/pages/secrets/relics → a curiosity %
worldMap.ts the journal map's layout, room links and per-room found/total counts
initialState.ts fresh save + engine context wiring
render/ canvas 2D presentation — no game logic
pixel.ts a tiny pixel-art toolkit: 16×16 sprites baked once
ck.ts CK's frames — walking, sitting, washing, tail flicks, napping —
plus `idleMood()`, and Dad, the tortoise, the bat, the magpie
sprites.ts every item and prop
tiles.ts per-region terrain with auto-tiled walls, frayed earth, trigger
bricks, floor scatter and flat dressing, baked per room
dressing.ts ~45 pieces of set dressing: pottery, rubble, roots, old tools…
fx.ts particles, shake, flashes, darts, rocks, ambient life, the room-entry
iris, area banners, squash-and-stretch, hit-stop and trot dust
surround.ts the region carrying on past a room's edge — canopy, bedrock — so a
tall phone never shows black bars around the play area
atmosphere.ts light for lit rooms (cloud shadows, temple shafts, window light)
and a region-tinted vignette
echo.ts the mew's answer: which tiles ring back, and the ring drawn over the dark
draw.ts camera, depth sorting, darkness and the Sunstone's light, and the
marker over whatever Paw would touch
app/controls.ts turn-then-walk, the timed dig and the hop — shared by touch and keyboard
app/ React shell: canvas, HUD, controls, dialogue, find/note
cards, chapter titles, journal, title and ending screens;
TitleScene.tsx is CK's front room and the trail on the title;
PixelText.tsx draws words in render/pixelFont.ts's 5×7 font
engine/audio.ts the mixer: synthesised SFX, the collar's pings, each region's room
reverb, the layered score and the volume settings
engine/score.ts pure: each region's eight-bar piece, split into the layers the
mixer brings in and out, and how much each room rings
engine/voices.ts pure: a voice for everyone CK meets, letter to syllable
core/
game.ts the live Store<GameState> + dispatch()
store.ts tiny framework-agnostic observable
debug.ts opt-in read-only introspection (?debug=1)
Two rules hold the shape:
src/game/* never touches the DOM or React. Every mechanic — movement,
digging, the collar, puzzles, traps, assembly — is a pure function over
plain data, which is why it's exhaustively unit-tested without a browser.world.ts.tick with the game clock,
which only runs while nothing modal is on screen. A tick with nothing in
flight returns the very same state, so idle rooms cost nothing.A new room is a buildMap() call in content/maps.ts: an ASCII grid for
terrain, an optional ASCII props grid for set dressing (legend in
game/mapBuilder.ts), buried finds and junk, plus a list of entities
(npc/item/door/switch/block/trap/roller/curio/clueNote/decoration)
positioned by tile coordinate. mapBuilder.ts throws immediately
on a bad legend character or a mismatched row length. A new fragment set is
entries in content/items.ts plus a recipe in content/recipes.ts; assembly
happens automatically the instant the inventory satisfies it. A new clue is an
entry in content/clues.ts, referenced by a clueNote or decoration
entity's clueId. tests/unit/content/maps.test.ts checks that every
exit points somewhere real, every map is reachable from home, every entity is
in bounds, every referenced item/clue id actually exists, every buried find
sits on soft ground with decoys and plenty of empty earth around it, every
trigger brick belongs to a trap, and every boulder rolls a connected path —
so a typo in content fails a test, not a player's game.
Flags, inventory, clues, per-room state, position and hearts are saved to
localStorage under unearth.save.v2 after every action that produces an
event (an older v1 key from before CK's journey is ignored, and retired
fields in older v2 saves are dropped on load). Play time
is tracked separately so the ending can compare it with Dad's twenty
minutes. A corrupt or missing save falls back to a fresh game; if storage is
unavailable the game just runs without persistence.
Load any build with ?debug=1 to get window.__unearth, exposing live game
state and a dispatch() for driving actions directly — used by the
end-to-end tests.
npm test — the engine (movement, turning, hopping, cat-gaps, digging
and junk, the directional collar, delayed dart strips, pebbles, falling
stones, crumbling floors, spike rhythms, the boulder, curios,
assembly, dialogue, doors, levers, blocks and pits, traps, knock-overs,
secrets, treats, item-gated exits, weighted-plate doors and block resets,
save/load), content validation (every exit, entity, item, clue and door
resolves; every map is reachable), and a full playthrough: a
pathfinder drives genuine move actions through the real maps from the
prologue to the credits, collecting all 17 shinies and all 5 pages without
ever being hit: it hops the dart strips, steps on and straight off one
to reach a nook, ducks into an alcove while the boulder passes, trots
across the Crumbling Span, and waits for the spikes to drop. Break a wall,
an exit or a trap's timing and it fails.npm run e2e — at a phone viewport with the real on-screen buttons: the
title screen, d-pad (including turn-before-walk), Dig and Hop, the journal, the whole prologue (Dad's goodbye, the
vase's find card, the old note, out the door into the Meadow), and the
ending from a finished save.