# Ice Lab: NHL regular-season query interface (2009–10 to 2026–27) Ice Lab answers questions about every NHL regular season from 2009–10 to 2026–27 (shootouts excluded from all shot and goal counts). Each query covers the seasons named in `seasons` (default: 2025–26, the most recent completed season); over several seasons, grouped totals are exact and listed rows carry a `season` column. Queries are JSON trees of blocks. POST them to /api/run to get rows, or to /api/link to validate and get a share link. A human guide with fourteen worked steps is at https://localhost:8080/query/guide. ## Building a query and a link for a user 1. Pick the seasons: `seasons: [20232024, 20242025]` (each also accepted as "2024-25", "2024/25" or 2024, the year it starts; a single `season` works too). Without any, the query runs on 2025–26. Over several seasons, group or rank rather than listing every event: each season is worked out in turn (a few seconds per season the first time), and an answer may hold at most 300,000 rows. Group by `season` for one row per season. 2. Pick the root entity: the thing the user wants rows of (teams, players, games, goals, shots…). Add conditions to it, and child blocks (via relations) for related things that must, may or must never exist. 3. Add clauses if needed: `grouping` (totals per group), `keep` (filter after grouping), `once` (one row per game), `ranking` (top or bottom N). 4. Validate it: `GET https://localhost:8080/api/link?q=` returns the normalised query, a plain-English sentence, the row count and two links. Check the sentence says what the user asked; fix and retry on an error. 5. Give the user `readableLink` (or `link`, which is shorter). You can also build the link yourself: `https://localhost:8080/query?q=` + encodeURIComponent(JSON.stringify({ q: , view: })). It opens the builder with the query loaded and run; the user can change it from there. 6. Prefer starting from the closest step or recipe below and changing it. Use only property keys, relation ids and operator names listed in this file. ## Seasons - `20092010` (2009–10): 1,230 games; no shift charts, so no on-ice, line, pair or shift data; 30 games miss a goal in the NHL's play-by-play (results use the official score). - `20102011` (2010–11): 1,230 games. - `20112012` (2011–12): 1,230 games. - `20122013` (2012–13): 720 games; 48-game season (lockout). - `20132014` (2013–14): 1,230 games. - `20142015` (2014–15): 1,230 games. - `20152016` (2015–16): 1,230 games. - `20162017` (2016–17): 1,230 games. - `20172018` (2017–18): 1,271 games. - `20182019` (2018–19): 1,271 games. - `20192020` (2019–20): 1,082 games; season stopped in March 2020 (teams played 68 to 71 games); about 15% of games lack usable shift charts. - `20202021` (2020–21): 868 games; 56-game season with temporary divisions and no conferences; about 11% of games lack usable shift charts. - `20212022` (2021–22): 1,312 games. - `20222023` (2022–23): 1,312 games. - `20232024` (2023–24): 1,312 games. - `20242025` (2024–25): 1,312 games. - `20252026` (2025–26): 1,312 games. - `20262027` (2026–27): 52 games, in progress. - Shift charts (on-ice, lines, pairs, shifts) from 2010–11. - EDGE tracking (skating speed, shot speed, distance) from 2021–22. - Teams: Atlanta Thrashers to 2010–11 (then Winnipeg Jets); Phoenix Coyotes to 2013–14, Arizona Coyotes 2014–15 to 2023–24, Utah from 2024–25; Vegas from 2017–18; Seattle from 2021–22. - Wild cards from 2013–14. Teams play 82 games up to 2025–26 (except 2012–13, 2019–20 and 2020–21) and 84 from 2026–27. ## Endpoints - `POST /api/run { query, view?, page?, pageSize?, drill?, chart? }` → rows, columns (labels, types), total, notes, per-row entity refs, available columns. `chart: true` returns the whole answer. - `GET /api/link?q=` or `POST /api/link { query, view? }` → normalised query, sentence, outline, row count, share links. Dangling column refs are an error. - Share links: `/query?q=` (readable), `?s=1…` (deflate) or `?s=j…` (base64 JSON). ## Query shape ```ts Query { v: 1; seasons?: number[] /* e.g. [20232024, 20242025] */; root: Block; grouping?: { by: string[]; measures: Measure[]; having?: Condition[] }; ranking?: { column; dir: 'desc'|'asc'; n; per?: string[]; ties?: boolean }; keep?: Condition[]; once?: boolean } Block { id; entity; relation (null for the root); mode?: 'required'|'optional'|'without'; join?: 'and'|'or'; items: (Condition|ConditionGroup)[]; shown?: boolean; children: Block[]; childJoin?; streak?: StreakSpec; alias?; label? } Condition { property; op; value } ConditionGroup { kind: 'group'; join; items: Condition[] } Measure { id; fn: 'count'|'countWhere'|'countDistinct'|'sum'|'avg'|'max'|'min'|'first'|'last'|'calc'|'rate'; column?; where?; a?; b?; op?; toiColumn?; label? } StreakSpec { over: 'games'; condition; conditionItems; scope: 'all'|'home'|'away'|'division'|'conference'|'custom'; scopeItems; keep: { kind: 'recent'|'longest'; n } | null } ``` Column refs are `.`; measures are `m.` (so no block may have id `m`); `season` is the season a row or group comes from. Missing ids, joins and flags are filled in; a bare root block is accepted. ## Engine rules - Blocks are existence checks: a child block narrows its parent and never multiplies rows unless it is the block being listed. - The row is the deepest shown block (first in canvas order on a tie). Hidden blocks only filter. `without` blocks (never) can't be shown. - Team in focus: a game reached via `team → played → game` is seen from that team's side, which unlocks team-relative properties (result, goalsFor, opponent…). A root game using such a property is tried from both sides; `once: true` keeps one row per game (winner's view first) and results report `repeats`. - Strength is relative: `strength = 5v4` on a shot means the shooting team had the advantage. - Aliases compare within one row: `{ property: 'self', op: 'is', value: { alias: 'A' } }` or `value: { alias: 'A', prop: 'gameSec' }`. - Clauses run in order: rows → grouping (measures, calc, having) → keep → once → ranking (per, ties; empties last) → sort → paging (≤ 500 per page). - `rate` measures: sum(column) ÷ sum(toiColumn) × 60, with TOI in decimal minutes. - Text compares ignore case and accents. Missing values fail numeric and date tests (never treated as 0). Incomplete conditions are ignored. - Relative dates (`inLastN`) are anchored to the season's last regular-season date, not today. `inMonth` takes `YYYY-MM` or a month name. - Head-to-head = a root game with two hidden `playedBy` team children. To filter an opponent under a focused game, use `playedAgainst`. - 'Never' questions: negate the block that must not exist (`mode: 'without'`) and exclude the subject itself where needed. - Traded players: `player → playedFor → team` can return several teams; group by the appearance's team to split by club. - `player` roots include goalies; add `positionGroup` conditions (or the Skaters / Goalies shortcuts) for leaderboards. ## Entities - `team` (Teams): One club (30 to 32 of them, depending on the season), with its record and team statistics for the season queried. - `game` (Games): One regular-season game. Reached from a team, it is seen from that team's side (result, goals for, opponent…). - `period` (Periods): One period of one game (1, 2, 3 or OT), with goals and shots in it. - `player` (Players): One person, skater or goalie, across every team they played for in the season queried. - `appearance` (Appearances): One player in one game: ice time, points, shots, and for goalies saves and goals saved above expected. - `shot` (Shot attempts): One shot attempt outside the shootout: a goal, a save, a miss or a block, with its location and expected-goal value. - `goal` (Goals): One goal outside the shootout, with scorer, assists, strength and who was on the ice. - `penalty` (Penalties): One penalty: the infraction, who took it, who drew it and whether a power-play goal followed. - `faceoff` (Faceoffs): One faceoff: the dot, the winner and what the winning side made of it in the next 20 seconds. - `hit` (Hits): One recorded hit. - `turnover` (Turnovers): One giveaway or takeaway. - `unit` (Lines and pairs): A forward line (three forwards) or defence pair (two defencemen) at 5-on-5. A defenceman used at forward still counts as a defenceman. - `shift` (Shifts, not a root): One shift by one player: when it started, how long it lasted, and whether a goal happened during it. - `streak` (Streaks, not a root): A run of consecutive games: a team's wins or point streak, a player's scoring streak, a goalie's run of wins. Reached from a team or a player. ## Operators - text: `contains` (contains), `startsWith` (starts with), `is` (is) - ref: `is` (is), `isNot` (is not), `isAnyOf` (is any of) - refMulti: `includes` (includes), `includesAnyOf` (includes any of) - enum: `is` (is), `isNot` (is not), `isAnyOf` (is any of) - number: `gt` (>), `gte` (≥), `lt` (<), `lte` (≤), `eq` (=), `ne` (≠), `between` (between) - date: `after` (after), `before` (before), `on` (on), `between` (between), `inMonth` (in month), `inLastN` (in the last) - bool: `is` (is) - tri: `is` (is), `isUnknown` (is unknown) ## Relations (child block `relation` ids) - `played`: team → game. Games the team played, seen from its side: result, goals for, opponent and the rest become available. - `wasOpponentIn`: team → game. Games the team played, seen from its opponent's side. - `hasStreak`: team → streak. Runs of wins, points, shutouts and more. - `hadPlayer`: team → player. Everyone who appeared for the team. - `teamHadAppearance`: team → appearance. Every player-game for the team. - `teamTook`: team → shot. Every shot attempt by the team. - `teamScored`: team → goal. Goals by the team. - `teamConceded`: team → goal. Goals against the team. - `wasCalledFor`: team → penalty. Penalties against the team. - `teamDrew`: team → penalty. Penalties called on its opponents. - `iced`: team → unit. The team's 5-on-5 units. Needs shift data. - `playedBy`: game → team. Either team. Two hidden 'played by' children make a head-to-head. - `playedAgainst`: game → team. The opponent of the team in focus. Needs a team in focus. - `fromSideOf`: game → team. See the game from this team's side. Needs a team in focus. - `gameHadShot`: game → shot. Every shot attempt in the game. - `theyTook`: game → shot. Shot attempts by the team in focus. Needs a team in focus. - `theyAllowed`: game → shot. Shot attempts against the team in focus. Needs a team in focus. - `gameHadGoal`: game → goal. Every goal in the game. - `theyScored`: game → goal. Goals by the team in focus. Needs a team in focus. - `theyConceded`: game → goal. Goals against the team in focus. Needs a team in focus. - `gameHadPenalty`: game → penalty. Every penalty in the game. - `gameHadFaceoff`: game → faceoff. Every faceoff (keeps the team in focus). - `gameHadHit`: game → hit. Every hit (keeps the team in focus). - `gameHadTurnover`: game → turnover. Every giveaway and takeaway (keeps the team in focus). - `gameHadAppearance`: game → appearance. Players who appeared (the team in focus's side if there is one). - `hadInLineup`: game → player. Players who appeared for either team. - `hadPeriod`: game → period. Each period (keeps the team in focus). - `followedBy`: game → game. The team in focus's next game. Needs a team in focus. - `cameAfter`: game → game. The team in focus's previous game. Needs a team in focus. - `used`: game → unit. Forward lines and defence pairs that played in the game (the team in focus's, if there is one). Needs shift data. - `periodWasIn`: period → game. The game (keeps the team in focus). - `playedIn`: player → game. Games they appeared in, seen from their team's side. - `startedGame`: player → game. Games they started (goalies), from their team's side. - `playedFor`: player → team. Every team they appeared for this season. - `made`: player → appearance. Every game they played: ice time, points, shots and more. - `playerTook`: player → shot. Their shot attempts. - `faced`: player → shot. Unblocked shots faced as the goalie in net. - `blocked`: player → shot. Opponents' shots they blocked. - `playerScored`: player → goal. Goals they scored. - `assistedOn`: player → goal. Goals with their first or second assist. - `allowed`: player → goal. Goals scored against them as the goalie in net. - `wasOnIceFor`: player → goal. Their team's goals while they were on the ice. Needs shift data. - `wasOnIceAgainst`: player → goal. Goals against their team while they were on the ice. Needs shift data. - `tookPenalty`: player → penalty. Penalties they committed. - `drew`: player → penalty. Penalties they drew. - `won`: player → faceoff. Faceoffs they won (seen from their team's side). - `lost`: player → faceoff. Faceoffs they lost (seen from their team's side). - `delivered`: player → hit. Hits by them. - `received`: player → hit. Hits on them. - `committed`: player → turnover. Their giveaways and takeaways. - `playedAlongside`: player → player. Teammates they shared 5-on-5 ice with (unlocks the pair's shared minutes and xGF%). Needs shift data. - `playedAgainstPlayer`: player → player. Opponents they faced for at least 5 minutes at 5-on-5. Needs shift data. - `playedOn`: player → unit. Forward lines or defence pairs including them. Needs shift data. - `hasRun`: player → streak. Scoring streaks, runs of appearances, a goalie's runs of wins or starts. - `hadShift`: player → shift. Every shift they took. - `wasScoredIn`: goal → game. The game, seen from the scoring team's side. - `goalCameIn`: goal → game. The game, with no side in focus. - `countedFor`: goal → team. The scoring team. - `wasAgainst`: goal → team. The team that conceded. - `wasScoredBy`: goal → player. The goal scorer. - `wasAssistedBy`: goal → player. Players with the first or second assist. - `hadOnIceFor`: goal → player. The scoring team's players on the ice (skaters and goalie). Needs shift data. - `hadOnIceAgainst`: goal → player. The conceding team's players on the ice. Needs shift data. - `cameFrom`: goal → shot. The shot attempt that became the goal. - `wasTakenIn`: shot → game. The game, seen from the shooting team's side. - `wasTakenBy`: shot → player. The shooter. - `wasFacedBy`: shot → player. The goalie in net (none for empty nets and blocked shots). - `wasBlockedBy`: shot → player. The player who blocked it. - `wasTakenFor`: shot → team. The shooting team. - `became`: shot → goal. The goal, if it went in. - `penaltyWasIn`: penalty → game. The game, seen from the penalised team's side. - `wasCommittedBy`: penalty → player. The player called for it. - `wasDrawnBy`: penalty → player. The player who drew it. - `wasCalledOn`: penalty → team. The penalised team. - `ledTo`: penalty → goal. The power-play goal scored while it was being served. - `faceoffWasIn`: faceoff → game. The game (keeps the team in focus). - `wasWonBy`: faceoff → player. The player who won the draw. - `wasLostBy`: faceoff → player. The player who lost the draw. - `hitWasIn`: hit → game. The game (keeps the team in focus). - `wasDeliveredBy`: hit → player. The player who made the hit. - `wasReceivedBy`: hit → player. The player who was hit. - `turnoverWasIn`: turnover → game. The game (keeps the team in focus). - `wasCommittedByPlayer`: turnover → player. The player credited with it. - `wasMadeBy`: appearance → player. The player. - `appearanceWasIn`: appearance → game. The game, seen from the player's team's side. - `wasFor`: appearance → team. The team they played for. - `appearanceHadShift`: appearance → shift. The player's shifts in this game. - `includes`: unit → player. The players in the line or pair. - `wasIcedBy`: unit → team. The team. - `unitPlayedIn`: unit → game. Games in which the unit was on the ice together, seen from its team's side. - `wasTakenByPlayer`: shift → player. The player. - `shiftWasIn`: shift → game. The game, seen from the player's team's side. - `shiftWasFor`: shift → team. The player's team. - `contains`: streak → game. The games in the run, from the team's side. ## Properties ### team - `name` (ref): The team's full name, e.g. Colorado Avalanche. - `abbrev` (text): Three-letter code, e.g. COL. - `conference` (enum: Eastern | Western): Conference - `division` (enum: Atlantic | Metropolitan | Central | Pacific): Division - `gp` (number): Games played - `wins` (number): Games won, in regulation, overtime or a shootout. - `losses` (number): Games lost in regulation time. - `otLosses` (number): Losses after regulation. They still earn a point. - `points` (number): Standings points: 2 for any win, 1 for a loss after regulation. - `pointPct` (number, %): Share of the available points a team collected. - `regWins` (number): Wins decided in the first 60 minutes. The first standings tie-breaker. - `regOtWins` (number): Wins that didn't need a shootout. - `goalsFor` (number): Goals scored, excluding the shootout. - `goalsAgainst` (number): Goals conceded, excluding the shootout. - `goalDiff` (number): Goals for minus goals against, excluding shootouts. - `leagueRank` (number): Final position in the league table (1 = first). - `conferenceRank` (number): Conference rank - `divisionRank` (number): Division rank - `madePlayoffs` (bool): Qualified for that season's playoffs (from the final standings). - `ppPct` (number, %): How often a power play produced a goal. - `pkPct` (number, %): How often the team killed a penalty without conceding. - `foPct` (number, %): Share of faceoffs won. - `shotsForPerGame` (number): Shots for per game - `shotsAgainstPerGame` (number): Shots against per game - `cfPct5v5` (number, %): Share of all shot attempts (on goal, missed or blocked) at 5-on-5 that went the team's way while the player was on the ice. A proxy for puck possession. - `xgfPct5v5` (number, %): Share of the 5-on-5 expected goals that went the team's way. Above 50% means creating better chances than allowing: the single best summary of territorial control. - `xgfPct5v5Adj` (number, %): xGF% after correcting for score and venue: trailing teams push and leading teams sit back, which distorts raw shares. - `pdo5v5` (number): On-ice shooting percentage plus save percentage at 5-on-5, on a 1000 scale. Far above 1000 usually means good luck that tends not to last. - `finishing5v5` (number): Goals scored minus expected goals at 5-on-5. Positive means the team converted chances better than average. - `goaltending5v5` (number): Expected goals against minus goals against at 5-on-5. Positive means the goalies stopped more than expected. - `gsax` (number): Expected goals faced minus goals allowed. Positive means the goalie stopped more than an average goalie would have, given the quality of shots. Empty-net and shootout shots are excluded. - `expectedPoints` (number): Standings points a team would expect from its shot quality alone: every game is replayed 10,000 times with each shot scoring at its xG. - `pointsAboveExpected` (number): Actual points minus expected points. Positive means results ran ahead of the underlying play. - `points3210` (number): Standings if a regulation win were worth 3 points, an overtime or shootout win 2, and an overtime or shootout loss 1. - `points20` (number): Standings if every win were worth 2 and every loss 0. - `lineBlender` (number): How much the coaching staff mixed the forward lines. 0 means one trio played every 5-on-5 minute; values near 1 mean constant shuffling. - `travelKm` (number, km): Distance travelled between arenas over the season. - `backToBacks` (number): Games played on the second of consecutive nights. ### game - `label` (text, column only): Away @ home, with the date. - `date` (date): Date - `month` (enum: October | November | December | January | February | March | April): Month - `dayOfWeek` (enum: Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday): Day of the week - `homeTeam` (ref): Home team - `awayTeam` (ref): Away team - `venue` (ref): Venue - `venueType` (enum: standard | neutral | outdoor): Neutral-site (Global Series) and outdoor games are flagged. - `decidedIn` (enum: REG | OT | SO): Regulation, overtime or shootout. - `totalGoals` (number): Goals by both teams, not counting the shootout. - `margin` (number): Goal difference at the end, not counting the shootout. - `score` (text, column only): Final score, away first. - `totalShots` (number): Total shots on goal - `totalXg` (number): How many goals an average shooter would score from these chances. Each unblocked shot gets a probability based on distance, angle, shot type, rebounds, rushes and game state; xG adds them up. - `leadChanges` (number): Lead changes - `winnerTrailed` (bool): The eventual winner was behind at some point. - `winnerMaxDeficit` (number): Winner's biggest deficit - `excitement` (number): How exciting the game was, from 0 to 100: the share of games since 2009/10 it beat. It blends three things: how much the win probability swung, how many goals came while the game was in reach, and the biggest lead that was clawed back. Standing out on any one of them scores high; blowouts score low. - `comebackIndex` (number, %): The lowest win probability the eventual winner had. Low means a big comeback. - `emptyNetGoals` (number): Empty-net goals - `fightingMajors` (number): Fighting majors - `pimTotal` (number): Penalty minutes (both teams) - `ppGoalsBoth` (number): Power-play goals (both teams) - `shiftsKnown` (bool): The NHL's shift charts for this game are complete, so on-ice figures are available. - `team` (ref, team in focus): The team whose side the game is seen from. - `opponent` (ref, team in focus): Opponent - `ground` (enum: Home | Away, team in focus): Home or away - `result` (enum: Win | Loss, team in focus): Result - `resultDetail` (enum: W | OTW | SOW | L | OTL | SOL, team in focus): W and L are regulation; OT and SO mark overtime and shootout results. - `pointsEarned` (number, team in focus): Standings points earned - `gameNumber` (number, team in focus): 1 to 82 for this team. - `goalsFor` (number, team in focus): Goals for - `goalsAgainst` (number, team in focus): Goals against - `goalDiff` (number, team in focus): Goal difference - `scoredFirst` (tri, team in focus): Unknown in a 0–0 game. - `stateAfterP1` (enum: Lead | Tied | Trail, team in focus): After the 1st - `stateAfterP2` (enum: Lead | Tied | Trail, team in focus): After the 2nd - `diffAfterP1` (number, team in focus): Goal difference after the 1st - `diffAfterP2` (number, team in focus): Goal difference after the 2nd - `maxLead` (number, team in focus): Biggest lead - `maxDeficit` (number, team in focus): Biggest deficit - `blewLead` (bool, team in focus): Led by two or more and lost. - `shotsFor` (number, team in focus): Shots for - `shotsAgainst` (number, team in focus): Shots against - `shotDiff` (number, team in focus): Shot difference - `cfPct` (number, %, team in focus): Share of all shot attempts, all situations. - `xgFor` (number, team in focus): Expected goals created by a team, or by a player's team while they were on the ice. - `xgAgainst` (number, team in focus): Expected goals allowed. - `xgDiff` (number, team in focus): Expected goal difference - `xgfPct5v5` (number, %, team in focus): Share of the 5-on-5 expected goals that went the team's way. Above 50% means creating better chances than allowing: the single best summary of territorial control. - `simWinPct` (number, %, team in focus): How often this team wins the game when every shot is replayed 10,000 times at its xG. - `minWinProb` (number, %, team in focus): The team's lowest win probability during the game. - `wonDespiteXg` (bool, team in focus): Won despite lower xG - `ppOpps` (number, team in focus): Power-play opportunities - `ppGoals` (number, team in focus): Power-play goals - `shGoals` (number, team in focus): Shorthanded goals - `ppGoalsAgainst` (number, team in focus): Power-play goals against - `pim` (number, team in focus): Penalty minutes - `hits` (number, team in focus): Hits - `blocks` (number, team in focus): Blocked shots - `giveaways` (number, team in focus): Giveaways - `takeaways` (number, team in focus): Takeaways - `foPct` (number, %, team in focus): Faceoff % - `startingGoalie` (ref, team in focus): Starting goalie - `goaliePulled` (bool, team in focus): Sent out an extra attacker while trailing late. - `pullSecondsLeft` (number, s, team in focus): Seconds left at the pull - `restDays` (number, team in focus): Rest days - `oppRestDays` (number, team in focus): Opponent's rest days - `secondOfB2B` (bool, team in focus): Second of a back-to-back - `oppSecondOfB2B` (bool, team in focus): Opponent on a back-to-back - `travelKm` (number, km, team in focus): Travel before the game ### period - `label` (text, column only): Period - `number` (enum: 1 | 2 | 3 | OT): Period - `date` (date): Date - `goals` (number): Goals - `shots` (number): Shots on goal - `goalsFor` (number, team in focus): Goals for - `goalsAgainst` (number, team in focus): Goals against - `shotsFor` (number, team in focus): Shots for - `shotsAgainst` (number, team in focus): Shots against - `xgFor` (number, team in focus): Expected goals created by a team, or by a player's team while they were on the ice. - `xgAgainst` (number, team in focus): Expected goals allowed. - `ppGoals` (number, team in focus): Power-play goals ### player - `name` (text): The player's name. Ignores case and accents. - `position` (enum: C | LW | RW | D | G): Position - `positionGroup` (enum: F | D | G): Forward, defence or goalie. - `shoots` (enum: L | R): Shoots / catches - `age` (number): Age on 1 February of the season queried (1 February 2025 for 2024–25). - `birthCountry` (ref): Birth country - `heightCm` (number, cm): Height - `weightKg` (number, kg): Weight - `draftYear` (number): Draft year - `draftRound` (number): Draft round - `draftOverall` (number): Draft pick (overall) - `undrafted` (bool): Undrafted - `rookie` (bool): Rookie - `teams` (refMulti): Every team the player appeared for in the season queried. - `traded` (bool): Traded during the season - `gp` (number): Games played - `goals` (number): Goals scored, excluding shootouts. - `assists` (number): First and second assists. - `points` (number): Goals plus assists. - `primaryPoints` (number): Goals plus first assists: the points most closely tied to creating the goal. - `ppPoints` (number): Power-play points - `gwg` (number): Game-winning goals - `shots` (number): Shots on goal - `shootingPct` (number, %): Goals per shot on goal. - `toiPerGame` (number, min): Ice time per game - `toi5v5` (number, min): Total minutes at 5-on-5, in decimal minutes. - `plusMinus` (number): Official plus/minus from the NHL boxscore: even-strength and shorthanded goals for, minus against, while on the ice. - `pim` (number): Penalty minutes - `hits` (number): Hits - `blocks` (number): Blocked shots - `giveaways` (number): Giveaways - `takeaways` (number): Takeaways - `foPct` (number, %): Share of faceoffs won. - `ixg` (number): The expected goals from a player's own shots: how many goals their chances were worth. - `gax` (number): Goals minus individual xG. Positive means the player finished better than an average shooter would from the same chances. - `xgBlocked` (number): The expected goals of the shots a player blocked: what those shots would have been worth had they reached the net. The NHL records where a shot was blocked, not where it was taken, so each block is valued from similar unblocked shots taken further out on the same line. - `xgBlocked60` (number): Expected goals blocked per 60 minutes of ice time: how much danger the player removes by blocking shots. - `xgPerBlock` (number): How dangerous the shots a player blocks are, on average. Blocking a one-timer from the slot is worth several point shots through traffic. - `blockShare5v5` (number, %): Of all the danger the opponents created at 5-on-5 with the player on the ice (unblocked xG plus the xG of blocked shots), the share the player blocked personally. - `ixgBlockedPct` (number, %): How much of a player's shooting danger gets blocked. High for players who shoot through traffic from the point; low for players who find clear lanes. - `points60_5v5` (number): Points per 60 (5v5) - `penaltyDiff60` (number): Penalties drawn minus penalties taken, per 60 minutes of ice time. - `cfPct5v5` (number, %): Share of all shot attempts (on goal, missed or blocked) at 5-on-5 that went the team's way while the player was on the ice. A proxy for puck possession. - `xgfPct5v5` (number, %): Share of the 5-on-5 expected goals that went the team's way. Above 50% means creating better chances than allowing: the single best summary of territorial control. - `xgfPct5v5Adj` (number, %): xGF% after correcting for score and venue: trailing teams push and leading teams sit back, which distorts raw shares. - `relXgfPct` (number): How much better the team's expected-goals share was with this player on the ice than off it, in the same games. - `ozsPct` (number, %): Of the player's shifts that began with a faceoff in either end, the share that began in the attacking zone. High numbers mean sheltered, offence-first usage. - `qoc` (number): How important the opponents a player faced were, measured by those opponents' share of their team's 5-on-5 ice time. Higher means tougher minutes. - `qot` (number): The same idea as QoC, for the linemates a player shared the ice with. - `gs` (number): Games started (goalies) - `goalieWins` (number): Wins (goalies) - `svPct` (number): Share of shots on goal the goalie stopped. - `gaa` (number): Goals allowed per 60 minutes played. - `shutouts` (number): Complete games with no goals allowed. - `gsax` (number): Expected goals faced minus goals allowed. Positive means the goalie stopped more than an average goalie would have, given the quality of shots. Empty-net and shootout shots are excluded. - `hdSvPct` (number): Save percentage on shots worth 0.15 xG or more: the hardest chances. - `reboundControl` (number): Rebounds the goalie avoided, per 100 saves, compared with the league rate for the same mix of shots. Positive means fewer second chances than expected. - `topSpeedKmh` (number, km/h): Top skating speed - `maxShotSpeedKmh` (number, km/h): Hardest shot - `distanceSkatedKm` (number, km): Distance skated - `bursts20` (number): Speed bursts over 20 mph - `pair` (text, team in focus): Both names, sorted, so each pair can be grouped once. - `sharedToi5v5` (number, min, team in focus): Shared 5v5 minutes - `sharedGames` (number, team in focus): Games together (5v5) - `pairXgfPct` (number, %, team in focus): Pair xGF% - `pairCfPct` (number, %, team in focus): Pair CF% ### appearance - `label` (text, column only): Appearance - `date` (date): Date - `player` (ref, column only): Player - `team` (ref): Team - `opponent` (ref): Opponent - `position` (enum: C | L | R | D | G): Position - `sweater` (number): Sweater number - `started` (bool): Started - `toi` (number, min): Ice time - `evToi` (number, min): Even-strength ice time - `ppToi` (number, min): Power-play ice time - `shToi` (number, min): Shorthanded ice time - `shifts` (number): Shifts - `avgShiftSec` (number, s): Average shift - `goals` (number): Goals - `assists` (number): Assists - `points` (number): Points - `shots` (number): Shots on goal - `ixg` (number): The expected goals from a player's own shots: how many goals their chances were worth. - `wpa` (number, %): The change in win probability on the goals a player scored or assisted on, added up. Goals that swing close games count most. - `hits` (number): Hits - `blocks` (number): Blocked shots - `pim` (number): Penalty minutes - `plusMinus` (number): Official plus/minus from the NHL boxscore: even-strength and shorthanded goals for, minus against, while on the ice. - `foWins` (number): Faceoffs won - `foPct` (number, %): Faceoff % - `onIceXgf` (number): On-ice xG for (5v5) - `onIceXga` (number): On-ice xG against (5v5) - `onIceXgfPct` (number, %): On-ice xGF% (5v5) - `ozStarts` (number): Offensive-zone starts - `dzStarts` (number): Defensive-zone starts - `shotsAgainst` (number): Shots against (goalies) - `saves` (number): Saves - `svPct` (number): Share of shots on goal the goalie stopped. - `goalsAgainst` (number): Goals against - `xgFaced` (number): xG faced - `gsax` (number): Expected goals faced minus goals allowed. Positive means the goalie stopped more than an average goalie would have, given the quality of shots. Empty-net and shootout shots are excluded. - `decision` (enum: W | L | O): Decision - `pulled` (bool): Replaced by the other goalie during the game. ### shot - `label` (text, column only): Shot - `date` (date): Date - `shooter` (ref, column only): Shooter - `team` (ref): Team - `outcome` (enum: Goal | On net | Missed | Blocked): Outcome - `shotType` (enum: wrist | snap | slap | backhand | tip-in | deflected | wrap-around | bat | poke | between-legs | cradle | other): Shot type - `distance` (number, ft): Distance - `angle` (number, °): Angle - `xg` (number): How many goals an average shooter would score from these chances. Each unblocked shot gets a probability based on distance, angle, shot type, rebounds, rushes and game state; xG adds them up. - `dangerTier` (enum: Low | Medium | High): Low (under 0.05 xG), medium (0.05–0.15) or high (0.15 and up). - `strength` (enum: 5v5 | 5v4 | 4v5 | 4v4 | 3v3 | 5v3 | 3v5 | 4v3 | 3v4 | 6v5 | 5v6 | 6v4 | 4v6 | other): Skaters on the ice, shooting team first: 5v4 means the shooting team was on the power play. - `strengthGroup` (enum: EV | PP | SH): Even strength, power play or shorthanded, for the shooting team. - `isRebound` (bool): Within 3 seconds of the same team's previous unblocked shot. - `isRush` (bool): Within 4 seconds of play in the shooting team's own half of the ice. - `period` (enum: 1 | 2 | 3 | OT): Period - `minute` (number): Minute of the period - `gameSec` (number, s): Seconds since the opening faceoff (overtime starts at 3600). - `scoreState` (number): The shooting team's goal difference at the time, capped at ±2. - `emptyNet` (bool): Empty net - `penaltyShot` (bool): Penalty shot - `missReason` (enum: wide-left | wide-right | above-crossbar | high-and-wide-left | high-and-wide-right | short | hit-left-post | hit-right-post | hit-crossbar | failed-bank-attempt): Miss reason - `secondsAfterFaceoff` (number, s): Time since the most recent faceoff in the game. - `afterFaceoffWin` (tri): The shooting team won the most recent faceoff. - `x` (number, column only): x (ft) - `y` (number, column only): y (ft) ### goal - `label` (text, column only): Goal - `date` (date): Date - `scorer` (ref, column only): Scorer - `team` (ref): Team - `opponent` (ref): Opponent - `strength` (enum: 5v5 | 5v4 | 4v5 | 4v4 | 3v3 | 5v3 | 3v5 | 4v3 | 3v4 | 6v5 | 5v6 | 6v4 | 4v6 | other): Strength - `strengthGroup` (enum: EV | PP | SH): Strength group - `emptyNet` (bool): Empty net - `penaltyShot` (bool): Penalty shot - `gwg` (bool): The NHL definition: the goal that put the winner one ahead of the loser's final total. Never awarded for shootout wins. - `gameTying` (bool): Tied the game - `goAhead` (bool): Go-ahead goal - `firstGoal` (bool): First goal of the game - `unassisted` (bool): Unassisted - `shotType` (enum: wrist | snap | slap | backhand | tip-in | deflected | wrap-around | bat | poke | between-legs | cradle | other): Shot type - `distance` (number, ft): Distance - `xg` (number): How many goals an average shooter would score from these chances. Each unblocked shot gets a probability based on distance, angle, shot type, rebounds, rushes and game state; xG adds them up. - `wpDelta` (number, %): How much the goal changed the scoring team's chance of winning, in percentage points. - `period` (enum: 1 | 2 | 3 | OT): Period - `minute` (number): Minute of the period - `gameSec` (number, s): Game time (seconds) - `secondsAfterFaceoff` (number, s): Seconds after a faceoff - `afterFaceoffWin` (tri): The scoring team won the most recent faceoff. - `scoreAfter` (text, column only): Score after ### penalty - `label` (text, column only): Penalty - `date` (date): Date - `player` (ref, column only): Player - `team` (ref): Team - `infraction` (ref): Infraction - `severity` (enum: minor | double minor | major | misconduct | game misconduct | match | penalty shot | bench minor): Severity - `minutes` (number): Minutes - `period` (enum: 1 | 2 | 3 | OT): Period - `minute` (number): Minute of the period - `zone` (enum: O | N | D): Zone from the penalised team's side. - `ppGoalResulted` (bool): Power-play goal followed - `scoreState` (number): The penalised team's goal difference at the time. ### faceoff - `label` (text, column only): Faceoff - `date` (date): Date - `winner` (ref, column only): Winner - `loser` (ref, column only): Loser - `dot` (enum: centre | oz-left | oz-right | nz-o-left | nz-o-right | nz-d-left | nz-d-right | dz-left | dz-right): Named from the home team's attacking view; with a team in focus, from that team's. - `strength` (enum: 5v5 | 5v4 | 4v5 | 4v4 | 3v3 | 5v3 | 3v5 | 4v3 | 3v4 | 6v5 | 5v6 | 6v4 | 4v6 | other): From the home team's side; with a team in focus, from that team's. - `period` (enum: 1 | 2 | 3 | OT): Period - `gameSec` (number, s): Game time (seconds) - `won` (bool, team in focus): Won - `zone` (enum: O | N | D, team in focus): Zone - `aftermathXgDiff` (number, team in focus): Expected goals for minus against in the 20 seconds after the faceoff (or until the next whistle). ### hit - `label` (text, column only): Hit - `date` (date): Date - `hitter` (ref, column only): Hitter - `period` (enum: 1 | 2 | 3 | OT): Period - `strength` (enum: 5v5 | 5v4 | 4v5 | 4v4 | 3v3 | 5v3 | 3v5 | 4v3 | 3v4 | 6v5 | 5v6 | 6v4 | 4v6 | other): Strength - `zone` (enum: O | N | D, team in focus): Zone ### turnover - `label` (text, column only): Turnover - `date` (date): Date - `player` (ref, column only): Player - `kind` (enum: Giveaway | Takeaway): Kind - `period` (enum: 1 | 2 | 3 | OT): Period - `zone` (enum: O | N | D, team in focus): Zone - `shotAgainstWithin10s` (bool): Shot against within 10 s ### unit - `label` (text, column only): Players - `kind` (enum: Forward line | Defence pair): Kind - `team` (ref): Team - `players` (refMulti): Players - `toi5v5` (number, min): 5v5 ice time together - `games` (number): Games together - `cfPct` (number, %): Share of all shot attempts (on goal, missed or blocked) at 5-on-5 that went the team's way while the player was on the ice. A proxy for puck possession. - `xgfPct` (number, %): Share of the 5-on-5 expected goals that went the team's way. Above 50% means creating better chances than allowing: the single best summary of territorial control. - `goalsFor` (number): Goals for - `goalsAgainst` (number): Goals against - `xgf60` (number): Expected goals created per 60 minutes of 5-on-5 play. - `xga60` (number): Expected goals allowed per 60 minutes of 5-on-5 play. ### shift - `label` (text, column only): Shift - `date` (date): Date - `player` (ref, column only): Player - `durationSec` (number, s): Length - `period` (enum: 1 | 2 | 3 | OT): Period - `startType` (enum: OZ faceoff | NZ faceoff | DZ faceoff | On the fly): Start - `goalFor` (bool): Goal for during the shift - `goalAgainst` (bool): Goal against during the shift ### streak - `label` (text, column only): Streak - `length` (number): Games in the run. - `startDate` (date): Start date - `endDate` (date): End date - `active` (bool): Still going at season's end - `mostRecent` (bool): The latest run among those passing the block's other conditions. - `endedBy` (ref): The opponent in the game that broke the run. - `goalsFor` (number): Goals for - `goalsAgainst` (number): Goals against - `points` (number): Standings points for team runs; scoring points for player runs. - `durationDays` (number, days): Duration ## Streak conditions and scopes - `wins` (team): Consecutive wins of any kind. - `regWins` (team): Consecutive wins inside 60 minutes. - `points` (team, skater): Teams: games earning at least a point (the NHL point streak). Skaters: games with at least one point. - `losses` (team): Consecutive losses of any kind. - `regLosses` (team): Consecutive losses in regulation. - `winless` (team): Consecutive games without a win. - `scoredFirst` (team): Consecutive games scoring the opening goal. - `scored` (team): Consecutive games with at least one goal. - `failedToScore` (team): Consecutive games without a goal. - `shutouts` (team): Consecutive games holding the opponent to no goals (shootout excluded). - `ppGoal` (team): Consecutive games with a power-play goal. - `outshot` (team): Consecutive games with more shots on goal. - `wonXg` (team): Consecutive games with more expected goals. - `appeared` (skater, goalie): Consecutive games of their team that they played in. A trade continues the run if they played the new team's next game. - `goals` (skater): Consecutive appearances with a goal. Missed games neither extend nor break the run. - `assists` (skater): Consecutive appearances with an assist. - `multiPoint` (skater): Consecutive appearances with two or more points. - `starts` (goalie): Consecutive team games started in goal. - `goalieWins` (goalie): Consecutive appearances credited with the win. - `svPct900` (goalie): Consecutive starts with a save percentage of .900 or better. - `custom` (team, skater, goalie): Consecutive games passing your own conditions. - scope `all`: Every game. - scope `home`: Home games only; road games neither extend nor break a run. - scope `away`: Road games only. - scope `division`: Games against division rivals only. - scope `conference`: Games against conference rivals only. - scope `custom`: Only games passing your own conditions. ## Shortcuts - At 5v5 (shot): Five skaters a side with both goalies in. → [{"property":"strength","op":"is","value":"5v5"}] - High-danger shots (shot): Chances worth 0.15 xG or more. → [{"property":"dangerTier","op":"is","value":"High"}] - Close game (game): Decided by one goal or fewer (shootout excluded). → [{"property":"margin","op":"lte","value":1}] - Went to overtime (game): Decided in overtime or a shootout. → [{"property":"decidedIn","op":"isAnyOf","value":["OT","SO"]}] - Back-to-back (game): The second game of consecutive nights. → [{"property":"secondOfB2B","op":"is","value":true}] - Full shift data only (game): Games with complete shift charts, so on-ice figures exist. → [{"property":"shiftsKnown","op":"is","value":true}] - Forwards (player): Centres and wingers. → [{"property":"positionGroup","op":"is","value":"F"}] - Defence (player): Defencemen. → [{"property":"positionGroup","op":"is","value":"D"}] - Goalies (player): Goalies only. → [{"property":"positionGroup","op":"is","value":"G"}] - Skaters (player): Forwards and defencemen (no goalies). → [{"property":"positionGroup","op":"isAnyOf","value":["F","D"]}] - Not into an empty net (goal): Leaves out empty-net goals, which inflate late-game totals. → [{"property":"emptyNet","op":"is","value":false}] ## From simple to complex (the guide's steps) ### 1. List something Every query starts with one block: the thing you want rows of. Pick it from the start panel (or press Examples). A block with nothing in it lists everything of that kind. In JSON the block is the `root`, with an `entity` such as `team`, `player`, `game`, `goal` or `shot`. Answer (2025–26): Every team, one row each. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22seasons%22%3A%5B20252026%5D%2C%22grouping%22%3Anull%2C%22ranking%22%3Anull%2C%22root%22%3A%7B%22id%22%3A%22t%22%2C%22entity%22%3A%22team%22%2C%22relation%22%3Anull%2C%22join%22%3A%22and%22%2C%22items%22%3A%5B%5D%2C%22shown%22%3Atrue%2C%22children%22%3A%5B%5D%7D%7D%7D ```json {"v":1,"seasons":[20252026],"grouping":null,"ranking":null,"root":{"id":"t","entity":"team","relation":null,"join":"and","items":[],"shown":true,"children":[]}} ``` ### 2. Add a condition Click + Condition on the block and choose a property, a comparison and a value. Numbers take `gt`, `gte`, `lt`, `lte`, `eq`, `ne` or `between`; names and categories take `is`, `isNot` or `isAnyOf`. Each condition is `{ property, op, value }` in the block's `items`. Answer (2025–26): The players who scored 40 or more. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22seasons%22%3A%5B20252026%5D%2C%22grouping%22%3Anull%2C%22ranking%22%3Anull%2C%22root%22%3A%7B%22id%22%3A%22p%22%2C%22entity%22%3A%22player%22%2C%22relation%22%3Anull%2C%22join%22%3A%22and%22%2C%22items%22%3A%5B%7B%22id%22%3A%22c1%22%2C%22kind%22%3A%22cond%22%2C%22property%22%3A%22goals%22%2C%22op%22%3A%22gte%22%2C%22value%22%3A40%7D%5D%2C%22shown%22%3Atrue%2C%22children%22%3A%5B%5D%7D%7D%7D ```json {"v":1,"seasons":[20252026],"grouping":null,"ranking":null,"root":{"id":"p","entity":"player","relation":null,"join":"and","items":[{"id":"c1","kind":"cond","property":"goals","op":"gte","value":40}],"shown":true,"children":[]}} ``` ### 3. Combine conditions Conditions in a block all have to hold (AND). To accept either of two things, put them in a group and switch the group to OR. Mixing AND and OR always needs a group, so the order is never ambiguous. A group is `{ kind: "group", join: "or", items: [...] }` inside the block's items. Answer (2025–26): Defencemen with 15 or more goals or 60 or more points. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22seasons%22%3A%5B20252026%5D%2C%22grouping%22%3Anull%2C%22ranking%22%3Anull%2C%22root%22%3A%7B%22id%22%3A%22p%22%2C%22entity%22%3A%22player%22%2C%22relation%22%3Anull%2C%22join%22%3A%22and%22%2C%22shown%22%3Atrue%2C%22children%22%3A%5B%5D%2C%22items%22%3A%5B%7B%22id%22%3A%22c1%22%2C%22kind%22%3A%22cond%22%2C%22property%22%3A%22positionGroup%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22D%22%7D%2C%7B%22id%22%3A%22g1%22%2C%22kind%22%3A%22group%22%2C%22join%22%3A%22or%22%2C%22items%22%3A%5B%7B%22id%22%3A%22c2%22%2C%22kind%22%3A%22cond%22%2C%22property%22%3A%22goals%22%2C%22op%22%3A%22gte%22%2C%22value%22%3A15%7D%2C%7B%22id%22%3A%22c3%22%2C%22kind%22%3A%22cond%22%2C%22property%22%3A%22points%22%2C%22op%22%3A%22gte%22%2C%22value%22%3A60%7D%5D%7D%5D%7D%7D%7D ```json {"v":1,"seasons":[20252026],"grouping":null,"ranking":null,"root":{"id":"p","entity":"player","relation":null,"join":"and","shown":true,"children":[],"items":[{"id":"c1","kind":"cond","property":"positionGroup","op":"is","value":"D"},{"id":"g1","kind":"group","join":"or","items":[{"id":"c2","kind":"cond","property":"goals","op":"gte","value":15},{"id":"c3","kind":"cond","property":"points","op":"gte","value":60}]}]}} ``` ### 4. Rank the answer Add Rank from the clause bar to keep the top (or bottom) N by any column. Columns are named `.`, so a player block with id `p` has `p.points`. Ranking is `{ column, dir: "desc" | "asc", n }`; add `ties: true` to keep everyone level with the last place. Answer (2025–26): The ten forwards with the most points. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22seasons%22%3A%5B20252026%5D%2C%22grouping%22%3Anull%2C%22ranking%22%3A%7B%22column%22%3A%22p.points%22%2C%22dir%22%3A%22desc%22%2C%22n%22%3A10%7D%2C%22root%22%3A%7B%22id%22%3A%22p%22%2C%22entity%22%3A%22player%22%2C%22relation%22%3Anull%2C%22join%22%3A%22and%22%2C%22shown%22%3Atrue%2C%22children%22%3A%5B%5D%2C%22items%22%3A%5B%7B%22id%22%3A%22c1%22%2C%22kind%22%3A%22cond%22%2C%22property%22%3A%22positionGroup%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22F%22%7D%5D%7D%7D%7D ```json {"v":1,"seasons":[20252026],"grouping":null,"ranking":{"column":"p.points","dir":"desc","n":10},"root":{"id":"p","entity":"player","relation":null,"join":"and","shown":true,"children":[],"items":[{"id":"c1","kind":"cond","property":"positionGroup","op":"is","value":"F"}]}} ``` ### 5. Look inside with a child block Add a block under another to ask about related things: a team's games, a player's goals, a game's penalties. A child block is an existence check: the parent stays only if at least one child matches. Hide the child (the eye icon, or `shown: false`) to keep listing the parent. Children name their `relation`; a team's games are `played`, which also shows each game from that team's side (result, goals for, opponent). Answer (2025–26): The teams that won at least one game by six or more. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22seasons%22%3A%5B20252026%5D%2C%22grouping%22%3Anull%2C%22ranking%22%3Anull%2C%22root%22%3A%7B%22id%22%3A%22t%22%2C%22entity%22%3A%22team%22%2C%22relation%22%3Anull%2C%22join%22%3A%22and%22%2C%22items%22%3A%5B%5D%2C%22shown%22%3Atrue%2C%22children%22%3A%5B%7B%22id%22%3A%22g%22%2C%22entity%22%3A%22game%22%2C%22relation%22%3A%22played%22%2C%22join%22%3A%22and%22%2C%22shown%22%3Afalse%2C%22children%22%3A%5B%5D%2C%22items%22%3A%5B%7B%22id%22%3A%22c1%22%2C%22kind%22%3A%22cond%22%2C%22property%22%3A%22result%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Win%22%7D%2C%7B%22id%22%3A%22c2%22%2C%22kind%22%3A%22cond%22%2C%22property%22%3A%22goalDiff%22%2C%22op%22%3A%22gte%22%2C%22value%22%3A6%7D%5D%7D%5D%7D%7D%7D ```json {"v":1,"seasons":[20252026],"grouping":null,"ranking":null,"root":{"id":"t","entity":"team","relation":null,"join":"and","items":[],"shown":true,"children":[{"id":"g","entity":"game","relation":"played","join":"and","shown":false,"children":[],"items":[{"id":"c1","kind":"cond","property":"result","op":"is","value":"Win"},{"id":"c2","kind":"cond","property":"goalDiff","op":"gte","value":6}]}]}} ``` ### 6. List the child instead Show the child block and the rows become the child: the deepest shown block is what gets listed. The same question now returns the games themselves, each seen from the winner's side. Answer (2025–26): One row per game won by six or more, with the team and the margin. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22seasons%22%3A%5B20252026%5D%2C%22grouping%22%3Anull%2C%22ranking%22%3Anull%2C%22root%22%3A%7B%22id%22%3A%22t%22%2C%22entity%22%3A%22team%22%2C%22relation%22%3Anull%2C%22join%22%3A%22and%22%2C%22items%22%3A%5B%5D%2C%22shown%22%3Atrue%2C%22children%22%3A%5B%7B%22id%22%3A%22g%22%2C%22entity%22%3A%22game%22%2C%22relation%22%3A%22played%22%2C%22join%22%3A%22and%22%2C%22shown%22%3Atrue%2C%22children%22%3A%5B%5D%2C%22items%22%3A%5B%7B%22id%22%3A%22c1%22%2C%22kind%22%3A%22cond%22%2C%22property%22%3A%22result%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Win%22%7D%2C%7B%22id%22%3A%22c2%22%2C%22kind%22%3A%22cond%22%2C%22property%22%3A%22goalDiff%22%2C%22op%22%3A%22gte%22%2C%22value%22%3A6%7D%5D%7D%5D%7D%7D%7D ```json {"v":1,"seasons":[20252026],"grouping":null,"ranking":null,"root":{"id":"t","entity":"team","relation":null,"join":"and","items":[],"shown":true,"children":[{"id":"g","entity":"game","relation":"played","join":"and","shown":true,"children":[],"items":[{"id":"c1","kind":"cond","property":"result","op":"is","value":"Win"},{"id":"c2","kind":"cond","property":"goalDiff","op":"gte","value":6}]}]}} ``` ### 7. Count with grouping Add Group to turn rows into totals: choose the columns to group by and the measures to work out (count, sum, average, max, min, distinct count, a calculation of two measures, or a rate per 60). Measures are columns named `m.`, so you can rank by them. Here goals are filtered to the power play, grouped by team and counted. Answer (2025–26): Every team's power-play goals, most first. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22seasons%22%3A%5B20252026%5D%2C%22grouping%22%3A%7B%22by%22%3A%5B%22gl.team%22%5D%2C%22measures%22%3A%5B%7B%22id%22%3A%22n%22%2C%22fn%22%3A%22count%22%2C%22label%22%3A%22Power-play%20goals%22%7D%5D%2C%22having%22%3A%5B%5D%7D%2C%22ranking%22%3A%7B%22column%22%3A%22m.n%22%2C%22dir%22%3A%22desc%22%2C%22n%22%3A32%7D%2C%22root%22%3A%7B%22id%22%3A%22gl%22%2C%22entity%22%3A%22goal%22%2C%22relation%22%3Anull%2C%22join%22%3A%22and%22%2C%22shown%22%3Atrue%2C%22children%22%3A%5B%5D%2C%22items%22%3A%5B%7B%22id%22%3A%22c1%22%2C%22kind%22%3A%22cond%22%2C%22property%22%3A%22strengthGroup%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22PP%22%7D%5D%7D%7D%7D ```json {"v":1,"seasons":[20252026],"grouping":{"by":["gl.team"],"measures":[{"id":"n","fn":"count","label":"Power-play goals"}],"having":[]},"ranking":{"column":"m.n","dir":"desc","n":32},"root":{"id":"gl","entity":"goal","relation":null,"join":"and","shown":true,"children":[],"items":[{"id":"c1","kind":"cond","property":"strengthGroup","op":"is","value":"PP"}]}} ``` ### 8. Count through a relation Grouping works on whatever is listed, so list the goals under each player and count them per player. This is the top ten 5-on-5 goal scorers: player → scored → goal (strength 5v5), grouped by the player's name, ranked with ties. Answer (2025–26): Ten names or a few more when tied, with their 5-on-5 goals. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22p%22%2C%22entity%22%3A%22player%22%2C%22children%22%3A%5B%7B%22id%22%3A%22gl%22%2C%22entity%22%3A%22goal%22%2C%22relation%22%3A%22playerScored%22%2C%22items%22%3A%5B%7B%22property%22%3A%22strength%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%225v5%22%7D%5D%7D%5D%7D%2C%22grouping%22%3A%7B%22by%22%3A%5B%22p.name%22%5D%2C%22measures%22%3A%5B%7B%22id%22%3A%22g%22%2C%22fn%22%3A%22count%22%2C%22label%22%3A%225v5%20goals%22%7D%5D%7D%2C%22ranking%22%3A%7B%22column%22%3A%22m.g%22%2C%22dir%22%3A%22desc%22%2C%22n%22%3A10%2C%22ties%22%3Atrue%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"p","entity":"player","children":[{"id":"gl","entity":"goal","relation":"playerScored","items":[{"property":"strength","op":"is","value":"5v5"}]}]},"grouping":{"by":["p.name"],"measures":[{"id":"g","fn":"count","label":"5v5 goals"}]},"ranking":{"column":"m.g","dir":"desc","n":10,"ties":true},"seasons":[20252026]} ``` ### 9. Ask “never” Switch a block to Never (`mode: "without"`) to keep the parent only when nothing matches. This finds teams that played Colorado but never beat them: one hidden child requires a game against Colorado, a Never child rules out any win against them. Answer (2025–26): The teams with no win against Colorado. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22t%22%2C%22entity%22%3A%22team%22%2C%22items%22%3A%5B%7B%22property%22%3A%22name%22%2C%22op%22%3A%22isNot%22%2C%22value%22%3A%22Colorado%20Avalanche%22%7D%5D%2C%22children%22%3A%5B%7B%22id%22%3A%22w%22%2C%22entity%22%3A%22game%22%2C%22relation%22%3A%22played%22%2C%22mode%22%3A%22without%22%2C%22shown%22%3Afalse%2C%22items%22%3A%5B%7B%22property%22%3A%22result%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Win%22%7D%5D%2C%22children%22%3A%5B%7B%22entity%22%3A%22team%22%2C%22relation%22%3A%22playedAgainst%22%2C%22shown%22%3Afalse%2C%22items%22%3A%5B%7B%22property%22%3A%22name%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Colorado%20Avalanche%22%7D%5D%7D%5D%7D%2C%7B%22entity%22%3A%22game%22%2C%22relation%22%3A%22played%22%2C%22shown%22%3Afalse%2C%22children%22%3A%5B%7B%22entity%22%3A%22team%22%2C%22relation%22%3A%22playedAgainst%22%2C%22shown%22%3Afalse%2C%22items%22%3A%5B%7B%22property%22%3A%22name%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Colorado%20Avalanche%22%7D%5D%7D%5D%7D%5D%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"t","entity":"team","items":[{"property":"name","op":"isNot","value":"Colorado Avalanche"}],"children":[{"id":"w","entity":"game","relation":"played","mode":"without","shown":false,"items":[{"property":"result","op":"is","value":"Win"}],"children":[{"entity":"team","relation":"playedAgainst","shown":false,"items":[{"property":"name","op":"is","value":"Colorado Avalanche"}]}]},{"entity":"game","relation":"played","shown":false,"children":[{"entity":"team","relation":"playedAgainst","shown":false,"items":[{"property":"name","op":"is","value":"Colorado Avalanche"}]}]}]},"seasons":[20252026]} ``` ### 10. Compare within a row Give a block an alias and other conditions can refer to it (“same game as A”, “after A’s time”). Head-to-head questions use a game with two hidden team children, one for each side: here every Toronto v Montréal game. Answer (2025–26): The four games between Toronto and Montréal. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22g%22%2C%22entity%22%3A%22game%22%2C%22children%22%3A%5B%7B%22id%22%3A%22a%22%2C%22entity%22%3A%22team%22%2C%22relation%22%3A%22playedBy%22%2C%22shown%22%3Afalse%2C%22items%22%3A%5B%7B%22property%22%3A%22name%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Toronto%20Maple%20Leafs%22%7D%5D%7D%2C%7B%22id%22%3A%22b%22%2C%22entity%22%3A%22team%22%2C%22relation%22%3A%22playedBy%22%2C%22shown%22%3Afalse%2C%22items%22%3A%5B%7B%22property%22%3A%22name%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Montreal%20Canadiens%22%7D%5D%7D%5D%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"g","entity":"game","children":[{"id":"a","entity":"team","relation":"playedBy","shown":false,"items":[{"property":"name","op":"is","value":"Toronto Maple Leafs"}]},{"id":"b","entity":"team","relation":"playedBy","shown":false,"items":[{"property":"name","op":"is","value":"Montreal Canadiens"}]}]},"seasons":[20252026]} ``` ### 11. Find streaks Streak blocks hang off a team or a player and find runs of consecutive games: wins, points, goals, a goalie's wins, or your own condition, over all games or only home, road, division or conference games. Keep the longest or the most recent. Answer (2025–26): The longest point streaks. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22p%22%2C%22entity%22%3A%22player%22%2C%22shown%22%3Atrue%2C%22children%22%3A%5B%7B%22id%22%3A%22s%22%2C%22entity%22%3A%22streak%22%2C%22relation%22%3A%22hasRun%22%2C%22streak%22%3A%7B%22over%22%3A%22games%22%2C%22condition%22%3A%22points%22%2C%22conditionItems%22%3A%5B%5D%2C%22scope%22%3A%22all%22%2C%22scopeItems%22%3A%5B%5D%2C%22keep%22%3A%7B%22kind%22%3A%22longest%22%2C%22n%22%3A1%7D%7D%7D%5D%7D%2C%22ranking%22%3A%7B%22column%22%3A%22s.length%22%2C%22dir%22%3A%22desc%22%2C%22n%22%3A10%2C%22ties%22%3Atrue%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"p","entity":"player","shown":true,"children":[{"id":"s","entity":"streak","relation":"hasRun","streak":{"over":"games","condition":"points","conditionItems":[],"scope":"all","scopeItems":[],"keep":{"kind":"longest","n":1}}}]},"ranking":{"column":"s.length","dir":"desc","n":10,"ties":true},"seasons":[20252026]} ``` ### 12. Ask another season Choose the seasons in the toolbar (`seasons` in the JSON, such as `[20152016]`). Without any, a query runs on the most recent completed season. Shared links always carry their seasons, so they keep their meaning. This is step 4 again, for 2015–16. Answer (2015–16): The ten forwards with the most points in 2015–16. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22seasons%22%3A%5B20152016%5D%2C%22grouping%22%3Anull%2C%22ranking%22%3A%7B%22column%22%3A%22p.points%22%2C%22dir%22%3A%22desc%22%2C%22n%22%3A10%7D%2C%22root%22%3A%7B%22id%22%3A%22p%22%2C%22entity%22%3A%22player%22%2C%22relation%22%3Anull%2C%22join%22%3A%22and%22%2C%22shown%22%3Atrue%2C%22children%22%3A%5B%5D%2C%22items%22%3A%5B%7B%22id%22%3A%22c1%22%2C%22kind%22%3A%22cond%22%2C%22property%22%3A%22positionGroup%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22F%22%7D%5D%7D%7D%7D ```json {"v":1,"seasons":[20152016],"grouping":null,"ranking":{"column":"p.points","dir":"desc","n":10},"root":{"id":"p","entity":"player","relation":null,"join":"and","shown":true,"children":[],"items":[{"id":"c1","kind":"cond","property":"positionGroup","op":"is","value":"F"}]}} ``` ### 13. Add up several seasons Tick several seasons and the answer covers all of them. Grouping adds them up exactly: here goals are listed under each player across three seasons, grouped by player and ranked, so each player's total is their three-season total. Without grouping, rows from every season are listed together, with a Season column so you can tell them apart (a player appears once per season). Answer (2023–24 to 2025–26): The ten top goal scorers over 2023–24 to 2025–26, with their totals. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22seasons%22%3A%5B20232024%2C20242025%2C20252026%5D%2C%22grouping%22%3A%7B%22by%22%3A%5B%22p.name%22%5D%2C%22measures%22%3A%5B%7B%22id%22%3A%22g%22%2C%22fn%22%3A%22count%22%2C%22label%22%3A%22Goals%22%7D%5D%2C%22having%22%3A%5B%5D%7D%2C%22ranking%22%3A%7B%22column%22%3A%22m.g%22%2C%22dir%22%3A%22desc%22%2C%22n%22%3A10%2C%22ties%22%3Atrue%7D%2C%22root%22%3A%7B%22id%22%3A%22p%22%2C%22entity%22%3A%22player%22%2C%22relation%22%3Anull%2C%22join%22%3A%22and%22%2C%22shown%22%3Atrue%2C%22items%22%3A%5B%5D%2C%22children%22%3A%5B%7B%22id%22%3A%22gl%22%2C%22entity%22%3A%22goal%22%2C%22relation%22%3A%22playerScored%22%2C%22join%22%3A%22and%22%2C%22shown%22%3Atrue%2C%22items%22%3A%5B%5D%2C%22children%22%3A%5B%5D%7D%5D%7D%7D%7D ```json {"v":1,"seasons":[20232024,20242025,20252026],"grouping":{"by":["p.name"],"measures":[{"id":"g","fn":"count","label":"Goals"}],"having":[]},"ranking":{"column":"m.g","dir":"desc","n":10,"ties":true},"root":{"id":"p","entity":"player","relation":null,"join":"and","shown":true,"items":[],"children":[{"id":"gl","entity":"goal","relation":"playerScored","join":"and","shown":true,"items":[],"children":[]}]}} ``` ### 14. Compare seasons side by side Group by `season` to get one row per season: the Season column works like any other. Here are power-play goals per season, to see whether power plays are scoring more. Each season is worked out in turn and the parts are combined, so the first run over many seasons takes a few seconds per season; after that it is quick. Answer (2023–24 to 2025–26): One row per season with its power-play goals. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22seasons%22%3A%5B20232024%2C20242025%2C20252026%5D%2C%22grouping%22%3A%7B%22by%22%3A%5B%22season%22%5D%2C%22measures%22%3A%5B%7B%22id%22%3A%22n%22%2C%22fn%22%3A%22count%22%2C%22label%22%3A%22Power-play%20goals%22%7D%5D%2C%22having%22%3A%5B%5D%7D%2C%22ranking%22%3Anull%2C%22root%22%3A%7B%22id%22%3A%22gl%22%2C%22entity%22%3A%22goal%22%2C%22relation%22%3Anull%2C%22join%22%3A%22and%22%2C%22shown%22%3Atrue%2C%22children%22%3A%5B%5D%2C%22items%22%3A%5B%7B%22id%22%3A%22c1%22%2C%22kind%22%3A%22cond%22%2C%22property%22%3A%22strengthGroup%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22PP%22%7D%5D%7D%7D%7D ```json {"v":1,"seasons":[20232024,20242025,20252026],"grouping":{"by":["season"],"measures":[{"id":"n","fn":"count","label":"Power-play goals"}],"having":[]},"ranking":null,"root":{"id":"gl","entity":"goal","relation":null,"join":"and","shown":true,"children":[],"items":[{"id":"c1","kind":"cond","property":"strengthGroup","op":"is","value":"PP"}]}} ``` ## Worked recipes (with expected answers for 2025–26) ### Every Toronto v Montreal game Expected (2025–26): 4 rows. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22g%22%2C%22entity%22%3A%22game%22%2C%22children%22%3A%5B%7B%22id%22%3A%22a%22%2C%22entity%22%3A%22team%22%2C%22relation%22%3A%22playedBy%22%2C%22shown%22%3Afalse%2C%22items%22%3A%5B%7B%22property%22%3A%22name%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Toronto%20Maple%20Leafs%22%7D%5D%7D%2C%7B%22id%22%3A%22b%22%2C%22entity%22%3A%22team%22%2C%22relation%22%3A%22playedBy%22%2C%22shown%22%3Afalse%2C%22items%22%3A%5B%7B%22property%22%3A%22name%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Montreal%20Canadiens%22%7D%5D%7D%5D%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"g","entity":"game","children":[{"id":"a","entity":"team","relation":"playedBy","shown":false,"items":[{"property":"name","op":"is","value":"Toronto Maple Leafs"}]},{"id":"b","entity":"team","relation":"playedBy","shown":false,"items":[{"property":"name","op":"is","value":"Montreal Canadiens"}]}]},"seasons":[20252026]} ``` ``` FIND Game THAT played by Team [hidden] WHERE Name is “Toronto Maple Leafs” THAT played by Team [hidden] WHERE Name is “Montreal Canadiens” ``` ### Top 10 goal scorers at 5v5 Expected (2025–26): 12 rows. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22p%22%2C%22entity%22%3A%22player%22%2C%22children%22%3A%5B%7B%22id%22%3A%22gl%22%2C%22entity%22%3A%22goal%22%2C%22relation%22%3A%22playerScored%22%2C%22items%22%3A%5B%7B%22property%22%3A%22strength%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%225v5%22%7D%5D%7D%5D%7D%2C%22grouping%22%3A%7B%22by%22%3A%5B%22p.name%22%5D%2C%22measures%22%3A%5B%7B%22id%22%3A%22g%22%2C%22fn%22%3A%22count%22%2C%22label%22%3A%225v5%20goals%22%7D%5D%7D%2C%22ranking%22%3A%7B%22column%22%3A%22m.g%22%2C%22dir%22%3A%22desc%22%2C%22n%22%3A10%2C%22ties%22%3Atrue%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"p","entity":"player","children":[{"id":"gl","entity":"goal","relation":"playerScored","items":[{"property":"strength","op":"is","value":"5v5"}]}]},"grouping":{"by":["p.name"],"measures":[{"id":"g","fn":"count","label":"5v5 goals"}]},"ranking":{"column":"m.g","dir":"desc","n":10,"ties":true},"seasons":[20252026]} ``` ``` FIND Player THAT scored Goal WHERE Strength is “5v5” ⟶ PER Player COUNT AS “5v5 goals” ⟶ KEEP top 10 by 5v5 goals, highest first (with ties) ``` ### Wins after trailing by 2+ entering the third period Expected (2025–26): 30 rows. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22t%22%2C%22entity%22%3A%22team%22%2C%22children%22%3A%5B%7B%22id%22%3A%22g%22%2C%22entity%22%3A%22game%22%2C%22relation%22%3A%22played%22%2C%22items%22%3A%5B%7B%22property%22%3A%22result%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Win%22%7D%2C%7B%22property%22%3A%22diffAfterP2%22%2C%22op%22%3A%22lte%22%2C%22value%22%3A-2%7D%5D%7D%5D%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"t","entity":"team","children":[{"id":"g","entity":"game","relation":"played","items":[{"property":"result","op":"is","value":"Win"},{"property":"diffAfterP2","op":"lte","value":-2}]}]},"seasons":[20252026]} ``` ``` FIND Team THAT played Game WHERE Result is “Win” AND Goal difference after the 2nd ≤ -2 ``` ### Teams that never beat the Colorado Avalanche Expected (2025–26): 8 rows. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22t%22%2C%22entity%22%3A%22team%22%2C%22items%22%3A%5B%7B%22property%22%3A%22name%22%2C%22op%22%3A%22isNot%22%2C%22value%22%3A%22Colorado%20Avalanche%22%7D%5D%2C%22children%22%3A%5B%7B%22id%22%3A%22w%22%2C%22entity%22%3A%22game%22%2C%22relation%22%3A%22played%22%2C%22mode%22%3A%22without%22%2C%22shown%22%3Afalse%2C%22items%22%3A%5B%7B%22property%22%3A%22result%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Win%22%7D%5D%2C%22children%22%3A%5B%7B%22entity%22%3A%22team%22%2C%22relation%22%3A%22playedAgainst%22%2C%22shown%22%3Afalse%2C%22items%22%3A%5B%7B%22property%22%3A%22name%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Colorado%20Avalanche%22%7D%5D%7D%5D%7D%2C%7B%22entity%22%3A%22game%22%2C%22relation%22%3A%22played%22%2C%22shown%22%3Afalse%2C%22children%22%3A%5B%7B%22entity%22%3A%22team%22%2C%22relation%22%3A%22playedAgainst%22%2C%22shown%22%3Afalse%2C%22items%22%3A%5B%7B%22property%22%3A%22name%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Colorado%20Avalanche%22%7D%5D%7D%5D%7D%5D%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"t","entity":"team","items":[{"property":"name","op":"isNot","value":"Colorado Avalanche"}],"children":[{"id":"w","entity":"game","relation":"played","mode":"without","shown":false,"items":[{"property":"result","op":"is","value":"Win"}],"children":[{"entity":"team","relation":"playedAgainst","shown":false,"items":[{"property":"name","op":"is","value":"Colorado Avalanche"}]}]},{"entity":"game","relation":"played","shown":false,"children":[{"entity":"team","relation":"playedAgainst","shown":false,"items":[{"property":"name","op":"is","value":"Colorado Avalanche"}]}]}]},"seasons":[20252026]} ``` ``` FIND Team WHERE Name is not “Colorado Avalanche” THAT never played Game WHERE Result is “Win” THAT played against Team [hidden] WHERE Name is “Colorado Avalanche” THAT played Game [hidden] THAT played against Team [hidden] WHERE Name is “Colorado Avalanche” ``` ### Longest point streaks Expected (2025–26): 17 rows. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22p%22%2C%22entity%22%3A%22player%22%2C%22shown%22%3Atrue%2C%22children%22%3A%5B%7B%22id%22%3A%22s%22%2C%22entity%22%3A%22streak%22%2C%22relation%22%3A%22hasRun%22%2C%22streak%22%3A%7B%22over%22%3A%22games%22%2C%22condition%22%3A%22points%22%2C%22conditionItems%22%3A%5B%5D%2C%22scope%22%3A%22all%22%2C%22scopeItems%22%3A%5B%5D%2C%22keep%22%3A%7B%22kind%22%3A%22longest%22%2C%22n%22%3A1%7D%7D%7D%5D%7D%2C%22ranking%22%3A%7B%22column%22%3A%22s.length%22%2C%22dir%22%3A%22desc%22%2C%22n%22%3A10%2C%22ties%22%3Atrue%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"p","entity":"player","shown":true,"children":[{"id":"s","entity":"streak","relation":"hasRun","streak":{"over":"games","condition":"points","conditionItems":[],"scope":"all","scopeItems":[],"keep":{"kind":"longest","n":1}}}]},"ranking":{"column":"s.length","dir":"desc","n":10,"ties":true},"seasons":[20252026]} ``` ``` FIND Player THAT has a run of Streak (points across all games, keeping the longest) ⟶ KEEP top 10 by Length, highest first (with ties) ``` ### Most-used forward lines at 5v5 Expected (2025–26): 20 rows. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22u%22%2C%22entity%22%3A%22unit%22%2C%22items%22%3A%5B%7B%22property%22%3A%22kind%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Forward%20line%22%7D%5D%7D%2C%22ranking%22%3A%7B%22column%22%3A%22u.toi5v5%22%2C%22dir%22%3A%22desc%22%2C%22n%22%3A20%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"u","entity":"unit","items":[{"property":"kind","op":"is","value":"Forward line"}]},"ranking":{"column":"u.toi5v5","dir":"desc","n":20},"seasons":[20252026]} ``` ``` FIND Line or pair WHERE Kind is “Forward line” ⟶ KEEP top 20 by 5v5 ice time together, highest first ``` ### Wins despite being outshot by 15 or more Expected (2025–26): 75 rows. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22t%22%2C%22entity%22%3A%22team%22%2C%22children%22%3A%5B%7B%22id%22%3A%22g%22%2C%22entity%22%3A%22game%22%2C%22relation%22%3A%22played%22%2C%22items%22%3A%5B%7B%22property%22%3A%22result%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Win%22%7D%2C%7B%22property%22%3A%22shotDiff%22%2C%22op%22%3A%22lte%22%2C%22value%22%3A-15%7D%5D%7D%5D%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"t","entity":"team","children":[{"id":"g","entity":"game","relation":"played","items":[{"property":"result","op":"is","value":"Win"},{"property":"shotDiff","op":"lte","value":-15}]}]},"seasons":[20252026]} ``` ``` FIND Team THAT played Game WHERE Result is “Win” AND Shot difference ≤ -15 ``` ### Best defence pairs by 5v5 xGF% (min 300 minutes) Expected (2025–26): 15 rows. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22u%22%2C%22entity%22%3A%22unit%22%2C%22items%22%3A%5B%7B%22property%22%3A%22kind%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Defence%20pair%22%7D%2C%7B%22property%22%3A%22toi5v5%22%2C%22op%22%3A%22gte%22%2C%22value%22%3A300%7D%5D%7D%2C%22ranking%22%3A%7B%22column%22%3A%22u.xgfPct%22%2C%22dir%22%3A%22desc%22%2C%22n%22%3A15%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"u","entity":"unit","items":[{"property":"kind","op":"is","value":"Defence pair"},{"property":"toi5v5","op":"gte","value":300}]},"ranking":{"column":"u.xgfPct","dir":"desc","n":15},"seasons":[20252026]} ``` ``` FIND Line or pair WHERE Kind is “Defence pair” AND 5v5 ice time together ≥ 300 ⟶ KEEP top 15 by xGF%, highest first ``` ### Goalies' goals saved above expected on the second night of back-to-backs Expected (2025–26): 10 rows. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22p%22%2C%22entity%22%3A%22player%22%2C%22items%22%3A%5B%7B%22property%22%3A%22positionGroup%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22G%22%7D%5D%2C%22children%22%3A%5B%7B%22id%22%3A%22a%22%2C%22entity%22%3A%22appearance%22%2C%22relation%22%3A%22made%22%2C%22items%22%3A%5B%7B%22property%22%3A%22started%22%2C%22op%22%3A%22is%22%2C%22value%22%3Atrue%7D%5D%2C%22children%22%3A%5B%7B%22id%22%3A%22g%22%2C%22entity%22%3A%22game%22%2C%22relation%22%3A%22appearanceWasIn%22%2C%22shown%22%3Afalse%2C%22items%22%3A%5B%7B%22property%22%3A%22secondOfB2B%22%2C%22op%22%3A%22is%22%2C%22value%22%3Atrue%7D%5D%7D%5D%7D%5D%7D%2C%22grouping%22%3A%7B%22by%22%3A%5B%22p.name%22%5D%2C%22measures%22%3A%5B%7B%22id%22%3A%22gsax%22%2C%22fn%22%3A%22sum%22%2C%22column%22%3A%22a.gsax%22%2C%22label%22%3A%22GSAx%22%7D%5D%7D%2C%22ranking%22%3A%7B%22column%22%3A%22m.gsax%22%2C%22dir%22%3A%22desc%22%2C%22n%22%3A10%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"p","entity":"player","items":[{"property":"positionGroup","op":"is","value":"G"}],"children":[{"id":"a","entity":"appearance","relation":"made","items":[{"property":"started","op":"is","value":true}],"children":[{"id":"g","entity":"game","relation":"appearanceWasIn","shown":false,"items":[{"property":"secondOfB2B","op":"is","value":true}]}]}]},"grouping":{"by":["p.name"],"measures":[{"id":"gsax","fn":"sum","column":"a.gsax","label":"GSAx"}]},"ranking":{"column":"m.gsax","dir":"desc","n":10},"seasons":[20252026]} ``` ``` FIND Player WHERE Position group is “G” THAT made Appearance WHERE Started is yes THAT was in Game [hidden] WHERE Second of a back-to-back is yes ⟶ PER Player TOTAL Goals saved above expected AS “GSAx” ⟶ KEEP top 10 by GSAx, highest first ``` ### Most 5v5 minutes shared by teammates Expected (2025–26): 10 rows. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22p%22%2C%22entity%22%3A%22player%22%2C%22children%22%3A%5B%7B%22id%22%3A%22q%22%2C%22entity%22%3A%22player%22%2C%22relation%22%3A%22playedAlongside%22%7D%5D%7D%2C%22grouping%22%3A%7B%22by%22%3A%5B%22q.pair%22%5D%2C%22measures%22%3A%5B%7B%22id%22%3A%22toi%22%2C%22fn%22%3A%22max%22%2C%22column%22%3A%22q.sharedToi5v5%22%2C%22label%22%3A%22Shared%205v5%20minutes%22%7D%5D%7D%2C%22ranking%22%3A%7B%22column%22%3A%22m.toi%22%2C%22dir%22%3A%22desc%22%2C%22n%22%3A10%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"p","entity":"player","children":[{"id":"q","entity":"player","relation":"playedAlongside"}]},"grouping":{"by":["q.pair"],"measures":[{"id":"toi","fn":"max","column":"q.sharedToi5v5","label":"Shared 5v5 minutes"}]},"ranking":{"column":"m.toi","dir":"desc","n":10},"seasons":[20252026]} ``` ``` FIND Player THAT played alongside Player ⟶ PER Pair HIGHEST Shared 5v5 minutes AS “Shared 5v5 minutes” ⟶ KEEP top 10 by Shared 5v5 minutes, highest first ``` ### Power-play goals within 10 seconds of a faceoff win Expected (2025–26): 839 rows. The most recent faceoff in the same period must be won by the scoring team. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22gl%22%2C%22entity%22%3A%22goal%22%2C%22items%22%3A%5B%7B%22property%22%3A%22strengthGroup%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22PP%22%7D%2C%7B%22property%22%3A%22secondsAfterFaceoff%22%2C%22op%22%3A%22lte%22%2C%22value%22%3A10%7D%2C%7B%22property%22%3A%22afterFaceoffWin%22%2C%22op%22%3A%22is%22%2C%22value%22%3Atrue%7D%5D%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"gl","entity":"goal","items":[{"property":"strengthGroup","op":"is","value":"PP"},{"property":"secondsAfterFaceoff","op":"lte","value":10},{"property":"afterFaceoffWin","op":"is","value":true}]},"seasons":[20252026]} ``` ``` FIND Goal WHERE Strength group is “PP” AND Seconds after a faceoff ≤ 10 AND After a faceoff win is yes ``` ### Players with a goal in 5+ straight appearances against division rivals Expected (2025–26): 4 rows. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22p%22%2C%22entity%22%3A%22player%22%2C%22children%22%3A%5B%7B%22id%22%3A%22s%22%2C%22entity%22%3A%22streak%22%2C%22relation%22%3A%22hasRun%22%2C%22shown%22%3Afalse%2C%22items%22%3A%5B%7B%22property%22%3A%22length%22%2C%22op%22%3A%22gte%22%2C%22value%22%3A5%7D%5D%2C%22streak%22%3A%7B%22over%22%3A%22games%22%2C%22condition%22%3A%22goals%22%2C%22conditionItems%22%3A%5B%5D%2C%22scope%22%3A%22division%22%2C%22scopeItems%22%3A%5B%5D%2C%22keep%22%3Anull%7D%7D%5D%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"p","entity":"player","children":[{"id":"s","entity":"streak","relation":"hasRun","shown":false,"items":[{"property":"length","op":"gte","value":5}],"streak":{"over":"games","condition":"goals","conditionItems":[],"scope":"division","scopeItems":[],"keep":null}}]},"seasons":[20252026]} ``` ``` FIND Player THAT has a run of Streak (goals across division games) [hidden] WHERE Length ≥ 5 ``` ### Games where a team led by 3+ and lost Expected (2025–26): 25 rows. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22t%22%2C%22entity%22%3A%22team%22%2C%22children%22%3A%5B%7B%22id%22%3A%22g%22%2C%22entity%22%3A%22game%22%2C%22relation%22%3A%22played%22%2C%22items%22%3A%5B%7B%22property%22%3A%22maxLead%22%2C%22op%22%3A%22gte%22%2C%22value%22%3A3%7D%2C%7B%22property%22%3A%22result%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Loss%22%7D%5D%7D%5D%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"t","entity":"team","children":[{"id":"g","entity":"game","relation":"played","items":[{"property":"maxLead","op":"gte","value":3},{"property":"result","op":"is","value":"Loss"}]}]},"seasons":[20252026]} ``` ``` FIND Team THAT played Game WHERE Biggest lead ≥ 3 AND Result is “Loss” ``` ### Shots from 40+ feet that beat a goalie at 5v5 Expected (2025–26): 528 rows. Open: https://localhost:8080/query?q=%7B%22q%22%3A%7B%22v%22%3A1%2C%22root%22%3A%7B%22id%22%3A%22s%22%2C%22entity%22%3A%22shot%22%2C%22items%22%3A%5B%7B%22property%22%3A%22outcome%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%22Goal%22%7D%2C%7B%22property%22%3A%22distance%22%2C%22op%22%3A%22gte%22%2C%22value%22%3A40%7D%2C%7B%22property%22%3A%22strength%22%2C%22op%22%3A%22is%22%2C%22value%22%3A%225v5%22%7D%2C%7B%22property%22%3A%22emptyNet%22%2C%22op%22%3A%22is%22%2C%22value%22%3Afalse%7D%5D%7D%2C%22seasons%22%3A%5B20252026%5D%7D%7D ```json {"v":1,"root":{"id":"s","entity":"shot","items":[{"property":"outcome","op":"is","value":"Goal"},{"property":"distance","op":"gte","value":40},{"property":"strength","op":"is","value":"5v5"},{"property":"emptyNet","op":"is","value":false}]},"seasons":[20252026]} ``` ``` FIND Shot attempt WHERE Outcome is “Goal” AND Distance ≥ 40 AND Strength is “5v5” AND Empty net is no ``` ## Metrics glossary - Games played (GP): Games played in the regular season. Formula: count of games. - Wins (W): Games won, in regulation, overtime or a shootout. Formula: W + OTW + SOW. - Regulation losses (L): Games lost in regulation time. Formula: count of regulation losses. - Overtime and shootout losses (OTL): Losses after regulation. They still earn a point. Formula: OTL + SOL. - Points (PTS): Standings points: 2 for any win, 1 for a loss after regulation. Formula: 2 × W + OTL. - Points percentage (P%): Share of the available points a team collected. Formula: PTS ÷ (2 × GP). - Regulation wins (RW): Wins decided in the first 60 minutes. The first standings tie-breaker. Formula: count of regulation wins. - Regulation and overtime wins (ROW): Wins that didn't need a shootout. Formula: RW + OTW. - Goals for (GF): Goals scored, excluding the shootout. Formula: count of goals. - Goals against (GA): Goals conceded, excluding the shootout. Formula: count of goals conceded. - Goal differential (GD): Goals for minus goals against, excluding shootouts. Formula: GF − GA. - Power-play percentage (PP%): How often a power play produced a goal. Formula: PP goals ÷ PP opportunities. - Penalty-kill percentage (PK%): How often the team killed a penalty without conceding. Formula: 1 − PP goals against ÷ times shorthanded. - Faceoff percentage (FO%): Share of faceoffs won. Formula: faceoffs won ÷ faceoffs taken. - Goals (G): Goals scored, excluding shootouts. Formula: count. - Assists (A): First and second assists. Formula: count. - Points (PTS): Goals plus assists. Formula: G + A. - Primary points (P1): Goals plus first assists: the points most closely tied to creating the goal. Formula: G + first assists. - Plus/minus (+/−): Official plus/minus from the NHL boxscore: even-strength and shorthanded goals for, minus against, while on the ice. Formula: official. - Shooting percentage (S%): Goals per shot on goal. Formula: G ÷ shots on goal. - Time on ice per game (TOI/GP): Average ice time per game, in all situations. Formula: TOI ÷ GP. - Save percentage (SV%): Share of shots on goal the goalie stopped. Formula: saves ÷ shots against. - Goals-against average (GAA): Goals allowed per 60 minutes played. Formula: GA × 60 ÷ minutes. - Shutouts (SO): Complete games with no goals allowed. Formula: count. - Expected goals (xG): How many goals an average shooter would score from these chances. Each unblocked shot gets a probability based on distance, angle, shot type, rebounds, rushes and game state; xG adds them up. Formula: Σ P(goal) over unblocked attempts. - Expected goals for (xGF): Expected goals created by a team, or by a player's team while they were on the ice. Formula: Σ xG of attempts for. - Expected goals against (xGA): Expected goals allowed. Formula: Σ xG of attempts against. - Individual expected goals (ixG): The expected goals from a player's own shots: how many goals their chances were worth. Formula: Σ xG of the player's unblocked attempts. - ixG per 60 (ixG/60): Individual expected goals per 60 minutes of ice time. Formula: ixG × 60 ÷ TOI. - Blocked shots (BLK): Opponents' shot attempts the player got in front of before they reached the net. Formula: count of blocks credited to the player. - Blocks per 60 (BLK/60): Blocked shots per 60 minutes of ice time. Formula: blocks × 60 ÷ TOI. - xG blocked (xGB): The expected goals of the shots a player blocked: what those shots would have been worth had they reached the net. The NHL records where a shot was blocked, not where it was taken, so each block is valued from similar unblocked shots taken further out on the same line. Formula: Σ estimated xG of blocked attempts. - xG blocked per 60 (xGB/60): Expected goals blocked per 60 minutes of ice time: how much danger the player removes by blocking shots. Formula: xG blocked × 60 ÷ TOI. - xG per block (xG/BLK): How dangerous the shots a player blocks are, on average. Blocking a one-timer from the slot is worth several point shots through traffic. Formula: xG blocked ÷ blocks. - Share of on-ice danger blocked (Block share): Of all the danger the opponents created at 5-on-5 with the player on the ice (unblocked xG plus the xG of blocked shots), the share the player blocked personally. Formula: player's 5v5 xG blocked ÷ (on-ice xGA + on-ice xG blocked). - Own xG lost to blocks (ixG blocked): The estimated xG of the player's own attempts that were blocked before they reached the net. Formula: Σ estimated xG of the player's blocked attempts. - Share of own attempt xG blocked (ixGB%): How much of a player's shooting danger gets blocked. High for players who shoot through traffic from the point; low for players who find clear lanes. Formula: ixG blocked ÷ (ixG + ixG blocked). - Goals above expected (GAx): Goals minus individual xG. Positive means the player finished better than an average shooter would from the same chances. Formula: G − ixG. - Goals saved above expected (GSAx): Expected goals faced minus goals allowed. Positive means the goalie stopped more than an average goalie would have, given the quality of shots. Empty-net and shootout shots are excluded. Formula: xG faced − GA. - High-danger save percentage (HD SV%): Save percentage on shots worth 0.15 xG or more: the hardest chances. Formula: saves ÷ shots on goal, xG ≥ 0.15. - Medium-danger save percentage (MD SV%): Save percentage on shots worth 0.05 to 0.15 xG. Formula: saves ÷ shots on goal, 0.05 ≤ xG < 0.15. - Low-danger save percentage (LD SV%): Save percentage on shots worth less than 0.05 xG. Formula: saves ÷ shots on goal, xG < 0.05. - Rebound control (Reb ctrl): Rebounds the goalie avoided, per 100 saves, compared with the league rate for the same mix of shots. Positive means fewer second chances than expected. Formula: (expected rebounds − rebounds) × 100 ÷ saves. - Corsi for % (5v5) (CF%): Share of all shot attempts (on goal, missed or blocked) at 5-on-5 that went the team's way while the player was on the ice. A proxy for puck possession. Formula: CF ÷ (CF + CA). - Fenwick for % (5v5) (FF%): Like CF%, but only unblocked attempts. Formula: FF ÷ (FF + FA). - Expected goals share (5v5) (xGF%): Share of the 5-on-5 expected goals that went the team's way. Above 50% means creating better chances than allowing: the single best summary of territorial control. Formula: xGF ÷ (xGF + xGA). - Expected goals share, adjusted (5v5) (xGF% adj): xGF% after correcting for score and venue: trailing teams push and leading teams sit back, which distorts raw shares. Formula: weighted xGF ÷ weighted (xGF + xGA). - Relative xGF% (Rel xGF%): How much better the team's expected-goals share was with this player on the ice than off it, in the same games. Formula: on-ice xGF% − off-ice xGF%. - xGF per 60 (5v5) (xGF/60): Expected goals created per 60 minutes of 5-on-5 play. Formula: xGF × 60 ÷ 5v5 TOI. - xGA per 60 (5v5) (xGA/60): Expected goals allowed per 60 minutes of 5-on-5 play. Formula: xGA × 60 ÷ 5v5 TOI. - PDO (PDO): On-ice shooting percentage plus save percentage at 5-on-5, on a 1000 scale. Far above 1000 usually means good luck that tends not to last. Formula: 1000 × (SH% + SV%). - Finishing (5v5) (Finishing): Goals scored minus expected goals at 5-on-5. Positive means the team converted chances better than average. Formula: GF − xGF. - Goaltending (5v5) (Goaltending): Expected goals against minus goals against at 5-on-5. Positive means the goalies stopped more than expected. Formula: xGA − GA. - Offensive zone start % (OZS%): Of the player's shifts that began with a faceoff in either end, the share that began in the attacking zone. High numbers mean sheltered, offence-first usage. Formula: OZ starts ÷ (OZ + DZ starts). - Quality of competition (QoC): How important the opponents a player faced were, measured by those opponents' share of their team's 5-on-5 ice time. Higher means tougher minutes. Formula: TOI-weighted mean of opponents' 5v5 TOI share. - Quality of teammates (QoT): The same idea as QoC, for the linemates a player shared the ice with. Formula: TOI-weighted mean of teammates' 5v5 TOI share. - Shot quality (xG/attempt): The average expected-goal value of an unblocked attempt: how dangerous a typical chance is. Formula: xGF ÷ unblocked attempts. - Shot quantity (FF/60): Unblocked attempts per 60 minutes at 5-on-5. Formula: FF × 60 ÷ 5v5 TOI. - Penalty differential per 60 (Pen ±/60): Penalties drawn minus penalties taken, per 60 minutes of ice time. Formula: (drawn − taken) × 60 ÷ TOI. - Faceoffs against an average centre (FO% adj): Faceoff win rate with the opponents taken into account: 50% plus the draws won beyond what an average centre would have won against the same opponents. An average centre wins against an opponent as often as that opponent loses; each opponent's season win rate is shrunk toward 50% by 25 wins and 25 losses. Formula: 50% + (wins − Σ(1 − opponent's win rate)) ÷ draws. - Faceoff value (FO value): Expected goals each side generated in the 20 seconds after a faceoff (or until the next whistle), so a win in the offensive zone is worth more than one at centre ice. Formula: Σ aftermath xG differential. - Close and late (Close/late): The third period or overtime with the score tied or within one goal: when games are decided. Formula: P3/OT, |goal diff| ≤ 1. - Expected points (xPts): Standings points a team would expect from its shot quality alone: every game is replayed 10,000 times with each shot scoring at its xG. Formula: Σ simulated points per game. - Points above expected (Pts − xPts): Actual points minus expected points. Positive means results ran ahead of the underlying play. Formula: PTS − xPts. - Points (3-2-1-0) (3-2-1-0): Standings if a regulation win were worth 3 points, an overtime or shootout win 2, and an overtime or shootout loss 1. Formula: 3 × RW + 2 × (OTW + SOW) + OTL. - Points (no loser point) (2-0): Standings if every win were worth 2 and every loss 0. Formula: 2 × W. - Excitement index (Excitement): How exciting the game was, from 0 to 100: the share of games since 2009/10 it beat. It blends three things: how much the win probability swung, how many goals came while the game was in reach, and the biggest lead that was clawed back. Standing out on any one of them scores high; blowouts score low. Formula: percentile of a power mean (p = 8) of the percentiles of Σ |ΔWP| (×2), live goals and lead erased. - Comeback index (Comeback): The lowest win probability the eventual winner had. Low means a big comeback. Formula: min WP of the winner. - Line-blender index (Blender): How much the coaching staff mixed the forward lines. 0 means one trio played every 5-on-5 minute; values near 1 mean constant shuffling. Formula: 1 − Σ (trio TOI share)². - Shift fatigue curve (Fatigue): Expected goals for and against depending on how long the skaters on the ice have been out there. Formula: xGF/60, xGA/60 by shift-age bin. - Goalie-pull profile (Pulls): When a trailing team pulled its goalie for an extra attacker, and what happened next. Formula: time remaining at pull; GF and GA during. - Rest and travel splits (Rest): Results and shot share by days of rest and distance travelled, compared with the opponent's rest. Formula: P%, xGF% by rest days. - Score-state conversion (Conversion): How often teams turned a lead, tie or deficit after each period into each final result. Formula: P(result | state after P1, P2). - Linemate share (Linemates): Share of a player's 5-on-5 time spent with each teammate, game by game. Formula: shared 5v5 TOI ÷ player 5v5 TOI. - Similar players (Similar): Players with the most similar statistical profile in the same position group. Formula: cosine similarity of z-scored metrics. - Special-teams anatomy (ST): How power plays and penalty kills actually work: chance quality per minute, shots per power play, and how fast the first attempt comes. Formula: PP xGF/60, PK xGA/60, shots per PP, time to first attempt. - Win probability added (WPA): The change in win probability on the goals a player scored or assisted on, added up. Goals that swing close games count most. Formula: Σ ΔWP on the player's goals and assists. ## Data caveats - The NHL API is unofficial and undocumented. Official totals (scores, standings, player counting stats) are validated against it; see /methodology#data-quality. - On-ice properties and relations need valid shift charts: none in 2009–10, and some games in every later season (most in 2019–20 and 2020–21). Those games are left out of on-ice figures and results carry a note. - xG, GSAx, GAx, win probability and simulations are model-based; see /methodology. - EDGE tracking values are missing for some players and show as unknown. - Plus/minus is the official boxscore value.