WebNest
Team/Md Abir Hossain/waynest

Repository

waynest

WayNest is a React app that shows the cheapest evacuation route on a building map and updates it when you block rooms, corridors, or exits. It runs entirely in the browser, supports English and বাংলা, and includes sample scenarios for demos and judging.

View on GitHub ↗
TypeScript★ 0 stars⑂ 0 forkswaynest.devabir.me/ ↗

README

<div align="center"> <img src="docs/assets/waynest-icon.svg" alt="WayNest" width="112" />

WayNest

Smart Escape topic · Interactive evacuation route simulator — pick a start, toggle hazards, watch the lowest-cost exit path update instantly in English and বাংলা

React TypeScript Vite Vitest i18n Frontend only

AI DevFest Vibe Coding · Smart Escape topic · practice / mock test · frontend-only

Live demo · Repository · Quick start · How it works · Sample checks · Feature tour · Two-minute demo · What this is not

</div>

Why is this hard? An evacuation map is only useful while the building keeps changing. A blocked corridor, a closed exit, a room that just became unsafe — the “best” path a second ago may be wrong now. Hard-coding paths fails the moment the hazard map moves.

WayNest answers one question, on every click: from this start, through the current hazards, what is the lowest-cost route to an open exit — and why that path, not another with the same cost?

<table> <tr> <td align="center"><h2>8</h2>nodes · 9 corridors<br/>East Annex sample</td> <td align="center"><h2>5 / 5</h2>§4.1 sample checks<br/>in Judge mode</td> <td align="center"><h2>40 / 40</h2>unit tests<br/>passing</td> <td align="center"><h2>EN + বাংলা</h2>full UI<br/>including errors</td> <td align="center"><h2>0</h2>backend calls<br/>everything local</td> </tr> </table> <div align="center"> <img src="screenshots/01-baseline-R1.png" alt="WayNest map with R1 selected and the lowest-cost route to exit E1 highlighted" width="92%" /> </div> <div align="center">
NameMD ABIR HOSSAIN
Registration number261-15-001
Live link (HTTPS)waynest.devabir.me
Repositorygithub.com/0xdevabir/waynest
</div>

🎯 The problem and how we answer it

The problemWhat WayNest doesWhere to see it
Paths go stale the moment a hazard changesDijkstra recalculates synchronously after every toggleMap highlight · Route panel
Ties between equal-cost paths are ambiguousLexicographically smallest exit ID, then smallest node sequenceWhy this path? · Tie screenshot
Invalid building files crash or silently lieStrict §3.1 validation; bilingual error list; current map keptInvalid-file screenshot
Judges need to verify §4.1 without a checklistBuilt-in Judge mode runs the five sample checks through the real engineJudge mode panel
Bangla users get English-only toolsEvery label, status, error and walkthrough is translated; Bangla digits in BN modeBangla screenshot

Hero workflow: open the app → brand intro plays → East Annex loads → click R1 → see R1 → C1 → C2 → E1 (cost 7) → block C2 → the route flips to R1 → C1 → C3 → C4 → E2 (cost 11) with a 7 → 11 (+4) badge and a faint ghost of the old path.


🔁 How it works

One click, start to finish

flowchart LR
    A["📂 building.json<br/>import or sample"] --> B["✅ Validate §3.1"]
    B -- reject --> X["❌ Bilingual error list<br/>keep current map"]
    B -- ok --> C["🗺️ Draw map<br/>rooms · junctions · exits · costs"]
    C --> D["👆 Pick start<br/>or toggle a hazard"]
    D --> E["🧮 usableGraph<br/>drop blocked / closed"]
    E --> F["⚡ Dijkstra<br/>sum of edge costs"]
    F --> G{"Open exits<br/>reachable?"}
    G -- no --> H["🚫 No route / start blocked"]
    G -- yes --> I["🏁 Best exit<br/>then lex-smallest path"]
    I --> J["✨ Highlight + explain<br/>top-3 · walkthrough · ghost"]

What the user sees when a hazard flips

sequenceDiagram
    autonumber
    actor U as User
    participant UI as WayNest UI
    participant E as Route engine
    U->>UI: Block corridor / close exit / pick start
    UI->>UI: Push hazard history (undo stack)
    UI->>E: computeRoute(building, hazards, start)
    E->>E: usableGraph → Dijkstra → best exit → lex path
    alt ok
        E-->>UI: path · exit · cost · ties · other exits
        UI-->>U: Map highlight + status + Why this path?
    else no-route / start-blocked
        E-->>UI: failure status
        UI-->>U: Clear status + trapped / reachable hints
    end

Routing rules (§3.3) in src/lib/route.ts

  1. Remove blocked nodes, closed exits, blocked edges, and every edge that touches a removed node. A closed exit is never used, even as an intermediate.
  2. Run Dijkstra from the start using the sum of edge costs. Coordinates and hop counts are never used.
  3. Pick the reachable open exit with the lowest cost. On a tie, pick the lexicographically smallest exit ID.
  4. Among equal-cost paths to that exit, return the lexicographically smallest node sequence (second Dijkstra from the exit, then greedy walk preferring the smallest-ID neighbour on a shortest path).

