Inspiration

Summers keep getting hotter. In Tokyo, walking ten minutes in direct August sun is genuinely dangerous — heatstroke sends thousands of people to hospital every year. Yet every walking navigation app answers the same question: what is the shortest way? Nobody asks what is the coolest way.

Ten years ago, a few friends and I built a prototype that answered that second question, and we obtained a patent for the shade calculation and route rendering. Then life happened and it sat unused for a decade. This summer I rebuilt it from scratch — worldwide, on-device, and free.

What it does

inShade finds walking routes that keep you in the shade.

For every street segment it computes how much of that segment is shaded right now, from building heights, the sun's position, and the time of day. Then it shows you two routes side by side:

  • Shade route (blue) — maximizes time spent in shadow
  • Shortest route (orange) — the usual answer

The trade-off is explicit: 13 min, +25% more shade versus 10 min. You decide which one you want.

Move the time slider and the shade recomputes. Leaving at 3pm and leaving at 5pm through the same neighborhood produce different routes, because the buildings throw their shadows the other way.

How I built it

  • On-device routing. A* pathfinding with a shade-weighted cost function. No server round-trip — the route is computed on your phone.
  • Worldwide street and building data as z14 SQLite tiles with R*Tree spatial indexes, fetched on demand for the area you are in and cached locally. Once tiles are cached, routing works offline.
  • Shared logic across platforms. Sun position, shadow projection, A*, and tile loading are written in Kotlin Multiplatform and mirrored in Swift, with identical expected-value tests on both platforms so the two apps compute the same numbers.
  • iOS in SwiftUI (iOS 26, Liquid Glass). Android in Jetpack Compose.
  • 33 languages, 175 territories, free.

Monetization — designed not to be annoying

This is the part I care most about.

Every feature is free. Revenue comes from two places, and I worked hard to make the ad side something users don't resent:

  • The interstitial appears only when a route search succeeds — never on a failure, never on launch.
  • The first search after launch never shows an ad.
  • A 180-second cooldown between ads.
  • Nothing is requested until UMP consent has actually been granted.
  • Anyone who would rather not see ads can remove them permanently with a one-time purchase, managed through RevenueCat, which unifies StoreKit 2 and Play Billing behind a single entitlement check.

The bet is simple: an ad that respects your attention converts better than one that ambushes you, and offering a way out turns annoyance into revenue instead of churn.

Challenges I ran into

  • Getting two platforms to agree on a number. Shadow geometry is unforgiving — one degree of difference in sun altitude moves a shadow edge by meters. Shared expected-value tests were the only way to keep iOS and Android honest.
  • Shipping worldwide, not just Tokyo. Generating and serving street and building tiles for the entire planet, then making the app fetch only what it needs.
  • Two App Store rejections. The Google Maps SDK refused to draw tiles under iPad compatibility mode — a blank map that reproduced only on iPad. I traced it, fell back to Apple Maps on iPad, and wrote the decision down so the next person doesn't lose the same day.

What I learned

Write the decision down — including the ones you rejected, and why. This repository keeps a docs/ tree where every architectural choice, every rejected alternative, and every incident (including the two rejections above) is recorded as the source of truth. Coming back to a problem three weeks later, that saved me every single time.

Shipped since submitting

  • Android is live. inShade launched on Google Play on August 13, 2026 — the same 33 languages, the same on-device shade routing, and the same one-time "remove ads" purchase, unified across both stores by a single RevenueCat entitlement.
  • Shade in the mountains. Tree canopy is now part of the shadow model. On forested trails, computed shade coverage went from about 1% to 80–97% — buildings alone were never going to explain a mountain path.
  • Tablets, natively. iPad and Android large screens get real layouts instead of a stretched phone UI.
  • Funnel instrumentation on both platforms, so I can see exactly where someone drops off before reaching their first shade route — and fix that instead of guessing.

What's next for inShade

  • Heat awareness beyond shade: humidity, pavement temperature, drinking fountains along the way
  • Better shade data outside dense city centers, where buildings are sparse and trees do the work
  • Turning the funnel data into a first-run experience that gets people to their first shade route faster

Built With

Share this project:

Updates

Submission history