routeable

    An explainable accessibility route-planning engine and WebAssembly demo.

    accessibility
    routing
    wasm
    campus
    moonbit
    Download zip
    Version
    0.2.0
    License
    Apache-2.0
    Last updated
    2 months ago
    Downloads
    43

    No dependencies

    #RouteAble / 路见无碍

    RouteAble is an explainable accessibility route planner written primarily in MoonBit. Instead of returning only the shortest path, it filters obstacles for a chosen mobility profile and shows why each route segment was selected.

    #Why it exists

    Ordinary navigation usually assumes that every pedestrian can use stairs, narrow paths or poorly lit shortcuts. RouteAble models practical constraints for wheelchair users, people with low vision, stroller users and ordinary walkers. It is designed for bounded places such as campuses, parks, communities and venues where accessibility data can be maintained carefully.

    #Features

    • Profile-aware hard constraints for stairs, slope, width, construction and rough surfaces.
    • Weighted Dijkstra search that balances distance with lighting, crossings, incline and coverage.
    • Segment-level explanations and warnings rather than a black-box recommendation.
    • Standard-library JSON import/export for graphs and versioned maintenance state.
    • Auditable add/update/remove operations for facilities, closures and route segments.
    • Machine-readable algorithm metadata and detailed graph validation findings.
    • A deterministic campus demonstration graph with 56 locations and 194 directed paths.
    • A runnable MoonBit CLI and browser demo backed by the same tested Wasm engine.

    #Quick start

    Prerequisites: MoonBit and Node.js 20+.

    npm run generate:data npm run check npm test npm run demo

    Build the WebAssembly target:

    npm run build

    Open the interactive MoonBit/Wasm demo at http://127.0.0.1:4173:

    npm run web

    The server exposes the locally built web/bridge/bridge.wasm. Browser distance, duration, segment count, warning count and grade are calculated by MoonBit, not duplicated as JavaScript fixtures.

    #JSON and versioned updates

    let graph = demo_campus_graph()
    let encoded = graph_to_json(graph)
    let restored = graph_from_json(encoded)
    let state = new_graph_state(restored).unwrap()
    let closed = set_edge_construction(
    state,
    4,
    true,
    "scheduled maintenance",
    ).unwrap()
    println(graph_state_to_json(closed))

    Malformed JSON raises a standard parse/decode error. validate_graph returns all structural findings, and every accepted update increments GraphState.version while appending a GraphChange record.

    #Project layout

    PathPurpose
    routeable.mbtPublic MoonBit domain model, constraints, planner and explanation API
    graph_io.mbtJSON exchange and detailed structural validation
    graph_state.mbtVersioned edge updates and auditable change history
    metadata.mbtAlgorithm identity, complexity and limitations
    campus_network.mbtGenerated, deterministic demonstration graph
    cmd/mainRunnable CLI demonstration
    web/bridgeStandalone Wasm exports over the MoonBit planner
    web/Dependency-free browser UI that calls the Wasm bridge
    tools/generate_demo_network.mjsReproducibly generates the checked-in sample map
    .github/workflows/ci.ymlChecks, tests and Wasm build

    #Safety and data boundary

    The included map is synthetic. RouteAble is a decision-support demonstration, not an emergency-navigation system. Real deployment requires local accessibility verification, a data maintenance process and context-appropriate safety review. Do not include personally identifying location trails in route data.

    #Licence and third-party material

    The source is licensed under Apache-2.0. The web demo uses no third-party images, map tiles or JavaScript packages. The campus data is generated by this repository and is synthetic.

    #Release

    The public package is available as 13131116363/routeable on mooncakes.io. Version 0.2.0 adds JSON exchange, versioned graph maintenance, randomized scenario tests, metadata and the real browser/Wasm integration.

    AlertLevel

    pub(all) enum AlertLevel {
    Info
    Notice
    Warning
    Blocked
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    AlgorithmMetadata

    pub(all) struct AlgorithmMetadata {
    id : String
    name : String
    version : String
    objective : String
    deterministic : Bool
    supports_constraints : Bool
    complexity : String
    limitations : Array[String]
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Machine-readable metadata for selecting and explaining the route engine.

    Edge

    pub(all) struct Edge {
    id : Int
    from : Int
    to : Int
    meters : Int
    slope_percent : Int
    steps : Int
    lighting : Int
    crossing : Int
    construction : Bool
    surface : Surface
    width_cm : Int
    covered : Bool
    note : String
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    GraphChange

    pub(all) struct GraphChange {
    version : Int
    kind : String
    edge_id : Int
    previous : String
    current : String
    reason : String
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    One auditable graph mutation. Values are stored as JSON text so history is compact and exchangeable without weakening the typed graph representation.

    GraphState

    pub(all) struct GraphState {
    version : Int
    graph : Graph
    changes : Array[GraphChange]
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Versioned graph state used by editors, maintenance tools and simulations.

    MobilityProfile

    pub(all) enum MobilityProfile {
    Wheelchair
    LowVision
    Stroller
    Standard
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    RouteAble is an offline-first, explainable accessibility route planner. Applications supply a small campus graph, community map, or compatible public data and receive a route plus a human-readable rationale.

    Node

    pub(all) struct Node {
    id : Int
    label : String
    zone : String
    x : Double
    y : Double
    has_rest_area : Bool
    has_tactile_paving : Bool
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    ProfileComparison

    pub(all) struct ProfileComparison {
    profile : MobilityProfile
    reachable : Bool
    distance_meters : Int
    friction_score : Double
    grade : String
    message : String
    } derive(
    Debug
    )

    ProfileConfig

    pub(all) struct ProfileConfig {
    max_slope : Int
    max_steps : Int
    minimum_lighting : Int
    minimum_width_cm : Int
    avoid_crossings : Bool
    avoid_gravel : Bool
    rest_bonus : Double
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Route

    pub(all) struct Route {
    profile : MobilityProfile
    node_ids : Array[Int]
    segments : Array[RouteSegment]
    total_meters : Int
    total_score : Double
    accessible : Bool
    summary : String
    warnings : Array[String]
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    RouteMetrics

    pub(all) struct RouteMetrics {
    distance_meters : Int
    average_slope : Double
    total_crossings : Int
    low_light_segments : Int
    covered_segments : Int
    rest_stops : Int
    warning_count : Int
    estimated_minutes : Int
    } derive(
    Debug
    )

    Route quality analysis built on top of the planner's public route result. These helpers make it possible for a UI to compare options without duplicating accessibility policy outside MoonBit.

    RouteSegment

    pub(all) struct RouteSegment {
    edge_id : Int
    from_label : String
    to_label : String
    meters : Int
    score : Double
    reasons : Array[String]
    alerts : Array[String]
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Surface

    pub(all) enum Surface {
    Asphalt
    Paving
    Brick
    Gravel
    Indoor
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    accessibility_grade

    fn accessibility_grade(route : Route) -> String

    add_edge

    fn add_edge(state : GraphState, edge : Edge, reason : String) -> GraphState?

    Add a newly surveyed route segment and record its introduction.

    algorithm_metadata

    fn algorithm_metadata() -> AlgorithmMetadata

    algorithm_metadata_json

    fn algorithm_metadata_json() -> String

    alternative_destinations

    fn alternative_destinations(graph : Graph, start : Int, profile : MobilityProfile) -> Array[Route]

    compare_profiles

    fn compare_profiles(graph : Graph, start : Int, destination : Int) -> Array[ProfileComparison]

    debug_graph_summary

    fn debug_graph_summary(graph : Graph) -> String

    demo_campus_graph

    fn demo_campus_graph() -> Graph

    Generated demo map: 56 locations and 194 directed accessible paths. Regenerate with: node tools/generate_demo_network.mjs

    demo_landmarks

    fn demo_landmarks() -> Array[Int]

    edge_alerts

    fn edge_alerts(edge : Edge, profile : MobilityProfile) -> Array[String]

    edge_block_reason

    fn edge_block_reason(edge : Edge, profile : MobilityProfile) -> String?

    edge_reasons

    fn edge_reasons(edge : Edge, profile : MobilityProfile) -> Array[String]

    edge_score

    fn edge_score(edge : Edge, profile : MobilityProfile) -> Double?

    estimate_minutes

    fn estimate_minutes(distance_meters : Int, profile : MobilityProfile) -> Int

    graph_change_at

    fn graph_change_at(state : GraphState, version : Int) -> GraphChange?

    graph_from_json

    fn graph_from_json(source : String) -> Graph raise

    Decode a graph from JSON. Parse and schema errors are propagated to callers.

    graph_json_is_valid

    fn graph_json_is_valid(source : String) -> Bool

    graph_state_from_json

    fn graph_state_from_json(source : String) -> GraphState raise

    graph_state_to_json

    fn graph_state_to_json(state : GraphState) -> String

    graph_to_json

    fn graph_to_json(graph : Graph) -> String

    Encode a graph as stable, human-readable JSON using MoonBit's standard JSON representation. The result can be stored or exchanged with tools.

    nearest_rest_stop

    fn nearest_rest_stop(graph : Graph, route : Route) -> Node?

    new_graph_state

    fn new_graph_state(graph : Graph) -> GraphState?

    plan

    fn plan(graph : Graph, start : Int, destination : Int, profile : MobilityProfile) -> Route?

    Compute the lowest-friction route for a profile using constrained Dijkstra.

    profile_config

    fn profile_config(profile : MobilityProfile) -> ProfileConfig

    profile_name

    fn profile_name(profile : MobilityProfile) -> String

    reachable_profile_count

    fn reachable_profile_count(graph : Graph, start : Int, destination : Int) -> Int

    remove_edge

    fn remove_edge(state : GraphState, edge_id : Int, reason : String) -> GraphState?

    Remove a segment by identifier while keeping an audit record.

    route_briefing

    fn route_briefing(graph : Graph, route : Route) -> String

    fn route_can_be_recommended(graph : Graph, route : Route) -> Bool

    route_has_rest_stop

    fn route_has_rest_stop(graph : Graph, route : Route) -> Bool

    route_markdown

    fn route_markdown(route : Route) -> String

    route_metrics

    fn route_metrics(graph : Graph, route : Route) -> RouteMetrics

    route_quality_label

    fn route_quality_label(metrics : RouteMetrics) -> String

    route_steps

    fn route_steps(route : Route) -> Array[String]

    set_edge_construction

    fn set_edge_construction(state : GraphState, edge_id : Int, construction : Bool, reason : String) -> GraphState?

    Mark or clear a construction closure without mutating an earlier version.

    surface_name

    fn surface_name(surface : Surface) -> String

    update_edge

    fn update_edge(state : GraphState, replacement : Edge, reason : String) -> GraphState?

    Replace an edge while preserving its identifier and recording the change.

    valid_graph

    fn valid_graph(graph : Graph) -> Bool

    validate_graph

    fn validate_graph(graph : Graph) -> Array[String]

    Return all validation findings instead of only a boolean result.

    walking_speed_meters_per_minute

    fn walking_speed_meters_per_minute(profile : MobilityProfile) -> Int