An interactive, real-time Bus Transit Simulation, Multi-Modal Trip Planner, and Analytics Dashboard designed to optimize urban mobility, monitor vehicle status, and provide intelligence for public transport operations in Ho Chi Minh City. Built with a modern, high-performance web technology stack.
- Problem Statement
- Solution Overview
- Features
- Setup and Installation
- Run Instructions
- User Guide
- Tech Stack and Architecture
In dense, rapidly expanding urban areas like Ho Chi Minh City, public bus transit systems face several core challenges that deter passenger ridership and complicate route planning:
- Commuter Waiting Uncertainty: Passengers wait at bus stops without knowing whether the approaching bus is already full, if it will bypass them, or exactly when it will arrive.
- Last-Mile and Transfer Friction: Commuters lack reliable tools to estimate walking transfer durations between adjacent stops or plan multi-modal fallback options when transit delays occur.
- Operational Inefficiencies and Fuel Waste: Electric and internal combustion buses consume energy and fuel while idling in traffic jams, but operators lack live telemetric dashboards showing vehicle state-of-charge relative to route congestion.
- Lack of Spatial Traffic Realism in Planning: Standard simulations use static timers rather than dynamic, progress-based vehicle kinematics that dynamically respond to traffic jams.
The Grab-UNDP Smart Bus Transit Simulation System addresses these issues through a unified commuter-dispatcher portal:
- Real-Time Kinematic Simulation: Animates buses along five actual Ho Chi Minh City transit routes (Lines 01, 03, 19, 45, 56) tracing physical streets at a smooth 60 frames per second.
- Intelligent Passenger Recommendation System: Computes live boarding probabilities at any stop using an estimation of passengers at arrival. If overcrowding or excessive delay is detected, it suggests alternative options.
- Grab Ride-Hailing Integration (GrabAlternative): If a bus stop suffers from a predicted boarding overflow (the bus will arrive full), the passenger can book a discounted Grab ride directly from the stop recommendation banner.
- Multi-Modal Route Planner: Utilizes a custom Dijkstra shortest-path search algorithm across intersecting transit lines, computing transfers, transfer waiting penalties, and walk legs to the origin and destination stops.
- Telemetry and Operator Dashboard: Tracks fuel and battery consumption rates (which spike during dwell and traffic periods) and provides a simulated driver console where operators can report and clear traffic segments.
- Geospatial Realism: Projects transit networks directly onto OpenStreetMap coordinates mapping actual Ho Chi Minh City routes.
- Moving Headers: Bus markers display travel direction, line identifiers, occupancy level color-codings, and active battery or fuel capacities.
- Selected Route Overlay: Animates path lines and outlines active travel trajectories.
- Decision Engine: Evaluates oncoming buses and issues action tags:
- WAIT: The bus is arriving in less than 4 minutes with space available.
- LEAVE (Walk / Alternative): The next bus is more than 8 minutes away or is predicted to be full (exceeding 90% crowding).
- UNCERTAIN: Non-optimal timing or route overlaps.
- Boarding Probability: Calculates the exact chance of boarding based on intermediate stops' passenger alighting and boarding behaviors.
- Multi-Segment Paths: Computes optimal route combinations across lines (including walking to and from stations and transferring at interchange nodes).
- Transfer Penalty: Factored in as an extra 180 seconds to avoid recommending paths with frequent, short transfers.
- Walking Details: Integrates distance and duration calculations based on standard human walking speeds (1.2 meters per second).
- In the event of a boarding overflow warning (the bus is full), a Book GrabAlternative (20% discount) option appears in the sidebar. Clicking it books a discounted backup vehicle.
- Integrates miniature sparklines in the sidebar. It charts the historical number of waiting passengers at your active station over the last 10 minutes (sampled at 10-second intervals) to show demand trends.
- Clicking a bus reveals live seat status grids, fuel and battery capacity levels, schedule timeline, and previous boarding/alighting events at its last stop.
- Spatial Traffic Congestion: Speed reduces to 15% in traffic jams. The route behind the bus clears dynamically.
- Toast Alert System: Fires notifications when buses encounter or clear traffic jams.
- Node.js (v18.0.0 or higher is recommended)
- npm (v9.0.0 or higher)
-
Clone the Repository:
git clone https://github.com/longtoZ/Grab-UNDP-Hackathon.git cd Grab-UNDP-Hackathon -
Install Dependencies:
npm install
-
Verify Setup (Optional): Run the TypeScript type checker to ensure there are no compilation issues:
npx tsc --noEmit
To launch the hot-reloading development server:
npm run dev- Once running, open your browser and navigate to
http://localhost:5173/.
To create an optimized static bundle for deployment:
npm run buildThe output will be placed in the dist/ directory. You can preview the production build locally:
npm run previewThe application is fully client-side and compiles into pure HTML, JS, CSS, and asset files. It can be hosted on any cloud static provider.
Ensure you have the Vercel CLI installed (npm install -g vercel), then run:
vercel --prodBuild the files first, then deploy:
npm run build
netlify deploy --dir=dist --prodTo publish via GitHub Actions, configure a workflow that triggers on push to the main branch, runs npm run build, and deploys the dist/ folder using JamesIves/github-pages-deploy-action.
- Map Method: Click any circular station marker on the map. The map will place a pulsing ring indicating your start location.
- Search Method: Use the floating search bar at the top-left to search by stop name (e.g., Hồ Con Rùa) or stop ID (e.g., S7693).
- When a station is selected, the sidebar switches to the Stations tab.
- The Your Station panel will display the station name, a passenger queue trend sparkline, and the Nearest Buses approaching.
- Check the Recommendation Banner:
- If a Wait for Bus banner is visible, the next bus has room.
- If a Walk / Alternative banner is visible, check if you need to book a GrabAlternative by clicking the button.
- Click the Trip Planner tab in the sidebar.
- Input your Origin stop and Destination stop. You can swap them with the swap button.
- The pathfinder will show up to 3 routes. Each card shows:
- Total travel time (including transfer penalties and walking times).
- Total distance (in meters).
- Transfer count (e.g. Direct, 1 Transfer).
- Select a route option to highlight the full walking and transit paths on the map.
- Click Track on any approaching bus card, or click a bus marker on the map.
- The camera will center on the bus and automatically follow it as it travels. Click and drag the map at any time to break camera lock-on.
- Clicking an active bus opens the Bus Inspector drawer at the bottom:
- Seat Map: Green seats are free, orange/red seats are occupied.
- Fuel/Battery: Visual indicator of energy reserves. Fuel drains faster during traffic jams.
- Timeline: Shows upcoming schedule list.
- Drivers can use the Driver Console components to mock traffic congestion:
- Open
src/components/Sidebar/DriverConsole.tsxor click driver reporting overrides. - A dispatcher/driver can toggle traffic jams along active bus paths. System toast messages will immediately warn other users in the network.
- Open
- Core Logic and UI: React 19 (TypeScript)
- Build tool: Vite 8
- GIS Engine: Leaflet and React-Leaflet 5
- Pathfinding Engine: Dijkstra (Custom Graph Path search)
- Animation System: high-performance DOM-ref hooks
graph TD
subgraph Core ["Application Core"]
App["App.tsx"]
useSim["engine/simulation.ts"]
App --> useSim
end
subgraph Data ["Data and Simulation Utilities"]
graphFile["data/graph.ts"]
schedule["data/schedule.ts"]
polyline["engine/polyline.ts"]
useSim --> graphFile
useSim --> schedule
useSim --> polyline
end
subgraph MapComponents ["Map Visualization Layer"]
Map["components/TransitMap/TransitMap.tsx"]
EdgeL["components/TransitMap/EdgeLayer.tsx"]
NodeL["components/TransitMap/NodeLayer.tsx"]
BusLayer["components/TransitMap/BusLayer.tsx"]
User["components/TransitMap/UserMarker.tsx"]
Destination["components/TransitMap/DestinationMarker.tsx"]
Map --> EdgeL
Map --> NodeL
Map --> BusLayer
Map --> User
Map --> Destination
end
subgraph SidebarComponents ["Sidebar Control Panel"]
Sidebar["components/Sidebar/Sidebar.tsx"]
RoutePlanner["components/Sidebar/RoutePlanner.tsx"]
RecBanner["components/Sidebar/RecommendationBanner.tsx"]
BusCard["components/Sidebar/BusCard.tsx"]
Sparkline["components/Sidebar/Sparkline.tsx"]
Sidebar --> RoutePlanner
Sidebar --> RecBanner
Sidebar --> BusCard
Sidebar --> Sparkline
end
subgraph InspectorComponents ["Inspection Panel"]
Inspector["components/Sidebar/BusInspector.tsx"]
end
App --> Map
App --> Sidebar
App --> Inspector
RoutePlanner --> pathfind["engine/pathfinding.ts"]
pathfind --> polyline
- Dijkstra Route Pathfinder (
src/engine/pathfinding.ts):- Models the transit system as a directed, weighted graph.
- Features dynamic path weight interpolation that factors in transfer costs and walking transitions.
- 60fps Animation Loop (
src/engine/simulation.ts):- Rather than updating React state 60 times a second (which causes expensive Virtual DOM reconciliations), the simulation tick uses a
requestAnimationFrameloop. - Buses register direct reference-updating callbacks (
registerBusUpdater). - The loop updates coordinate nodes directly inside Leaflet DOM markers, resulting in smooth animations while keeping React component rerenders throttled at a low frequency (2 Hz).
- Rather than updating React state 60 times a second (which causes expensive Virtual DOM reconciliations), the simulation tick uses a
- Spatial Congestion and Speed Interpolation (
src/engine/polyline.ts):- Maps physical coordinates onto polylines using Haversine equations to accurately simulate vehicle positions.
- Calculates relative speed reductions (85% reduction) inside congestion zones.
- Multi-Modal Walking Engine (
src/engine/walking.ts):- Creates realistic, hashed walking starting and ending offsets around bus stop pins.
- Integrates walking speed and duration computations dynamically.
Note
This application is developed as part of the Grab-UNDP Urban Mobility Hackathon to support sustainable city transit networks, clean energy vehicle tracking, and multi-modal transport planning.