Case study: F1 dashboard
Context
I wanted a single page that answers the questions I keep asking during a race weekend:
- What sessions are coming up?
- Who’s leading the standings?
- What’s the minimum I need to know right now?
Most F1 sites are feature-rich, but they’re also noisy and heavy. The goal here was the opposite: fast, compact, and readable.
Problem
Build a dashboard that:
- Loads quickly and stays responsive
- Is readable at a glance
- Combines multiple datasets into a cohesive view
- Doesn’t require ten tabs (or a scrolling marathon)
Constraints
- Data comes from multiple sources with different formats and reliability
- Some datasets are “nice to have” (visualizations), others are “must have” (sessions/standings)
- The UI must degrade gracefully if a specific endpoint is down
Approach
1) Start with the user flow
I designed the UI around a “race weekend glance” workflow:
- upcoming sessions
- current standings
- essentials grouped logically
2) Normalize upstream data
The key step was building a normalized internal representation so the UI can stay simple even if upstream APIs are messy.
- map different response shapes into one model
- join datasets where needed
- keep the view layer focused on rendering
3) Performance as a feature
I treated performance as part of the product:
- minimize payloads
- cache when safe
- avoid unnecessary re-renders
Tradeoffs
- Some “deep detail” views are intentionally missing — the dashboard is optimized for glanceability
- Visualizations are fun, but they’re allowed to be optional (feature-flag-ish)
Results
Replace with real numbers when you have them:
- Page load: ~TBD
- API calls: ~TBD
- User outcome: fewer tabs, faster “what’s next?” answers
What I’d do next
- Add simple error states per module (sessions/standings/etc.)
- Add a small “data freshness” indicator per source
- Add a tiny integration test suite to detect upstream API shape changes early