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,即可驗證所有權並自行管理介紹。
一分鐘完成驗證bracket betting for debate
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
Bracket pools for debate elimination rounds. Fill in a Tabroom elim bracket, lock
it, and it scores itself as results post — a March-Madness-style pool with a
leaderboard per tournament. Built with Next.js + Supabase; deploys to Vercel (or
anywhere that runs Next).檢視完整 README ↗Bracket pools for debate elimination rounds. Fill in a Tabroom elim bracket, lock it, and it scores itself as results post — a March-Madness-style pool with a leaderboard per tournament. Built with Next.js + Supabase; deploys to Vercel (or anywhere that runs Next).
/new (guarded by an admin key).Scoring: points double each round so every round is worth the same total, plus an
upset bonus of 1 point per N seeds of gap (4 in small fields, 8 in fields of 64+),
capped at double the round value. Rounds already decided before a tournament is
added don't count. Full explanation lives at /about.
supabase/schema.sql, then supabase/seed.sql
(the seed loads the two tournaments already tracked — delete those rows if you
want to start clean). Already running an older copy? Run
supabase/migrations/002_accounts_and_stats.sql (accounts) and
supabase/migrations/003_career_cache.sql (career cache) instead.anon public key,
and the service_role secret key.Copy .env.example to .env.local and fill it in:
| var | what it is |
|---|---|
NEXT_PUBLIC_SUPABASE_URL | Supabase Project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY | anon public key (browser, read-only) |
SUPABASE_SERVICE_ROLE_KEY | service role key (server only — all writes) |
ADMIN_KEY | passphrase required to add tournaments at /new |
UPDATE_SECRET | shared secret the scheduled updater must send |
TABROOM_USERNAME / TABROOM_PASSWORD | a Tabroom account (results pages need a login) |
The NEXT_PUBLIC_* values are the only ones shipped to the browser. Everything
else stays server-side.
npm install
npm run dev # http://localhost:3000
.github/workflows/update.yml), since Vercel's Hobby plan only allows daily
crons. In the GitHub repo, add Settings → Secrets and variables → Actions
secrets SITE_URL (your deployed URL) and UPDATE_SECRET (same value as the
app's env var), and it curls the updater every hour.Admins can also use the "Admin: force update" button on the home page, or trigger a refresh by hand:
curl -X POST https://YOUR-SITE/api/update -H "x-update-secret: YOUR_UPDATE_SECRET"
The dossier is built from Tabroom's public REST API (api.tabroom.com/v1) — no
login needed: the event's field, prelim seeds, speaker awards, final places, and the
per-entry records document (every round with side, opponent, ballots, points and
judges). Documents are cached in memory per server instance (5 minutes while a
tournament is live, an hour once it's complete) so a busy pool page stays cheap for
Tabroom. GET /api/stats/:tournament?code=Emory%20GY returns the compiled shape.
Every dossier ends with each debater's full Tabroom record: every tournament,
season by season, with partners, prelim and elim records, deepest elim round,
titles, speaker averages, and past meetings against teams in the current bracket.
It comes from Tabroom's per-student results page (team_results.mhtml?id1=…), which
needs a login — the app uses the same TABROOM_USERNAME account as the updater —
and is cached for 12 hours in student_records
(supabase/migrations/003_career_cache.sql; optional, memory cache otherwise).
Open /new, enter the admin key, and paste the Tabroom bracket link
(…/bracket.mhtml?tourn_id=…&result_id=…). The updater finds that event's elim
rounds on Tabroom's API by itself and walks forward from the first one, so the
first elim round's results link (…/round_results.mhtml?…&round_id=…) is only
a fallback for the rare event whose rounds it can't work out. The bracket fills
in on the next update, or paste the seeded team list to open it for picks
immediately.
/api/update logs into Tabroom, and for each unfinished tournament:
round_id is known
yet, then reads each round's results page walking forward from the last known
one, matching pairings against the bracket (side columns may be labelled
Aff/Neg, Pro/Con or Gov/Opp);ADV, never guessed);It never touches anyone's picks.
tournaments — one row per tournament (bracket, results, status, Tabroom ids).entries — one bracket per person per tournament; carries a private token
that proves ownership for edits. The browser reads the entries_public view,
which omits the token.Row-level security lets the browser only read; every write goes through the API routes with the service-role key.
app/
page.tsx home — tournament index
t/[id]/page.tsx one tournament: bracket, pool, leaderboard, results
new/page.tsx add a tournament (admin-key gated)
about/page.tsx scoring explained
api/
entries/ create + edit brackets (token-checked)
tournaments/ add a tournament (admin-key)
update/ the Tabroom results updater (secret-gated, cron)
lib/
bracket.ts scoring + bracket engine (shared client/server)
tabroom.ts Tabroom session + result parsing/sync
useBreak.ts client data hooks (realtime + polling)
supabase/
schema.sql tables, view, RLS, realtime
seed.sql the two tournaments already tracked