Inspiration
My inspiration for this project came when I was thinking of another game to build. I had already shipped a daily movie trivia game and wanted to build something that was as unique as I could find (or more appropriately couldn't find). I thought back to growing up and how my brother would always ask "hey, who would win in a fight, A or B?" He would usually insert athletes, and look for an answer with some reasoning behind it.
Thinking that would be a fun app, I looked around the App Store and other places to see if anything like that already existed. There were a couple similar ones geared mostly toward actual battles, but nothing whimsical like I was looking for. So I set out to create a simple Versus game that allowed someone to type virtually any name or thing, and pit it against another name or thing.
What it does
Who'd Win? allows you to type in any 2 names (no minors or world leaders) and pick from 20 different battles to run. Choose any battle type from fist fight, to chess match, to dance off, to even a cooking competition. The app then generates a quirky play-by-play match resulting in a winner and key moment. Imagine Gordon Ramsay vs. Spongebob in a dance-off? The possibilities can be wildly entertaining. Outcomes are different even for a reused battle, with upsets popping up on occasion, making it endlessly replayable. Every result is shareable as a card built for group chats or social media.
How I built it
I am working as a solo dev for this project that is built as a React Native / Expo App. It uses a Supabase backend and Claude for the battle generation. And of course RevenueCat for monetization. As a solo builder, I leaned on AI for much of the development, but the architecture decisions, debugging, and product nuances made up the long working hours.
Challenges I ran into
There were certainly several challenges along the way but a couple in particular stand out.
- I encountered an infinite generation loop while trying to implement a useEffect dependency. One battle simulation turned into 11 in under a minute until I had to force quit to halt the flow. Thankfully that got resolved through effect design.
- A frozen screen when backgrounding the app mid-simulation. I initially tried patching it with guards and listeners, which made it worse. The real fix was architectural — I moved the battle generation off the animated result screen entirely so there was nothing to interrupt. That taught me removing code often beats adding it.
- Getting AI to be unpredictable with the battle simulations was a challenge. Trying to get different outcomes each time for the same battle proved to be tricky. I realized that since language models do not self-randomize, the random aspects belong in the code while the storytelling belongs in the model.
Accomplishments that I am proud of
I am proud of the way I implemented RevenueCat into the app. I built a RevenueCat webhook where a Supabase Edge Function writes an is_premium flag to the user's row on every purchase, renewal, and expiration. Since I have a cap on the daily battle number (3), the battle-generation Edge Function reads the flag to enforce that cap (free vs. premium) server-side. That same function also gates the API call to protect from abuse. This lets the subscription truth live on the server, which is exactly where I want it.
What I learned
Here are a few things I learned during this fun but challenging process:
- It is most definitely worth the extra work to set up server-authoritative monetization. This is especially true when costs scale with usage as my app is geared toward.
- Removing code is often the best fix. It helped a lot to simplify the architecture instead of piling on guards.
- Understand what your model can and cannot do. I realized that Claude has an incredible writing style but is a poor roller of the dice. Deciding to design around that helped tremendously.
- Ship honestly. I first decided that if this is not a product I would play myself, then don't make it. Once that decision was made, I was not comfortable shipping something that was just good enough. I understand the importance of testing and then testing some more. I realize things will come up down the road, but if I can do my best to ensure that I got as much as possible right today, then tomorrow's problems will be easier to solve.
What's next for Who'd Win?
I am really excited to see what the possibilities for Who'd Win? can be. I intend to add more battle types, faster generation, optional user account linking, and most certainly an Android release. I know that my foundation is built to scale so I can't wait to see where this goes!
Built With
- ai
- anthropic
- claude
- deno
- edge-functions
- expo.io
- in-app-purchases
- llm
- postgresql
- react-native
- revenuecat
- rork
- supabase
- typescript
- webhooks