StrideBound

Turn every run into a quest.

StrideBound

StrideBound turns GPS-tracked runs into a creature-collection RPG. Before a run, users choose a loadout of up to three items from their backpack. After the run, the app awards points and pet XP, then rolls a monster encounter influenced by distance traveled and which items were equipped - a loop designed to make item choice matter and give the next run a reason to happen.

The core tracking challenge was GPS noise. Mobile location updates arrive continuously, including low-accuracy readings that can accumulate as phantom distance when the user is standing still. Two things gate each location update before it touches the distance calculation: an accuracy threshold that drops noisy readings, and a CoreMotion pedometer check that skips processing entirely when steps haven’t advanced. The previous coordinate also resets on pause/resume, so the app never draws a straight-line jump between pre-pause and post-resume positions as counted distance. CoreLocation updates flow through an AsyncStream<CLLocation> wrapper in LocationService, which lets the session coordinator handle them with Swift concurrency rather than delegate callbacks scattered across the codebase.

The monster spawn system is data-driven: 36 monsters and 26 items live in JSON catalogs, so balancing doesn’t require touching Swift code. Each encounter starts by filtering monsters against a minimum distance threshold, then assigns weights based on lure item IDs in the loadout, matching item tags, and a rarity-scaled distance bonus - common monsters scale up faster with distance, legendaries scale slower. A recent fix addressed monsters not spawning at all after run completion, which turned out to be the run completion pipeline not reaching the encounter generation step.

ItemGridView - a compositional-layout grid with 2x2 paging, lock states for undiscovered entries, configurable info strings, and a selection callback - is the same component powering the shop, backpack loadout, and collection index screens. Building it once and reusing it across three tabs meant design changes to that grid propagated everywhere automatically. The same pattern applied to StatsCardView, CurrencyBarView, and the chart views in the profile analytics surface.

StrideBound shipped to the App Store as a solo project - concept, implementation, and Apple review. The TestFlight build is live (ID 6751173998). A multiplayer layer was cut before first release to keep the scope focused; the single-player loop - run, encounter, collect, progress - needed to feel complete on its own before adding social mechanics on top.