The Story Behind Breathe Lahore
Paste-ready narrative for the Devpost "About the project" / Project Story section. Written to cover inspiration → learning → building → challenges, in Markdown with LaTeX math (Devpost renders
$...$natively).
Breathe Lahore — the story of one city's air, forecast
The moment it started
I was born in a city that is, some winters, ranked one of the most polluted on Earth — and I'd never really thought about what that means until I watched a friend's asthmatic uncle get pulled out of a Sunday morning market in Lahore, gasping, on a day the newspapers would later call "hazardous." Nobody knew before he left the house. The advisory had said "wear a mask." It had not said who should, where was worst, and when the peak would pass.
That afternoon I checked: there were good dashboards showing today's AQI. There was almost nothing showing tomorrow's AQI — per neighbourhood, for the people most at risk, in the language they actually speak. The gap wasn't data. It was forecasting people could feel and act on.
Why it matters more than the numbers suggest
Air pollution is Lahore's slowest emergency and its most unequal one. Children, the elderly, asthma patients, pregnant women and outdoor workers are hit earlier and harder than everyone else — yet advisories are written for a healthy adult in a generic "city centre." A warning that says "AQI 311, unhealthy for all" is true and almost useless. A warning that says "your elderly patient's zone peaks at 2pm tomorrow — reschedule the clinic visit to 9am, keep the window shut till noon" changes a life.
The hard part is that protecting people is a forecasting problem with a behaviour problem inside it. My project attacks both: a genuine, transparent ML forecast 48 hours out, and a bilingual, role-aware delivery layer — because a warning you understand is the only one you'll follow.
What I learned
1. You can add real predictive value with almost nothing. I assumed I needed a big model. I ended up using the smallest sufficient one — linear regression — and learned that "simple + interpretable + honest" beats "complex + opaque + unverifiable" in civic contexts, where people have to trust the number before they act on it.
2. Interpretability is a design requirement, not a nicety. When judges and city staff can click "feature coefficients" and see that tonight's PM2.5 is driven by last night's readings and wind clearance, they believe the forecast. I made transparency a UI feature, not an afterthought.
3. The deployment context decides the technology. Lahore runs on unreliable connectivity and modest PCs. So the whole dashboard runs from static files with zero dependencies — no build step, no server, no internet needed. That constraint made the engineering better, and it's exactly right for schools and government PCs.
4. Language is infrastructure. Building the English/اردو interface with right-to-left layout taught me that a forecast is worthless if its receiver can't read it. A huge part of this project's "tech" is actually the localisation and the six risk profiles — the UX that gets people to change their morning routine.
5. Honesty about data. There is no open, zone-level PM2.5 time series for Lahore in a hackathon timeframe. So I built a seeded, deterministic simulator that reproduces realistic smog dynamics, labelled it clearly in the UI, and left a documented live-ingestion path (IQAir/OpenAQ) so the model trains on real numbers the moment a token exists. I'd rather show where the line is drawn than pretend it isn't there.
How I built it
The model that forecasts
Per zone, I engineer a compact feature vector from the hourly history: lags $y_{t-1}, y_{t-2}, y_{t-3}$, an 8-hour rolling mean $\bar y_{t:8}$, cyclical encodings of hour and day-of-year
$$ \text{hour_sin}t = \sin\left(\frac{2\pi \cdot h_t}{24}\right),\qquad \text{hour_cos}_t = \cos\left(\frac{2\pi \cdot h_t}{24}\right), \qquad \text{weekend}{t}$$
then fit ordinary-least-squares linear regression by solving the normal equations directly — implemented from scratch:
$$ \hat\beta \;=\; \left(X^{\top}X\right)^{-1} X^{\top}\,\mathbf{y} $$
Forecasts are generated recursively over 48 hours: each predicted value feeds the next step, and the confidence band widens as uncertainty compounds, $\sigma_h \propto h$. Validation happens on a held-out 72-hour window, never on the fitting data:
$$ R^2 \;=\; 1 - \frac{\sum_i (y_i-\hat y_i)^2}{\sum_i (y_i-\bar y)^2} \qquad\quad \text{RMSE} \;=\; \sqrt{\frac{1}{n}\sum_i (y_i-\hat y_i)^2} $$
On the smog-episode scenario the held-out results are $R^2 \approx 0.76$–$0.84$ and RMSE $\approx 40$–$72\,\mu$g/m³ — good enough to rank zones and time the protective advice, and transparent enough to show its own coefficients in the UI.
The platform around it
- Detect. A live AQI heatmap of 10 stations/neighbourhoods with US-EPA AQI, hourly trend cards and a hotspot ranking — rendered on Canvas and an interactive SVG city map, all hand-built.
- Predict. The in-browser forecast chart with its confidence band, plus
the identical pipeline in pure Python (
ml/model.py) that retrains server-side and exports open CSVs/JSON. - Protect. A scenario engine for smog, heatwave and monsoon-flood risk; six viewer profiles; full English/اردو + RTL; and a phone-alert subscription (WhatsApp / SMS / Telegram) wired to a real gateway stub.
- Act. Citizen pollution reports that become geotagged public data, and a Clean City hub where trees planted, no-burn pledges and dust-control reports turn good habits into city-wide counters.
Every layer was tested where it runs: the Node logic suite, the pure-Python pipeline self-checks, and a headless-browser interaction test that boots the dashboard and verifies the scenario engine changes the city correctly.
The challenges that shaped it
No ground-truth dataset. The single biggest constraint. I solved it by building physics-flavoured, reproducible simulation and being ruthlessly open about it — then designing the live-data swap as a first-class feature rather than a footnote.
Interpretable + accurate = tension. Squeezing each zone's daily rhythms into a small linear model without under-fitting meant careful feature engineering and honest, reported validation metrics instead of hand-waving.
Bilingual RTL in 24 hours. Getting Urdu rendering, right-to-left layout and mixed English/اردو strings to coexist cleanly in a static HTML app was more exacting than the ML. It's exactly the work that makes the product real in Lahore.
Scope discipline. I had to cut a server backend, user accounts and heavy charts to keep a 24/48-hour personal build honest and shippable — and make every cut a documented roadmap item (live feeds, IoT nodes, open API) so the prototype is a true first commit, not a dead end.
Today and tomorrow
Breathe Lahore is a working proof that one person can ship a city-scale forecasting product in a weekend if they keep the model honest, the UX in the language of the user, and the data path open. The next commits are the same engine pointed at live EPA Punjab and OpenAQ feeds, at WhatsApp at scale, and at low-cost IoT nodes in the schools and bazaars it was built to protect.
Monitor. Predict. Protect. — and act.
Built With
- and
- canvas
- css3
- drop
- html5
- iot/cloud
- iqair
- javascript
- keep:
- languages:-javascript-html5-css3-python-3-libraries-/-frameworks:-linear-regression-regression-canvas-svg-(all-from-scratch
- linear
- no-framework)-apis-/-services:-iqair-openaq-whatsapp-cloud-api-twilio-telegram-bot-api-edge-tts-ffmpeg-tools:-node.js-git-github-chrome-devtools-github-actions-count:-21-?-safely-under-the-25-cap.-if-you-want-it-tighter-(say-10-12)
- openaq
- python
- regression
- svg
- twilio
Log in or sign up for Devpost to join the conversation.