NCAA Men's Basketball Tournament selection probabilities for all 365 Division I teams, based on current team-sheet metrics and rankings.
This app provides NCAA tournament odds calculated from key metrics (NET, BPI, SOR, KPI, WAB, KenPom, Torvik) by scraping official data sources. Features include:
- Team Profiles - Dedicated page for all 365 D1 teams with rankings, schedules, records, and projected seeds
- Bracket Projection - Full 68-team field with seeds, auto-bids, and play-in games
- Bubble Watch - Live tracker for teams on the tournament bubble with critical upcoming games
- Resume Comparison - Side-by-side comparison tool for analyzing team resumes
- Conference View - Multi-bid breakdown with full conference standings and odds
- Odds Tracking - Daily updates with biggest movers and historical comparisons
- React 18 - Core UI library for component-based architecture
- TypeScript - Type safety and enhanced developer experience
- Vite - Fast build tool and dev server with hot module replacement
- Tailwind CSS v4 - Utility-first CSS framework for rapid UI development
@tailwindcss/postcss- PostCSS plugin for Tailwind v4 integrationpostcss&autoprefixer- CSS processing and browser compatibility
- IBM Plex Sans - Custom heading font (via Google Fonts)
- Geist & Geist Mono - Body and monospace fonts (via Google Fonts)
- Radix UI - Unstyled, accessible component primitives
@radix-ui/react-dialog- Modal/dialog functionality@radix-ui/react-popover- Popover menus and tooltips
- Lucide React - Icon library for UI elements
- cmdk - Command palette component for team search/selection
- clsx - Conditional className utility
- tailwind-merge - Intelligent Tailwind class merging
- class-variance-authority - Type-safe component variants
- Python scrapers - Backend data collection scripts (not committed to repository)
all_teams_scrape.py- Scrapes team rankings, metrics, and tournament oddsschedule_scraper.py- Collects full season schedules with opponent logos and slugs from ESPN APIgenerate_team_mappings.py- Creates team identity mappings across data sourcesbackfill_previous_rankings.py- Retroactively adds historical ranking comparisonsbackfill_tournament_odds.py- Backfills historical tournament odds data
- CommandPalette - Global keyboard-accessible team search (⌘K)
- Speedometer - SVG-based gauge displaying tournament odds percentage with animated needle
- RankingSparkline - Visual ranking indicator with color coding
- TournamentDashboard - Overview cards showing key tournament selection metrics
- OddsMovers - Component displaying biggest risers, fallers, and bubble teams
- BubbleSidebar - Sidebar showing Last Four In, Last Four Byes, and First Four Out
- BubbleGames - Display of important upcoming games for bubble teams
- Combobox - Searchable team selector with keyboard navigation
- LandingView - Homepage with scrolling logo grid, team search, random odds gauge, and biggest odds movers
- TeamView - Detailed team page with rankings table, schedule, record breakdowns, and projected seed
- AllTeamsView - Comprehensive sortable table of all 362 teams with rankings and tournament odds
- BracketView - Full 68-team bracket projection with seeds, auto-bids, and play-in games
- BubbleWatchView - Dedicated bubble team tracker with odds movers and critical upcoming games
- ConferenceListView - Conference-by-conference breakdown with tournament odds and standings
- ResumeCompareView - Side-by-side resume comparison tool (up to 8 teams) with all key metrics
ncaa-tournament-odds/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── ui/ # shadcn/ui-style primitives
│ │ ├── Layout.tsx
│ │ ├── Header.tsx
│ │ ├── Footer.tsx
│ │ ├── CommandPalette.tsx
│ │ ├── Speedometer.jsx
│ │ ├── RankingSparkline.tsx
│ │ ├── TournamentDashboard.tsx
│ │ ├── OddsMovers.tsx
│ │ ├── BubbleSidebar.tsx
│ │ └── BubbleGames.tsx
│ ├── views/ # Page-level components
│ │ ├── LandingView.tsx
│ │ ├── TeamView.tsx
│ │ ├── AllTeamsView.tsx
│ │ ├── BracketView.tsx
│ │ ├── BubbleWatchView.tsx
│ │ ├── ConferenceListView.tsx
│ │ └── ResumeCompareView.tsx
│ ├── lib/ # Utility functions
│ │ ├── utils.ts
│ │ ├── cn.ts
│ │ └── bracketProjection.ts
│ ├── types/ # TypeScript type definitions
│ │ └── team.ts
│ ├── App.tsx # Main app component with routing
│ ├── main.tsx # React entry point
│ └── index.css # Global styles + Tailwind directives
├── public/ # Static assets and JSON data (committed)
│ ├── all_teams_rankings.json # Team rankings and tournament odds
│ ├── all_teams_schedules.json # Complete schedules with opponent slugs
│ ├── odds_movers.json # Biggest risers/fallers in tournament odds
│ ├── team_mappings.json # Team identity mappings
│ └── rankings/ # Daily historical snapshots (not committed)
├── scrape/ # Python data collection scripts (not committed)
│ ├── all_teams_scrape.py
│ ├── schedule_scraper.py
│ ├── generate_team_mappings.py
│ ├── backfill_previous_rankings.py
│ ├── backfill_tournament_odds.py
│ └── git-push.sh # Automation script for daily updates
├── index.html # Entry HTML with Google Analytics
├── vite.config.ts # Vite configuration
├── tailwind.config.js # Tailwind CSS configuration
├── postcss.config.js # PostCSS configuration
└── package.json # Dependencies and scripts
-
Scraping - Python scripts collect data from team-sheet sources
- Rankings scraper: NET, BPI, SOR, KPI, KenPom, Torvik rankings from NCAA team sheets
- Schedule scraper: Full season schedules with opponent logos, scores, slugs, and rankings
- Odds calculator: Tournament odds based on weighted metrics and historical data
- Bubble Watch: Teams closest to 50% tournament odds
- Risers/Fallers: Shows which teams jumped or dropped in today's rankings
- Team mappings: Cross-reference between ESPN IDs, slugs, display names, and data source names
-
Storage - Data saved to JSON files in
/publicall_teams_rankings.json- 362 teams with all ranking metrics and tournament oddsall_teams_schedules.json- Complete schedule data with pre-computed opponent slugsodds_movers.json- Biggest risers, fallers, and bubble teams based on odds changesteam_mappings.json- Team identity mapping
-
Frontend - React app fetches JSON on load
App.tsxloads all data files and manages global state- Client-side routing via URL slugs (e.g.,
/nebraska-cornhuskers,/all-teams) - Tournament odds pre-calculated in at scraper runtime
- Google Analytics tracks page views and navigation
-
Display - Component hierarchy renders views
LandingView- Homepage with team search, odds movers, and scrolling logosTeamView- Detailed team page with rankings, schedule, records, and projected seedAllTeamsView- Sortable table of all 362 teamsBracketView- Full 68-team bracket projection based on current dataBubbleWatchView- Bubble team tracker with odds movers and critical gamesConferenceListView- Conference standings with tournament oddsResumeCompareView- Side-by-side team resume comparison
Tournament odds are calculated using a weighted algorithm:
- NET ranking
- BPI, SOR, KPI, WAB, KenPom and Torvik rankings
- Quadrant records (Q1-Q4)
- Overall record and strength of schedule
- Day-over-day odds changes tracked via
previousTournamentOdds
- Full 68-team field projection based on composite rankings
- Automatic bid tracking for conference tournament winners
- Play-in game assignments (First Four)
- Seed line calculations (1-16) with proper distribution
- Last Four In, Last Four Byes, and First Four Out indicators
- Bubble team rankings with composite scores
- Biggest Risers - Teams with largest positive odds changes
- Biggest Fallers - Teams with largest negative odds changes
- Bubble Teams - Teams closest to 50% tournament odds threshold
- Real-time tracking via
odds_movers.json - Integrated into LandingView and BubbleWatchView
- Dedicated page for tracking bubble teams
- Live tournament dashboard with key metrics
- Critical upcoming games for bubble teams with opponent odds
- Sidebar showing Last Four In, Last Four Byes, First Four Out
- Integration with schedule data to highlight important games
- Side-by-side comparison of up to 8 teams
- All key metrics in one view (NET, BPI, SOR, KPI, WAB, KenPom, Torvik)
- Quadrant records comparison
- Conference standings comparison
- Preset groups (e.g., Last Four Byes, First Four Out)
- Conference-by-conference breakdown of all D1 teams
- Conference standings with tournament odds
- Projected seeds and bids per conference
- Sortable and filterable by conference
- Global command palette (⌘K) with instant search across 362 teams
- Header and footer team selectors
- Keyboard navigation support
- Logo previews in dropdown
- Accessible and fast
- Sortable by tournament odds, seed, or any ranking metric
- Responsive design with horizontal scroll
- Direct links to team pages
- Color-coded tournament odds indicators
npm install
npm run devnpm run build
npm run previewNote: Scraper scripts are not included in the repository. Only the output JSON files are committed.
# If you have access to the scraper scripts:
python3 scrape/all_teams_scrape.py
python3 scrape/schedule_scraper.py
# Or use the automated script:
sh scrape/git-push.shGoogle Analytics tracks:
- Page views per team
- Team selection events
- User navigation patterns
- Single-page application (SPA) route changes
- Navigation between different views
The app uses prerendering to optimize SEO and initial load times:
- @prerenderer/rollup-plugin - Vite plugin for static prerendering
- Puppeteer - Headless browser for rendering routes
- Dynamic route generation - Prerenders all team pages, views, and key routes
- Meta tag injection - Custom title, description, and Open Graph tags per route
- Environment-specific config - Uses @sparticuz/chromium on Vercel, local Chrome in development
- Sitemap generation - Automated sitemap.xml creation for search engines
- Routes prerendered:
- Home page (
/) - All 362 team pages (
/team-slug) - Latest rankings (
/latest-rankings) - Conferences (
/conferences) - Bracket view (
/bracket) - Bubble watch (
/bubble-watch) - Resume compare (
/compare-resumes)
- Home page (