Inspiration

Every monsoon, Lahore floods at the same streets. WASA's own incident record documents 55 "sore points" — localities that waterlog after every intense spell, 110 incidents between 2012 and 2017. The 2025 monsoon made it brutal: 276 mm in 24 hours on June 25 (the wettest June day ever recorded), then ~355 mm on August 5 — the heaviest since 1895. And every winter, Lahore wakes to air quality headlines; on November 1, 2025, it hit AQI 2,026 — the most polluted city on Earth that morning.

The data isn't missing. Rain gauges, PM2.5 monitors, waste studies, flood maps — they all exist. What's missing is the last mile: turning city-scale numbers into a decision for one person, on one street, in the next six hours. Should I move my car? Should my kids stay in? Which drain should a crew clear first, before the rain arrives? Nigran (نارگن — "the guardian") is our answer to that last mile.

What it does

Nigran is a hyperlocal, multi-hazard decision layer for Lahore, with three surfaces:

  • Citizen view — pick your neighborhood (or hit "locate me") and get that zone's own live temperature, humidity, US AQI, and rain forecast — not a city average. A flood-risk map of 8 real Lahore localities, a plain-language "What to do now" list, a 6-hour rain timeline, and a full 72-hour rain-chance outlook with per-hour probability. Every score opens a "Why?" drawer that explains its reasoning and cites its source.
  • Field Ops view — a re-prioritizing dispatch queue for WASA/LWMC-style drain teams. Tasks rank themselves by blockage and rain urgency, each with a "Why now" explanation, one-tap Google Maps navigation, and persistent completion state. Servicing a drain empties it — and the model refills it realistically over the following days, so it genuinely needs maintenance again.
  • City Overview — the operator's dashboard: hazard-layer map, city impact counters, 24-hour and 72-hour rainfall outlooks, a 24-hour AQI sparkline, and a zone drill-down table synced two-way with the map (click a row, the map flies there and pulses; click a zone, the row highlights).

All weather and air data is live and per-zone — one multi-location Open-Meteo request serves the city center plus all 8 zones. And when the network fails, Nigran withholds values honestly ("values withheld rather than guessed") instead of showing invented numbers. A missing reading is honest; a fabricated one is dangerous.

How we built it

No backend. No database. No API keys. A pure client-side React app — a judge opens one URL and everything works.

$$\text{flood risk} = 0.45 \cdot R_{rain} + 0.25 \cdot B_{blockage} + 0.15 \cdot H_{history} + 0.15 \cdot V_{vulnerability}$$

$$\text{task priority} = 0.40 \cdot B + 0.30 \cdot U_{rain\ urgency} + 0.20 \cdot P_{population} + 0.10 \cdot S_{stale}$$

Every constant traces to a published source, kept in a single auditable file (calibration.js):

  • Rain risk bands — design-storm intensities from Ahmad et al. 2024 (calibrated SWMM, NSE 0.71–0.78), cross-checked against the observed 2025 records above.
  • Flood history & vulnerability — WASA's sore-point incident record and Ravi-corridor flood studies.
  • Waste/drain parameters — Batool & Ch 2009: 0.84 kg/cap/day generated, only ~60% collected, ~67% organics — the drain-clogging fraction that drives our fill rates.
  • Dispatch formulation — Metson et al. 2021 (capacitated transportation problem); we use its greedy priority-queue analogue.
  • Drain telemetry — the one thing no open API provides anywhere, so it's a transparent, time-driven simulation: fill levels climb from paper-calibrated seeds (the Shahdara trunk fills in ~9 days), and the UI labels it as simulated everywhere.

Live inputs come from Open-Meteo's weather and air-quality APIs, fetched client-side every 10 minutes with a cache/status machine (live → stale → offline) shown as a header pill.

Challenges we ran into

  • The honesty problem. Our first offline mode silently showed a fake static snapshot. We ripped it out entirely and rebuilt the contract: cached-but-stale data is labeled stale, and with no cache the app shows "—" with an explanation. Rain is never silently zero; the risk engine renormalizes to telemetry-only and flags the missing input. Harder to build — and the feature we're proudest of.
  • One request, nine locations. Fetching per-zone data naively meant 9× the API traffic. Open-Meteo accepts comma-separated coordinates in a single call, but our first parser then ran the weather decoder over the air payloads too — a bug that surfaced as an inscrutable reading 'time' crash. Fixing it taught us to validate payload shape at every boundary.
  • Stale-cache crashes in the wild. A cache written by an older build could crash the map on real users' browsers (but never in a fresh test run). We now validate the cache shape, skip broken entries, and guard every parse.
  • Testing a cinematic UI. Dual WebGL backgrounds (a fluid simulation plus a starfield shader) kept killing headless Chrome mid-test. SwiftShader flags, forced clicks around 0.8s luxury transitions, and single-worker execution got the browser suite deterministic — 5/5 stable E2E alongside 85 unit/component tests.

Accomplishments that we're proud of

  • Every number is defensible. No invented values anywhere: live APIs for weather/air, published research for every calibration constant, and clear UI labeling wherever anything is modeled. The "Why?" drawers mean a judge — or a citizen — can audit any score in two clicks.
  • A 100% honest data contract. Missing data never masquerades as safety.
  • Per-zone truth. Not "Lahore is 34°" but "Township is 35.6°, Shahdara is 34.9°" — from a single API call.
  • A real test suite. 85 unit/component tests covering the risk-engine weights, band boundaries, missing-data semantics, and timezone parsing; 5 end-to-end browser flows including offline mode.

What we learned

  • Data honesty beats data quantity. Judges (and users) trust a system that admits gaps far more than one that always shows a confident number.
  • Research papers are a superpower. Calibrating to published parameters turned our "simulated" drains from a weakness into a defensible design choice with citations.
  • Multi-location APIs change the math. One well-shaped request replaced nine — worth reading the docs twice.
  • The last mile is a product decision, not a data problem. The hard part wasn't getting numbers; it was deciding what a person should do.

What's next for Nigran-Lahore

  • Real municipal integration — swap the simulated drain telemetry for live WASA/LWMC sensor or work-order feeds the moment they're available; the engine is already shaped for it.
  • Push alerts — SMS/WhatsApp warnings when a zone crosses the severe band, so the six-hour warning reaches people who never open an app.
  • Hindcast validation — replay the July–August 2026 archive and score Nigran's warnings against what actually flooded, street by street.
  • More zones and Urdu localization — all of Lahore's ~250 union councils, with plain-language Urdu guidance.
  • Heat-wave mode — routing to the nearest filtration plant and relief camp, building on the cool-asset layer already in the map.

Built With

  • air-quality
  • climate-change
  • data-visualization
  • disaster-management
  • figma
  • framer-motion
  • gps
  • leaflet.js
  • maps
  • open-meteo
  • openstreetmap
  • playwright
  • smart-city
  • tailwindcss
  • three.js
  • vercel
  • vite
  • vitest
  • weather-api
Share this project:

Updates

Submission history