The pitch

Your city, as a living diorama.

Live Weather turns any city on Earth into an AI-generated miniature that reacts to its real conditions. When thunderstorms roll over Lahore, the miniature Lahore on your screen darkens, floods with rain, and lights up with lightning that is actually striking, right then, in the real city.

Inspiration

Every weather app is the same app. A big number, a cloud glyph, seven columns of smaller numbers. They tell you it's 34° and raining. None of them make you feel that it's 34° and raining.

I wanted a weather app you look at, not one you read.

What it does

Every city becomes a diorama. Each city is rebuilt as a scale model, its real skyline, its landmarks, its character , generated with Google's Gemini image models. Six variants per city cover the lighting and season states, so the miniature in front of you matches the hour and the sky outside your actual window.

The weather driving it is real, live, and redundant.

  • Five forecast providers behind one abstraction AccuWeather, Foreca, OpenWeather, The Weather Channel and Xweather , normalised into a single model, so one vendor having a bad morning doesn't blank the screen.
  • Live lightning.
  • NOAA / NWS for the dangerous weather. Hurricane and tropical storm tracks come straight from the National Hurricane Center's live feed, and NWS alerts flow into the severe-weather warnings card alongside other national met offices.
  • Minutely precipitation, air quality, storm cells, wind fields, and sun and moon position computed from ephemeris rather than fetched.

A weather map that actually renders. Metal-shaded precipitation raster overlays, GPU wind-particle advection, a scrubbable timeline, tappable storm cells, and hurricane detail sheets.

It follows you out of the app. WidgetKit widgets, including diorama widgets on the home screen, App Intents for switching cities , and an ActivityKit Live Activity that puts "rain starts in 8 minutes" on the Lock Screen.

How I built it

Client. SwiftUI, iOS 18+, roughly 119 source files. The diorama scene lives in an in-house WeatherSceneKit module. Precipitation, wind and special effects are custom Metal shaders (WeatherParticles.metal), with SpriteKit overlays layering droplets and settling snow onto the front plane, so weather falls through the diorama and beads on the screen in front of it at the same time. That double layer is what sells the illusion; either one alone reads as a screensaver.

Backend. A Flask service, backed by SQLite, that owns device identity, entitlements, remote configuration, and the Gemini generation proxy.

Monetization. Revenue Cat subscriptions plus per-city unlocks. One free city per device, and a referral path that unlocks a city after five verified invite installs.

Challenges I ran into

Image generation is the expensive call. Six Gemini generations per city, real money every time. One stray trigger, a map pan, a pull-to-refresh, a 404 from the image endpoint, a restored purchase on relaunch, could have burned the month's budget in an afternoon. A comment telling future-me to be careful was never going to survive future-me.

No view, view model, or service anywhere else in the app can construct one. Reaching the generator without a grant the backend actually made isn't discouraged by convention, it doesn't compile. On top of that sits per-device, per-city request suppression with a 24-hour retry window, so even a legitimate retry storm costs nothing.

Five providers, one truth. Every vendor has its own condition codes, units, update cadence and failure modes. Normalising them was the easy half. The hard half was keeping the diorama's visual state stable when the active provider switches mid-session, nothing breaks the illusion faster than the sky flickering because a JSON field disagreed.

Making it survive a real phone. A 3D scene, particle systems, video-backed effects and map rasters will happily cook a battery. A dedicated performance configuration tunes effect density per device, and every heavy layer tears down the moment it leaves the screen.

What I learned

Push invariants into the type system when breaking them costs real money, a fileprivate initialiser did more for my API bill than any amount of discipline. Put trust boundaries on a server you control, never in a binary you ship. And the hardest problem in a weather app isn't accuracy: it's giving someone a reason to open it on a day when nothing is happening.

What's next

an Android build, and shareable postcards, a shortcut which update mobile wallpaper based on weather, your city's miniature at the exact moment something happened in it.

Built With

Share this project:

Updates

Submission history