Inspiration
Whenever my family visits New York, I end up being the tour guide, and I keep hitting the same wall: Seeing cool things isn't optimized for you. The Met opens at 10, the dinner place we want only has a 5–8 PM window, Top of the Rock sells timed tickets, and getting between all of them means juggling the subway, PATH, maybe the LIRR, Citi Bike, and an Uber when everyone's exhausted. Each system has its own app, its own fare, and its own way to pay.
The hackathon track asked about moving smarter: commuters juggling the MTA, LIRR, Metro-North, PATH, and Citi Bike with no unified routing or payment experience. We realized visitors feel that pain the hardest. A local knows PATH isn't on OMNY-only fare logic and that you need TrainTime for the LIRR; a family from London doesn't. So we built NYSee: See New York. Skip the transit maze.
What it does
NYSee turns a wishlist of sights into an optimized, door-to-door day across every NYC transit system.
- AI trip planner. A six-question quiz (who's coming, interests, pace, getting around, whether to leave Manhattan, plus free-text notes like "it's our anniversary"). Claude picks the places and explains each pick, then our optimizer orders and routes the day.
- Itinerary optimizer. It respects opening hours, timed tickets, and preferences like "dinner between 5 and 8." It separates must-sees from nice-to-haves, and when something doesn't fit it tells you why ("closed that day," "about 20 min short").
- Multimodal legs. Every leg is broken into segments (walk → subway → PATH → walk) with time and cost. Switch any leg to Uber, driving, Citi Bike, or walking, and the rest of the day re-times in place.
- "Along the way" surprise stops. For each leg, NYSee finds places within a ~10 minute detour that match your interests and still fit the schedule. One click inserts them.
- The fare bundle. One view of the whole day's cost: which legs are a single contactless tap, which need their own app (TrainTime, Uber), per-rider vs per-vehicle costs, and deep links out, including an Uber link with pickup and drop-off already filled in.
- Time awareness. Everything runs on NYC time, DST-safe, with a jet-lag note: "your 9:00 AM start is 2:00 PM in London."
How we built it
NYSee is a Next.js + TypeScript app with a Leaflet map. The core is a planning pipeline that runs on the server:
- Build a travel-time matrix with a fast local model.
- Optimize the order of stops.
- Route only the legs of the final plan through the real router (Google Routes API).
- Repair the plan if real travel times broke it, dropping the lowest-value nice-to-have.
- Find along-the-way suggestions and re-simulate each one to make sure it still fits.
- Build the fare bundle from a fare table covering OMNY, PATH, LIRR/Metro-North, Citi Bike, Uber, and driving.
The optimizer. Picking which sights to visit and in what order, under opening hours and a time budget, is the orienteering problem with time windows, which is NP-hard. We solve it heuristically: greedy insertion (must-sees first, then nice-to-haves ranked by value per added minute), then local search with 2-opt and single-stop relocate moves. Each candidate order is scored by simulating the day:
$$\text{cost} = T_{\text{travel}} + 0.8\,T_{\text{wait}} + 0.01\,t_{\text{end}}$$
Waiting outside a closed museum is penalized almost as much as travel, and the small last term breaks ties toward finishing earlier. Nice-to-haves are inserted in order of \( \text{score} / \Delta\text{cost} \), so a popular stop that's barely out of the way wins over a so-so one across town.
Two-tier routing. The optimizer evaluates thousands of candidate orders, so calling a real routing API for each would be slow and expensive. Instead it uses a fast local model, and only the 6–10 legs of the final plan go to Google, departing at their scheduled times. That's about one API call per leg per re-plan, and it makes OpenTripPlanner (with the public MTA, LIRR, Metro-North, and PATH GTFS feeds) a drop-in replacement.
AI picks with guardrails. The AI planner calls Claude with structured outputs. The place ID is an enum of our catalog, so Claude literally can't invent a place, and we validate every pick again (allowed area, open that day). Without an API key, a deterministic recommender scores places by interests, party type, pace, and distance.
Works offline. Every provider (routing, places, Citi Bike GBFS, AI) has a fixture fallback, so the demo runs with zero API keys on bad venue Wi-Fi.
Challenges we ran into
- You can't actually buy the bundle. None of the agencies offers a public API for third parties to sell tickets, and Uber's price-estimate API needs partner approval. Rather than fake a checkout, we reframed the bundle as one plan, one cost estimate, one tap per leg, with our own fare model and honest deep links.
- Time windows break simple routing. 2-opt alone handled time windows badly; reversing a segment can push a museum past closing. Adding single-stop relocate moves and a "swap out a nice-to-have" retry fixed most cases.
- Real times vs. estimates. An order that looks feasible on the fast model can break once real transit times come back, so we added a repair step that drops the lowest-value optional stop and re-routes.
- Timezones. We store every clock time as minutes after midnight in NYC local time and only convert at the edges, so the optimizer never touches timezone math and DST can't bite us.
- Keeping the AI honest. Early on, a model could recommend a place that was closed that day or outside the area the traveler chose. The enum schema plus server-side validation solved it.
What we learned
- How to model a real-world planning problem as a known optimization problem, and why heuristics beat exact solvers at hackathon speed.
- How fragmented NYC transit payment really is: OMNY, PATH's TAPP, TrainTime for commuter rail, Citi Bike, and rideshare all live in separate worlds.
- That designing for failure (fixture fallbacks for every provider) made development and demos far less stressful.
- How to use structured outputs to keep an LLM's answers inside a trusted set of data.
What's next for NYSee
- Swap in OpenTripPlanner with live GTFS-realtime feeds for schedule-accurate transit times and delays.
- Multi-day trips that split a wishlist across days.
- Live event and ticket availability.
- Partnerships that could turn the fare bundle into a real one-tap checkout.
Built With
- anthropic
- carto
- citi-bike-gbfs
- claude
- google-maps
- google-places
- google-routes-api
- gtfs
- leaflet.js
- lucide
- nextjs
- node.js
- openstreetmap
- react
- react-leaflet
- typescript
- vitest
- zod
Log in or sign up for Devpost to join the conversation.