A motion dashboard built in After Effects that connects to a live API and visualizes real-time Air Quality Index (AQI) data for any city in the world. It dynamically fetches data, calculates standard AQI values based on real pollutant concentrations, updates every minute, and smoothly animates visuals — all with no plugins required.
Automatically fetches from the OpenWeather API and updates the dashboard every minute — no manual input needed.
All values controlled via sliders in After Effects. Great for teaching, presenting, or testing edge cases interactively.
Most motion dashboards are pre-rendered, static, or purely mockups — great for visuals, but limited in real-world applicability. I wanted to explore something different.
I wanted to explore:
Type city → press Enter → dashboard updates instantly
The dashboard needed to:
// ================ AQI CALC ================ function calculateAQI(concentration, breakpoints) { for (let bp of breakpoints) { if (concentration >= bp.C_low && concentration <= bp.C_high) { return Math.round( ((bp.I_high - bp.I_low) / (bp.C_high - bp.C_low)) * (concentration - bp.C_low) + bp.I_low ); } } return 0; }
Below is the simplified architecture that drives the entire system:
To fetch data from OpenWeather, the Node.js script chains three API calls:
The script then writes a structured JSON file for After Effects to consume.
{
"city": "Tokyo",
"aqi": 66,
"pm25": 19.4,
"pm10": 46.21,
"no2": 7.99,
"o3": 103.77,
"timestamp": "2026-02-23T22:30:21.000"
}
OpenWeather's built-in AQI scale (1–5) didn't align with real-world weather apps. So I implemented official EPA AQI logic:
This turns raw pollutant concentration into meaningful, standardised numbers.
| Color | Category | AQI Range | Health Impact |
|---|---|---|---|
| Green | Good | 0–50 | Air quality is satisfactory |
| Yellow | Moderate | 51–100 | Acceptable; some risk for sensitive groups |
| Orange | Unhealthy for Sensitive | 101–150 | General public not likely to be affected |
| Red | Unhealthy | 151–200 | Everyone may experience effects |
| Purple | Very Unhealthy | 201–300 | Health alert for entire population |
| Maroon | Hazardous | 301+ | Emergency conditions |
A surprisingly complex challenge: the API gives timestamps in UTC and only one server chain — but we wanted city-local time, not viewer local time.
To fix this:
To make this workshop-friendly, the system supports two fully-functional operating modes:
Instead of restarting scripts each time, the Node script was converted into a persistent interactive loop:
OpenWeather's built-in AQI scale didn't match apps like Apple Weather.
Timestamps were inconsistent:
AE sometimes cached an old JSON file, displaying stale data.
The scale, indicator, and refresh dot all inherit consistent AQI color logic — every visual element reacts to the same data source.
A human character element reacted automatically to the AQI logic — showing visual health stress in unhealthy zones and clear appearance in clean air conditions. The mask opacity, color, and overlay all drive from the same AQI expression.
Ideas for expanding this system further: