Won & deservedWon, out-chancedLost, out-chancedLost, outplayed opp
GAME —
Drag the playhead (or range handles in Season) · ◀ ▶ step · Space to play · Click panels to drill down
How this dashboard works
Formulas · Caveats · Honesty lines
Design principles
Every signal on this dashboard is built to answer the same coach's question: what is my team actually doing well or badly, separated from what the score says? The score conflates process, luck, and finishing. These metrics try to keep them apart.
Two rules the whole tool follows:
Impact and hotness are separate. A team or player can be good and cold, or mediocre and hot. Merging them recreates the score trap.
Labels tell the truth about what's underneath. When the data doesn't support "impact," the label says "scoring output" or "reference — not rated" instead. Different leagues get different metrics if their data cuts differently — we don't force one number when the data means two things.
Time windows
Two modes control what "recent" means:
Game mode — a point-in-time view after game N. The primary window (L5, L10, or L20) is a rolling average of the last N games ending at the playhead.
Season mode — the two handles on the scrubber define a range. All stats are aggregated over that range, no rolling window.
The playhead drags left/right and shows the state of the team as of that game. There is no future data — everything is what you would have known at the time.
Situational hero (top strip)
Four level-1 signals, always shown for the primary window:
Positive = scoring above expected (regression risk). States: RUNNING HOT (≥ +0.4), ON EXPECTED, SNAKEBITTEN (≤ −0.4).
Honesty: "Running hot" is a warning, not a compliment. Shooting % above expected is unsustainable — the goals slow down, not the process.
Goaltending
GSAx = avg(xGA − GA) per game
Positive = goalies saving more than shot quality warranted. States: STEALING GAMES (≥ +0.5), STEADY, LEAKING (≤ −0.5).
Trend
Trend = L5 xGΔ − L20 xGΔ
States: RISING (≥ +0.25), HOLDING, SLIDING (≤ −0.25). Early signal that the underlying play is shifting.
Signal panels
Chance Creation
both leagues
xGΔ/g = avg(xGF − xGA)
Same as the hero metric, with a full read + sparkline. The panel that most predicts future scoreline — if you're winning on chances, points follow.
Finishing
both leagues
Finishing = avg(GF − xGF)
High = regression risk. Low = due positive. Don't confuse hot finishing with skill.
Goaltending
both leagues
GSAx = avg(xGA − GA)
Isolates the goalie's contribution from the defense in front of them. Positive means the crease is helping.
Honesty: Approximate — assumes the shots faced were of average quality for the game. Slightly misranks a goalie who faced unusually easy or hard shot distributions.
Season Points Pace
both leagues
pts/g = total points / games played
Compared to the live playoff cut — the current pts/g of the team occupying the last playoff spot in the league as of the playhead date.
League
Playoff rank
How the cut is computed
NHL
Top 16 of 32
Team currently at #16 in the standings, using only games played on or before the playhead date. No future data.
Liiga
Top 10 of 15
Team currently at #10 in the standings, using only games played on or before the playhead date. No future data.
If no standings snapshot is available for the current date (e.g. very early in the season), the historical fallback is used:
NHL fallback: 1.11 pts/g (2024-25 UTA at #16)
Liiga fallback: 1.35 pts/g (2024-25 Sport at #10)
Honesty: Early in the season, the live cut is noisy — a couple of leaders skew things. It settles toward historical values as more games are played. Teams with under 3 GP are excluded from the ranking to reduce the noise. Read the cut as "the current bar to clear," not as a prediction.
Power Play
LiigaNHL
Liiga:PP% = PPG / opportunities × 100
Baseline: ~20% (Liiga league average). Flag thresholds: above 22% "above avg", below 15% "below avg".
NHL:PP xG/g = avg(PP xG for) over window
Computed from nhl_shots where strength_state ∈ {5v4, 5v3, 4v3} and the shooting team is us. Baseline: 0.4 xG/g (rough NHL norm).
Honesty: NHL PP is chance-based, not efficiency-based — opportunities (PP count) isn't cleanly available. PIM ÷ 2 overcounts because of majors, misconducts, and coincidental penalties, so we don't report PP%. We report the honest question: "is the PP creating chances?"
Small samples: PP% needs ~30+ opportunities before it stabilizes. Same regression discipline as finishing luck — a hot PP will cool.
Penalty Kill
LiigaNHL
Liiga:PK% = (1 − PPGA / PKs) × 100
Baseline: ~80% (Liiga league norm).
NHL:PK xGA/g = avg(PP xG against) over window
Same shot filter as PP but the shooting team is the opponent. Baseline: 0.5 xGA/g.
Honesty: "Bleeding chances" and "leaking goals" are different problems. NHL panel catches the former; Liiga panel catches the latter. Read them for what they are.
Alert feed
Ranked crit → watch → info → ok. Fired only when the metric crosses honest thresholds and the sample supports it. Common triggers:
Goaltending down to ≤ −0.5 GSAx/g — the crease is where the points are going
Being out-chanced ≤ −0.3 xGΔ/g — the process is losing before puck luck enters
Provisional sample — under 10 GP, signals are directional
Roster (left column)
Per-position, per-league metric families. Rate what the data can rate; refuse to rank what it can't.
Goalies
both leagues
GSAx/game = (team_xGA × goalie_seconds/3600) − GA
Impact ranking. Hotness = z-score of last 5 appearances vs season baseline. Gate: ≥5 appearances and ≥150 minutes.
Honesty: GSAx approximates shots faced as average game quality — it isolates the goalie from team defense better than save% or wins, but it's an estimate, not shot-by-shot.
Forwards
NHL
Impact: ixG/game = sum(per-shot xG) / games
Hotness: z-score of (goals − ixG) over L5 vs season baseline
Honesty: Ranks chance generation, not two-way play or defense. Without ice-time or on-ice data, a forward's defensive value is invisible here. Finishing luck flags likely regression — ▲▲ "running hot" is a warning, not a compliment.
Forwards
Liiga
Scoring output: pts/game = (G + A) / games
Hotness: z-score of pts over L5 vs season baseline
Label is "scoring output," not "impact" — the data doesn't support impact claims. Gate: ≥10 games.
Honesty: Ranks raw scoring only. No xG or ice-time available — this does not measure chance quality, defense, or two-way play, and undersells defensive forwards. A hot streak here may be finishing luck the data can't separate.
Defencemen
both leagues
Not ranked. Shown for reference only, in a muted row with G/A/±.
Honesty: Their primary job — suppressing chances against — is invisible without on-ice data. Points miss ~80% of what a defenceman does. +/− is team-context noise (a good D on a bad team looks terrible). Ranking on these would mislead. A coach knows their D better than +/− does.
Hotness (z-score) semantics
Hotness ≠ impact. It's how far the player is from their own recent baseline, not from the league. Formula:
z = (mean_of_last_5_appearances − season_mean) / season_stdev
Requires ≥3 recent appearances and a baseline std > 0. Below thresholds → "provisional."
Goalies — green (hot = stealing games) / cold (leaking)
NHL forwards — amber for +z (regression risk, not "good") / cold-blue for −z (due positive). The hotness metric is finishing luck.
Liiga forwards — neutral hot/cold (metric is points, no finishing-luck separation available)
Scrubber timeline (bottom)
Every game as a bar. Color = combined result and process:
Won & out-chanced opponentWon but got out-chancedLost & got out-chancedLost but out-chanced opp
Bar height = |xGΔ| for that game. Above baseline = out-chanced; below = out-chanced against. Amber wins and cold losses are the honesty signal — result diverged from process.
What the data can't see
Cross-cutting caveats that apply to every metric on this dashboard:
No shift/on-ice data — we can't compute real on-ice xG differential per player, so a forward's defense and a defenceman's suppression are invisible.
No skater time-on-ice — no per-60 rate stats. Volume is compared per-game, which conflates a top-line minute-eater with a fourth-liner.
Individual xG is NHL only — Liiga forwards get raw points, honestly labeled as scoring output.
PP opportunities are NHL-invisible — we use chance-based PP xG for NHL instead of PP%, avoiding a known-wrong estimate.
Sample size gates everything — early-season and small-window signals are directional, not confident. The dashboard shows the sample size next to hotness for exactly this reason.
When you don't see a caveat here, it's not because we've solved the problem — it's because we've chosen a metric that doesn't need one.