Inspiration

Most idle games are a number that goes up and a button that makes it go up faster. I wanted one where the decisions are the game: a parking lot is a tiny business with real trade-offs — price per hour against occupancy, monthly subscribers against peak-hour walk-ins, a canopy that costs money today and pays back only when it rains. Every mechanic in No Spaces is something a real lot operator actually thinks about.

What it does

You lease an empty plot with room for ten cars. From there:

  • Upgrade the lot — surface, barrier, lighting, canopy. Each raises capacity, hourly rate or occupancy, and the panel tells you exactly which.
  • Hire a crew — attendants and cashiers add income but their wages tick off the till every second; grow too fast and you bleed.
  • Set the tariff — hourly, first hour free, or flat daily. The right one depends on how long cars stay at this location, and the tariff panel computes the real daily income of each option before you choose.
  • Sell subscriptions — reserve spaces for monthly subscribers: never empty at night, but they pay a discount and at peak hour that space is not yours.
  • Expand — Market Square fills by day, Opposite the Hospital never sleeps, Next to the Stadium only on match nights, Airport Long Stay 24/7. Each location has its own 24-hour demand curve, so the same upgrade pays differently in each.
  • Prepare for events — rain, a barrier failure, a festival. Every event has a counter-move you may or may not have bought in advance: a canopy turns rain into a windfall; a cashier softens a barrier failure.
  • Tender and prestige — win permanent licences through tenders and achievements, not only by resetting.

An isometric lot you watch fill and empty, a drawer that slides up over it, two languages (Turkish and English) switchable in-app, no account, offline-first.

How I built it

Two native codebases. iOS: SwiftUI, iOS 17+, 22 Swift files, ~6,000 lines, no third-party code besides Firebase Analytics and RevenueCat. Android: Kotlin + Jetpack Compose, ported from iOS with the same economy: the expected values of the Android EconomyParityTest were produced by compiling the iOS Swift economy with swiftc and running it on the same inputs — if the two platforms ever diverge, the test fails. Strings are generated from the iOS String Catalog into Kotlin, so a copy change happens once.

Balance — the offline rule. Idle games leak value while you are away. After measuring that a player with the Patron pass could return from 24 hours away with 34 hours of active play worth of cash, offline earnings were redesigned around one invariant: offline window × yield = 1 hour of production, in every case. Free players get a 1-hour window, Patron gets 6 hours, trophies extend it up to a hard ceiling of 10, and the yield is a flat 10%. The game itself always out-earns waiting. A unit test locks this.

Monetization — RevenueCat. Two currencies with two jobs. Cash packs (2/6/16 hours of takings) buy scale and are priced in game time, so they scale with how big you have grown and never go stale. Gold packs buy time: instant collection, calling in a break, permanent multipliers. Patron is a one-time purchase that sells a concrete thing — a six-hour offline window and +15% income, forever — not a vague "pro". All nine products are one-time products; RevenueCat handles consumption and acknowledgement, and the game only ever asks "deliver this product ID". On a device without Play the till switches to a clearly labelled simulation instead of failing silently.

Challenges

  • Honest numbers cost performance. The tariff comparison runs three tariffs across 24 hours, plus a subscriber sweep, per frame. Moving to one economy pass per frame and caching formatters took Android from janky to 20 fps on the canvas with nothing to spare.
  • Offline income was paid twice on a cold start — applyOffline ran from both init and enterForeground against the same timestamp. Found while rebalancing, fixed by stamping immediately.
  • Google's new one-time product model hides products from older billing clients until a compatibility flag is set — an hour lost to an empty store.

What's next

Read which tariff players actually pick per location and whether Patron converts on the offline ticket; a fifth location; and the iOS release, which is awaiting App Store review.

Built With

  • firebase-analytics
  • google-play-billing
  • jetpack-compose
  • kotlin
  • kotlinx-serialization
  • revenuecat
  • swift
  • swiftui
Share this project:

Updates

Submission history