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 small 3D game about the world's least efficient search problem. You are a
farmhand in a barn full of hay. A needle is buried in one of the piles. Walk
over, dig it out one shovel-load at a time, sift it on the conveyor, and keep going
until the needle turns up — then move to a bigger barn.
Built with three.js (vendored, MIT). No build step, no
network calls, no dependencies to install.查看完整 README ↗A small 3D game about the world's least efficient search problem. You are a farmhand in a barn full of hay. A needle is buried in one of the piles. Walk over, dig it out one shovel-load at a time, sift it on the conveyor, and keep going until the needle turns up — then move to a bigger barn.
Built with three.js (vendored, MIT). No build step, no network calls, no dependencies to install.
▶ Play it: https://needleinahaystack.politecarrot.com
| Desktop | Touch | |
|---|---|---|
| Move | W A S D / arrow keys | left stick |
| Dig / sift | hold Space or E | hold the action button |
| Look around | drag the scene | drag the scene |
| Pause | Esc | ⏸ button |
There is no ad network in the repository. js/ads.js owns when an ad is
allowed and hands the showing to a provider you plug in with
NIAH.ads.use({ interstitial, rewarded }); with nothing plugged in every call
resolves immediately and the game plays exactly as it does without it. A
provider that fails, or one that never comes back, is treated as "no ad" — an
interstitial can never strand a player between barns, and a reward is only ever
paid when the provider says it was watched to the end.
One interstitial, on the way out of the win card — not on the needle. The finale and the win card are the payoff; an ad on top of them lands badly. By the time "On to the next barn" is tapped the player has had both, and the ad covers the walk into the next one. Three conditions all have to pass:
firstBarn: 4 | nothing at all until barn 4 is cleared |
minBarns: 3 | barns cleared since the last one |
minGapMs: 180000 | and three minutes since the last one |
sessionGraceMs: 90000 | and ninety seconds into this session |
firstBarn only ever protects a brand-new player; someone returning at barn 30
has long passed it and would otherwise catch an ad on their first barn back,
which is the worst possible moment. The session grace covers that. A session is
one page load.
A barn takes about a minute, so a time gate on its own would land one every couple of levels — the barn counter is what stops that on a fast run. The counters ride along in the save, so closing the tab is not a way to dodge the gap. The Daily Barn is excluded outright: it is timed and competitive.
Three rewarded doubles, each beside a button that already does the job for free — the crew's night's work on the menu, the needle bounty on the win card, and the crate behind the barn. The three exclusive finds are never doubled and never behind an ad; the whole point of them is that they cannot be had any other way.
Append ?adstub=1 to the URL to install a fake provider and see the placements
work before choosing an SDK. It is only ever installed from that parameter.
If you also set frequency capping in the ad network's dashboard you will be capping in two places and get noticeably fewer ads than either implies. Keep the cadence here, where it can see barns as well as the clock.
Two choices, both off until the player turns them on, in the same shape as the other Polite Carrot titles: Send usage data and Personalised ads.
The usage-data question is asked once, on a Before you start card, before
anything is collected. Both live afterwards in Privacy & Data, reachable
from the foot of the main menu and from the pause card. The choice is saved,
handed to NIAH.ads.setConsent() — which passes it to the network adapter's
consent() whenever it changes, including to an adapter plugged in later — and
published as window.__consentState = { analytics, ads }, which is what the
label's other games read.
This is the game's own surface for the choice. It is not by itself the consent signalling an ad network requires: whichever SDK you use still has to be given the decision through its own privacy API, and in the UK and EU a certified CMP may be required on top. The adapter is where those meet.
Each barn has more piles and bigger piles than the last (×1.5 hay), and pays
×1.85 per hay. Shovels are gated behind barn levels as well as price, so
clearing barns — not grinding one — is what opens the next tier.
That curve outruns its own sinks: by barn 10 a single barn pays about 6.4M coins while everything buyable in the game costs about 9.8M put together, and barn 13 pays 137M. Retiring is the sink. It puts the whole shop back in front of you, and rosettes pay out in the two things a fresh run is actually short of — dig rate and early shovels — rather than in coins alone, which the barn gates would have swallowed.
Open index.html in a browser, or serve the folder:
npx serve . # or: python3 -m http.server
Progress is saved in localStorage under niah.save.v2; Erase save on the
main menu clears it. Older saves are migrated forward on load, so an existing
game keeps its coins, barn and wardrobe.
The service worker only registers over http(s), so opening index.html
straight off disk still works. When you change any file in the shell, bump
CACHE in sw.js so returning players fetch it.
The site is the repository root on main — static files, relative paths, so it
serves from a project subpath. .nojekyll stops Pages running it through Jekyll.
Settings → Pages → Build and deployment → Source: Deploy from a branch, then
pick main and / (root).
CNAME points the site at needleinahaystack.politecarrot.com; GitHub reads
it on every deploy, so it has to stay at the repository root. On a custom
domain the game is served from /, which suits the relative paths and gives
the service worker the whole origin as its scope.
| Path | What it does |
|---|---|
index.html | Canvas plus every UI overlay (menu, HUD, shop, cutscene, modals) |
css/style.css | Barn-themed UI, responsive down to small phones |
js/world.js | Renderer, barn geometry, hay piles, sifter, particles |
js/player.js | Farmhand mesh, walk/dig animation, movement, camera rig |
js/game.js | State, economy, barn flow, digging, input, save/load |
js/ui.js | Screens, HUD, shop and wardrobe rendering |
js/cosmetics.js | Outfits, hats, faces, shovel skins and their procedural textures |
js/wardrobe.js | The My Farmer preview scene and its auto-framing |
js/helpers.js | Hired farmhands: their round trip, steering and animation |
js/animals.js | The yard livestock: how they are built and how they wander |
js/audio.js | WebAudio sound effects |
js/haptics.js | Vibration patterns, and the feature test that hides them on iOS |
js/ads.js | When an ad is allowed, and the provider seam — no network in it |
sw.js | Service worker: precaches the shell so the game runs offline |
manifest.webmanifest | Web app manifest — name, colours, icons, display mode |
assets/ | Polite Carrot logo and wordmark, plus the app icon in SVG and PNG |
CNAME | The custom domain GitHub Pages serves the game from |
vendor/three.min.js | three.js r160 (MIT, see vendor/three.LICENSE) |
The original 2D tap version lives in this repo's git history, before the 3D rework.
navigator.vibrate, so on an iPhone
every call is a silent no-op and the toggle is hidden rather than offering
a setting that does nothing.localStorage.