A personal basketball data project

NBA Analysis

I wanted to know when NBA players usually peak, so I collected the data and looked at it a few different ways. The project now covers individual career trends, league-wide peak patterns, next-season forecasts and salaries across different cap eras.

01Individual careers · 1976–2026

NBA Performance Trends

Search for a player and follow BPM, VORP, win shares, win shares per 48 minutes or PER across their career.

  • Career highs, season logs and league-average references
  • Probabilities for improving, staying stable or regressing
  • A projected BPM change with the factors behind it
  • Past forecasts compared with the next observed season

02League-wide patterns · Updated through 2025–26

NBA Peak Performance Analysis

See when qualifying players reached their strongest consecutive three-season stretch across the same five metrics.

  • Average performance by age with confidence intervals
  • Peak-age distributions and metric comparisons
  • Raw single-season peaks compared with smoothed peaks
  • Stricter eligibility filters to check the result

03Contracts by era · 1984-85 onward

NBA Salary Cap Explorer

Compare contracts across eras using salary as a share of that season’s cap instead of nominal dollars.

  • Team payrolls shown as bars or a donut chart
  • Cap share and nominal salary views
  • Player salary histories across teams and seasons
  • A cross-era leaderboard with season filters

How it works

From raw data to the charts

Data collection

Python pipelines clean season, prediction, salary and salary-cap data before publishing it to Supabase. The site reads those tables instead of scraping data when a page loads.

Queries and caching

The pages load data on the server, while API routes handle player search and the salary explorer’s follow-up requests. Larger indexes and aggregate results are cached, and each view only sends the rows it needs to the browser.

Charts and shareable views

The career, peak-age and salary charts are built for this project with Canvas and SVG. Player, metric, team, season and display choices are kept in the URL where it makes sense, so a specific view can be shared.

Checks and limitations

The analysis defines its eligibility rules and separates observed results from forecasts. The player search, salary calculations, chart helpers, URL state and loading and error states are covered by automated tests.

Next.js and TypeScript on the site, Python for the data pipelines, and Supabase PostgreSQL for the cleaned data.

Next.js · TypeScript · Python · Supabase · PostgreSQL · Canvas · SVG · Vitest

← back to all projects