Fullstack · Civic Data

Haze Check SG

Python · Vanilla JS · SVG · GitHub Actions · GitHub Pages · data.gov.sg

What it is

A haze tracker for Singapore, aimed at the public rather than data specialists. It is one src/page.html file (HTML, CSS and JS together) with no framework and no build step beyond a Python script. A small pipeline (fetch.py → merge.py → build.py) pulls PSI and PM2.5 from NEA via the data.gov.sg API and Changi weather from an aviation METAR feed, merges both into one data.json, and GitHub Actions refreshes it twice daily and redeploys. The region map, 7-day chart, and weather-correlation plots are hand-written SVG.

The hard part

PSI is a 24-hour average, so the page has to keep saying so. It explicitly points people to NEA's faster 1-hour PM2.5 reading elsewhere instead of implying this one updates in real time. The map has a PSI/PM2.5 toggle, and PM2.5's scale isn't the same as PSI's, so I couldn't reuse PSI's color bands for it. I had to find NEA's actual published PM2.5→PSI conversion table and check it against their own worked example before coloring anything.

What it taught me

The interactive parts (map, charts, dark mode, the metric toggle) run with no npm install and nothing to compile, which makes the whole thing easy to read end to end. I also learned not to trust a scheduled job just because it's scheduled: the deploy step had been failing silently on every push because GitHub Pages was never switched on in the repo settings. It looked like it was working. It wasn't.