Pool League Stat Tracker

Add Player

One roster for the whole league. You'll split players into two teams per game, since teams change each time.

Roster

Who's Coming?

Pick a date and mark who said they're showing up. This doesn't create a game or affect stats by itself, it's just a plan to check actual attendance against later. Once at least one game is logged for that date, whoever RSVP'd but never ended up rostered on any game that day counts toward their Flake % on their own Player Detail page. Saving again for a date already RSVP'd overwrites that entry rather than adding a second one.

Create Game

Balance Teams

Load from Who's Coming? pulls in whoever RSVP'd for a saved date above, instead of clicking through the roster by hand: pick a date, click Use These RSVPs, then adjust the picker below if anyone's plans changed. Otherwise, pick who's showing up, set a team size, and generate a few different balanced splits to choose from, ranked primarily by how close each team's average Two-Way/20 is to the others (or a real power-ranking-based estimate for anyone with no dashboard stats yet, marked with a *; a truly unknown player falls back to a neutral 0.0), adjusted for real history with these specific players: each team's average already includes a nudge from actual past "with this teammate vs. without" individual performance (Chemistry) and from this exact pairing's own win rate when they've shared a team before (Past record), both shown as their own line whenever the adjustment is large enough to matter. Height, build, effort, and role from Ben's own Player Profiles notes (hover a name for height/build/effort/role and the original note; a few players carry two roles when their notes clearly describe two distinct contributions) only ever settle things between options that are already close on quality, never override a real gap, and all four are weighted equally light, except one guideline held a little stronger: every team should have someone above today's group's own average height, since a team with nobody above that line is a real disadvantage here, not just a stat that reads worse. Chemistry and Past record don't just re-rank the options either: the search itself gets a refinement pass afterward that tries small player swaps looking for an even better-balanced split on those same signals. This doesn't create anything by itself; for a straight 2-team split, Use These Teams creates a game with that roster pre-filled, using whatever date is set above. Click Generate again for a different set of options, since the search is randomized and won't always turn up the same shortlist.

Video Setup

Session video

If one recording covers several games back-to-back, upload it once here and reuse it across all of them. Each game just remembers its own start time in the shared video, instead of you splitting the file into separate clips.

Or a video just for this game

or paste a link:

A chosen file is stored in this browser (via IndexedDB) so it stays loaded next time you open this game on this computer, but it never leaves the browser, so it isn't included in exports.

Mark a Clip

