BikeControl (SwiftControl)
使用 Zwift Click、Zwift Play、Shimano Di2,或任何藍牙控制器搭配 MyWhoosh、Rouvy、Zwift 等。可於 iOS、Android、Windows 與 macOS 免費試用。
AI 翻譯
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
The league website: standings, matchups, records, rules, playoff odds — and a
commissioner tool that turns pasted WhatsApp score reports into rows in the
league's Google Sheet.
Built with Next.js 14 (App Router), Tailwind, and the Google Sheets API.檢視完整 README ↗The league website: standings, matchups, records, rules, playoff odds — and a commissioner tool that turns pasted WhatsApp score reports into rows in the league's Google Sheet.
Built with Next.js 14 (App Router), Tailwind, and the Google Sheets API.
WhatsApp scores ──paste──▶ /commish ──review──▶ Google Sheet (Scores tab)
│
site reads it live (60s cache)
▼
standings · matchups · records · odds
data/seasons/<year>/ and feed
the Record Book and all-time head-to-head numbers.| Route | What it shows |
|---|---|
/ | Weekly hub: results, awards (top score, MVP, beatdown, nailbiter), next slate, standings snapshot |
/matchups | Week browser with full box scores (?week=, ?season=) |
/standings | Full table with playoff line + Turd Bowl zone, Monte Carlo playoff odds, power rankings, luck index |
/teams/<owner> | Team page: weekly chart vs league average, top contributors, all-time H2H, season history |
/draft | Position-color-coded draft board per season with steals/busts value analysis; live-updating on draft night |
/waivers | Transactions: waiver log with per-team spending, the live pot (dues + waiver fees), and the trade ledger |
/players/<slug> | Player analytics: weekly chart, game log, position rank, draft/waiver history |
/records | All-time record book computed from the box scores |
/rules | The constitution and full scoring tables |
/recap/<week> | Shareable 1080×1080 recap card (native share on mobile → straight into WhatsApp) |
/my-board | A manager's private draft board: the Player Pool dragged into their own order, kept in their browser (nothing server-side), with live cross-outs, on-the-clock cues and a roster-minimums tracker (2 QB · 5 RB · 5 WR/TE · 1 K · 1 DEF) |
/rosters | Every team's current roster with how each player was acquired (draft pick, waiver, trade) |
/lineups | Submitted starting lineups per week — partials show what's in so far; flags starters that differ from the box score |
/awards | Weekly awards (Top Gun, Cupcake, Bad Beat, Heist, Nailbiter, Hammer) and the season tally |
/predictions | Preseason ballots — hidden until kickoff, then scored against the standings every week |
/commish | Passcode-protected score entry: paste WhatsApp reports, review, save to the Sheet |
/commish/draft | Draft-night mode: typeahead picks, best available, traded-pick overrides, skipped-pick fill-in, post-draft grades |
/commish can append rows)..env.example to .env.local and fill it in. On
Vercel, set the same variables in Project Settings → Environment Variables.npm install && npm run devWithout Sheet credentials the site still runs, serving the most recent archived season — useful for local development.
Three tabs (names configurable via env):
Week, Team 1, QB Name, QB, RB1 Name, RB1, … Flex2, Total1, Team 2, …, Total2, Winner, Loser. /commish writes rows in exactly this shape, into
the first open row under the data (or a row already numbered for that
week), never wherever Google's append would put it. Re-saving a matchup
overwrites its own row. Rows with a week and teams but no scores are
treated as placeholders, not 0–0 games.Week column plus one column
per team, cells naming that week's opponent. A row label like
RIVALRY WEEK 7 still parses as week 7 and shows as "Rivalry Week" on the
site. Note this is NOT the tab named Schedule, which in these workbooks is
a free-form weekly scratch area; both names are tried in order, and
SCHEDULE_TAB pins one explicitly./rosters and the parser's fuzzy name matching
("Romeo" → Romeo Doubs, "Mathew Stafford" → Matthew Stafford). Create the
tab empty: the draft-night tool writes the header and every pick, and the
waiver and trade forms keep it current from then on. Without it, parsing
still works but spellings aren't corrected.Player Name | Team | Position,
one row per draftable player, kept in rough draft-value order. Powers the
typeahead in the draft-night tool and the waiver form (picks write the
canonical Name TEAM POS form), the commissioner's Best available
panel, name matching on /my-board, the Free agents list on /rosters, position and
NFL-team fill-in for anyone typed as a bare name, and a spelling fallback
in the score/lineup parsers for players not yet on a roster.Team | Grade | Best Pick | Worst Pick | Notes,
one row per team, written by the Draft grades form on /commish/draft
after the draft. Shows on /draft.Week | Team | Slot | Player | Submitted, one row per slot,
appended by the Log lineups form on /commish. Rows are never edited:
a Thursday partial and Sunday's full lineup both stay, and the site shows
the latest row per slot — so the tab doubles as an audit trail for
deadline disputes. Powers /lineups.Every page load that misses the 60-second cache reads the whole workbook in
one values:batchGet call (plus one cheap metadata call to learn which
tabs exist), so a season refresh costs two requests, not eleven — well under
Google's ~60 reads/minute per service account. Rate limits and 5xx responses
are retried with a short backoff. A read that still fails throws rather
than reading as empty: the cache never stores a blank season, and each server
instance keeps serving its last good copy until the sheet answers again (a
cold instance with no copy yet falls back to the committed season files).
Only a tab that genuinely doesn't exist reads as empty. Appends are never
retried, so a lost reply can't double-write a score or a waiver.
Everything runs from /commish — the Sheet is the database, not the interface:
/lineups shows the league who's starting whom./commish adds whatever is missing./recap/<week> and either share the image or hit Copy for the group
chat for a text recap (results, awards, standings, next week's slate).The site updates within a minute of any save.
data/seasons/<year>/ as teams.csv, players.csv, schedule.csv
(same long format as data/seasons/2025/), and add the year to
ARCHIVED_SEASONS in lib/league.ts.LEAGUE_SHEET_ID at the new sheet (or clear the old tabs), bump
CURRENT_SEASON, and update the Rosters tab after the draft.lib/league.ts (OWNERS — aliases
handle nickname spellings like Eloy/Elaf, Mono/Monaf).HONORS in lib/league.ts.PREDICTIONS_LOCK_AT to the new Week 1 kickoff and post the
LEAGUE_PASSCODE in the chat so ballots can come in before the draft.npx tsx tests/parser.test.ts # parser acceptance tests (real league samples)
npx tsx tests/data.test.ts # transforms, schedule rules, clinch math
npx tsx tests/features.test.ts # awards, recap metrics + text, predictions, career
npx tsx tests/rosters-lineups.test.ts # lineup merging, team names, roster provenance, lineup-mode parsing
npx tsx tests/sheet-writes.test.ts # score row placement, 2- and 3-team trades -> rosters
NODE_OPTIONS=--conditions=react-server npx tsx tests/sheets-api.test.ts # trade writes against a mocked Sheets API
npm run lint && npx tsc --noEmit
Round NNDRAFT ORDERTEAMS/draftTeam NameOWNERSlib/league.tsWEEK | TEAM | PLAYER | COST | DROP rows: every add
names the player cut to make room (the DROP column is added on first use).
Powers /waivers and the live pot math (fees join the pot; scoring champ
stays $250 and the rest splits 60/30/10). /commish logs a move by
swapping the drop for the add on the Rosters tab, and lists any add still
missing its drop so it can be filled in. /commish has a one-click form that appends rows here.TEAM 1 | TEAM 1 GETS | TEAM 2 | TEAM 2 GETS, plus
TEAM 3 | TEAM 3 GETS for three-team deals (added automatically the first
time one is logged). Each team's column lists what it receives, one asset
per row, with blank team cells continuing a deal. In a three-team deal a
player may carry his sender — Josh Allen (from Jay) — which /commish
fills in from the rosters; typed without it, the sender is found the same
way. Powers the trade ledger on /waivers. An On Rosters column is
stamped once a deal's players have moved on the Rosters tab; /commish
lists any unstamped deal (typed straight into the sheet, say) with the
moves it would make, and applies them on one click. Tabs too narrow or
short for a write are extended automatically.Submitted | Manager | Order | Champion | Turd | Bold Take,
one row per ballot, appended by /predictions (requires LEAGUE_PASSCODE).
Order is a comma-separated list, best first; a manager's latest row wins.
Ballots lock at PREDICTIONS_LOCK_AT (Week 1 kickoff).Week | Team | Points | Reason rows explaining
any gap between a row's official total and its players' sum (e.g. the §VII
-5 confirmation penalty). The site detects the gap automatically either way
and shows it as an "Adj" line in the box score; this tab just supplies the
reason. /commish writes here when you apply a penalty at score entry.