Inspiration

Every crossing game since Frogger has one thing in common: a level designer decided where the cars go. We wanted to find out what happens when nobody does, when the traffic is simply whatever was on the road that day in Gangnam or Mong Kok or Hanoi.

What it does

CityCat is a crossing game played on real street video. A YOLO11s model runs on device and tracks every vehicle in the frame; those tracked boxes are the hitboxes. If a bus blocks the lane, that is because a bus was there. No two runs are the same, because traffic never repeats.

Ten street maps ship with the game, across nine countries (Gangnam, Shinjuku, Mong Kok, Hennessy Road, Hanoi, Regent Street, Bangkok, Lagos, Trastevere, Havana), and players can upload their own street footage to a shared Map Market, where an on-device quality scorer grades it for vehicle density, real movement and camera stability before it goes live.

How we built it

Detection. YOLO11s via Core ML and Vision, running on the Neural Engine, with a Kalman-filtered tracker and static-vehicle suppression so parked cars never become hitboxes.

Game layer. A SwiftUI and UIKit hybrid. The video is an AVPlayer layer with the pixel-art sprite composited above it. Collision uses a sliding-window majority vote, two hits out of four frames, which kills false positives without adding lag.

Maps. Generated and validated with a custom pipeline. Every clip is loop-sealed so the start frame equals the end frame and traffic flows without a visible seam.

Monetization. RevenueCat handles the consumable coin pack end to end via Purchases.shared.purchase, and the verified transaction ID is handed to our Cloudflare Workers ledger for idempotent crediting. Rewarded ads run through AdMob, with Google UMP for EU consent.

Judges: no promo code is needed. To celebrate the launch we grant every new player 500 coins on first launch — enough to unlock every map in the Map Market and to try the roulette and all three items without spending anything. If the 500 coins did not arrive, the launch grant may have ended; in that case redeem this judges-only code: https://apps.apple.com/redeem?ctx=offercodes&id=6792511960&code=CITYCATJUDGE

Challenges we ran into

Parked cars. A detector cannot tell a bus driving at you from a bus that has been parked for an hour. Both are "bus". We added static suppression, and then had to add a straightness test on top of it, because trams travel in a dead-straight line and were being mistaken for street furniture. Net displacement over path length separates them: a tram scores near 1.0, a shop sign oscillating in the wind scores about 0.5.

HDR video that rendered black. Our default map was encoded as H.264 High 10 with HLG HDR. Apple's decoder returned black frames. Tone-mapping to 8-bit BT.709 fixed it, but a naive conversion blew the colors out, so the pipeline now runs an explicit zscale tone-map and every new clip is checked with ffprobe before it ships.

Invincibility that killed you. Our ghost item expired silently, and if it ran out while you were standing inside a car you died instantly with no warning. We measured it: death at 4.11 seconds, exactly when the timer hit zero. Now a countdown shows on screen and the cat blinks before the item ends.

What we learned

Measurement beats intuition, every time, and our own checks were the thing we trusted too easily.

We had a metric that confirmed each generated map looped seamlessly. It passed. Then we looked at the frames and found the model was not closing the loop at all, it was pasting our end frame over the last two frames, and on a later attempt dissolving it in like a ghost. The metric measured whether the final pixels matched the first pixels, which is not the same question as whether the traffic came back around. Once we measured the right thing, half of our shipped maps turned out to have visible loop jumps.

The same lesson twice more. We tuned the background music by guessing, failed, guessed again, failed again, then measured spectral centroid and found the real problem was brightness rather than tempo. And a batch of deprecation warnings we had been ignoring turned out to be pointing straight at synchronous frame extraction on the main actor: the UI froze during 58% of uploads, and the fix was in the warning all along.

What's next for CityCat

Korean and Japanese store localization, a creator program for the Map Market, and city packs submitted by players themselves.

Built With

Share this project:

Updates

Submission history