Skip to content
All writing
A mobile interface connected to a beacon signal and cloud services

Shwoop: Connecting a Mobile Game to the Physical World

Shwoop was an iBeacon-based alternate-reality game with a treasure-hunt concept. I worked on it as a Junior Full-stack Developer from June to November 2019, developing the app in React Native and TypeScript and a REST API using AWS Lambda, DynamoDB, Cognito, and CloudFormation. We used Jira for our Scrum workflow and Bitbucket for the code.

An alternate-reality game brings the world around the player into the experience. In this case, iBeacons connected the mobile app to physical proximity. That makes it a different engineering problem from an app where every input is a button press. The phone is interpreting something outside the interface, and the interface has to turn that observation into something intelligible.

My backend contributions included treasure and reward handling, request telemetry, and challenge-completion statistics. Those changes make the connection between the physical game and the services behind it more concrete than a list of technologies.

A beacon reports proximity

An iBeacon broadcasts identifying information over Bluetooth Low Energy. A nearby phone can detect it and estimate proximity. That is not the same as receiving an exact geographic position or a guaranteed distance measurement.

Apple's iBeacon documentation explains that ranging depends on radio signal strength. Walls, doors, other objects, and even the human body affect it. The observation is useful, but it carries uncertainty.

For a proximity-based game, that uncertainty should shape the design. An interface should not imply centimetre-level certainty when the input is a changing radio signal. A single observation should not accidentally become a stronger statement about the player than the hardware can support.

The hardware-facing layer and the game-facing layer should have different responsibilities: one reports observations; the other decides what those observations mean for the experience.

From a beacon to a prize

In July 2019, I contributed an initial treasure and redemption flow. The change added a treasure handler, extended challenge completion, and updated the API Gateway definition and CloudFormation template. It crossed the API contract, application logic, and infrastructure in one piece of work.

The treasure handler took a beacon identifier and reported longitude and latitude. It looked up the treasure in DynamoDB and checked those coordinates against the treasure's stored location and a tolerance. It then selected a configured prize using the reward quantities and existing claimed count, constructed a redemption record, requested its storage, and returned the prize data to the client.

The backend was doing more than turning a detected beacon into a success screen. It connected that observation to a configured game object and reward. The interface could present a result that came from the game's stored definition rather than carrying the reward rules itself.

This was an early implementation, with further work still identified in the code. A coordinate check based on client-reported data is also not proof that someone physically visited a location. The useful architectural boundary is that an observation enters the API, and application rules interpret it. Reliability and trust still require their own design.

Working with the phone's operating system

React Native and TypeScript were our app stack. Familiar components and types are useful, but a mobile application still lives inside a device's operating system. Permissions, hardware availability, and the application's lifecycle affect what it can observe.

Those conditions deserve visible states in a sensor-dependent interface. “No beacon detected” is a different situation from “the app cannot currently detect beacons.” The first concerns the surroundings; the second concerns the app's ability to inspect them. Showing the same empty screen for both leaves the player with no useful next action.

Recording activity and understanding the game

Later in the role, I added telemetry calls to existing request handlers, covering challenge starts, prize retrieval, user retrieval, registration, and surveys. These recorded request activity; they were separate from the existing rules deciding whether an action was permitted or completed.

I also worked on the statistics script for challenge-completion times. That is a different view of the same game: the API handles an individual request, while analysis looks across recorded activity.

For a physical treasure hunt, being able to inspect activity matters alongside the visible app. A screen can explain the current interaction. The data behind it helps the team ask how challenges are being used and where to investigate further.

Infrastructure is part of the product's definition

CloudFormation describes AWS resources through templates. It makes the infrastructure part of the reviewable code, alongside the mobile app and API.

The treasure change is a concrete example: it touched both the handler and the resources exposing it. A TypeScript function and the infrastructure making it available belong in the same reviewable change.

Shwoop is an early example in my work history of an app reaching beyond its own screen. The interesting design problem is making each boundary clear: a beacon observation, a mobile state, an API request, and a shared result. The player should understand what the app is doing without needing to understand any of that machinery.

See this role and my full work history.