Data | Product design

AirFloor

AirFloor

AirFloor

A data tool that scores every floor of an Indian apartment building for air quality, built solo and shipped in three languages.

A data tool that scores every floor of an Indian apartment building for air quality, built solo and shipped in three languages.

A data tool that scores every floor of an Indian apartment building for air quality, built solo and shipped in three languages.

Role

Product design | Data visualization | Frontend build

Timeline

Solo build, 2026

Stack

Vanilla JS | Canvas | Open-Meteo | Copernicus CAMS + DEM

Platform

Web

Context

AirFloor (originally scoped around Kengeri, a neighborhood in Bangalore, then generalized to all of India) started as a personal flat-buying question: on a multi-storey building, which floor actually has the healthiest air. Street-level fumes and the night inversion layer sit low, but the top floors lose on wind exposure and daily friction, not oxygen. The project turned that question into a public, free tool.

Problem

There was no way to see, for a specific building in a specific place, how air quality changes floor by floor. Generic AQI apps report one number for a whole city or area, not a curve across height, and nothing served this for Indian cities in local languages.

Approach

Combine two live open data sources, real ground elevation from a Copernicus digital terrain model and live air quality from the Copernicus CAMS service through Open-Meteo, into a per-floor score built on a physics-informed weighting we defined (PM2.5/inversion, street fumes, ventilation, liveability and oxygen). The interface is a two-step hero: pick an area with a hybrid combobox, then set building height with a big highlighted floor field with no default value, so the first real action is deliberate. Results render as animated canvas charts with three views (curve, bars, table), an AQI severity scale bar in the style of aqi.in, and a plain-language household advice engine that reads the live AQI band and writes persona-specific guidance. Every string ships in English, Telugu and Kannada with natural (non-literal) translations, and location is hard-locked to India through a bounding box plus a reverse-geocode country check, because the geocoder alone leaked results from Kathmandu, Dhaka and Colombo. A print stylesheet (not a PDF library) lets people export the whole report, keeping the live charts and local-language text intact.

Outcome

The tool is live at airfloor.netlify.app, open source (MIT for code, CC BY 4.0 for content) at github.com/yashkotha/airfloor, and applied for Netlify’s Open Source hosting plan. It shipped through several rounds of visible self-correction: an early India-wide live AQI map was built, then pulled because it didn’t earn its space next to the per-building tool; the first building/air logo was replaced by a drifting-clouds animation; a first pass at the advice engine broke on an empty state and was hardened with a PM2.5 AQI fallback. Verifiable output only: no user or usage metrics exist for this project.

Decisions | Reasoning

No default value in the building-height field, and it is visually the largest, most highlighted input on the page.

No default value in the building-height field, and it is visually the largest, most highlighted input on the page.

The whole result depends on that one number. Memory notes call it out explicitly: a highlighted floors field with no default, forcing a real answer instead of letting people skim past a pre-filled number and get a meaningless result.

The whole result depends on that one number. Memory notes call it out explicitly: a highlighted floors field with no default, forcing a real answer instead of letting people skim past a pre-filled number and get a meaningless result.

Hard India lock on the geocoder using a bounding box PLUS a reverse-geocode country-code check, not just the box.

Hard India lock on the geocoder using a bounding box PLUS a reverse-geocode country-code check, not just the box.

The box alone leaked results from Kathmandu, Dhaka and Colombo, which sit just outside India but inside a loose lat/lon rectangle. The fix split place selection into a gate step and a commit step, with a countrycode==='IN' check and a fail-closed reverse verify, because a data tool that quietly returns a foreign city's air data under an Indian search is worse than no result.

The box alone leaked results from Kathmandu, Dhaka and Colombo, which sit just outside India but inside a loose lat/lon rectangle. The fix split place selection into a gate step and a commit step, with a countrycode==='IN' check and a fail-closed reverse verify, because a data tool that quietly returns a foreign city's air data under an Indian search is worse than no result.

PDF export built as window.print() plus a dedicated @media print stylesheet, not a client-side PDF library like jsPDF.

PDF export built as window.print() plus a dedicated @media print stylesheet, not a client-side PDF library like jsPDF.

Print keeps the live Telugu/Kannada text and the real canvas charts rendering exactly as shown, with zero added CDN dependency. A PDF library would have meant re-rendering charts and text in a second code path, doubling the surface for language and chart bugs.

Print keeps the live Telugu/Kannada text and the real canvas charts rendering exactly as shown, with zero added CDN dependency. A PDF library would have meant re-rendering charts and text in a second code path, doubling the surface for language and chart bugs.

Dropped the Motion (Framer Motion / motion one) animation library for the height slider and rebuilt it as a CSS-transition spring.

Dropped the Motion (Framer Motion / motion one) animation library for the height slider and rebuilt it as a CSS-transition spring.

The Motion UMD build played the animation via WAAPI but did not commit final styles on finish, even for a plain opacity tween, so the slider visually snapped back to zero after every drag. Documented as a reusable lesson: for a static-site slider, prefer CSS transitions that write inline styles over Motion One's animate call.

The Motion UMD build played the animation via WAAPI but did not commit final styles on finish, even for a plain opacity tween, so the slider visually snapped back to zero after every drag. Documented as a reusable lesson: for a static-site slider, prefer CSS transitions that write inline styles over Motion One's animate call.

Removed an India-wide live AQI map after shipping it, and separately replaced the first logo concept with a second one.

Removed an India-wide live AQI map after shipping it, and separately replaced the first logo concept with a second one.

Commit history shows the map ("Live Air across India") was added, then explicitly removed one day later in favor of redesigning the logo as animated drifting clouds. The per-building floor tool is the product; a country-wide map competed with it for attention rather than supporting it, so it was cut rather than kept as a feature to justify.

Commit history shows the map ("Live Air across India") was added, then explicitly removed one day later in favor of redesigning the logo as animated drifting clouds. The per-building floor tool is the product; a country-wide map competed with it for attention rather than supporting it, so it was cut rather than kept as a feature to justify.

Translations for Telugu and Kannada were written as natural phrasing, not literal calques, and a prior "magic floor" literal translation was explicitly removed.

Translations for Telugu and Kannada were written as natural phrasing, not literal calques, and a prior "magic floor" literal translation was explicitly removed.

A tool meant to be read and trusted by Telugu- and Kannada-speaking home buyers fails if the copy reads as machine-translated. Around 150 strings per language were rewritten to match the English key count while sounding native, which is a deliberate quality bar above just having three language files.

A tool meant to be read and trusted by Telugu- and Kannada-speaking home buyers fails if the copy reads as machine-translated. Around 150 strings per language were rewritten to match the English key count while sounding native, which is a deliberate quality bar above just having three language files.

Results

Live at airfloor.netlify.app under an open MIT and CC BY 4.0 license, a solo build with no invented usage numbers to report.

Next project