Statcast-style player cards, leaderboards, and search for iOS. Mobile-friendly Baseball Savant percentile bars with nightly Python ingestion from pybaseball.
The pitch
Baseball Savant is incredible on desktop, but unusable on mobile. The percentile bars don't fit, the tables require horizontal scrolling, and search is buried under menus.
StatScout brings the Savant experience to iPhone: player search in two taps, percentile bars optimized for portrait, leaderboards that actually scroll smoothly. Built for checking stats at the ballpark.
Specs
| Platform | iOS 17+ |
| Language | Swift |
| Data Pipeline | Python + pybaseball → Supabase, nightly GitHub Actions |
| Backend | Supabase Postgres with search indexes |
| Data Coverage | All MLB players, 2020-2025 seasons, 50+ stat categories |
| Percentiles | Calculated against positional averages (min 100 PA/IP) |
What mattered
Mobile-first percentile bars. Savant's bars are designed for desktop width. I redid the component for portrait: stacked when needed, compact labels, touch-friendly targets. Same data density, different geometry.
Fuzzy search. Type "judge" and get Aaron Judge. Type "shohei" and get Ohtani. Handles nicknames, misspellings, and partial matches. Search is local after initial sync. Works offline at the stadium.
Nightly data refresh. A Python script runs every night via GitHub Actions, pulls fresh data from pybaseball, calculates percentiles, and upserts to Supabase. The iOS app pulls incrementally. No full refresh unless the schema changes.
Leaderboard performance. Lists are virtualized with SwiftUI's LazyVStack. 500+ players in a list scrolls at 60fps. Images are lazy-loaded with a tiny LRU cache. First paint is under 2 seconds on cellular.
Positional context. A shortstop's 90th percentile OPS is different from a first baseman's. All percentiles are calculated within position groups, not league-wide. The app knows you're looking at a defender vs. a slugger.
The best baseball stats app is one that doesn't make you wait for the website to load.