尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗A browser game about late-game football play-calling. You get the score, the clock, the timeouts and 22 players on the field; you call the plays (27 of them), manage the clock and call the defense. Every decision is graded by playing the rest of the game out thousands of times for every option you had.
Rosters, jersey numbers and season statistics come from nflverse (CC-BY 4.0; see scripts/build-rosters.mjs, which also documents how the 0-100 game ratings are computed from those statistics). Game situations are made up. Results come from a simplified simulation written for this game; grades are its estimates, not official evaluations or real-world probabilities.
npm install
npm run dev # http://localhost:5173
npm test # engine tests (Vitest)
npm run build # type-check + production build into dist/
npm run preview # serve dist/ at http://localhost:4173
Requires Node 18 or newer.
Copy .env.example to .env.production (or set the same variables in your host's build settings):
| Variable | Required | What it does |
|---|---|---|
VITE_SITE_URL | Required for search | Your public address, e.g. https://your-domain.com (no trailing slash). Makes the social-preview image, canonical link and structured data absolute, and adds sitemap.xml plus its line in robots.txt. Without it, search engines get no sitemap and no canonical URL. |
VITE_GA_ID | Optional | Google Analytics 4 measurement ID. The site tag is built in (in src/game/analytics.ts); set this to use another, or off to load no analytics (for local builds). |
VITE_FEEDBACK_URL, VITE_SUPPORT_URL | Optional | The footer's Feedback and Support the developer links (https:// or mailto:). Not shown when empty. |
VITE_ADS, VITE_ADSENSE_CLIENT, VITE_ADSENSE_SLOT | Optional | Display ads, off by default. See MONETIZATION.md before setting them. |
Analytics events (when enabled): game_start, call_made, spot_complete (game complete), play_again, daily_complete, survivor_end, share (the full list is in src/game/analytics.ts).
No personal data is sent. If you enable analytics for visitors in the EU/UK, you may need a consent banner.
The build is a static site in dist/ with relative asset paths and hash-based navigation (#survivor,
#practice), so it needs no server rewrites. Any static host works:
npm run build, output directory
dist, Node 18+. Add VITE_SITE_URL (and optionally VITE_GA_ID) as build environment variables. Point your
domain at the project in the host's dashboard.npm run build locally with .env.production in place and
upload the contents of dist/.public/404.html is the not-found page (Netlify, Cloudflare Pages and GitHub Pages use it automatically).
The title, description and crawlable text (the pre-render fallback in index.html and the footer blurb in
src/App.tsx) describe the game in generic terms: a free football strategy and play-calling game built around the
two-minute drill. They deliberately don't lead with "NFL": the game is an independent fan game, and "NFL" is the
league's trademark (and "NFL 2 Minute Drill" is also the name of Sega's arcade game). Keep the no-affiliation disclaimer
(footer, About, fallback text) in place.
vite.config.ts adds JSON-LD (WebSite + VideoGame), robots.txt and sitemap.xml at build time from
VITE_SITE_URL. The sitemap lists only the indexable pages: / and /how-to-play/. The Worker's /leaderboard/ and
/stats/ pages are noindex, follow while they are thin; to index them later, flip INDEXABLE in
server/site/worker.js and add them back to PAGES in vite.config.ts. After deploying:
https://your-domain.com/sitemap.xml
and use URL Inspection → Request indexing on the home page.npm run indexnow after a deploy.marketing/). A new site with no inbound links ranks for very little,
whatever its tags say.The launch checklist is marketing/LAUNCH_CHECKLIST.md. Open search tasks are in TODO.md.
src/engine/: the football engine (pure TypeScript). sim.ts resolves plays and runs the clock, evaluate.ts
values decisions by simulation, scenario.ts builds the daily/survivor spots, worker.ts runs evaluations off the
main thread. Tests in sim.test.ts.src/game/: session (deterministic replay of saved picks), grading, storage, sharing, analytics.src/ui/: React screens and the SVG field renderer (field.ts).The game uses real teams and players. src/data/nfl-rosters.json is generated, never hand-edited:
node scripts/build-rosters.mjs 2025 # downloads nflverse data into data-cache/ (git-ignored) and rebuilds the JSON
scripts/build-rosters.mjs from that season's statistics, by the
formulas documented at the top of that script (rank among the league's starters at the position, mapped to 52–98).
Linemen, kickers and low-snap players have no usable individual stats and are marked estimated. These are this
game's own ratings, not official measurements and not any other game's ratings.validateRoster() (src/engine/roster.ts) runs on every team in the test suite: missing players,
duplicate or position-illegal jersey numbers, missing or out-of-range ratings, stat-derived ratings with no season.makeTeam) is still there as a fallback if you need to switch back.The Daily is one game a day, the same for everyone (by UTC date). Its situation type rotates through a weekly shuffle of seven kinds (two-minute drill, dig out of the hole, win it on this drive, close it out, goal-line stand, four downs to win, fourth-down call), and the two teams are never the same as the day before.
The end-of-day screen shows the score, a percentile against simulated play-callers (src/data/percentiles.json,
regenerate with npm run percentiles after balance changes), the coach profile, a share card and, when connected,
Everyone today: your rank, a histogram and today's best.
"Everyone today" is served by the site's own Worker (server/site/worker.js, configured in wrangler.jsonc): the
static game from dist/, and the leaderboard API under /v1/. Scores are kept in Durable Objects (one per day, plus
one for the all-days summary), which the migration in wrangler.jsonc creates on deploy, so there is nothing to set
up by hand. The worker stores a nickname, the score and the grade string per browser token per day; nothing
identifying. Names are cleaned and obvious abuse is replaced with "Coach". Scores are self-reported by the browser, so
treat the board as friendly competition, not a contest with prizes.
Run the site and the leaderboard locally with npm run build && npx wrangler dev. VITE_LEADERBOARD_URL points the
game at a different server, or off turns the board off; the Vite dev server has no Worker, so the board is off
there.