Inspiration
We wanted to make getting to class and around campus less stressful. Students often don’t know whether to walk or take the bus, when to leave, or if the bus will actually show up. We focused on Madison Metro Route 80 and found the solution to "When should I leave?", "Should I walk or take the bus?", How crowded will it be? and "Is the bus really coming?"
What it does
SmartTransit is a Route 80 transit app for UW–Madison and downtown Madison. Next class & leave time – Uses your schedule and your location to suggest when to leave, with live bus ETAs and crowd risk (low/medium/high) and ghost risk (chance the scheduled bus doesn’t show). Walk vs bus – Compares walking the whole way vs walking to the nearest stop. Gives a clear “walk” or “bus” recommendation and arrival times. Nearest stop & live map – Finds the closest Route 80 stop, shows live bus positions and stop markers on a map, and displays real-time predictions for that stop. Schedule page – Add/edit classes and events with locations and times; the main page uses this to show “next class” and leave-by time.
How we built it
Front end: Next.js 16 (App Router), React 19, TypeScript, and Tailwind CSS. The main dashboard and schedule page share localStorage for the schedule and use sessionStorage to know when the user came from the schedule page.
Route 80 logic: GTFS-derived stops and variants, segment-level travel times between timepoints, variant inference from bus destination, and “loop rule”. Used for ETAs and for walk-vs-bus bus travel time. Backend (Python/FastAPI): Crowding service (stop-level density, time-of-day heuristics, optional weather) and ghost risk Data: UW and downtown Madison buildings from OpenStreetMap (Overpass), uw_buildings.json, and a curated list of UW buildings and housing; Route 80 stops and variants from JSON.
Challenges we ran into
Route 80 is a loop – Buses go both directions and repeat. We had to infer variant from destination, snap vehicles to the correct stop sequence, and implement the “loop rule” so we don’t suggest a bus that has already passed the stop.
Keeping the UI responsive – Avoiding setState-in-effect issues and unnecessary re-renders. Making sure the map and sidebar feel smooth with polling and live updates. Backend optional – The crowding service needs a Madison Metro API key for ghost risk and runs separately.
Accomplishments that we're proud of
Segment-based walk vs bus – Bus time isn’t a flat guess; it’s computed from Route 80’s schedule. Ghost risk – Surfacing the chance that a scheduled bus won’t show using live vehicle count and time windows so users can plan for no-shows. One big location list – Merging OSM buildings, downtown Madison, and UW housing into one deduped, searchable list so students can pick dorms, libraries, and classrooms by name. Schedule : dashboard integration - Schedule page and main page share the same schedule; “next class” and leave-by time stay in sync, with a clear path from “Manage schedule” to “See when to leave.”
What we learned
How to infer bus direction and variant from real-time data and apply loop rules for a circular route. Designing the app so the Python crowding/ghost service is optional and the UI degrades gracefully when it’s unavailable. Balancing real-time updates (buses, predictions, crowding) with performance and clear dependency arrays in React.
What's next for SmartTransit
More routes – Generalize beyond Route 80 so users can compare routes or choose alternate lines. Notifications – “Leave in 10 minutes” or “Bus is 2 min away” based on schedule and location. Historical accuracy – Use past prediction vs actual arrival to improve ETA and ghost-risk models.
Built With
- chatgpt
- fastapi
- javascript
- json
- leaflet.js
- madison-metro-api
- next.js
- open-meteo
- openstreetmap
- python
- react
- tailwind
- typescript
Log in or sign up for Devpost to join the conversation.