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
Stats, standings, and match history for Dan's Gaming League Series — a CS2 Wingman league.
GamesTypeScript · PythonGitHub @zgreenhalgeOnlineOwner 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
Loading the full README. The saved excerpt is shown below.
A stat tracker for DGLS — a CS2 Wingman league played in the Individual Rotating Mixer format. Because teammates rotate randomly every week, standard win/loss records are misleading. This platform surfaces individual skill through rate-based metrics, primarily ADR (Average Damage per Round).
Full reference docs live in docs/. Start with docs/README.md for the index. Highlights:Read the full README ↗A stat tracker for DGLS — a CS2 Wingman league played in the Individual Rotating Mixer format. Because teammates rotate randomly every week, standard win/loss records are misleading. This platform surfaces individual skill through rate-based metrics, primarily ADR (Average Damage per Round).
Full reference docs live in docs/. Start with docs/README.md for the index. Highlights:
docs/glossary.md — DGLS domain terms + a map of where each concept lives in the code (read this first)docs/patterns.md — cross-cutting conventions every change should followdocs/recipes.md — step-by-step patterns for common changesdocs/architecture.md — routes, auth, mutation API, database schema, deploymentdocs/calculations.md — the formulas behind every stat and rankingdocs/visual-conventions.md — the shared hover/glow/accent CSS systemdocs/ehog.md — the EHOG player skill rating enginedocs/demo-ingestion.md — the CS2 demo upload → parse → stats pipelinenpm install
npm run dev # http://localhost:3000
Other useful commands:
npm run build # production build (also type-checks)
npm run lint # ESLint
Development shortcut: When NODE_ENV=development, two mock login buttons appear (Dev: Zach / Dev: Dan) that skip Steam auth entirely and sign you in as a known player. You do not need STEAM_API_KEY or NEXTAUTH_URL for local dev if you use these.
Create .env.local at the repo root. (In a Claude Code web session, skip this — a SessionStart
hook auto-provisions a local Supabase stack instead when .env.local is absent; see
docs/e2e.md's "Claude Code sessions" section.)
| Variable | Purpose |
|---|---|
NEXT_PUBLIC_SUPABASE_URL | Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Supabase anon key — used only by the browser's Realtime subscriptions (src/lib/supabase-browser.ts); it can read just the tables those subscriptions watch. Unset, pages render without live updates |
SUPABASE_SERVICE_ROLE_KEY | Service role key — every server-side read and write (getAdminClient()), never sent to the client |
NEXTAUTH_URL | Full base URL, e.g. http://localhost:3000 |
NEXTAUTH_SECRET | Secret for signing session tokens (any random string locally) |
STEAM_API_KEY | Steam Web API key — fetches player avatars/nicknames |
DISCORD_CLIENT_ID | Discord application client id — self-service Discord account linking (/api/auth/discord/link) |
DISCORD_CLIENT_SECRET | Discord application client secret — token exchange in /api/auth/discord/callback, server-side only |
DISCORD_MATCH_NOTIFICATIONS_WEBHOOK_URL | Discord incoming webhook URL for the #match-notifications channel — server-live and final-score alerts (src/lib/discord-notify.ts). Omit to disable; every call site no-ops without it |
DISCORD_PUBLIC_KEY | Discord application public key — verifies incoming slash-command requests to /api/discord/interactions (src/lib/discordInteractions.ts) |
DISCORD_APPLICATION_ID | Discord application id — used only by scripts/register-discord-commands.ts to register/update the slash command definitions |
DISCORD_BOT_TOKEN | Discord bot token — grants/revokes @Participants and manages per-player name-color roles (src/lib/discord-roles.ts, #397), publishes weekly match threads and closes them once played (src/lib/discord-threads.ts, #398), scans each match thread's message history for a shared scheduled event and syncs its start time into scheduled_at (src/lib/discord-event-sync.ts, #398), and registers slash commands (); the interactions endpoint itself is verified by , not this token. Needs , , , (to archive/lock a played match's thread), and (to scan a thread for a shared event), plus a channel-level permission overwrite on each season's forum channel if it restricts access — with the bot's own role positioned at the top of the server's role hierarchy, above and above where name-color roles get created. Reading guild scheduled events needs no extra permission beyond guild membership |
For the route table, schema, API endpoints, and deployment details, see docs/architecture.md. For the Python ingestion pipeline, see ingestion/README.md.
scripts/register-discord-commands.tsDISCORD_PUBLIC_KEYManage RolesCreate Public ThreadsSend Messages in ThreadsManage ThreadsRead Message Historyseason-{N}@ParticipantsDISCORD_GUILD_ID | The DGLS Discord server's id — scopes the @Participants/name-color role, match-thread, and scheduled-event API calls to the right guild |
DISCORD_PARTICIPANTS_ROLE_ID | The @Participants role's id — what src/lib/discord-roles.ts grants/revokes |
CRON_SECRET | Bearer token checked by GET /api/cron/refresh-steam (Vercel cron) and POST /api/cron/match-reminder (Supabase pg_net-triggered). The same value must also be stored in Supabase Vault as the cron_secret secret — schedule_match_reminder() reads it from there to call the latter endpoint, since a Postgres function has no access to Vercel's env vars. Rotate in both places together; there's no automated sync between them |
CLOUDFLARE_R2_ACCOUNT_ID | Cloudflare R2 account ID (demo uploads) |
CLOUDFLARE_R2_ACCESS_KEY_ID | Cloudflare R2 access key (demo uploads) |
CLOUDFLARE_R2_SECRET_ACCESS_KEY | Cloudflare R2 secret key (demo uploads) |
CLOUDFLARE_R2_BUCKET_NAME | Cloudflare R2 bucket for uploaded .dem files |
GITHUB_DISPATCH_TOKEN | Fine-grained PAT (Actions: write) to dispatch the replay GitHub Actions jobs — see docs/replay.md |
GITHUB_REPO | owner/name of the repo whose Actions to dispatch (e.g. zgreenhalge/dans-gaming-league-series) |
REPLAY_AUTO_DISPATCH | replay-extract is auto-dispatched alongside demo_ingest on match end (/api/ingest/matchzy-log's map_result handler) by default; set to false for the manual override (Recap tab / admin dispatch button only) — see docs/replay.md |