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

Log in or sign up for Devpost to join the conversation.