Nothing is hard-coded: routes, IDs and positions all come from the imported file.


✅ Sample checks (§4.1)

Verified by unit tests and in the browser Judge mode.

ScenarioResult
Select R1R1 → C1 → C2 → E1, cost 7
Select R1, block C2R1 → C1 → C3 → C4 → E2, cost 11
Select R1, close E1 and E2No route available
Select R2R2 → C3 → C4 → E2, cost 7
Select R1, then block R1Starting location blocked

Tie example: with C2 blocked, R1 → C1 → C3 → C4 → E2 and R1 → R2 → C3 → C4 → E2 both cost 11. The app picks the one through C1, because C1 < R2 at the first differing hop. Why this path? lists both and marks the chosen one.

xychart-beta
    title "Sample-check route cost (lower is better; failures shown as 0)"
    x-axis ["R1 baseline", "R1 + block C2", "R1 exits closed", "R2 baseline", "R1 start blocked"]
    y-axis "Cost" 0 --> 12
    bar [7, 11, 0, 7, 0]

🖥️ Feature tour

<table> <tr> <td width="50%"><img src="screenshots/01-baseline-R1.png" alt="Baseline route from R1 to E1 at cost 7" /><br/><b>Baseline.</b> Pick R1 and the cheapest exit lights up: <code>R1 → C1 → C2 → E1</code>, cost 7.</td> <td width="50%"><img src="screenshots/02-reroute-after-blocking-C2.png" alt="Route rerouted to E2 after corridor C2 is blocked" /><br/><b>Live reroute.</b> Block C2 and the path flips to E2 at cost 11, with a cost-delta badge and ghost of the old path.</td> </tr> <tr> <td><img src="screenshots/03-no-route-exits-closed.png" alt="No route when both exits are closed" /><br/><b>No route.</b> Close E1 and E2 — status becomes <em>No route available</em> / <em>কোনো পথ পাওয়া যায়নি</em>.</td> <td><img src="screenshots/04-start-blocked.png" alt="Starting location blocked with bilingual error" /><br/><b>Start blocked.</b> Block the starting room — clear bilingual failure, not a silent empty map.</td> </tr> <tr> <td><img src="screenshots/05-bangla.png" alt="Full Bangla UI" /><br/><b>বাংলা.</b> Full UI translation, including statuses, errors, help and Bangla digits.</td> <td><img src="screenshots/06-invalid-file.png" alt="Invalid building.json import errors" /><br/><b>Strict import.</b> A bad <code>building.json</code> shows every §3.1 violation; the current map stays.</td> </tr> <tr> <td><img src="screenshots/07-why-this-path-tie.png" alt="Why this path panel with tie explanation" /><br/><b>Why this path?</b> Cost breakdown, exit-tie reason, and every equal-cost alternative marked.</td> <td><img src="screenshots/08-help-shortcuts.png" alt="Help dialog with shortcuts and rules" /><br/><b>Help.</b> Keyboard map, routing rules and validation catalog behind <b>?</b>.</td> </tr> <tr> <td colspan="2"><img src="screenshots/09-judge-mode.png" alt="Judge mode running five sample checks" /><br/><b>Judge mode.</b> The five §4.1 checks run through the real engine — <b>Run all 5</b> plays them as a demo.</td> </tr> </table>

Also built in

SurfaceWhat it does
Animated introBrand splash on load — logo assembles, path races, zoom reveal; respects prefers-reduced-motion
Top 3 routesYen-style k-shortest across open exits; hover/focus previews the path
Walkthrough + PlayStep list and a marker that walks the route
What changedPrevious route stays as a faint ghost; badge shows 7 → 11 (+4) or Route lost
Dead endsNodes with no reachable exit get a dashed ring; panel names reachable areas
Map HUDStart → exit · cost overlay; zoom/pan (+ − 0, Ctrl/⌘+wheel, drag)
Undo / redoHazard history; Reset restores initial_state and can itself be undone
AccessibilityHigh-contrast toggle, keyboard map + hazard switches, ARIA live status, prefers-reduced-motion
PNG export / printFull map with the current route, even when zoomed
PersistenceDataset, hazards, start, language and contrast in localStorage (re-validated on load)

🏗️ Architecture

flowchart TB
    subgraph UI["React UI"]
      App --> MapView
      App --> RoutePanel
      App --> HazardPanel
      App --> SelfCheck
      App --> HelpDialog
      App --> SplashIntro
    end
    subgraph Engine["src/lib — pure functions"]
      validate["validate.ts · §3.1"]
      route["route.ts · Dijkstra + ties + top-3"]
      selfCheck["selfCheck.ts · five §4.1 scenarios"]
      i18n["i18n.ts · EN + বাংলা"]
    end
    App --> validate
    App --> route
    SelfCheck --> selfCheck
    selfCheck --> route
    UI --> i18n
