The Idea
Blackjack Legend is a native iOS and Android blackjack game built to be a real shipped product, not a coding exercise. The goal was to handle the full arc: a correct blackjack engine, a mobile-first UX with animation and haptics, authentication with Google and Apple, cloud-synced progress across devices, and a global leaderboard, all wrapped in an EAS build pipeline that can actually push to the App Store.
The game ships with progression and engagement systems on top of the base ruleset: 8 unlock-gated tables, an 8-rank XP system, 18 achievements across three categories, seeded daily challenges, and a 7-day login streak reward cycle. The engagement layer is what turns "I wrote a blackjack engine" into "people open the app again tomorrow".
Tech Stack
| Layer | Technology | Purpose |
|---|---|---|
| Framework | React Native 0.81 + Expo SDK 54 | Cross-platform iOS and Android from one TS codebase |
| Language | TypeScript 5.9 | End-to-end types including Firestore documents |
| State | Zustand 5 | Game state, auth, and engagement systems |
| Navigation | React Navigation 7 | Bottom tabs plus native stack |
| Animation | Reanimated 4 + SVG | Card deal, chip drag, radar chart |
| Auth | expo-auth-session, expo-apple-authentication | Google OAuth 2.0 (PKCE) and native Apple Sign-In |
| Backend | Firebase (Auth + Firestore) + Analytics | User accounts, cloud save, leaderboard, events |
| Local storage | AsyncStorage | Source-of-truth for all game state on device |
| Audio + haptics | expo-audio, expo-haptics, expo-blur | Sound effects, tactile feedback, blur UI |
| Build | EAS Build + EAS Submit | Cloud builds and automated store submission |
Architecture Decisions
- Local-first with an AsyncStorage source of truth. The game is fully playable offline. Firestore is a sync target, not the authoritative state, which keeps the game responsive and removes network latency from the hot path.
- Zustand instead of Redux. A single-screen game with a handful of stores (game, auth, engagement, settings) does not need Redux ceremony. Zustand stores keep the code close to the state they manage.
- Firebase for the backend instead of a custom API. The features this app actually needs (OAuth, per-user documents, a top-100 leaderboard query, analytics) are exactly what Firebase Auth plus Firestore give you out of the box. Standing up a Django or Node service would have been weeks of work for a strictly worse product.
- Expo Managed with EAS Build. EAS removes the usual iOS signing and Android Gradle tax, and EAS Submit pushes straight to App Store Connect and the Play Console. That is what made TestFlight achievable as a solo developer.
- Reanimated 4 for the card deal animation and chip drag. UI-thread animations keep 60 fps during gameplay even when the JS thread is doing basic-strategy math.
Cloud Sync and Conflict Resolution
The interesting engineering problem in the app is not the blackjack math. It is reconciling local game state with the cloud in a way that never causes a player to lose progress, even across offline play, reinstalls, and multi-device usage.
- Writes are debounced by 3 seconds. Back-to-back state changes (hands, XP ticks, balance updates) coalesce into a single Firestore write instead of hammering the network.
- Reads are conflict-gated. On sign-in, the cloud document only replaces local state if the cloud XP is strictly greater than local XP. That rule prevents a fresh install on a new device from wiping out progress that has not yet been synced from the other device.
- Leaderboard writes are separate from the full save. The top-100-by-balance query reads a compact per-user record so the leaderboard stays cheap even as the full save grows.
- Guest mode is supported. A player who does not sign in still gets full gameplay, saved locally. Signing in later promotes the guest state to a cloud-backed account.
Authentication
Sign-in goes through expo-auth-session for Google (OAuth 2.0 with PKCE) and expo-apple-authentication for native Apple Sign-In. expo-crypto generates a secure nonce for the Apple flow so the identity token can be verified against the request.
Neither provider stores anything the app does not need. The user-facing account only exposes a display name and avatar; everything else is derived from Firestore documents that the user owns.
Gameplay Engine
- Full blackjack rules: hit, stand, double down, split up to 4 hands, insurance on dealer ace, auto-stand on 21, split-aces restricted to one card.
- Table-dependent variants: Soft 17 vs Hit 17 dealer rule, blackjack pays 1.5x or 1.2x, different deck counts from 1 to 8.
- Basic strategy tracker: every player decision is validated against the basic-strategy chart for the current table, and the accuracy percentage feeds the stats dashboard and achievements.
- Auto-play mode that runs basic strategy end-to-end, useful for QA and for players who want to watch optimal play.
- Two betting input modes: a chip tray for taps and a drag mode that lets the player physically drop chips onto the bet circle.
Progression and Engagement
The engagement layer on top of the engine:
- 8 unlock-gated tables from Starter ($5 to $100 bets) to Legend ($1k to $50k bets), gated by rank plus a total-wager threshold.
- 8-rank XP system (Newcomer to Legend) with a chip reward at each rank up. Base 10 XP per hand, +15 for a win, +25 for a blackjack.
- 18 achievements across Milestone, Skill, and Style categories with chip rewards from 25 to 2,000.
- Three seeded daily challenges per day across easy, medium, and hard difficulty, covering hands played, wins, blackjacks, doubles, strategy matches, and wagers.
- 7-day repeating login streak: 50, 75, 100, 150, 200, 300, 500 chips, resets on a missed day.
- Stats dashboard with a 6-axis radar chart profiling Skill, Aggression, Risk, Luck, Profit, and Experience, which resolves to one of eight play-style archetypes.
Status
Currently in TestFlight with 5 testers. The full game loop, cloud sync, leaderboard, and engagement systems are live in the test build. The repository is private while the app works its way toward a public App Store and Play Store release.