Inspiration
Every nutrition app treats eating well like a chore: log calories, feel guilty, repeat, delete the app in three weeks.
Meanwhile, collection games get people to check in daily for years. We wanted to steal that hook and point it at something that actually matters: what you eat and how your body is doing.
Your Apple Watch is already collecting heart rate, steps, and workouts that mostly sit in a dashboard nobody opens twice. We wanted that data to do something.
Scan real food. Get a character built from its real nutrition. Let a genuinely balanced day make your squad stronger.
There is no cash shop and no pay-to-win. Capsules are earned, not bought, because a game about eating well should not turn into one more thing trying to take your money.
What it does
The core loop
- Scan a barcode or snap a photo of a meal.
- NutriQuest pulls real nutrition data from Open Food Facts.
- That food becomes a permanent collectible character.
- Its stats come directly from its nutrition:
$$ \text{Protein} \rightarrow \text{Power} \quad \text{Fiber} \rightarrow \text{Guard} \quad \text{Micronutrients} \rightarrow \text{Vitality} \quad \text{Protein-to-sugar ratio} \rightarrow \text{Speed} $$
That is not flavor text sitting on top of a random number generator. It is the literal formula.
Your nutrition affects the whole squad
- Every day, your overall eating pattern creates a squad-wide multiplier from
0.8xto1.5x. - One good meal does not erase a junk day.
- One bad meal does not wreck a good one.
- Apple Watch heart rate, steps, and workouts feed into the same profile.
Battles, progression, and rewards
- Take your squad into deterministic, seeded 3v3 battles.
- The backend simulates battles authoritatively, so nobody can fake a win client-side.
- Win to earn XP and capsules toward a provably fair gacha system.
- Lose and your squad gets tired for a couple hours.
- You never lose the characters or collection you built.
How we built it
iOS app
- Built in SwiftUI
- On-device barcode scanning with
VisionKit - Nutrition lookups through Open Food Facts
- A deterministic battle engine,
BattleKit, built as a Swift actor - Custom design system built from scratch:
- Chibi food mascots
- Dynamic colors based on your active character
- Full animation kit
- No template skinning
Backend
- TypeScript +
Express - The same battle formula runs server-side so client and server never disagree about who won.
node:sqlitekept the app functional throughout the hackathon without relying on a network database that could fail mid-demo.
Data architecture
We also designed and deployed a real production-oriented architecture on Tiger Cloud:
Postgres 18TimescaleDB- Relational tables for:
- Accounts
- Character ownership
- Wallets
- Battle results
- Time-series hypertables for:
- Health readings
- Food logs
- Battle event streams
All of it is queryable in one transaction.
We built this migration additively:
- Kept the SQLite backend running.
- Deployed and validated the full Postgres schema.
- Seeded a live three-player demo loop.
- Proved a cross-store query worked.
- Only then prepared routes for the production transition.
Challenges we ran into
Integrating parallel work
Reconciling independently built work into one working main branch in a single sitting was the biggest challenge.
- More than 20 pull requests landed in
mainthat day. - Two people created database migrations with the same number and one had to be renumbered manually mid-merge.
- A UI polish pass and an arcade-HUD pass modified the same screens from different directions.
- Those changes had to be stitched together commit by commit instead of merging cleanly.
Deterministic cross-platform battle logic
The battle engine had to produce byte-identical results whether it ran in Swift on the phone or TypeScript on the server.
That meant:
- Hand-porting a seeded RNG across two languages
- Hunting down floating-point drift
- Controlling iteration order
- Making sure both runtimes resolved every battle exactly the same way
Tuning the gambling math
Plinko needed an actual tuned system:
- 5% house edge
- Capped jackpot
- Controlled reward distribution
It could not just be a random number generator that felt fair after a few test spins.
Operating two systems of record
Running SQLite live while Postgres and TimescaleDB mirrored behind it created a serious consistency risk: a write could succeed on one side and silently fail on the other.
We caught that by detecting a balance mismatch instead of assuming either store was automatically correct.
Accomplishments that we're proud of
- Real food becomes a real character whose stats trace back to real nutrition.
- Deterministic battles make results verifiable and resistant to client-side cheating.
- We shipped multiple services across battle math, daily multiplier logic, and the API layer.
- We deployed and validated a live Tiger Cloud service:
- Schema deployed
- Demo data seeded
- Relational battle records joined to time-series event streams in one transaction
- We did all of this without taking down the SQLite version people were already playing.
- We built a complete visual system from nothing: chibi mascots, dynamic character colors, and a full animation kit.
What we learned
Merge to
mainearlier and more often. Parallel work becomes expensive when every conflict arrives at once.Build risky infrastructure changes alongside what works. Add first, validate live, then replace. Never break the version people are actively using.
Deterministic logic across two languages is deceptively hard. Seeded randomness, floating point, and iteration order can create bugs that only appear on one platform.
Anti-cheat and anti-bot systems deserve core-product engineering rigor. Those are the parts people actively try to break.
Two systems cannot both be “the truth” without reconciliation. You need an explicit way to detect and resolve disagreement.
What's next for NutriQuest
Already in flight
- Ranked badges and matchmaking queues
- Generated rarity art
- Battle-display fixes
- Rarity fallback fixes
Next infrastructure step
- Move every route fully from SQLite to Postgres
- End the dual-write mirroring model
- Add retention policies so old battle replay data expires instead of growing forever
Next gameplay systems
- Character fusion
- Ranked Elo
- Arena stakes
- Full seasons
- LAN tournament support as a casual, unranked mode
LAN tournament support already has working iOS code on a branch waiting to be merged.
Further out
- Object storage for character art
- Object storage for gym-check photos
- A real App Store release built beyond the hackathon sprint
Built With
- claude
- codex
- css
- gemini
- git
- github-actions
- html
- ios
- javascript
- node.js
- pollinations
- postgresql
- railway
- sqlite
- swift
- swiftui
- tigerdata
- timescaledb
- typescript
- workflows
- xcode
Log in or sign up for Devpost to join the conversation.