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。 以下为已保存的摘录。
Installable, offline-capable PWA companion for EVE Online: multi-character
overview, skill planning with remap optimization, industry build planning,
a market browser, planetary industry, corp tools, and notifications.查看完整 README ↗Installable PWA companion for EVE Online: multi-character overview, skill planning with remap optimization, industry build planning, a market browser, planetary industry, corp tools, and notifications.
Live: https://neocomdesk.com
develop preview) — no app server.npm run sde:build) — no SDE calls at runtime.See GLOSSARY.md (glossary), docs/context/decisions/ (scope decisions),
docs/ARCHITECTURE.md (module map, data flows, feature inventory),
docs/DESIGN.md (design system), docs/adr/ (architecture decisions).
Do all work in a git worktree, never in this main checkout. The main
checkout is reserved for manually running/testing the app in a browser
(npm run dev); every code change belongs in a sibling worktree so it
doesn't race whatever else is running here. See CLAUDE.md.
npm install
npm run dev # dev server
npm test # vitest watch
npm run typecheck
npm run lint
npm install also sets up a pre-commit hook (husky + lint-staged) that
auto-fixes lint/format on staged files and runs typecheck on every commit —
but that setup step is silently skipped if ignore-scripts is set in your
npm config (npm config get ignore-scripts). After a fresh clone or npm ci, run npm run verify-hooks -- --fix once to install the hook and
confirm it's actually live; it fails loudly instead of pretending to work.
While iterating, prefer narrow checks over the full suite: npm run typecheck and npx vitest run <path> for the file(s) you're touching.
Never run npm run test:run or npm run build locally — CI's
validate job runs lint, format check, typecheck and build on every PR, a
test job runs the unit suite across four shards, and an e2e job runs
Playwright across four more; that's the gate, not a local pre-PR run.
Copy .env.example to .env and fill it in — see
Run your own copy for where each value comes from.
This is everything needed to fork the repo and get a working site of your own. Only step 1 is needed to run locally; steps 2 to 4 add sync, push alerts and hosting. The values that point at the original deployment are listed below, in steps 2 to 4 and "What a fork does not get".
You need Node 24, a GitHub account, an EVE account, and a Google account for Firebase.
Create an application at https://developers.eveonline.com with
Authentication & API access. Enable the ESI scopes the app requests
(the list is built from src/esi/registry.ts; enabling all of them is the
simplest choice).
Add callback URLs. The app uses PKCE with no client secret, and builds the
callback from the page origin: http://localhost:5173/callback for
development, and https://<your-domain>/callback for production. A callback
belongs to one application, so a separate dev or preview site needs its own
EVE application.
Fork and clone, then:
npm ci
npm run verify-hooks -- --fix
cp .env.example .env # set VITE_EVE_CLIENT_ID
npm run dev
With only VITE_EVE_CLIENT_ID set you get sign-in, every character view,
skill plans, build plans and the market, with data cached on the device.
Leave the other variables blank: Firebase sync and Sentry switch themselves off.
Firebase holds Skill Plans, Build Plans and synced settings, plus the Cloud
Functions behind push alerts, the Corp Tax Book, SRP and community features.
It never receives a refresh token except the opt-in grants listed in
CLAUDE.md. Full detail is in docs/SYNC-SETUP.md.
Create a Firebase project and upgrade it to the Blaze plan (Cloud Functions v2 requires it; hobby use stays inside the free quotas).
Enable Authentication (Get started; no provider is needed, since sign-in uses custom tokens) and create a Firestore database in production mode.
Add a Web app under Project settings and copy its config into .env:
VITE_FIREBASE_API_KEY, _AUTH_DOMAIN, _PROJECT_ID, _APP_ID,
_STORAGE_BUCKET, _MESSAGING_SENDER_ID. For push notifications also
generate a Web Push key pair (Project settings, Cloud Messaging) and set
VITE_FIREBASE_VAPID_KEY. VITE_FIREBASE_MEASUREMENT_ID (Google Analytics)
and VITE_SENTRY_DSN are optional; leave them empty to disable both.
Point the CLI at your project: edit .firebaserc and replace
neocom-desk with your project ID (or run firebase use --add).
Tell the functions which EVE applications they trust. Create
functions/.env (gitignored):
# comma-separated: every EVE application client ID that signs users in
EVE_CLIENT_ID=<dev client id>,<prod client id>
The functions refuse to deploy or start without it, so tokens minted for other EVE apps are rejected.
Create the alerts encryption key. It is a secret holding 32 random bytes, base64-encoded:
openssl rand -base64 32 | firebase functions:secrets:set ALERTS_TOKEN_KEY
The functions also declare the R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY
secrets, so the deploy fails until both exist. If you are not running R2
(see "What a fork does not get"), set placeholders:
echo unused | firebase functions:secrets:set R2_ACCESS_KEY_ID
echo unused | firebase functions:secrets:set R2_SECRET_ACCESS_KEY
Deploy:
npm install -g firebase-tools && firebase login
npm ci --prefix functions
firebase deploy --only functions,firestore
When asked to delete functions that the source no longer exports, answer
yes. Cloud Functions are not deployed by CI, so rerun this whenever
functions/ or firestore.rules changes.
Production is built and published by .github/workflows/deploy.yml on every
push to main.
.env:
VITE_EVE_CLIENT_ID and the VITE_FIREBASE_* variables. Optional:
VITE_SENTRY_DSN, SENTRY_ORG, SENTRY_PROJECT, and the secret
SENTRY_AUTH_TOKEN for source maps.public/CNAME to your domain (a user or org Pages
site at <user>.github.io also works). Serve from the domain root: subpath hosting is untested, since
public/ and the landing page use absolute /… asset paths.keep-old-assets.mjs step in deploy.yml names
https://neocomdesk.com. It never blocks a deploy, but point it at your
site so tabs on an older build keep their chunks.main. The deploy-dev job (Cloudflare Pages) is the original
author's preview channel for develop. It fails on every push to
develop unless you delete it or add the secrets: it needs CLOUDFLARE_API_TOKEN and
CLOUDFLARE_ACCOUNT_ID secrets in a dev environment, and you can delete
the job if you do not want a preview site.CI (.github/workflows/ci.yml) needs no secrets. The scheduled workflows
(public-data-*.yml, sde-refresh.yml, sde-verify.yml, cache-warm.yml,
keepalive.yml) are the original maintainer's housekeeping. Leave them
disabled in the Actions tab; the public-data-* jobs need the R2 secrets and
sde-refresh.yml needs a SDE_REFRESH_TOKEN that opens PRs.
These still carry the original identity and are worth changing for a public fork:
USER_AGENT in src/esi/userAgent.ts and its copy in
scripts/lib/constants.mjs: ESI and EVE Workbench ask for a
descriptive user agent that points at the real operator. Never use a
personal email address.REPO_URL and DISCORD_URL in src/lib/links.ts, shown in the landing
footer and Settings.public/ (brand/, icons/, screenshots/),
the app name in package.json, and public/privacy.html, which
names the operator and links the original repository.twa/, public/.well-known/assetlinks.json, package
com.neocomdesk.app) is optional. Skip it unless you publish to the Play
Store; see docs/ANDROID-TWA.md.The app reads a few shared public datasets (active wars, lawless systems,
public contract snapshots, market open prices) from
https://data.neocomdesk.com, a Cloudflare R2 bucket. That origin only allows
the original site and local development, so on your domain those fetches are
blocked and the app treats them as "no snapshot" and carries on: the
affected panels show less data, nothing breaks.
To produce them yourself, create an R2 bucket with a public custom domain and
GET-only CORS for your origin, then replace the origin in
src/features/contractSearch/r2OfferSnapshot.ts, src/features/wars/activeWars.ts,
src/features/travel/lawlessSystems.ts and src/lib/swRoutes.ts. Set
R2_ENDPOINT and R2_BUCKET in functions/.env, and the
secrets R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY for the functions
(firebase functions:secrets:set) and as GitHub repository secrets alongside
R2_ENDPOINT and R2_BUCKET, which the scheduled public-data-*.yml
workflows use. Design notes are in docs/adr/0019-contract-snapshots-served-from-r2-not-firestore.md.