BikeControl (SwiftControl)
Use Zwift Click, Zwift Play, Shimano Di2, or any Bluetooth controller with MyWhoosh, Rouvy, Zwift, and more. Free to try on iOS, Android, Windows, and macOS.
예상 득점 모델 기반의 일일 NHL 승률을 베팅 시장과 솔직히 비교, 팀·선수 분석·순위 확률·공개 모델 기록 제공
Nightly NHL win probabilities from an expected-goals model, compared honestly with the betting market. Team and player analytics, standings odds and a public model record.
스포츠·피트니스TypeScript · PythonGitHub @alexgarrison2온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
NHL game predictions, team analytics and playoff odds. A Python pipeline
collects free public data, runs the shot-quality (xG) and game models, and
writes plain CSV/JSON files. A Next.js app renders those files. There is no
database behind the site and no user accounts.
public/data/ is the canonical output directory: anything the browser needs
is written there and served at /data/. The most important files:README 전문 보기 ↗NHL game predictions, team analytics and playoff odds. A Python pipeline collects free public data, runs the shot-quality (xG) and game models, and writes plain CSV/JSON files. A Next.js app renders those files. There is no database behind the site and no user accounts.
NHL API · MoneyPuck · DailyFaceoff · sportsbook lines (free, public)
│
▼
pipeline/ (Python, GitHub Actions: hourly lite run, daily full run)
scrape games ─► score shots (xG) ─► team/goalie ratings ─► predict games
─► history, season simulation, playoff implications
│ writes files, workflow commits them to main
▼
public/data/ (canonical site data) data/ (server-side copies)
│
▼
Next.js 16 App Router (Vercel): server components read files with fs,
client components fetch /data/*.json|csv
| Path | What lives there |
|---|---|
app/ | Routes (App Router) and API route handlers |
components/, hooks/, lib/, utils/, types/ | UI, client hooks, helpers and shared types |
pipeline/ | Data pipeline scripts, models (*.pkl) and pipeline-internal state |
pipeline/tools/ | Offline, run-by-hand scripts (see its README) |
public/data/ | Pipeline outputs served to the browser |
data/ | Legacy server-side copies (predictions_detailed.csv, gamestats.csv, prediction_history.json, nhl_teams.csv, ...) |
scripts/ | Optional Supabase snapshot sync (see scripts/AUTOMATION_README.md) |
docs/ | Design notes; docs/archive/ holds superseded audits |
public/data/ is the canonical output directory: anything the browser needs
is written there and served at /data/<file>. The most important files:
| File | Written by | Used for |
|---|---|---|
predictions_detailed.csv | predict_games.py | Tonight's matchup cards (also copied to data/) |
upcoming_games.json | fetch_upcoming.py | Schedule, probable/confirmed goalies |
odds.json | fetch_odds.py | Market lines shown next to model prices |
gamestats.csv | refresh_pipeline.py | Team tables, splits, charts (current-season games) |
team_ratings.json, goalie_ratings.json | team_ratings.py | Power ratings and goalie GSAx |
season_projections.json | season_simulator.py | Playoff odds and projected points |
game_implications.json | game_implications.py | Playoff stakes of tonight's games |
SiteHistory/<date>.csv | pipeline/snapshot_predictions.py | Frozen pre-game predictions per day |
last_updated.json | predict_games.py | "Updated at" stamp |
manifest.json | refresh_pipeline.py | Run summary: season_id, generated_at (UTC), mode and per-stage status, used for freshness checks |
data/prediction_history.json (from generate_history.py) is the graded
record of past predictions. pipeline/ also holds pipeline-only state that
the site never serves: the season CSVs nhl_season_<yyyy>_<yyyy>_{gamestats, shots,shifts,pbp}.csv, the multi-season nhl_historical_*.csv training
files, and model artifacts (xg_model_xgb.pkl, game_model.pkl +
game_model_meta.json).
nhl_teams.csv exists in pipeline/, data/ and public/data/; the three
copies must stay identical (Utah Mammoth is NHL team id 68).
The current season is computed, never hardcoded:
pipeline/season.py: SEASON_ID ("20262027"), SEASON_LABEL,
season_file(kind) → nhl_season_2026_2027_<kind>.csv, SEASON_GAMES
(84 from 2026-27, 82 before) and read_season_csv(), which returns an
empty frame before the first game is scraped.lib/season.ts: the same values for the frontend (SEASON_ID,
seasonFile(), SEASON_GAMES, SEASON_START_DATE).Both roll over on July 1, the start of the NHL league year, so offseason runs already point at the new season's (still empty) files. At rollover, fold the finished season into the historical training files:
cd pipeline
python3 tools/archive_season.py
It defaults to the previous season and is safe to re-run. Last season's
season CSVs stay in pipeline/ as the archive; never delete them.
Requirements: Node 20+, Python 3.11+.
npm ci
npm run dev
The dev server runs at http://localhost:3000 and reads the committed data files, so no pipeline run is needed to work on the UI.
Pipeline (run from pipeline/, because scripts use paths relative to it):
pip install -r requirements.txt
cd pipeline
python3 fetch_upcoming.py
python3 fetch_odds.py
python3 predict_games.py
That is the core of the hourly lite run. The daily full refresh is
python3 refresh_pipeline.py from pipeline/ (scrape, re-score every shot,
ratings, player impact, predictions, history, simulation); it takes several
minutes and rewrites many committed files, so review git status before
committing anything it produces.
Retraining (from pipeline/): python3 xg_model.py rebuilds the shot model
(xg_model_xgb.pkl); python3 train_game_model.py rebuilds the game model
(game_model.pkl); python3 tools/backtest_model.py backtests it.
.github/workflows/update_data.yml runs hourly from 12:00 to 02:00 UTC.
Runs that start between 12:00 and 14:59
UTC do the full refresh; the rest do the lite update. It then commits the
changed data files to main, which triggers a Vercel deploy. Secrets:
DB_HOST, DB_USER, DB_PASSWORD (optionally DB_NAME, DB_PORT) for the
optional Supabase sync, and VERCEL_DEPLOY_HOOK. Nothing else needs
credentials: every data source is free and public.
npx tsc --noEmit
npm run lint
npm run build
npm run test:e2e
python3 scripts/check_doc_commands.py
test:e2e runs the Playwright specs in tests/ (it starts the dev server
on port 3000 itself; install browsers once with npx playwright install). check_doc_commands.py checks that every command in the README and
CLAUDE.md code blocks still points at real scripts and files.
Data: NHL (api-web.nhle.com, api.nhle.com), MoneyPuck.com (player data;
credit required by their terms), DailyFaceoff (lines, starting goalies) and
public sportsbook feeds for odds. Sources that were tried and do not work
from a headless runner or on a free tier are listed in CLAUDE.md.