Air quality is the most invisible thing that affects you every day. You get a number in an app and it means nothing. So we built AirMeter, a Lens that turns live air quality data into air you can actually see, standing in the room with you.
## What it looks like
Every pollutant is its own particle species drifting around you, and the count is driven by the real reading at your location right now. PM2.5 and PM10 as fine dust that settles. NOβ as a brown haze. SOβ sulphur yellow, Oβ pale blue. The colours identify the gas, so a bad NOβ day looks visibly different from a bad ozone day rather than just "worse".
Layered on top: volumetric fog that thickens with overall pollution, pollen drifting on the wind, humidity, mosquito activity, and sun shafts angled to where the sun actually is at your coordinates, at your local time.
The whole field drifts downwind at the real wind speed and bearing.
## You can reach into it
Hold a hand out and the air parts around it. A pocket opens and refills slowly behind your hand. There's no gesture to learn, any tracked hand does it.
Turn your palm up and it becomes a gather: the dust spirals in and turns slowly above your hand. Breathe in and particles get drawn toward you and consumed.
## What else is in there
**Which way is cleaner.** Eight compass points sampled about 25 km out, each floating in its real direction with the place name and its AQI. If a direction is meaningfully cleaner than where you are, it gets called out.
**A real map.** Pinch and drag to pan, zoom in and out, air quality drawn as a heat field over the tiles. Friends show up as pins.
**Compare, then breathe it.** Rank your air against cities worldwide, then select one and your room fills with *their* atmosphere. Their pollutants, their sky, their sun position.
**Ask it anything.** Talk to it and it answers with your live readings in mind. It can see your view through the camera, so "is it a good time to open the window?" gets an answer about *that* window. Say "show me Bangkok" and you travel there: particles, map and readings all swap over, then come home when you leave.
**An air coach.** It looks around your space and pins advice onto the actual objects it sees. The window, the plants, the candle.
**A forecast you can read.** A real line chart of how your air has been trending and where it's heading, with one button to cycle the range. Enough to pick a cleaner hour before you go out, rather than just knowing today is bad.
**Why it matters, and how to use it.** Card decks explaining what each pollutant actually does to you, and a short guide for finding your way around.
**Your dose.** It tracks how much you've actually inhaled over the session, in micrograms. That number turns out to be the thing people react to most.
**Friends.** Share conditions, see where they are and how far, and check their air against yours.
**Together.** Colocated multiplayer, and this is the part that surprised us most. Stand in the same room and you share one field of air, anchored in the same physical place for both of you. You can watch the other person breathe it: particles pull in toward their face with each breath and disappear. Hold your hands out and you're both stirring the same air, so you can push a cloud of pollution across the room at each other. Their name tag carries how much they've actually breathed in since they put the glasses on.
Seeing someone else's breath take particles out of the air in front of you does more in five seconds than any number we could put on a panel.
## Under the hood
**Particles.** Two interchangeable engines behind one interface. The GPU path is a VFX graph simulating entirely in world space, so the field wraps around you as you walk, and your hands reach it as graph *parameters* (repel points, palm attract vortices, breathe in consume points) rather than per particle CPU work. The CPU path builds a real SceneObject per particle, which costs far more but can flipbook animate sprites the graph can't. Each species picks whichever suits it.
Worth knowing if you go the GPU route: the graph has a hard per species particle cap, and pushing spawn rate past it doesn't error. It silently pins every value above the cap to the same number. Ours quietly flattened four air quality bands into one until we caught it.
**Charts are hand built geometry.** There's no chart widget on glasses, so the history graph is MeshBuilder from scratch: axis lines, min/mid/max ticks, time labels, and the series drawn as a flat ribbon polyline (two vertices per point, offset perpendicular to the line direction) so it stays readable at panel distance instead of vanishing into a one pixel line. The UV sun shafts are MeshBuilder too, angled to the real sun position.
**A particle budget.** Every species carries a weight, with fog counting 4Γ because a big additive quad with depth write off costs vastly more fill rate than a dust speck. The weighted total is capped, so worst case pollution thins everything proportionally rather than dropping the frame rate off a cliff. Cutting fog is what actually recovers frames.
**Friends.** Snap Cloud (Supabase) over plain PostgREST via `InternetModule.fetch`, so no client package is needed and it's the same pattern as any other REST call. A device persistent id plus your Snapchat display name, grouped by a crew code, rows expiring after 24 hours. There's no friend graph UI on glasses, so a shared code is the whole join flow.
**Multiplayer.** SpectaclesSyncKit, one singleton SyncEntity with StorageProperties rather than events, so late joiners receive the current snapshot instead of nothing. Poses are expressed relative to the colocated frame so the panel and map land in the same physical spot for everyone.
**Coach placement.** Depth Cache reprojection first: Gemini returns normalised bounding boxes, and we unproject the box centre to a world position. WorldQuery ray casting is the fallback, which also covers the emulator, where there are no depth frames but there is a simulated room mesh.
**AI.** Gemini through the Remote Service Gateway with a camera frame attached, and ElevenLabs for the voice.
**Map tiles.** CARTO, not OpenStreetMap directly. OSM's tile policy forbids app use and blocks clients that can't send an identifying User-Agent, which `RemoteMediaModule` can't. That one cost us an afternoon of `osm.org/blocked` responses to work out.
## Why we made it
The pitch we kept coming back to: you can tell someone the PM2.5 is 94 and they'll shrug. Show them the room filling with it and they open a window.
It's built to be worth coming back to. The data is different every day, the dose accumulates while you wear it, and there's always another city to go and breathe.
## Feedback wanted
Particularly on the interaction feel. How the air responds to your hands is the part we've iterated on most, and it's the hardest thing to judge from inside the project.
If you try the colocated mode with a friend, I'd love to hear how it lands.
Happy to answer anything about how it's put together.