waynest/
├── public/building.json     # East Annex sample
├── docs/assets/             # README icon
├── screenshots/             # feature tour images
├── src/
│   ├── App.tsx              # state, shortcuts, persistence
│   ├── components/          # MapView · RoutePanel · HazardPanel · SelfCheck · Help · SplashIntro
│   └── lib/
│       ├── route.ts         # Dijkstra, ties, ranked routes, regions
│       ├── validate.ts      # strict building.json rules
│       ├── selfCheck.ts     # §4.1 scenarios
│       ├── i18n.ts          # English + Bangla
│       └── *.test.ts        # 40 unit tests
├── docs/PLAN.md
└── .github/workflows/deploy.yml

⚡ Run it in 3 commands

Requirements: Node 20.19+ (or 22.12+).

npm install
npm run dev       # http://localhost:5173
npm test          # 40 unit tests
npm run build     # static production build in dist/
npm run preview   # serve dist/ locally

The build is fully static (base: './'). Host dist/ on GitHub Pages, Netlify, Vercel or Cloudflare Pages with no config. .github/workflows/deploy.yml deploys to GitHub Pages on every push to main — enable Settings → Pages → Source: GitHub Actions.


🎮 How to use

  1. East Annex (public/building.json) loads automatically. Import JSON or drop a file anywhere to load your own.
  2. With Select start on, click a room/junction or pick from the list — route, exit and cost appear immediately.
  3. Switch to Toggle hazards: click a room/junction to block it, an exit to close it, or a corridor (or its cost label) to block it. Click again to undo. The Hazards panel mirrors the same switches for keyboard use.
  4. Reset restores the file’s initial_state. বাংলা / English switches language. ↶ / ↷ undo and redo.
  5. Press ? for shortcuts, routing rules and the validation catalog.

Keyboard: R reset · E language · S/H mode · arrows move start (map focused) · P play · Ctrl/⌘ Z / ⇧Z undo/redo · + − 0 zoom · ? help.


🎬 Two-minute demo

TimeBeat
0:00Open the live link — animated brand intro, then East Annex and the map fill the viewport.
0:20Click R1 → route R1 → C1 → C2 → E1, cost 7.
0:40Block C2 → reroute to E2 at cost 11; show ghost path + delta badge.
1:00Open Why this path? — cost breakdown and the C1-vs-R2 tie.
1:20Switch to বাংলা — statuses and panel labels flip; digits become Bangla.
1:35Judge mode → Run all 5 — five §4.1 checks pass through the real engine.
1:50Close: frontend-only, bilingual, explained routes that update on every hazard.

⚠️ What this is not

Educational simulation only. Not a certified real-world evacuation planning tool.

  • No backend, no accounts, no telemetry — everything runs in the browser.
  • Dataset labels and IDs stay as authored; only the UI chrome is translated.
  • Judge mode appears only when the official East Annex sample graph is loaded.

🐞 Known issues

  • Dataset labels and IDs are shown exactly as written in the file; only the app's own text switches between English and Bangla.
  • The map is scaled to fit the file's coordinates. In very dense graphs, labels can overlap; zoom in (+) to read them.
  • The last dataset and hazards are restored from localStorage. Open the app with ?fresh (for example https://waynest.devabir.me/?fresh) to start again from the sample file.
  • The Bangla web font loads from Google Fonts. If that is blocked, the system Bangla font is used instead.
  • Judge mode only appears when the official sample graph is loaded, because its expected results only apply to that graph.

🤖 AI tools used

ToolUsed for
Claude CodeReading the problem statement and rulebook, the routing engine and validation, the React UI, tests, README
CursorFeature checklist from the rulebook, UI polish, intro animation, naming fixes

The full prompt history is in PROMPTS.md.

⭐ Most useful prompt

The requirements checklist prompt used to check and finish every mandatory feature (shortened):

Must-essential (mandatory — fail without these): local building.json import in the browser · strict JSON validation + clear reject message for bad/inconsistent files · render full map: nodes at x,y, edges, readable labels, distinct types, visible corridor costs · select start = unblocked room or junction only · lowest-cost route to an open exit (Dijkstra on edge costs — not pixel distance) · show node sequence + chosen exit + total cost · block/unblock rooms, junctions and corridors · close/reopen exits · instant recalculate on every change · Reset → restore the file's initial_state · "No route available" / "Starting location blocked" · tie-break: min cost → smallest exit ID → lexicographically smallest node-ID path · Bangla + English for everything · subtle animations, no flash or delay · sample checks pass.

It worked because it spelled out the exact tie-break order and both failure messages, so nothing was left to guess.


🙏 Acknowledgments

Built for AI DevFest Vibe Coding (practice / mock test). Routing follows the published §3.3 rules; sample checks follow §4.1.

← Back to profile