Hoop State Gameflows

Hoop State Gameflows is a data-gathering and presentation framework that turns NBA game data into visual, contextual breakdowns — lineup rotations, score-margin trends, shot charts, and full box scores.

  • Status: Active development
  • Stack: Next.js • TypeScript • SCSS • Node.js • SQLite

The Idea

For years I've been a fan of the NBA stats site popcornmachine.net — a project that, remarkably, dates back to 2003 and quietly built one of the longest-running, free game-level stat viewers on the web. (Its name comes from a quip by legendary Lakers announcer Chick Hearn: "He put him in the popcorn machine...he's got salt and butter all over him.") After the site went quiet at the beginning of 2026 — and after waiting a few months in hopes it would return — I decided to build a modern take on the idea it championed: a visual, stats-first look at NBA games.

System Outline

The site is constructed in three parts: the Ingest Layer, the Presentation Layer, and the Orchestration Layer.

Ingest Layer

  • The presentation layer is designed to be cleanly minimal, easy to browse and compare, and fast.
  • Each game is pre-rendered into its own lightweight (~700KB) static webpage, eliminating API fetches and hydration lag while maximizing page-load speed and browser caching.

Presentation Layer

  • The presentation layer is designed to be cleanly minimal, easy to browse and compare, and fast.
  • Each game is pre-rendered into its own lightweight (~700KB) static webpage, eliminating API fetches and hydration lag while maximizing page-load speed and browser caching.
  • Chart components (bar chart, game-flow, shot chart) were built and tested in isolation via Storybook.js before being wired into the static page templates.

Orchestration Layer

  • Using a persistent macOS LaunchAgent, scripts are automatically executed every morning to poll the latest game data, build the game pages, test the build, and deploy the update.

Key Decisions

The volume of data I process is staggering. For each season there are approximately 600,000 rows of data, with as many as 32 factors per row. That scale creates a few key decisions.

Balancing site speed and page weight

Instead of keeping a live SQLite database to hydrate pages at browse-time, I opted to pre-build pages. This eliminates the need for a Node.js server to operate the site and database, so I'm able to run a simple static website on S3 (and CloudFront).

Presenting the data clearly without overwhelming the user

With the amount and granularity of data I have, it's important to make every piece of it as useful as possible — opting for a comparison-based narrative that frames the adversarial nature of inter-team competition.

Instead of treating each filing as a single event, the system splits each filing into transaction-level rows. This allows downstream analysis to focus on the individual aspects of the transaction.

Bar chart example from a hard-fought win by the New York against Philadelphia

Bar charts to explain raw, numeric comparisons.

A score margin chart from a New York, Philadelphia game, showing several lead changes

A time-based score-margin chart paired with lineup plus/minus, to explain the push and pull of intra-game battles.

Image of the shot charts from the Knicks win over the 76ers

Shot charts that give a visual representation of a court and where shots were made or missed, with the ability to filter shots by distance.