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
Prove you know ball. One Daily, one try.
Translation pending
GamesTypeScript · PLpgSQLGitHub @PCollinxOnlineOwner 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
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Knowledge-first football app: The Daily, The League and rankings. Next.js (App Router, TypeScript) on Vercel, Supabase for Postgres, auth and scheduled jobs.
You need Node and Docker Desktop. The app runs against a local Supabase, so nothing touches the live database.
First time:
npm install
npx supabase start # needs Docker Desktop running
npx supabase db reset # applies migrations and loads supabase/seed.sql (a sample Daily for today)
npx supabase status -o env # prints the local URL and keys
Create .env.local from that output:
.env.local | from supabase status -o env |
|---|---|
NEXT_PUBLIC_SUPABASE_URL | API_URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY | ANON_KEY |
SUPABASE_SERVICE_ROLE_KEY | SERVICE_ROLE_KEY |
Also set NEXT_PUBLIC_SITE_URL=http://localhost:3000, HIGHLIGHTLY_API_KEY (any placeholder works locally) and a CRON_SECRET of at least 16 characters (openssl rand -hex 32). Then:
npm run dev # http://localhost:3000/daily
Stop: Ctrl+C on npm run dev, then npx supabase stop (local data is kept).
Start again: open Docker Desktop, npx supabase start, npm run dev.
The sample Daily is dated the day you ran npx supabase db reset. On a later day /daily shows "No Daily today" until you reset again, which also wipes local attempts.
/api/health reports which settings are present and whether the database answers.
The schema lives in supabase/migrations/. To apply it to the hosted project, always link first: db push goes to whichever project was linked last. The project ref is the part of the live NEXT_PUBLIC_SUPABASE_URL (in Vercel) before .supabase.co.
npx supabase login
npx supabase link --project-ref <your-project-ref>
npx supabase migration list # new migrations show as local only
npx supabase db push
npm run db:types # regenerate TypeScript types after a schema change
Testing and fixes happen against a second Supabase project, never the live one. Vercel previews (every pull request) and Claude's cloud sessions both use it.
Once:
iknowball-dev (the free plan allows two).npx supabase link --project-ref <dev ref>, npx supabase db push, then paste supabase/seed.sql into the dev SQL editor. Re-link the live ref before any live push.http://localhost:3000/** and https://*-collins-projects-3ea7974f.vercel.app/** as redirect URLs.NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY and SUPABASE_SERVICE_ROLE_KEY to the live values for Production only, and to the dev values for Preview. Previews sign in on their own branch URL (src/lib/env.ts). CRON_SECRET and HIGHLIGHTLY_API_KEY must be ticked for Preview too: the server checks every variable, so a Production-only one breaks every page that reads the database on previews.https://<dev ref>.supabase.co/auth/v1/callback as a redirect URI, and turn on the Google provider in the dev project with the same client.Migrations go to dev first, then live once the PR is merged.
/maker is the back office for writing Dailies: a list of the coming weeks, and an editor for each day's two parts with a live shirt preview and a "try a guess" box that uses the real answer matching. A part locks once anyone has started it.
Answer boxes take one answer per line:
Part 1, Free Recall: Cesc Fàbregas | Cesc, Fabregas (aliases after the bar)
Part 2, In Order: Emmanuel Petit | 2001 (correct order, top first; the reveal after the bar)
Locally, npx supabase db reset creates an admin: [email protected], password ball-knowledge.
On the live project, once:
update public.profiles set is_admin = true
where id = (select id from auth.users where email = '[email protected]');
/maker/login.Nobody writes a Daily from scratch. Two scheduled jobs (in vercel.json) do it, and a person reviews once a week in the maker:
/api/jobs/import-wikidata, daily 04:00 WAT: pulls every PL-era player (spells running into 1992 or later) for the 30 clubs in src/lib/drafts/clubs.ts from Wikidata (CC0), with their club spells, dates and nicknames, into players, player_aliases and player_spells. Each run does as many clubs as fit in about 4 minutes and skips clubs refreshed in the last 6 days, so a full refresh spreads over a few days and running it again carries on where it stopped. ?club=Arsenal%20F.C. imports one club now (the English Wikipedia title)./api/jobs/drafts, daily 20:00 WAT: fills every empty day in the next 8 with a draft. Part 1 is "players who've played for both X and Y since 1992", preferring that week's fixtures and never repeating a pair within 90 days. Part 2 orders five of them by the year they joined. Then any day starting tomorrow that is still a draft gets scheduled, so no day goes empty.Drafts show in /maker with a teal Auto tag. Check them, fix what Wikidata got wrong (missed loans, odd dates), and press Schedule.
On the live project, once, after pushing the migration:
curl -H "Authorization: Bearer $CRON_SECRET" https://playiknowball.com/api/jobs/import-wikidata
curl -H "Authorization: Bearer $CRON_SECRET" https://playiknowball.com/api/jobs/drafts
If the answer lists clubs under left, run the same command again until it says all clubs are up to date. It is safe to re-run.
Locally, point the import at a stand-in with WIKIDATA_SPARQL_URL in .env.local, or leave it unset to use the real Wikidata.
npm test # unit tests (game clock, later answer matching and scoring)
npm run typecheck
npm run lint
daily_answers, player_aliases) has no client read policy.src/lib/time.ts, public.game_date()).NEXT_PUBLIC_SITE_URL.Production hides server errors (for example "Minified React error #441"). To find the real one:
/api/health.SUPABASE_SERVICE_ROLE_KEY, HIGHLIGHTLY_API_KEY, or a CRON_SECRET under 16 characters) breaks every page that uses the service role, including /daily. Fix it in Vercel, then redeploy.npx supabase db push. No redeploy needed.