While the video is playing, mark the moment. It grabs a ~10 second clip centered on the current playback time. Needs a local video file or direct video link loaded above (YouTube embeds can't be read for their playback time). See the full list in Highlight / Lowlight Reel below.

Suggested Plays

Candidate clips pulled straight from what's already logged for this game (dunks, blocks, contested makes, deep 3s, steals, the game-winning shot) instead of scrubbing the whole video by eye looking for moments worth clipping. Adding one grabs the same ~10 second window Mark a Clip does, centered on that event's own timestamp — nothing gets added until you click. Click ▶ Jump to watch a suggestion before adding it. Only shows events with a real video timestamp, and never re-suggests something already added.

Team Rosters for This Game

Add players to Team A or Team B for this game. Click the × on a chip to remove them.

Game Stats

Everyone in this game at a glance, including shooting splits and defensive/advanced numbers derived from the Shot Log below: FG/3PT/FT (made/attempted, %), eFG% (FG% weighted for 3s counting extra), TS% (true shooting: scoring efficiency across FGs and FTs combined), A/TO (assist-to-turnover ratio), Pts Allowed and Beaten (points scored, and times scored on, while they were the tagged defender on a make), Opp FG% (shooting % of everyone they were tagged defending, make or miss), Stops (times they were the tagged defender on a miss), Off Rating (offense-only Game Score: PTS, shooting efficiency, rebounds, assists, TOV, and fouls), and Two-Way (Off Rating plus Def Rating: STL, plus BLK when it isn't already one of this player's own Stops, plus Stops minus Beaten minus 0.4×Pts Allowed, so it's 0 for anyone never tagged as a defender with no steals or blocks, not a penalty for conservative tagging). STL/BLK are shown as recorded. They also feed Def Rating, and their sum (Stocks) is in the CSV export if you want it, but isn't repeated here since it's just those two columns added together.

Shot Log

Every shot attempt, make or miss, with who (if anyone) was contesting it and, for makes, who assisted it. Click +1/+2/+3 (make) or the MISS buttons on a player above to log one. Each entry auto-captures the video's playback position when you logged it, so Jump takes you right back to it (needs a local video file or direct link loaded, not a YouTube embed). Click any column header to sort by it; puts it back the way it opened.

Other Events

Every turnover, steal, and foul, tagged with the one opponent involved where noted. Click the TOV/STL/PF +1 buttons on a player above to log one. Click any column header to sort by it; puts it back the way it opened.

Defensive Matchups

Track who was guarding who while you review the video. Add as many entries as the matchup changes. Click any column header to sort by it; puts it back the way it opened.

guarded

Highlight / Lowlight Reel

Every clip you've marked for this game (use the Mark Highlight / Mark Lowlight buttons above to add one). Click any column header to sort by it; puts it back the way it opened.

Plays every clip above in video-time order and records it live. This takes real time (roughly the reel's own total length), and the tab needs to stay open and in the foreground while it runs. Downloads as a .webm file when done.

Season Rates (Individual)

Every counting stat here (PTS, OREB, DREB, AST, STL, BLK, TOV, PF, Pts Allowed, Beaten, Stops, Def Rating) is a rate per 20 combined points scored in the game, not a season total or a per-game average. Only games with real shots logged and equal team sizes count toward these at all, so a game that's just been rostered but not reviewed yet (or a 3-on-2 that skews the whole game's competitive shape) doesn't drag anyone's numbers down. Games are capped at different totals (16 or 21), so a plain per-game average isn't a fair comparison between a player who mostly plays 16-point games and one who mostly plays 21s: the game's combined final score stands in for "how much game happened," since possessions aren't tracked. Includes shooting splits and defensive/advanced numbers derived from each game's Shot Log; see the Game Stats table in Stat Entry for what each one means. Off Rating is offense-only Game Score: PTS, shooting efficiency, rebounds, assists, TOV, and fouls, adapted from the standard basketball Game Score formula minus its STL and BLK terms. Def Rating is STL, plus BLK (only when it isn't already one of this player's own Stops, so a blocked-and-tagged shot isn't credited twice), plus Stops minus Beaten minus 0.4×Pts Allowed, this tool's stand-in for the NBA stat of the same name, since real Defensive Rating needs possession counts this tool doesn't track. 0 for anyone never tagged as a defender with no steals or blocks, not a penalty for conservative tagging. Two-Way is Off Rating plus Def Rating. Click a player's name for their full game log and head-to-head history. Click a column header to sort by it (click again to flip direction). Shot%/AST%/OREB%/DREB%/TRB%/TOV% are hidden by default; click below to show them (still always in the CSV export either way). Include Outlier Games (on by default, matching the original always-been-true behavior) drops a player's own statistical outlier games from their rates when turned off. For each player with at least 4 qualifying games, any single game whose Two-Way/20 falls outside 1.5x their own IQR (computed fresh from their own games, not a fixed cutoff) is set aside, so one absurdly good or bad night doesn't dominate a small-sample average. This reaches every per-player stat (this table, Two-Way Trend, Teammate Synergy/Quality, both Matchup Difficulty charts) but deliberately not panels that pool many players within the same game (League Heatmap, Matchup Grid, Head-to-Head, Balance Teams' chemistry/win-rate): an outlier for one player isn't necessarily one for everyone else who was in that same game. With fewer than 4 qualifying games, nothing gets excluded regardless of the toggle, since there isn't enough data yet to call anything an outlier.

Past Seasons (League)

The league-wide equivalent of each player's own Past Seasons panel on Player Detail: full standings for one closed season at a time, computed live off that season's own archived games (not a frozen snapshot, so these stay correct even if a stat's formula changes later), shown regardless of the Include Past Seasons toggle above. That toggle blends past seasons into the live current-season totals; this instead shows one past season completely on its own, the way it actually played out. Pick a season, click a name to jump to their Player Detail page.

Consistency

Standard deviation of each player's own per-game Two-Way/20 (the same numbers their Two-Way Trend chart on Player Detail plots). Lower means steadier output night to night, not necessarily better output. A player who's reliably average every game reads as more consistent here than a boom-or-bust one who's spectacular half the time and poor the other half, even if their season average lands the same as someone steadier. Needs at least 2 qualifying games, since a single game has no variance to measure. Worth knowing: with Include Outlier Games turned off above, this measures the spread of a player's typical games with their own most extreme night(s) already set aside, not their true overall variance including the outlier. One of the real voted MVP award's own criteria (see Awards vs. Stats below, where twoWayTotal, season-long Two-Way with volume included, is already the closest tracked comparison to that award), kept as its own ranking rather than folded into a made-up combined score, since "consistent" and "valuable overall" are different questions worth answering separately.

Player Comparison

Pick any two players to see their full stat lines side by side: every column from the table above, including the advanced % ones, whether or not they're currently shown there. Green marks whichever value is better for a given stat where "better" has a clear direction (lower for TOV/PF/Pts Allowed/Opp FG%/Beaten/TOV%, higher for everything else with a real quality read), left uncolored for GP and the shot-share percentages (Shot%/AST%/OREB%/DREB%/TRB%), since a bigger share of the team's shots or assists reflects a role, not necessarily better play.

vs.

Awards vs. Stats

Summer 2026's voted awards, from that season's closed ballot, checked against the closest tracked stat, computed live from whatever games are actually logged in this browser, so it's only as complete as your Shot Log is. A stat winner sitting outside the top of its column isn't a bug: the vote and the numbers are allowed to disagree, that's the point of comparing them.

Power Ranking vs. Performance

A "power ranking" isn't voted or tracked by this tool: it's the real site's own per-night rank/percentile for each party (rank 1 = best that night, percentile field-size-normalized: 100 = first, 0 = last), pulled from the season spreadsheet as a frozen historical record. Paired here with that same player's actual Two-Way/20 in just the games logged for that date, computed live. Only nights with at least one reviewed game show up here at all. The other 10 real parties predate any footage existing, and a night with footage nobody's gotten to reviewing yet is left out too, rather than showing a table of nothing but dashes. A player with no games logged for that specific night still shows "—", not a zero. A game flagged Stopped Early (Export, Review Stopped-Early Games) is left out of that night's Two-Way/20 too: it's exactly the single-game case a partial game would distort undiluted.

Two-Way Quadrant

Off Rating/20 (offense) vs. Def Rating/20 for every player who's played, plotted separately instead of pre-summed into Two-Way Score, so "who's good" splits into "good at what." Quadrant lines are drawn at zero on each axis.

Volume vs. Efficiency

Offense only, separate from the Two-Way Quadrant above: pure shot volume (FGA/20) on the x-axis against season TS% on the y-axis, so a high-volume/low-efficiency player and a low-volume/high-efficiency player show up as mirror opposites directly, instead of needing someone to cross-reference the FGA and TS% columns on the main table by hand.

Play Style Clusters

Groups players by how their actual stat profile compares to everyone else's, not by anyone's manual Scorer/Defender/Playmaker tag. Every qualifying player's Off Rating, Def Rating, Assists, Rebounds, and Stocks (all per-20) are standardized and run through k-means clustering, and each group's label is generated from whichever of those stats sit furthest from the league average within that group. Two players landing in the same group means their box scores actually look alike, not that someone decided they play the same way. Needs at least 4 qualifying players to say anything meaningful.

League Shot Heatmap

Every marked field goal, league-wide, bucketed by court zone. Color is FG% in that zone (red low, green high), the number is attempts. A zone stays blank until at least one shot lands in it. Only shots with a marked location are included (see Export → Backfill Shot Locations to fill in the rest).

Two-Way/20 Rank Over the Season

One line per player, tracking where they'd rank if the season had ended at each date shown. A checkpoint exists for every date with at least one qualifying game, and a player's rank there comes from their cumulative Two-Way/20 across every qualifying game up through that date (not just that date's own games), ranked against everyone else's own cumulative number at that same moment. Rank 1 is at the top, so a climbing line means genuinely improving standing, not just a good single night. Each point is the same colored avatar used everywhere else in the app, with that checkpoint's rank number inside it instead of an initial. Built on the same games Include Imbalanced Games/Include Past Seasons already gate, deliberately not on Include Outlier Games, since a per-player outlier exclusion would mean two players could disagree about which dates even count as checkpoints.

Shot Distance

Every field goal splits further by how far it actually was from the hoop, on both sides of the 3pt line. Close and Midrange split the 2PT zone at its midpoint; Line (a normal, makeable three right at the line; Poolean's three is straight, not a curved arc, hence "Line" not "Arc") and Deep (a much lower-percentage near-pool-length heave) split the 3PT zone the same way the plain 3PT% on the table above blends together. Both breakpoints are radial distance from the hoop against a single adjustable constant (`CLOSE_RANGE_THRESHOLD` and `THREE_PT_DEEP_THRESHOLD` in app.js), the 3PT one drawn from an early season sample, the 2PT one a rougher starting guess with no shot volume behind it yet, so treat it as even more provisional. Each zone column shows FG% there (click to sort); the small percentage beneath it is that zone's share of the player's own attempts: how well they shoot from there, and how much they lean on it, in one cell instead of two separate panels. The Mix column is the same shot-selection breakdown as a quick visual (color tracks typical shot quality: green close, amber midrange, teal at the line, red deep). Only field goals with a marked shot location count (see Export → Backfill Shot Locations to fill in the rest). Treat any one player's split as an early read, not a verdict, until more games are logged.

Close Midrange 3PT Line 3PT Deep

Shooting & Wins by Direction

League-wide, not per-player: does the team shooting at one hoop actually do better than the other, across every logged game where "Where is Team A shooting?" has been set in Stat Entry (see Shooting by Direction on each Player Detail page for the same split per player)? FG%/TS% pool every attempt from every player on the team shooting that direction; Win% is at the team level, one result per game per direction. Games with no direction set yet don't count either way.

TS% by Shot Distance

True Shooting %, league-wide, for each of the four Shot Distance bands: the same numbers as the Shot Distance table above, laid out so "shooting gets worse with distance" (or wherever it actually breaks down) lands in one glance instead of a table someone has to compare in their head. Free throws have no shot location, so this excludes them (unlike League TS% Over Time); each bar is just that zone's own points-per-attempt. Only field goals with a marked shot location count.

League TS% Over Time

True Shooting % pooled across every player, per date with a reviewed game: a single league-wide efficiency line, useful for spotting drift over the season or checking the effect of a future rule change. Not a player-comparison stat.

Wide-Open Shooting

Every field goal attempt with no tagged defender at all: the opposite end of the Matchup Grid above. Free throws are excluded entirely (they're uncontested by rule, not by circumstance, so folding them in would trivially inflate the numbers). Share of FGA is how much of a player's own shot diet was untagged, for context on how much signal the TS% column actually carries. Click any column header to sort.

Head-to-Head Matchup Grid

Every scorer down one axis, every defender across the other: the league-wide extension of the per-player Head-to-Head tables on Player Detail, which only ever show one player's matchups at a time. Each cell is that scorer's FG% against that specific defender (color follows the same red-low/green-high scale as the heatmap above, opacity ramping up with sample size). A blank cell means that pairing has never been tagged. Rows and columns are sorted by attempts, most data first. Not filtered to field goals only, same behavior as the Head-to-Head tables it extends.

Teammate Lift Matrix

The pairwise With/Without comparison the Best Teammate award's Average Teammate Lift boils into one number per player, here as a full grid instead: row player on the team, column player's own Two-Way/20 change as a result (green = boosts them, red = drags them down; opacity tracks how large the swing is relative to the biggest one on the grid). A blank cell means that pairing hasn't logged games both with and without each other yet. This grid is not symmetric: row A / column B ("does A help B") and row B / column A ("does B help A") are two different facts about two different people's games, not mirror images of each other.

Teammate Context

The season-average headline numbers from Player Detail's Teammate Quality, Offensive/Defensive Matchup Difficulty, and Assisted By panels, side by side for every player at once. Built to catch a specific pattern without clicking into each player one at a time: someone whose own Off Rating/20 leans heavily on strong teammates (high Teammate Quality), easy defenders to shoot over (low Off Matchup Difficulty), and light defensive assignments (low Def Matchup Difficulty) is a different case from someone producing the same number on their own. Teammate Quality is teammates' season Off Rating/20; Off Matchup Difficulty is the season Def Rating/20 of whoever defended this player's shots (how good those defenders have been defensively); Def Matchup Difficulty is the season Off Rating/20 of whoever this player defended (how good those scorers have been offensively). See the Player Detail panels for the full explanation and the game-by-game trend charts. Click a column header to sort by it.

Assist Connections

The top passer-to-scorer connections, league-wide, by assist count: who's set up whom the most. Directional: Alice assisting Bob is a separate row from Bob assisting Alice, since those are different facts. Trimmed to the same number of rows as Teammate Context next to it, just so the two panels line up at roughly the same height; not a meaningful cutoff on its own. See a player's own Assisted By panel on Player Detail for their full, untrimmed list of connections, or Export → Download Assist Connections CSV for every connection league-wide.

PasserScorerAssists

Out-of-Bounds Misses

How often a player's own missed shot ends up out of bounds. Per Poolean's rule, whoever last touched the ball loses possession, so this is really a "how often does the ball leave their hands for good on a miss" read, not a shooting-accuracy stat. Only misses count as the denominator (a make can't go out of bounds). Sorted by number of misses.

Second-Chance Conversion

"True" second-chance conversion, not just who grabs offensive rebounds: an OREB counts as converted when, within 20 seconds of the missed shot's own video timestamp, either that rebounder scored themselves or someone else scored with them credited as the assist (either path counts, a kick-out is worth the same as a putback). Both the miss and the scoring follow-up need a real video timestamp to be checked; an OREB logged without one still counts toward the total but can't be evaluated for conversion. The 20-second window is a single adjustable constant (`SECOND_CHANCE_WINDOW_SECONDS` in app.js), same pattern as the shot-distance thresholds. This panel runs the same algorithm as scripts/second-chance-analysis.js, just against whatever's loaded in this browser instead of an exported file.

Game-Winning Buckets

How many times a player's shot was the one that actually closed out a game their team won: the real game-ending basket in a race-to-a-target format. Worth being precise about what this is: in a race-to-target format with no clock, the last basket of every decided game is *by definition* scored by the winning team, so this isn't tracking rare, buzzer-beater moments. It's a "who tends to be the one closing games out" tally that grows by exactly one per fully-timestamped decided game. That's exactly why the Clutch comparison above is built on Close-Game Shooting instead of this, though it's still a real signal here (it correlates with who's on the floor and scoring late in wins), just not a scarce one. Only credited when that specific shot has a real video timestamp; without one, there's no trustworthy way to say it was really the last shot of the game, so the game is skipped rather than guessed at. A season count, not a rate.

PlayerGame-Winning Buckets

Close-Game Shooting

This is the tracked stat behind the Clutch comparison above: a margin-aware read, not Game-Winning Buckets, since GWB is explicitly non-scarce by construction (the last basket of every decided game belongs to the winning team, full stop) and measures "who tends to close games out," not performance under real pressure. This instead is TS%, but only counting attempts from games that actually finished close: decided by 5 points or fewer (`CLUTCH_MARGIN_THRESHOLD` in app.js, a starting guess, not a value backed by real season margin data yet). Tied games count here even though a tie has no "winning shot" for GWB to credit. Click any column header to sort.

Defensive Load

A companion to Def Rating, not a replacement: how much of the team's own tagged defensive workload each player is actually carrying, not just how well they handle what they get (see Def Rating/20 above). Every opponent field goal attempt with at least one tagged defender is divided evenly across the team's own roster that game for an "expected fair share"; Def Load is how many of those a player actually got tagged on, divided by that share. Above 1.0 is more than an even share, below 1.0 is less. A low number is genuinely ambiguous on its own (avoided as a tough matchup, genuinely uninvolved for other reasons, or just too small a sample), so Read always names what pairing it with this same player's own Opp FG% (leading) and Def Rating/20 (secondary context) suggests, never as a standalone verdict. Opp FG% leads deliberately: it means exactly one thing and needs no trust in Def Rating's own unvalidated formula weights. Click a player's name for their full page, or a column header to sort.

Win Shares Model (beta)

Diagnostics for the regression behind the Win Shares column below (advanced columns), refit fresh from this season's own logged games every time this page loads. Each stat is sign-constrained to only push in its basketball-plausible direction (points can only help, turnovers can only hurt, etc.), then the data determines the size of that effect within those bounds; the regularization strength (alpha) is picked by leave-one-out cross-validation, not a fixed guess. A weight sitting at exactly 0 isn't a failure: it means that stat isn't adding independent signal once its correlated neighbors are already in the model, given how little data exists so far. Beaten was dropped as a feature (not just Fouls): it correlates with Points Allowed at 0.99 in this season's own data, essentially the same information twice, so keeping only Points Allowed (it also captures shot value, a 3 beaten hurts more than a 2) frees up model capacity rather than losing signal. Assists gets a weakly-informative prior rather than the usual shrink-toward-0, since assists and points barely correlate (0.24), so its implausible weight looks like small-sample noise, not redundancy, the same fix wouldn't apply. The prior's value (0.5 points per assist) is sourced, not guessed: Basketball-Reference's own published Points Produced formula credits a flat 0.5 points per assist in its simplified (pre-1973-74) form, the only version of that formula that doesn't need minutes-played data Poolean has no equivalent of. It also gets its own, separately cross-validated regularization strength rather than sharing everyone else's, so the prior isn't just technically present but functionally outweighed by the data. Cross-validation has so far preferred weaker shrinkage here, not stronger, an honest result in its own right: it means the small sample isn't just noisy in a way regularization can smooth over, it's a real "wait for more games" case. Leave-one-out R² and correlation are the two numbers worth watching across future refits: report them alongside any change to this model so improvement (or regression) is directly comparable over time. Not enough data yet to trust for anything with real stakes (awards, "who's actually better" claims).

Best & Worst Individual Games

Every player-game ranked by that single game's actual score, deliberately not a per-20 rate or a season total, since the rest of this page normalizes for fair player-to-player comparison and that averages away exactly the thing this panel exists to surface: one specific night's story, buried otherwise inside that game's own box score. Overall is Two-Way (Off Rating + Def Rating, the default); Offense and Defense rank by either half on its own, since a huge scoring night can bury a genuinely dominant defensive one in a combined score, and vice versa. Every player on either roster for a reviewed game gets a row, even a quiet one. On a thin season the two lists are capped so they never show the same handful of games twice, just reversed. A game flagged Stopped Early (Export, Review Stopped-Early Games) never gets a row here: a partial game's score shouldn't compete for a spot against complete ones.

Highlights & Lowlights (League)

Every clip tagged to any player, across every game, most recent first: the league-wide version of the Highlights & Lowlights table on each player's own profile, which only ever shows one player's clips at a time. Same source: the Highlight / Lowlight Reel table in Stat Entry.

DatePlayerTypeTimeNote

Same real-time, in-browser recording as the per-game version in Stat Entry, extended across every game. Combines in chronological order (oldest game first), loading each game's video in turn. A game with a YouTube-embedded or otherwise non-direct video link can't be captured this way and is skipped, with a note in the final summary. This can genuinely take a while for a full season's worth of clips, and the tab needs to stay open and foregrounded the whole time.

Personalized Tips

This player's own numbers next to the league average for that same stat, only shown when something actually stands out, not a fixed checklist. Doubles as a real scouting note on whoever you're looking at: their preferred shot zone and a real strength/weakness zone (checked against the league's own FG% from that same distance), plus real matchup-specific splits (a defender who's genuinely held them below their own usual shooting, or a scorer who's shot well above what they normally allow), each needing 5+ real attempts before it counts as a pattern rather than one bad or good night. Several tips carry their own "Watch film" links, straight to the actual games behind that number.

Notable Matchups

Every real, exploitable shooting swing involving this player, either as scorer or defender, ranked biggest first, each with its own "Watch film" link to the actual games it came from. Needs 5+ attempts against that one specific opponent and at least a 15-point swing from the scorer's own overall FG% before it counts as a pattern rather than one lucky or unlucky night.

Past Seasons

This player's final numbers from every season closed out via Export → Data Management → Start New Season, one row per season, computed live off the actual archived games, not a frozen snapshot, so these stay correct even if a stat's formula changes later. The current season's own numbers are everywhere else on this page; toggle Include Past Seasons to blend these into the live totals instead of viewing them separately (same toggle as the Leaderboard's; flipping it here updates both).

Flake %

Of the dates this player RSVP'd yes for on the Games tab's Who's Coming? panel and that have since had at least one game logged, how many they never actually showed up for. A date they RSVP'd for with no game logged yet isn't counted either way: it's not resolved, not a no-show.

Two-Way Trend

Two-Way/20 for every reviewed game this player's played, in order: the line-graph version of the "Last 5" number and arrow already shown elsewhere (feeding the Most Improved comparison on the Leaderboard), since a real trend line makes "up or down lately, and by how much" legible at a glance instead of two numbers to compare in your head. The dashed line is the season average; where the recent points sit relative to it is the whole read.

Game Log

Every game this player was in, most recent first.

Shot Chart

Every marked field goal this player has taken, plotted at its actual spot on the court: green for a make, red for a miss. The individual-shot pattern the zone-bucketed heatmap below necessarily smooths over: a cluster, a gap, a lean to one side, is visible here in a way no table of percentages shows directly. Only shots with a marked location are included (see Export → Backfill Shot Locations to fill in the rest).

Shot Heatmap

Every marked field goal this player has taken, bucketed by court zone. Color is FG% in that zone (red low, green high), the number is attempts. Only shots with a marked location are included.

Head-to-Head: As Scorer

Shooting against each defender who has been tagged guarding this player's shots, across the season.

Defensive Heatmap

Every shot this player was tagged defending, bucketed by court zone. Color is opponent FG% allowed there (red high, green low; inverted from the offensive heatmap above, since a low percentage is good defense). This is what actually answers whether this player's overall Opp FG% holds up at every distance or collapses somewhere specific: a single season number can't say that on its own. A double-teamed shot counts toward every tagged defender, same rule the Head-to-Head: As Defender table below uses.

Head-to-Head: As Defender

Shooting allowed to each scorer this player has been tagged defending, across the season.

Teammate Synergy (With/Without)

For each teammate this player has shared a team with, this player's own per-20 numbers in games with that teammate on their side vs. games without them (opposing team or not playing). Only games with real shots logged count either way. "—" means there's no game in that bucket yet to compare against. A small GP on either side makes the comparison noisy, not a verdict.

Teammate Quality

Average season Off Rating/20 of this player's own teammates (not this player), game by game, with a dashed season-average line. Off Rating specifically, not Two-Way: what this measures is a teammate's offensive gravity, how much they draw defensive attention, create mismatches, or set up easy looks, not their own defense. Doesn't correct for this player also counting toward each teammate's own Off Rating/20 (no leave-one-out adjustment), a simplification, same tradeoff every other season-long number on this page already makes.

Assisted By

What share of this player's own made field goals were set up by someone else, and how good (season Off Rating/20) those passers have been: the direct test of "getting fed easy looks by good players" vs. creating shots alone. Field goals only; free throws don't carry an assist by rule.

Offensive Matchup Difficulty

Average season Def Rating/20 of whoever was tagged defending this player's own shot attempts, game by game, with a dashed season-average line. The mirror of Defensive Matchup Difficulty below, from the scorer's side: how tough have the defenders this player shoots over actually been? A double-teamed shot counts toward every tagged defender, not split, same rule Stops/Beaten/Pts Allowed already use. A wide-open (untagged) shot contributes nothing, since there's no defender to rate.

Defensive Matchup Difficulty

Average season Off Rating/20 of whoever this player was tagged defending, game by game, with a dashed season-average line. The defensive-side counterpart to Teammate Quality above: does this player draw the tough offensive assignments, or get sheltered on weaker ones? Weighted per shot, not per opponent: facing the same tough scorer five times in one game counts five times, the same way Stops/Beaten/Pts Allowed already weight every tagged shot equally.

Defensive Load

A companion to Def Rating, not a replacement: how much of the team's tagged defensive workload this player is actually carrying, not just how well they handle what they get. Every opponent field goal attempt with at least one tagged defender is divided evenly across the team's own roster that game for an "expected fair share"; this is how many of those this player actually got tagged on, divided by that share. Above 1.0 is more than an even share, below 1.0 is less. A low number here is genuinely ambiguous on its own (avoided as a tough matchup, genuinely uninvolved for other reasons, or just too small a sample) and can't fully separate those, so it's always shown paired with this same player's Def Rating/20 and a plain-language read of what the two together suggest, never as a standalone verdict.

Shooting by Direction

FG%/TS% split by which hoop this player's team was shooting at that game (set per game in Stat Entry: "Where is Team A shooting?"). Real question worth asking with an outdoor pool court: does the sun in one direction actually cost shooting, or is it just a feeling? Only counts games where the game's own direction has been set, and needs at least 5 attempts on a side before showing a number.

Highlights & Lowlights

Every clip tagged to this player, across all games. Tag a clip to a player from the Highlight / Lowlight Reel table in Stat Entry.

DateTypeTimeNote

Areas to Work On

This player's own rate in each category next to the league median for that same stat, not the average and not the league's best: a real "behind (or ahead of) where a typical player in this league is" bar, one specific thing at a time. Every category needs its own minimum real sample before it can be flagged at all (shot zones: 5+ attempts in that zone; turnover rate: 10+ FGA+FTA+TOV; assist-to-turnover: 5+ assists or turnovers combined; wide-open shooting: 5+ open attempts; defense: 10+ shots defended; out-of-bounds rate: 10+ misses; second-chance conversion: 5+ offensive rebounds) — below that gate, nothing gets said rather than a confident callout off a handful of shots. Both directions show up, not just weaknesses. This tool only ever names the area; deciding how to work on it is yours.

Export All Data

Full dump of players, games, box scores, and matchups. Give this to your friend to integrate into the website.

Export a Single Game

Backfill Shot Locations

Every field goal (2 or 3, not free throws) that's missing a shot chart location, across every game. Click a spot on the mini chart to set it, no need to reopen the game or its video. Each click saves immediately and the shot drops off this list.

Review Possible Dunks

Close/midrange 2PT field goals logged before the Dunk field existed, so Shot Arc's ball-flight fitting can exclude real dunks (a dunk is carried by hand through a close-range slam, not a free-flying arc: see shot-arc/FINDINGS.md). Click Watch film to check, then Dunk or Not a dunk; either answer removes it from this list.

Review Stopped-Early Games

A game stopped before completion breaks every stat that treats a game as a standardized, comparable unit (Best/Worst Games, Power Ranking vs. Performance, Shot Attempt Differential, Pace/PPP, Win Shares). This can't be detected from the box score alone, the same way dunk needed a human to watch the clip instead of being inferred: if you remember a game being cut short, flag it here. Season-total rate stats are unaffected either way.

Flagged Shot Locations

Every marked field goal where the spot disagrees with the point value picked at logging time: the same mismatch the Shot Log flags one row at a time with a "📍 2PT range"/"📍 3PT range" badge, collected here so a whole season's worth can be reviewed at once. Click a spot on the mini chart to re-mark it. If the new spot agrees with the point value, the shot drops off this list; if the point value itself was wrong (not the spot), remove and re-log the shot from the Shot Log instead, since this tool only ever moves the marked location.

Session Videos

Recordings uploaded once and shared across multiple games (see the Video panel in Stat Entry). Removing one here clears it from every game using it.

NameUsed by

Broken Session Video Links

A game can end up pointing at a session video id that no longer exists here. The video panel silently falls back to showing nothing useful, so this can go unnoticed for a while (an id can go stale if a browser profile changes, data gets imported from elsewhere, or a recording is removed some other way than the button above). A single-game export from a game listed here will carry a null masterVideo, even though masterVideoId is set.

Shot Arc Hand-Labeling

For fine-tuning ball detection on real footage (see shot-arc/FINDINGS.md: stock detection doesn't find the ball on real in-flight shots). Pick a shot below (whatever's currently in shot-arc/frames/, from extract_frames.py), then click the ball's center to mark a frame and jump ahead by the step size below (skipped frames get filled in by straight-line interpolation between your clicks on download, so you don't have to click every single frame), or "No ball visible" if it's occluded/off-screen. Space bar repeats "No ball visible". If the clip contains more than the shot itself (a pass or dribble before release, a bounce after), step to the real release frame and click "Mark Shot Start", then the frame it lands/settles and click "Mark Shot End" -- only that range gets used downstream, and interpolation never crosses outside it. If the whole clip isn't a clean single-flight shot at all (a dunk, multiple separate plays), skip labeling it and click "Not a valid shot" instead. A small dot shows where you last clicked once you've labeled a frame. When you're done with a shot (or want to stop partway), download the labels JSON and hand the whole batch back for fine-tuning.

Data Management

Start New Season clears every game, stat, matchup, and locally-stored video file, but keeps the player roster, since that's the one thing that's supposed to carry over. Download JSON above first if you want a backup of the season you're closing out. Reset All Data is the nuclear option underneath it: clears the roster too, back to a completely empty tracker.