Navigation that adapts to you.
Accessible routing, AR guidance, and community-driven obstacle reporting for people with disabilities.
Over 1.3 billion people worldwide live with some form of disability. When they open a navigation app, they get the same directions as everyone else — maybe with stairs filtered out if they're lucky. No consideration for the person's specific needs, the actual conditions of the path, or the hundreds of small barriers that make a "technically accessible" route practically unusable.
Able is built around a simple idea: navigation should adapt to the person, not the other way around. A blind user with a guide dog navigating downtown has completely different needs than a power wheelchair user crossing a college campus, who has completely different needs than someone with a cognitive disability trying to follow directions in an unfamiliar city. One-size-fits-all accessibility doesn't work.
The app has two parts:
- Mobile App — A PWA with map navigation, AR camera overlay, search, obstacle reporting, and deep accessibility settings for vision, hearing, mobility, cognitive, and vestibular needs
- Web Portal — An admin dashboard for drawing accessible routes on a map and syncing them to mobile devices in real time
Navigation & AR
- Turn-by-turn routing that adapts to the user's specific accessibility profile
- AR overlay — point your camera and see the route rendered as a glowing line on the ground
- Google Places search with autocomplete and geocoding fallback
- Community obstacle reporting with photo uploads
Accessibility Profiles
- Mobility — wheelchair (manual/power), scooter, walker, crutches, cane
- Vision — screen reader optimization, high contrast, large text, colorblind modes (protanopia, deuteranopia, tritanopia, achromatopsia)
- Vestibular — reduced motion, no flashing elements
- Cognitive — simplified interfaces, clearer step-by-step instructions
- Hearing — visual alerts, spatial audio support
- 8 language options
Portal
- Click-to-draw route creation on Google Maps
- Save, delete, and push routes to mobile in real time
- Obstacle placement and geolocation
- Cross-device sync via a lightweight Node.js server
This is where Able is fundamentally different from existing navigation.
Google Maps treats accessibility as a filter — remove stairs, done. It has no idea what the path is actually like for someone who uses it. It doesn't know that the curb cut on 5th Street has a 2-inch lip that catches wheelchair casters, that the brick sidewalk downtown vibrates a power chair so badly it's painful, that the crosswalk signal at Main and 3rd doesn't have an audible indicator for blind pedestrians, or that the elevator in the parking garage breaks every other Tuesday.
Able doesn't filter paths. It understands them. Every path segment in the graph carries detailed physical metadata, and the algorithm computes a personalized traversal cost based on the specific user's disability profile. The routing engine has four layers.
The physical world is represented as a directed graph where each edge (path segment) carries more than just distance:
- Surface type — smooth concrete, asphalt, brick, cobblestone, gravel, dirt, grass, metal grate. Each surface affects different disabilities differently — cobblestone is jarring for wheelchair users, but also a tripping hazard for cane users and disorienting for people with vestibular disorders.
- Running slope — percentage grade. ADA maximum is 5% for accessible routes. Steep slopes are dangerous for wheelchairs, exhausting for walker users, and a fall risk for people with balance disorders.
- Cross-slope — lateral tilt that causes wheelchairs to drift and creates uneven footing for ambulatory users with stability challenges.
- Width — scored against the user's minimum clearance. A wheelchair needs more space than a cane. A user with a guide dog needs more space than either.
- Curb cut quality — flush, gradual, steep, has a lip, or missing. Affects wheelchair users directly and ambulatory disabled users who can't step off curbs.
- Tactile paving — detectable warning surfaces critical for blind and low-vision users navigating intersections.
- Lighting — safety factor for users with low vision, cognitive disabilities, or anyone navigating after dark.
- Audible signals — whether crosswalks and transit stops have audible indicators for blind users.
- Shelter — weather protection, relevant for users who can't easily manage umbrellas or rain gear while using mobility aids.
Nodes are spatially indexed on a grid (~111m cells) for fast nearest-neighbor lookups, allowing O(1) amortized coordinate-to-node snapping.
The cost of traversing an edge depends entirely on who's traversing it. Each user has an accessibility profile that specifies their needs, limitations, and preferences.
The cost function evaluates each edge in two passes:
Hard constraints return cost = ∞ (impassable):
- Slope exceeds the user's stated maximum
- Path narrower than minimum clearance
- Surface type is on the user's avoid list
- A blocking obstacle exists with >70% confidence
- Missing tactile paving at a crossing (for users who require it)
Soft penalties scale the base distance cost using cost = distance × (1 + ΣPᵢ):
The slope penalty follows a cubic curve:
This keeps the penalty near zero for comfortable grades but ramps up sharply as you approach the user's limit — matching how difficulty is actually experienced.
Slope penalty across mobility profiles. The cubic curve keeps comfortable grades cheap while making near-limit slopes expensive. The red line marks the ADA maximum (5%).
Each profile type has different default weights reflecting how much each factor matters for that specific disability:
| Factor | Manual Chair | Power Chair | Walker | Cane | Low Vision |
|---|---|---|---|---|---|
| Slope | 1.0 | 0.5 | 0.7 | 0.5 | 0.3 |
| Surface | 0.7 | 0.8 | 0.5 | 0.6 | 0.4 |
| Width | 0.6 | 0.8 | 0.3 | 0.1 | 0.3 |
| Distance | 0.3 | 0.2 | 0.6 | 0.5 | 0.4 |
| Curb Cuts | 0.9 | 0.9 | 0.4 | 0.2 | 0.3 |
| Tactile Paving | 0.1 | 0.1 | 0.1 | 0.2 | 1.0 |
| Lighting | 0.2 | 0.2 | 0.3 | 0.3 | 0.9 |
| Obstacles | 0.8 | 0.8 | 0.5 | 0.4 | 0.7 |
Users can override any weight. A power chair user who's particularly sensitive to surface cracks can crank that weight up. A blind user who always travels with a sighted guide can reduce the tactile paving weight.
Surface penalties are assigned per material type:
Traversal penalty by surface type. Smooth concrete is baseline. Grass, dirt, and gravel are nearly impassable for most mobility aids and hazardous for ambulatory users with balance challenges.
Static graph data changes slowly, but the real world is dynamic — construction, broken elevators, fallen trees, flooding, missing audible signals, temporary barriers. Our obstacle engine handles these through community reports with a decay model.
When a user reports an obstacle, it gets spatially mapped to all graph edges within 15 meters, initialized with full confidence, and the affected edges get their scores recalculated.
Time decay. Different obstacles have predictably different lifespans:
| Obstacle | Half-Life | Reasoning |
|---|---|---|
| Stairs | 365 days | Permanent infrastructure |
| Missing tactile paving | 90 days | Slow infrastructure fix |
| Cracked surface | 30 days | Slow to repair |
| No audible signal | 14 days | May be reported/fixed at city level |
| Construction | 7 days | Changes week to week |
| Broken elevator | 5 days | Usually repaired within a week |
| Blocked path | 3 days | Often temporary |
| Flooding | 2 days | Recedes quickly |
Confidence decay over 30 days. Temporary obstacles like floods fade quickly. Infrastructure problems like missing tactile paving persist.
Confirmation and resolution. Other users can confirm (confidence +0.3, partial age reset) or resolve (confidence -0.4) obstacles. This keeps the data accurate through community validation — a broken elevator that multiple people confirm stays flagged indefinitely, while a false report decays and disappears.
The prediction engine learns from historical reports to anticipate problems before they happen:
- Temporal patterns — "This elevator breaks on weekday mornings" → preemptive cost penalty on those days/hours
- Recurrence detection — Obstacles that keep coming back after resolution get increasing probability scores:
P = min(0.8, 0.3 + n × 0.15) - Spatial clustering — Dense clusters of reports in a small area suggest expanding issues (construction zones, flooding patterns). Nearby edges get preemptive penalties even without individual reports.
Routes are computed with A* search using haversine distance as the heuristic (admissible — guarantees optimal paths). The pathfinder also:
- Generates alternative routes by penalizing edges shared with the primary route
- Attaches per-segment warnings — steep slope, narrow path, no curb cut, no tactile paving, poor lighting
- Computes a route accessibility score (0-100) with bottleneck detection — a route is only as accessible as its worst segment
- Estimates a fatigue index from distance, elevation, and surface difficulty
The algorithm lives in packages/shared/src/algorithm/ as a standalone engine with no UI dependencies:
algorithm/
├── types.ts # Graph, profile, cost, and result types
├── graph.ts # Spatial graph with grid indexing + geo utilities
├── cost-function.ts # Profile-aware composite cost with hard/soft constraints
├── pathfinder.ts # A* search with min-heap and alt route generation
├── obstacle-engine.ts # Crowdsourced reports, time decay, confirmations
├── prediction-engine.ts # Temporal, recurrence, and spatial pattern detection
├── scoring.ts # Route scoring, bottleneck analysis, fatigue index
└── index.ts # Public API exports
| Layer | Technology |
|---|---|
| Framework | React 19 |
| Language | TypeScript 5.7 |
| Build Tool | Vite 6 |
| Styling | Tailwind CSS 4 |
| State | Zustand |
| Maps | Google Maps JavaScript API |
| Animations | Framer Motion |
| Icons | Lucide React |
| Backend | Firebase (Auth, Firestore) |
| Sync | Custom Node.js sync server |
able/
├── apps/
│ ├── mobile/ # Mobile PWA
│ │ ├── src/
│ │ │ ├── components/
│ │ │ │ ├── ar/ # Camera feed, route line, HUD
│ │ │ │ ├── map/ # Google Maps, overlays, markers
│ │ │ │ ├── navigation/ # Search, bottom sheet, step list
│ │ │ │ ├── report/ # Obstacle reporting
│ │ │ │ └── shared/ # Reusable UI components
│ │ │ ├── hooks/ # Geolocation, compass, route progress
│ │ │ ├── screens/ # Home, Navigation, AR, Settings
│ │ │ └── stores/ # Zustand state
│ │ └── public/ # PWA manifest, icons, service worker
│ ├── portal/ # Web Portal
│ │ └── src/
│ │ ├── components/ # Map, sidebar, route tools
│ │ └── stores/ # Portal state
│ └── sync-server.js # Cross-device route sync
└── packages/
└── shared/ # Shared types, constants, Firebase mock
└── algorithm/ # Accessibility pathfinding engine
- Node.js 18+
- npm 9+
- Google Maps API key (Maps JS API, Places API, Geocoding API enabled)
git clone https://github.com/ajain189/Able.git
cd Able
npm install
cp .env.example apps/mobile/.env
# Add your Google Maps API key to apps/mobile/.env# Terminal 1
node apps/sync-server.js
# Terminal 2
npm run dev:mobile
# Terminal 3
npm run dev:portalMobile runs on https://localhost:5173, portal on http://localhost:5174.
For testing on a phone, use your machine's local IP (https://192.168.x.x:5173) and accept the self-signed cert.
Able is built to be accessible itself, not just route around inaccessibility:
- WCAG 2.1 AA color contrast throughout
- Screen reader optimized with semantic markup and ARIA labels
- Colorblind modes — protanopia, deuteranopia, tritanopia, achromatopsia
- Vestibular-safe reduced motion for users with motion sensitivity
- Cognitive simplification — cleaner interfaces, simpler language, fewer choices
- Photosensitivity protection — no flashing or strobing elements
- 8 languages — English, Spanish, French, German, Chinese, Japanese, Korean, Arabic
- Large text mode
- Voice control support
- Spatial audio cues for navigation
This project is proprietary. All rights reserved.
