College football Saturdays on one screen: venue, kickoff-hour stadium weather, TV and streaming, publicly posted spread and total, then live scores and cover/total state for every FBS game. Free, no a
翻译准备中
运动与健身Python · SwiftGitHub @ChristianVerdin在线运营者未确认
试用过了吗? 点一下就好,无需登录。
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证CFB GameDay Board: college football slate with venue, kickoff weather, posted lines, and live cover/total. Web at cfbgameday.app, iOS app, stdlib Python + vanilla JS.
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
Local, single-user college football slate board. Built for scanning a Saturday
slate in one place: venue, kickoff-hour weather, DraftKings lines (via ESPN),
implied scores, TV/streams, then live score / cover / total state once games
start.
Dark, mobile-first, ESPN-style cards. No build step, no framework, no accounts.查看完整 README ↗College football slate board. Built for scanning a Saturday slate in one place: venue, kickoff-hour weather, DraftKings lines (via ESPN), implied scores, TV/streams, then live score / cover / total state once games start, and a game sheet (scoring, box score, leaders, drives, ESPN win probability) for any game that has kicked off.
Dark, mobile-first, ESPN-style cards. No build step, no framework, no accounts.
How it works and why it is built this way, in a five-minute read: case study.
Last updated 2026-11-02 12:15 CT. The live board holds Week 10 (63 games, Tue 11/3 to Sat 11/7), from the snapshot generated 2026-11-02 11:48 CT. iOS 1.1.0 has been live since 2026-10-22 08:00 CT.
main on every push. The
snapshot rebuilds itself seven times a week via GitHub Actions (two on Tuesday, Wed,
Thu, Fri and two on Saturday), each well ahead of kickoff, and heals itself if a run
drops kickoff forecasts.ios/. On the App Store
since 2026-09-10, currently 1.1 (Today's Games widget and universal links, since
2026-10-22); Rivalry Games quick action and cfbgameday:// links since 1.0.5 (2026-10-20),
iPad and a resizable Mac window since 1.0.3 (2026-10-10):
https://apps.apple.com/app/id6809035228#rivalry links straight to the week's trophy games.cfbgameday:// links (from 1.0.5) open the app on a view: rivalry, live, starred,
tv, board, or game/<ESPN id>. The App Store's in-app event cards use them.games.json and /api/live, never odds or implied scores.cfbgameday.app and
its #rivalry, #live, #starred, #tv and #game/<ESPN id> views. Other pages
(/privacy, /support) stay in Safari.127.0.0.1, not a sportsbook
connection. Nothing here logs into or scrapes DraftKings, FanDuel, or any
book.python3 server.py
open http://127.0.0.1:8765/
server.py is a stdlib ThreadingHTTPServer bound to 127.0.0.1:8765. It
serves the folder and exposes two ESPN proxies. GET /api/live returns
scores, clock, situation, and current odds for the slate's dates; the page polls
it every 30 s and merges the result onto the snapshot in games.js.
GET /api/game?id= returns one game's summary for the game sheet.
Opening index.html directly as a file works for the snapshot only. Live mode
needs the server because the browser cannot call ESPN directly.
| File | Role |
|---|---|
index.html | UI shell and all CSS. The block between <!-- games:start --> and <!-- games:end -->, the week kicker, <title> and meta description are generated by refresh_week.py - edit the generator, not the block |
app.js | All client logic: filters, views, live merge, cover/total math |
games.js | Snapshot payload as window.CFB_DATA = {...} (loaded by the page) |
games.json | Same payload as plain JSON |
server.py | Static server + /api/live and /api/game ESPN proxies with per-date / per-game caches |
CONTEXT.md, AGENTS.md | Operator notes: live state and the map of everything that runs unattended. Not needed to run the board |
scripts/refresh_week.py | Rebuilds games.json / games.js for a new date range, plus the generated block in index.html and sitemap.xml |
docs/ARCHITECTURE.md | Snapshot vs live, ESPN endpoints, Open-Meteo process, weekly rebuild |
docs/screenshots/ | The images in this README (live board and iOS simulator, Week 8 2026) |
docs/superpowers/ | Design specs and plans for larger features (e.g. the game sheet) |
scripts/check.py | Offline smoke test: flag table, CT kickoff, cover/total math, snapshot shape, structured data |
scripts/run_summary.py | Prints the build's counts and warnings as Markdown for the GitHub Actions step summary |
scripts/ci_heal.py | Rebuilds once in CI when a run dropped kickoff forecasts (a forecast or venue-geocode failure), keeping the better result; --verify fails the job if still degraded |
scripts/promo_text.py | Builds the week's App Store promotional text from games.json; --apply pushes it with asc |
manifest.webmanifest, , |
The board is a Progressive Web App: a manifest, home-screen icons, and a service worker that caches only the UI shell. Live scores are never cached.
http://<your-mac-ip>:8765/ only if you change the bind address in
server.py; off-LAN needs a tunnel (Cloudflare Tunnel or Tailscale Serve).
The default 127.0.0.1 bind is deliberate, see Limitations.The page shows a one-time Add-to-Home-Screen hint in Safari on iOS; dismiss
with the ×. Ship a new shell by bumping VERSION in sw.js.
Fastest way to get the phone on it from anywhere, on gameday only:
brew install cloudflared
scripts/tunnel.sh # starts server.py if needed, prints the https URL, Ctrl+C ends both
Stable hostnames, Tailscale, and an always-on box are in docs/DEPLOY.md.
Test portrait on a 390 to 430 wide phone (iPhone 13 through 16 Pro Max).
proj implied score is gone
entirely, so nothing collides with the white score; the column stays aligned
against pre-kick cards.The GitHub Action does this on a schedule. To run it by hand:
python3 scripts/refresh_week.py
python3 scripts/promo_text.py --apply # App Store promotional text for the week (needs asc)
With no arguments it targets Tuesday through Monday of the slate in progress
(a new slate starts on Tuesday, so midweek MAC and CUSA games are included). Pass --start 20260911 --end 20260914 to pick dates. Rerun it on a game morning to refresh the forecast to
same-day accuracy, then restart server.py.
--no-enrich skips the per-game ESPN summary pass (~26s of the runtime) when
you just want a fast local rebuild. --seo-only rebuilds only the generated
block in index.html and the sitemap.xml lastmod from the committed
games.json, with no network calls at all. A normal run writes all four files,
so commit games.json games.js index.html sitemap.xml together.
The Action runs it seven times a week - Tue 4 AM with a Tue 10 AM backup, Wed 1 PM, Thu 7 AM, Fri 7 AM, Sat 4 AM and a Sat 8 AM backup. Each is scheduled hours ahead of when it is actually needed because GitHub creates scheduled runs late under load (measured 5h08m late once on this repo) and can drop them entirely.
That pulls the ESPN scoreboard for each date, geocodes each venue city with
Open-Meteo, pulls the hourly forecast at the local kickoff hour (a failed lookup
gets one retry from a per-run budget, since it leaves the game with no forecast), computes the
derived fields (implied score, weather flags, impact notes, CT kickoff), and
writes both games.json and games.js. Details in docs/ARCHITECTURE.md.
Live cards use the posted home spread and the current margin:
margin = home score - away score
coverBy = margin + homeSpread (> 0 means HOME is covering)
overNeed = total - (home + away)
The spread and total are the DraftKings numbers ESPN publishes in its scoreboard feed, refreshed with each live poll. They are a snapshot of the posted line, not a live steam feed.
server.py falls back across three ESPN hosts.enrich block fills in over the season: playing surface and the
ESPN projection are there from the start, but ATS records and attendance come
back empty in the early weeks and stadium capacity is usually null.lines.json; the hosted site keeps
them in the browser's local storage, so they are per device.docs/DEPLOY.md.The committed games.json / games.js is whatever the refresh Action last
wrote; its generated_at and week_label say which slate. Lines and weather
are as of that moment, with the last posted line carried forward once ESPN
drops odds at kickoff.
There are none. The repo must never contain .env files, API keys, AWS
credentials, sportsbook cookies, or model-provider tokens. .gitignore blocks
the usual filenames; scan the tree before adding anything new.
MIT. See LICENSE.
sw.jsicons/| PWA: install metadata, UI-shell service worker, home-screen icons |
api/live.py, vercel.json | The same ESPN proxy as a Vercel function, CDN-cached 20 s; project config |
api/game.py | Game sheet detail (scoring, box, leaders, drives, win probability) from ESPN's game summary |
.github/workflows/refresh.yml | Scheduled snapshot rebuild that commits games.json / games.js |
privacy.html, support.html, site.css | Public pages required for the App Store listing; shared stylesheet |
.well-known/apple-app-site-association | Universal links: lets iOS open board links (/ and /index.html only) in the app; served as JSON via vercel.json |
ios/ | SwiftUI iPhone and iPad app (also runs on Apple silicon Macs): project.yml (XcodeGen spec, versions, team), sources in CFBGameDay/, the Today's Games widget in CFBGameDayWidget/, unit tests and widget renders in CFBGameDayTests/ (frozen Week 8 snapshot), ExportOptions.plist, listing copy in APP_STORE.md, App Review reply kit APP_REVIEW_REPLY.md, live listing metadata in metadata/ (asc round-trip), review narration narration.txt + narrate.mts |
scripts/release_ios.sh | One-command iOS release: archive, export, validate, upload, attach (and --submit) via the asc CLI, altool fallback; stops if the archive or IPA is missing, and ASC_SIGNING_KEY_ID signs the export with an API key when Xcode has no account |
scripts/ios_tab_check.sh | Simulator smoke test: drives the tabs with AXe and fails on a blank revisit |
scripts/review_mux.py | Lays the narration lines over a phone screen recording at cue times, outputs H.264 for App Review |
scripts/tunnel.sh | Gameday Cloudflare quick tunnel for the local server (fallback only) |
CLAUDE.md | Rules and conventions for working in this repo with an AI agent |
.vercelignore | Keeps ios/, docs, scripts, and local state out of the Vercel upload |
docs/DEPLOY.md, deploy/ | Hosting: Vercel (live), tunnels, and self-host drafts |