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를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기a fun mobile game about guessing degen coin data
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A lobby party game for phones. Spin a wheel, land on a number, and that number is
a coin's market-cap rank. Everyone guesses what it's worth at once. Closest wins,
worst pays.
Open two browser windows (one private, so they get separate identities) and host
a game in one, join in the other.
No database is needed to develop: without Upstash credentials the app falls back
to an in-memory store and says so at startup. State dies with the dev server.README 전문 보기 ↗A lobby party game for phones. Spin a wheel, land on a number, and that number is a coin's market-cap rank. Everyone guesses what it's worth at once. Closest wins, worst pays.
npm install
echo "COINGECKO_API_KEY=your-demo-key" > .env.local
npm run dev
Open two browser windows (one private, so they get separate identities) and host a game in one, join in the other.
No database is needed to develop: without Upstash credentials the app falls back to an in-memory store and says so at startup. State dies with the dev server.
The first room you create builds the coin universe, which crawls 27 pages of the CoinGecko API and takes about 45 seconds. Every room after that is instant until the snapshot ages out.
Coins spins a market-cap rank and guesses price, market cap, ATH, FDV and 24h volume. NFTs spins an all-time-volume rank over Ethereum collections and guesses floor price, all-time volume, owners and sales. Punks spins a CryptoPunk's own index, 0–9999, and guesses what it last sold for.
They are the same game over a different universe. lib/universe.ts picks the
source; everything downstream — the state machine, scoring, every screen — is
indifferent to which one it got.
The two sources have opposite shapes, and that is the whole design:
| CoinGecko | OpenSea | |
|---|---|---|
| Ranked list | 27 requests, numbers included | 30 requests, no numbers at all |
| Per-entity numbers | free, in the list | one request each, at spin time |
| Budget | 10,000 credits/month | 120 per sub-minute window |
OpenSea's ranked list carries names and art but no floor price, and there is no batched stats endpoint. Pricing the whole ladder up front would cost one request per collection, so NFT mode stores only the ladder and fetches the numbers for the one collection a spin lands on: 30 requests to build, one per round. A 100-round game costs about 135.
That trade has one consequence worth knowing: the build can no longer filter
on numbers it hasn't fetched. A collection with no floor is only discovered on
landing, so applySpin walks to the next rank and burns the dead one. What can
be filtered up front — unverified, NSFW, disabled, art-less — is, because that
all arrives in the cheap list call.
Measured against the live API rather than assumed: thirty pages yield 2,876
collections, 96% of raw rows clear the filters (/collections/top is already
curated, so the safelist filter does less work than you would expect), and
5% of the ladder comes back unguessable — so a round costs 1.05 requests on
average. Slider bounds are set from the same crawl: floors run 0.00024 to 29.7
ETH, all-time volume 269 to 1.38M, owners 220 to 5.3K, sales 476 to 39K.
The number on the reel is the punk itself rather than a position in a ladder, because a punk's index says nothing about its value — so this mode has no difficulty tiers and the host screen hides the control.
Prices come from cryptopunks.app, which documents its own API at /llms.txt.
No key, no auth. One crawl of action=all-sales walks the entire history —
31 pages, ~30,500 sales back to June 2017, about 17 seconds — and folds it
into one row per punk. After that a round costs nothing: the prices are
local and the image is a URL the phone fetches itself, served immutable.
Three of its documented endpoints do not do what the docs say, so only the
crawl is trusted: /details?includeHistory=true returns no history at all,
batch-recent-history caps at three rows per punk, and hasNextPage is false
on every page including the first. The crawl stops when a page stops adding
anything rather than when the API claims to be done.
Two answers are not numbers, which is most of what makes this mode different:
Both are scored on the same axis as everything else, and the axis is left to
rank the near misses. Calling "never sold" outright is exact; failing that, the
lowest guess wins, because it was most nearly right that the punk was worth
nothing. A sale above the cap sits off the top of the axis, so the highest guess
takes it — and OVER_CAP_GUESS is tuned so that saying "over" beats pinning
the slider at 5,000 for all three sales that live up there, rewarding the call
rather than a guess at how far over. Nobody has to have named a bucket for
someone to have been closest to it.
The reveal carries the date of both the last and the highest sale. It has to: only 10% of punks have sold in the last year and 60% last changed hands four or more years ago, so 45 ETH in 2021 and 45 ETH today are not the same claim.
The documented 600/hour is not what a key reports. X-RateLimit-Limit comes
back as 120 against a sub-minute reset, and 67 requests in 40 seconds drew no
429 at all — far more headroom than this game asks for. lib/nfts.ts backs off
to X-RateLimit-Reset rather than trusting any of these numbers.
Get a free Demo key from the CoinGecko developer dashboard — no card required, 10,000 credits a month, of which this uses roughly 7,000.
The keyless public API returns 429 on the third consecutive request, and the
snapshot builder needs 27 in a row. CoinGecko's own docs say the keyless tier is
"not suitable for production workloads, scheduled polling, or high-frequency
updates."
UPSTASH_REDIS_REST_URL and
UPSTASH_REDIS_REST_TOKEN or KV_REST_API_URL and KV_REST_API_TOKEN
depending on how the store was added. The app reads both pairs, so nothing
needs renaming. REDIS_URL is the rediss:// protocol endpoint and is not
used — the client speaks REST.COINGECKO_API_KEY under Settings → Environment Variables, and
OPENSEA_API_KEY too if you want NFT mode. Either mode fails with a plain
503 naming the key it is missing, so a game without one is never a mystery.There is no cron to configure: the coin snapshot rebuilds itself lazily whenever a lobby is created and the existing one is more than three hours old, behind a lock so only one builder ever runs. Vercel's Hobby plan only permits daily cron fired within a ±59 minute window, which is no use for this.
Note that Vercel's Hobby plan is for personal, non-commercial projects.
| Resource | Ceiling | This uses |
|---|---|---|
| CoinGecko credits | 10,000/mo | ~7,000/mo |
| OpenSea requests | 120/window | ~30/ladder/day + ~1.05/round |
| cryptopunks.app | undocumented | ~31/history + 0/round |
| Upstash commands | 500,000/mo | ~1,200/game |
| Upstash storage | 256 MB | ~1.8 MB (all three snapshots) |
npm run dev # local server
npm test # 85 tests, no test framework — node --test runs the TS directly
npm run snapshot # rebuild the coin universe and print what it found
npm run snapshot:nft # rebuild the collection ladder, and measure the dead rate
npm run snapshot:punks # rebuild the punk sale history and report the split
npm run playthrough # drive a full game over HTTP against a running server
playthrough is the fastest way to check a change end to end:
npm run dev &
BASE=http://localhost:3000 npm run playthrough
MODE=nfts BASE=http://localhost:3000 npm run playthrough
MODE=punks BASE=http://localhost:3000 npm run playthrough
lib/types.ts domain model, and every constant both sides need
lib/score.ts log-squared error, winner/loser split, FDV merge, reveal tiers
lib/universe.ts which source a game draws from (server only)
lib/coins.ts CoinGecko: crawl, exclude, filter, chunk, lazy rebuild
lib/nfts.ts OpenSea: the ladder up front, the numbers per round
lib/punks.ts cryptopunks.app: the whole sale history, folded per punk
lib/room.ts the game state machine (server only)
lib/useRoomState.ts polling hook — the transport seam
components/phases/ one file per screen
Four runtime dependencies: next, react, @upstash/redis, zod.
A few decisions worth knowing before changing things:
market_cap_rank
field disagrees with its own market_cap_desc ordering — one sampled page held
ranks 2113–2588 interleaved, with all 250 rows mismatched.