# NHL Game Pages

A page for every NHL game on file. The score by period, every goal in order, the three stars, the full box score for both clubs, the goaltending lines, and the team totals for shots, hits, blocks, penalty minutes, giveaways and takeaways.

**One route, not a thousand pages.** A static page per game would be 1,312 files in a regular season, and this site deploys under a hard 20,000-file ceiling. So `/games/` is a single shell that reads `?id={gameId}` and fetches exactly one small file: `data/games/{season}/{gameId}.json`. A reader on a phone downloads the game asked for and nothing else. The nights on file, and the prev/next rail that walks between them, come from `data/games/index.json`.

**Where the figures come from.** Four official endpoints, no key and no scraping: `api-web.nhle.com/v1/score/{date}` for the slate, and `gamecenter/{gameId}/landing`, `gamecenter/{gameId}/boxscore` and `gamecenter/{gameId}/right-rail` for the game itself. Scorer, assists, clock and strength are the league's own fields. The period-by-period line and the team totals are the right rail's. The three stars are the league's, and no star is chosen here.

**Missing is absent, never zero.** A figure the NHL did not publish for a game is omitted from the file rather than written as a zero, and the page prints "not filed" in that cell. A zero on this page is a zero the league printed. A game with no boxscore yet says so plainly instead of showing an empty table dressed as data.

**Replay clips are the league's own.** Where the NHL published a highlight for a goal, its `highlightClipSharingUrl` rides on the goal and the page links to it on nhl.com. No video is hosted or re-encoded here. The `ppt-replay` endpoint answers for a goal but publishes no clip URL, so it is not used.

**There is no written account.** The NHL endpoint named `wsc/game-story` carries a second structured box and no prose. Rather than write a recap and pass it off as reporting, the page prints the box and says there is no account. The builder still checks the field on every run, so the day the league starts publishing one it appears, credited.

**No rating, no composite.** The shot, hit and block ledger draws each pair of team totals to one shared scale, so a longer bar means a larger count and nothing else. Giveaways are printed plainly, because a giveaway count is not a verdict. Mint and coral appear only where they carry meaning: a power-play goal and a shorthanded goal on the period strip, and a win or loss on a goaltender's decision.

**Before the game, the same page is a preview.** A scheduled game carries `state: "preview"` and a `preview` block in the same file under the same id. `/games/?id=` then renders the pre-game state. The all-time series between the two clubs is drawn as one split bar with the last meeting on it. Beside that sit the probable goaltenders with their last ten starts and their share of the club's starts, the top line and first power play from the lineup files, and who is out and in whose words. Below: the streaks in play with the season they belong to, the league's leader block, the two clubs on the rates the league publishes, and the seven days of schedule each club just came through. When the league files the final, the nightly builder overwrites that same file and the page becomes the box score on its own.

**A projection is labelled as one, and nothing is a bet.** A probable starter and a top line are a lineup source's projection, printed with that source and the date it last moved. There is no odds line, no win probability, no projected score and no betting language of any kind on this route, before a game or after it. What the league does not publish before a game is simply not written: the pre-game feed carries no `seasonSeries` record and no `teamLeaders` block, and no last-ten club record, so none appear.

Scheduled dates live under `upcoming` in `data/games/index.json` and in `data/games/upcoming.json`, never under `dates`, which is the record of nights played.

Every player name links to that player's file and every club links to its club file. Built by `python scripts/build-games.py` for played games and `python scripts/build-previews.py --date YYYY-MM-DD --next 7` for the week ahead.
