True Count

Master Development Plan

Phased development roadmap for True Count, organized into implementable slices.

This page is the single source of truth for what gets built, in what order, and the current status of every slice. Each slice is a vertical increment of work that produces testable, working code within a single development session.

Last Updated

March 25, 2026 — S-IAP (IAP Credit Safety, Plans A–E) implemented. CloudKit bankroll backup, purchase support tooling, remote credit grants, and Next.js admin panel shipped in PR #90. Feature complete: iap-safety (S-IAP).

Overall Progress

2
Not Started
0
In Progress
35
Implemented
0
Tested

Phase Overview

PhaseFocusSlicesDesign BlockedStatus
A: Core EnginePure game logic, no UI, no persistenceS01 -- S10 + S-FW (11)0Implemented
B: PersistenceSwiftData + CloudKit schemaS11 -- S12 (2)0Implemented
C: ViewModels & ServicesService protocols, VMs, integrationsS13 -- S19 (7)0Implemented
D: UI ShellSpriteKit scene, SwiftUI app shell, bettingS20 -- S22 (3)3Implemented
E: Feature PolishFeature UI, integration, polishS24 -- S-IAP (11)6Implemented
F: Design & PolishDesign refinement, comprehensive accessibilityS-DD, S-DS, S23 (3)2In Progress

Pre-Design Execution Order

While visual design is pending, prioritize all no-design slices: S01 -- S19, then S27 and S26. S-FW (framework extraction) should be completed before S04 to establish the package boundary early. This front-loads core logic, persistence, services, and integration plumbing before UI styling work begins. Total: 36 slices across 6 phases.


Phase A: Core Engine

Pure Logic, Zero Dependencies

Every slice in Phase A produces pure Swift structs and enums with no UI, no persistence, and no framework imports beyond GameplayKit. This is the foundation everything else builds on.

SliceNameDependenciesDesignEst. FilesStatus
S01Card and Deck Models--No~3Implemented
S02Hand Model and EvaluationS01No~2Implemented
S03Table Rules Configuration--No~2Implemented
S-FWExtract TrueCountEngine Swift PackageS01, S02, S03No~7Implemented
S04Action ValidationS-FW, S01, S02, S03No~2Implemented
S05Dealer LogicS-FW, S02, S03No~2Implemented
S06Betting Math and Chip SystemS-FW, S03No~2Implemented
S07Basic Strategy EngineS-FW, S02, S03, S04No~2Implemented
S08Hi-Lo Card Counting EngineS-FW, S01No~2Implemented
S09Player Rank and XP SystemS-FW, S03No~2Implemented
S10Game State MachineS-FW, S01 -- S06No~5Implemented
Slice Details and Acceptance Criteria

S01: Card and Deck Models

Card value type (suit, rank, face value, Ace flexibility) and the Shoe struct with configurable multi-deck construction, Fisher-Yates shuffle via GKMersenneTwisterRandomSource, seeded replays, and cut-card penetration tracking.

Doc sources: Rules Reference, Shuffling, Technical Overview

  • Card model represents all 52 cards with suit, rank, and value (Ace = 1 or 11)
  • Shoe initializes with 2, 4, 6, or 8 decks and tracks remaining card count
  • Fisher-Yates shuffle via GKMersenneTwisterRandomSource produces deterministic output for a given seed
  • Cut card position calculated from penetration percentage, triggers reshuffle flag when reached
  • Drawing past cut card sets shouldReshuffle but does not interrupt dealing mid-round
  • Unit tests cover all deck counts, seeded replay determinism, and penetration thresholds for all 5 table configs

S02: Hand Model and Evaluation

Hand struct that holds cards, calculates hard/soft totals with Ace flexibility, detects bust, blackjack (natural 21 on first two cards), and determines if a hand is a pair for splitting.

Doc sources: Rules Reference, Hand Actions

  • Hand correctly evaluates hard totals, soft totals (Ace counted as 11), and automatic Ace demotion when total exceeds 21
  • isBlackjack returns true only for exactly two cards totaling 21 (not after split)
  • isBusted returns true when all possible totals exceed 21
  • isPair correctly identifies same-rank pairs including 10-value face cards (K-J counts as pair)
  • bestTotal returns the highest non-busting total, or the lowest busting total if all bust
  • Unit tests cover edge cases: soft 21 vs blackjack, multi-Ace hands, Ace demotion chains

S03: Table Rules Configuration

TableRules struct (pure data) encoding all 5 dealer table configurations plus BlackjackPayout enum (3:2, 6:5, 1:1), SurrenderMode (none, late, early), and DoubleRestriction (any, 9-11, 10-11). dealerSoft17 is a global user setting, not a table property. All production tables use SurrenderMode.none; late and early are retained for Beta Tweaks testing only.

Doc sources: Dealer Tables, Dealer Hits Soft 17, Rules Reference

  • TableRules struct encodes: deckCount, blackjackPayout, surrenderMode, doubleRestriction, doubleAfterSplit, penetration, minBet, hintsAvailability, insuranceAvailable (all 5 dealer tables set surrenderMode to .none; dealerSoft17 is a global user setting, not part of TableRules)
  • All 5 dealer table configurations defined as static constants with exact values matching documentation
  • Unlock levels (1, 10, 25, 50, 100) associated with each table
  • Beta Tweaks presets (Player+, Standard, Casino) defined as additional static configs
  • Unit tests verify each table's config matches documented values exactly

S-FW: Extract TrueCountEngine Swift Package

Move all game logic (Card, Shoe, Hand, TableRules) from the truecount app target into a local Swift Package called TrueCountEngine. This creates a compile-time boundary: the package cannot import UIKit or SwiftUI. All future Phase A slices (S04-S10) are developed directly inside the package.

Plan file: docs/plans/2026-02-18-refactor-game-engine-swift-package-plan.md

Doc sources: Technical Overview, Architecture Principles

  • TrueCountEngine/Package.swift created with swift-tools-version 6.0, iOS 18 platform, library product, source target, and test target
  • Card.swift, Shoe.swift, Hand.swift, TableRules.swift moved to TrueCountEngine/Sources/TrueCountEngine/
  • CardAndShoeTests.swift, HandTests.swift, TableRulesTests.swift moved to TrueCountEngine/Tests/TrueCountEngineTests/
  • All public types have public access modifier with explicit public init(...) declarations
  • App target builds with plain import TrueCountEngine (not @testable), proving the public API surface is correct
  • All 126+ existing tests pass in the new package location
  • Adding import SwiftUI to any package source file causes a build failure (import barrier verified)
  • Shoe.swift audited for arrayByShufflingObjects(in:) bridging (fix if found)
  • iOS app CLAUDE.md updated with package structure, file placement rules, engine test command, and access control policy

S04: Action Validation

Pure BlackjackRules struct with static functions to determine available actions for a given hand state, table rules, and bankroll. Covers Hit, Stand, Double Down, Split, and Insurance eligibility. Surrender validation is retained but all production tables have it disabled.

Doc sources: Hand Actions, Insurance, Rules Reference

  • availableActions returns correct action set for any combination of hand state, dealer upcard, table rules, and bankroll
  • Hit: available when hand < 21 and not split-ace
  • Stand: always available during player turn
  • Double: first two cards only, bankroll covers, double restriction respected, DAS rule respected, not on split aces
  • Split: pair required, bankroll covers second bet, max 4 hands, no re-split aces
  • Surrender: first two cards, non-split hand, surrender mode enabled (all tables default to .none; only reachable via Beta Tweaks)
  • Insurance: dealer Ace upcard, table allows insurance

S05: Dealer Logic

Dealer play algorithm: hit/stand rules, S17/H17 branching, peek-for-blackjack logic, and skip-dealer-turn when all player hands busted.

Doc sources: Dealer Rules, Dealer Hits Soft 17

  • Dealer hits on 16 or below, stands on hard 17+
  • Dealer soft 17 determined by: (1) Beta Tweaks if active, (2) user's Settings toggle. No per-table value.
  • dealerShouldHit returns correct boolean for all hand totals and soft/hard states
  • Peek logic correctly identifies dealer natural from hole card + upcard
  • Dealer turn skipped when all player hands are busted
  • Unit tests cover soft 17 with both S17 and H17, multi-card soft hands, bust scenarios

S06: Betting Math and Chip System

Chip denomination calculation from bankroll tier, payout calculations for all outcomes, split/double bet deduction, and minimum bet enforcement.

Doc sources: Betting, Dealer Tables

  • chipDenominations(forBankroll:) returns correct 5 denominations for all 6 documented tiers
  • Tier transitions at exact power-of-10 boundaries (100, 1000, 10000, etc.)
  • Payout returns correct gross return for BJ (3:2, 6:5, 1:1), win, push, surrender, loss
  • Split bet deduction: equal to original bet per additional hand
  • Double bet deduction: doubles current hand bet
  • Minimum bet validation per table

S07: Basic Strategy Engine

Three strategy charts (hard totals, soft totals, pairs) encoded as lookup tables. Strategy lookup tables include both S17 and H17 variants. Maps (player hand, dealer upcard) to recommended action with fallback when table restricts the recommended action.

Doc sources: Basic Strategy, Auto Hint

  • Hard totals chart: correct recommendation for all (hand total 5-17+) x (dealer 2-A) combinations
  • Soft totals chart: correct recommendation for all (A,2 through A,9) x (dealer 2-A) combinations
  • Pairs chart: correct recommendation for all (2,2 through A,A) x (dealer 2-A) combinations
  • Fallback: when table restricts recommended action, returns next-best action
  • Auto Hint mode: never returns Surrender (all tables have surrender disabled; fallback to Hit if enabled via Beta Tweaks)
  • Unit tests verify every cell in all 3 charts against documented values

S08: Hi-Lo Card Counting Engine

Running count tracker (+1 for 2-6, 0 for 7-9, -1 for 10-A), true count calculation, player edge estimation. Resets on shoe shuffle.

Doc sources: Count Peek, Shuffling

  • Running count updates correctly for each card dealt (+1 for 2-6, 0 for 7-9, -1 for 10-A)
  • True count = running count / decks remaining
  • Player edge estimation derived from true count
  • Counter resets to zero when shoe reshuffles
  • decksRemaining calculated from (total cards - cards dealt) / 52
  • Unit tests cover full shoe deal-down, reshuffle reset, edge cases

S09: Player Rank and XP System

Compressed power-law XP formula with participation floor, win streak multiplier, level calculation, and table unlock checks. Rebalanced in PR #72 to prevent single-hand level jumps.

Doc sources: Player Rank, Dealer Tables, Level Progression Audit

  • XP formula: minimumXP + outcomeWeight × bet^0.35 × 1.5 (compressed power-law, not linear)
  • Participation floor: loss/push/surrender = 3 XP, win = 8 XP, blackjack = 15 XP
  • Outcome weights: loss/push = 1, win = 3, blackjack = 5
  • Win streak multiplier: 2 = 1.25x, 3-4 = 1.5x, 5-6 = 1.75x, 7+ = 2.0x; any non-win resets streak
  • Level = floor((totalXP / 100)^(2/3)) matches documented milestones (level 10 = 3162 XP, level 100 = 100000 XP)
  • Bet incentive ratio compressed from 10,000x to ~12x between min and max bets
  • isTableUnlocked checks against unlock levels (1, 10, 25, 50, 100)
  • XP never decreases
  • Unit tests verify compression ratios, single-hand max level bounds, streak tiers, and all milestones

S10: Game State Machine

GKStateMachine with all round states (Betting, Dealing, Insurance, PlayerTurn, DealerTurn, Evaluating, Payout, RoundComplete). Transition validation. Round orchestration function that drives a complete round using all prior engine slices.

Doc sources: Technical Overview, Gameplay, Hand Actions, Insurance

  • All 8 states defined with isValidNextState enforcing documented transitions
  • Natural BJ flow: Dealing to Evaluating (skipping PlayerTurn/DealerTurn)
  • Insurance branch: only entered when dealer shows Ace and insurance is enabled
  • Split handling: PlayerTurn tracks active hand index, sequential play, split-ace auto-stand
  • Round orchestrator drives a complete round using Shoe, Hand, BlackjackRules, DealerLogic, BettingEngine
  • Unit tests cover: normal flow, BJ detection (player, dealer, both), insurance, split with re-split, surrender (via Beta Tweaks config), all-bust skip-dealer

Phase B: Persistence

High-Risk Phase

SwiftData models with CloudKit sync. Schema is permanent after the first CloudKit production deployment. All relationships must be optional, no unique constraints, all properties need defaults, and changes are additive-only post-launch.

SliceNameDependenciesDesignEst. FilesStatus
S11SwiftData Models: Game StateS03, S09No~3Implemented
S12SwiftData Models: StatisticsS11No~3Implemented
Slice Details and Acceptance Criteria

S11: SwiftData Models: Game State

SwiftData models for bankroll, player rank (XP, level), settings toggles, and selected dealer table. CloudKit-safe schema.

Doc sources: Technical Overview, Settings, Player Rank, Betting

  • GameState model persists bankroll (default 1000), totalXP, currentLevel, selectedTable
  • SettingsModel persists 5 toggles with documented defaults (haptic=on, insurance=off, autoHint=off, handCount=off, dealerSoft17=stand)
  • All properties have default values (CloudKit requirement)
  • No @Attribute(.unique) constraints (CloudKit requirement)
  • All relationships optional (CloudKit requirement)
  • Reset Game clears bankroll to 1000, XP to 0, level to 1, statistics, hand count

S12: SwiftData Models: Statistics

SwiftData models for statistics accumulator (10 tracked metrics), calculated rates, win streaks, monthly grouping, and hand history.

Doc sources: Statistics, Technical Overview

  • StatisticsModel tracks all 10 documented metrics (hands, wins, losses, pushes, player BJs, dealer BJs, player busts, dealer busts, total wagered, net result)
  • Calculated rates derived correctly (win%, loss%, push%, BJ%, bust%, realized house edge)
  • Win streak tracking: current streak and best-ever streak persisted
  • Monthly grouping: statistics grouped by month for historical review
  • Precomputed summary model for aggregate stats
  • Date fields indexed for query performance

Phase C: ViewModels & Services

Architecture Layer

Service protocols, composition root, ViewModels, and external framework integrations (StoreKit, GameKit). Still no UI pixels. Everything is testable via mock services.

SliceNameDependenciesDesignEst. FilesStatus
S13Service Protocols and Composition Root--No~4Implemented
S14GameViewModelS10, S11, S12, S13No~3Implemented
S15Statistics ViewModelS12, S13No~2Implemented
S16StoreKit Service + Store ViewModelS11, S13No~4Implemented
S17Game Center ServiceS13No~2Implemented
S18Daily Challenge LogicS07, S09, S11No~3Implemented
S19Settings ViewModelS03, S11, S13No~2Implemented
Slice Details and Acceptance Criteria

S13: Service Protocols and Composition Root

Protocol definitions for all services and the composition root that assembles production vs test dependency graphs.

Doc sources: Architecture Principles, Technical Overview

  • GameCenterServiceProtocol defines: authenticate, submitScore, fetchLeaderboard
  • StoreKitServiceProtocol defines: fetchProducts, purchase, restorePurchases, transactionUpdates
  • HapticPlaying defines: playPattern(for event)
  • AudioPlaying defines: playSound(for event)
  • ErrorReporting defines: publish(error), clear()
  • Composition root assembles all services with constructor injection for ViewModels and environment entry points for SwiftUI views
  • Mock implementations for all protocols

S14: GameViewModel

Central ViewModel bridging the Phase A engine with service protocols. Orchestrates round flow, exposes observable state for UI binding, manages pendingAction for SpriteKit communication.

Doc sources: Technical Overview, Architecture Principles, Gameplay

  • @Observable class with @MainActor isolation
  • Exposes: currentHands, dealerHand, bankroll, currentBet, gamePhase, availableActions, isAnimating, pendingAction
  • Drives full round flow: placeBet to deal to insurance to playerAction to dealerTurn to evaluate to payout
  • Updates PlayerRank (XP/level) and Statistics after each round
  • Persists state changes via SwiftData using a ModelActor boundary (PersistentIdentifier handoff)
  • Publishes recoverable failures to the shared ErrorReporting channel for centralized banners
  • Unit tests using mock services verify complete round flows

S15: Statistics ViewModel

StatsVM that reads from SwiftData models, exposes calculated rates, win streaks, and monthly history.

Doc sources: Statistics

  • Reads all 10 tracked metrics from persistence
  • Exposes all calculated rates (win%, loss%, push%, BJ%, bust%, realized house edge)
  • Exposes current and best-ever win streaks
  • Provides monthly-grouped data for historical display

S16: StoreKit Service + Store ViewModel

StoreKitService conforming to StoreKitServiceProtocol plus StoreVM for observable store state. Handles product fetch, purchase flow, transaction verification, entitlement state, and credit delivery.

Doc sources: Credits & Pricing, Technical Overview

  • Fetches all 11 products (1 free + 3 budget + 1 ad-free + 6 premium)
  • StoreVM exposes product list, purchase state, restore state, ad-free entitlement, and user-facing errors
  • Purchase flow: product request to payment to transaction verification to credit delivery
  • Ad-free flag set for Ad-Free Upgrade ($3.99) and all premium packs ($4.99+)
  • Credit amounts match documentation exactly (500 through 400,000)
  • Transaction.updates listener for pending/interrupted transactions
  • Product fetching is deferred until first store/challenge access (no launch-time blocking)
  • Restore purchases restores ad-free status

S17: Game Center Service

GameCenterService conforming to GameCenterServiceProtocol. Auto-authentication, score submission to 2 leaderboards, offline queueing.

Doc sources: Game Center, Technical Overview

  • Authenticates GKLocalPlayer during post-launch idle work or on first Game Center dashboard access
  • Submits net winnings to all-time and monthly leaderboards
  • Queues submissions when offline, retries on reconnection
  • App is fully playable without Game Center authentication

S18: Daily Challenge Logic

Challenge question generator using basic strategy charts, difficulty scaling by player level, reward credit calculation, daily reset logic.

Doc sources: Daily Challenge, Basic Strategy

  • Generates 5 questions per day from basic strategy pool matching difficulty tier
  • 5 difficulty tiers with correct level ranges (1-9, 10-24, 25-49, 50-99, 100+)
  • Available actions per tier match docs (Beginner: H/S only through Master: H/S/D/P)
  • Reward credits match docs (1500, 3000, 5000, 8000, 12000)
  • Uses Jean-Luc's rule set always for question generation
  • Daily reset logic with level-based tier assignment
  • Reward is claimable once per UTC day
  • Mid-day level changes do not alter the active day's challenge tier

S19: Settings ViewModel

SettingsVM managing the 5 toggles (was 4; add Dealer on Soft 17) with table-aware availability. Reset Game action.

Doc sources: Settings, Auto Hint, Insurance

  • 5 toggles with correct defaults (haptic=on, insurance=off, autoHint=off, handCount=off, dealerSoft17=stand)
  • Auto-hint toggle hidden when table hints are unavailable (Lady Lux, Aunty)
  • Auto-hint defaults to on at hint-available tables (Jean-Luc, Czarita, Jack); user can toggle off in Settings
  • Insurance toggle hidden when table disables insurance (Lady Lux, Aunty)
  • Reset Game clears bankroll to 1000, XP to 0, stats cleared, hand count to 0
  • Changes persist via SwiftData

Phase D: UI Shell

Complete

All Phase D slices are implemented. S23 (Accessibility) was moved to Phase F for a single comprehensive pass after all UI screens exist.

SliceNameDependenciesDesignEst. FilesStatus
S20SpriteKit Table SceneS14Yes~5Implemented
S21SwiftUI App ShellS14, S20Yes~5Implemented
S22Betting Screen UIS06, S14, S20Yes~3Implemented
Slice Details and Acceptance Criteria

S20: SpriteKit Table Scene

BlackjackTableScene (SKScene) with table felt, card node positioning, chip stack nodes, particle emitters. SpriteView integration with pause/unpause lifecycle.

Doc sources: Technical Overview, Dealer Rules

  • Scene renders table felt, card positions (player area, dealer area), and chip stack area
  • Card deal animation: alternating player/dealer sequence
  • Card flip animation for dealer hole card reveal
  • Chip stacking/removal animations for bet placement and payout
  • Visible cut-card marker updates as cards are dealt through the shoe
  • When cut-card depth is reached, round finishes first, then shuffle animation plays before next deal
  • Scene pauses during idle, unpauses on pendingAction, re-pauses after animation completes
  • 2048x2048 texture atlas for 52 card faces + backs

S21: SwiftUI App Shell

App entry point, navigation structure, main menu, game table screen (ZStack with SpriteView + HUD overlay), dealer selector with 5 dealer portraits and lock states.

Doc sources: Technical Overview, Dealer Tables, Gameplay

  • App launches to main menu or game table
  • Game table screen: SpriteView with ZStack HUD overlay containing action buttons
  • Action buttons with VoiceOver, Dynamic Type, disabled during animations
  • Dealer selector: 5 portraits, locked dealers show required level, current dealer highlighted
  • Table color changes per dealer selection (green, red, blue, purple, gold)
  • Bankroll display, bet amount display, rank bar visible on game screen
  • Auto-deal control and hand-count HUD binding wired to S26 observable state
  • Centralized non-blocking error banner for StoreKit, GameKit, and persistence failures

S22: Betting Screen UI

Chip rack with 5 dynamic denominations, tap-to-add stacking, clear bet button, deal button, bet persistence between rounds.

Doc sources: Betting, Dealer Tables

  • 5 chip denominations displayed, correct for current bankroll tier
  • Tap chip to add to bet with visual stacking
  • Clear Bet resets wager to zero
  • Deal button enabled when bet > 0 and bet >= table minimum
  • Bet cannot exceed bankroll
  • Bet persists between rounds for quick re-deal

Phase E: Feature Polish

Final Integration

Feature UI, polish, and integration. S26 and S27 are no-design slices and should start immediately after their dependencies are met. UI-heavy slices remain blocked on S21/design assets.

SliceNameDependenciesDesignEst. FilesStatus
S24Auto-Hint UIS07, S14, S19, S21Yes~2Implemented
S25Insurance UIS04, S14, S19, S21Yes~2Implemented
S26Auto-Deal and Hand Count LogicS14, S19No~3Implemented
S27Haptic and Audio IntegrationS13, S14No~3Implemented
S28Count Peek Easter EggS08, S14, S20Yes~2Implemented
S29Daily Challenge UIS16, S18, S21Yes~4Implemented
S30Statistics ScreenS15, S21Yes~2Implemented
S31Settings ScreenS03, S14, S19, S21Yes~3Implemented
S32Store ScreenS16, S21Yes~2Implemented
S33Game Center DashboardS17, S21Yes~2Implemented
S-IAPIAP Credit Safety (Plans A–E)S11, S13, S16, S31, S32No~15Implemented
Slice Details and Acceptance Criteria

S24: Auto-Hint UI

Hint display overlay during player turn showing recommended action from BasicStrategy engine. Table-aware visibility. Disabled during Daily Challenge.

Doc sources: Auto Hint

  • Hint displays recommended action (Hit, Stand, Double, Split) during player turn
  • Hint updates after each hit/split for the new hand state
  • Always visible at Jean-Luc and Czarita; toggle-controlled at Jack; hidden at Lady Lux and Aunty
  • Surrender is not part of the action set (all tables have surrender disabled)
  • Disabled during Daily Challenge regardless of settings

S25: Insurance UI

Insurance prompt overlay when dealer shows Ace and setting is enabled. Accept/decline buttons, half-bet display, immediate resolution.

Doc sources: Insurance, Hand Actions

  • Prompt appears when dealer upcard is Ace, insurance setting is on, and table allows insurance
  • Shows insurance cost (half original bet)
  • Accept/decline buttons
  • On accept: insurance bet placed, dealer peeks, result shown (2:1 payout or loss)
  • On decline: play continues normally
  • Not shown at Lady Lux or Aunty tables

S26: Auto-Deal and Hand Count Logic

Auto-deal 1.2s timer orchestration and hand-count round tracking in ViewModel/persistence layers. Visual wiring is attached later in S21/S31.

Doc sources: Auto-Deal, Hand Count

  • Auto-deal fires 1.2 seconds after round end, using same bet
  • Manual Deal tap cancels pending auto-deal timer
  • Auto-deal disabled by default, state persisted between sessions
  • Hand count increments by 1 per round (not per split hand)
  • Hand count resets to zero on Reset Game
  • Exposes observable state for later table HUD binding in S21

S27: Haptic and Audio Integration

HapticsService and AudioService wrappers for gameplay feedback, including lifecycle/performance handling.

Doc sources: Haptic Feedback, Technical Overview, Architecture Principles

  • CoreHaptics engine created with isAutoShutdownEnabled = true
  • AVFoundation-based AudioService plays deal/flip/chip/win/loss cues via AudioPlaying protocol
  • Haptics cover documented gameplay events (action tap, deal, hole-card reveal, win, loss/bust)
  • Fires on correct GameViewModel events
  • Audio/haptics preload runs after first frame to protect launch performance
  • Respects haptic toggle in Settings
  • Graceful no-op on devices without haptic hardware

S28: Count Peek Easter Egg

Long-press gesture on table felt reveals translucent popover with running count, true count, decks remaining, and player edge. Values frozen at press moment.

Doc sources: Count Peek

  • Long-press gesture on SpriteKit table felt triggers popover
  • Popover shows: running count, decks remaining, true count, player edge
  • Values are snapshot at press time (do not update while visible)
  • Popover disappears on finger lift
  • No visible indicator that the feature exists (hidden easter egg)

S29: Daily Challenge UI

Challenge screen with 5-question checklist, question view, retry flow with ad gate, reward delivery, banner in dealer selector.

Doc sources: Daily Challenge

  • 5-item checklist with checkbox per question
  • Question view shows dealer upcard + player cards + action buttons for current difficulty tier
  • Correct answer checks the checkbox; wrong answer shows Retry button
  • Retry triggers ad (or bypasses if ad-free user)
  • Unlimited retries supported; each failed attempt re-enters retry flow
  • All 5 correct: credits added to bankroll immediately
  • Progress persists across app exits throughout the day
  • Reward payout allowed once per day, then banner shows completed state
  • Banner in dealer selector shows progress/completion status

S30: Statistics Screen

Statistics screen wired to StatsVM, displaying all tracked metrics and historical data.

Doc sources: Statistics

  • Stats screen displays all 10 tracked metrics and all calculated rates
  • Win streak display (current + best-ever)
  • Monthly history with SwiftUI Charts visualization

S31: Settings Screen

Settings screen with native iOS Form UI, all gameplay toggles, and Reset Game. Beta Tweaks removed from scope — internal debug tool retained in code behind #if DEBUG || DEV_BUILD but not a user-facing feature.

Doc sources: Settings

  • Settings screen: 7 toggles (Haptic Feedback, Sound Effects, Insurance, Auto Hint, Hand Count, Auto-Deal, Dealer on Soft 17) with correct defaults and table-aware visibility
  • Auto Hint toggle only visible at hint-available tables (Jean-Luc, Czarita, Jack)
  • Reset Game button with irreversible warning
  • Changes take effect on next dealt hand

S32: Store Screen

Store screen wired to StoreVM, listing all purchasable packs with purchase flow integration.

Doc sources: Credits & Pricing

  • Store screen lists all 11 packs with price, credits, and ad-removal badge
  • Quick Chips (free) triggers ad then delivers 500 credits
  • Purchase flow integrates with StoreKitService

S33: Game Center Dashboard

Game Center dashboard showing leaderboard status, wired to GameCenterService.

Doc sources: Game Center

  • Game Center dashboard shows all-time and monthly leaderboard status
  • Game Center unavailable/auth-failed state renders a playable fallback UI

Phase F: Design & Polish

Design-Dependent Polish + Accessibility

Design refinement slices replace placeholder native UI with proper Figma-designed screens. S23 (Accessibility) was deferred here for a single comprehensive pass after all UI screens are built — covering SpriteKit scene, game shell, betting, auto-hint, insurance, count peek, daily challenge, statistics, settings, store, and Game Center.

SliceNameDependenciesDesignEst. FilesStatus
S-DDDealer Selector Proper DesignS21Yes~2Implemented
S-DSSettings Screen Proper DesignS31Yes~2Not Started
S23Accessibility LayerS20 -- S33 (all UI slices)No~4Not Started
Slice Details and Acceptance Criteria

S-DD: Dealer Selector Proper Design

Replace the placeholder native UIKit dealer selector sheet with a properly designed dealer selection screen based on Figma specs. The current implementation uses a standard iOS list with avatars, dealer names, and table info — this slice will elevate it to match the app's casino visual identity.

Doc sources: Dealer Tables

  • Dealer selector screen matches Figma design specs
  • Dealer avatars, names, and table rule summaries displayed with casino-themed styling
  • Level-gated dealers show lock state with required level
  • Selected dealer highlighted with visual feedback
  • Smooth transitions between dealer selection and game table

S-DS: Settings Screen Proper Design

Replace the native iOS Form settings screen with a properly designed settings screen based on Figma specs. The current implementation uses a standard SwiftUI Form with grouped sections — this slice will elevate it to match the app's casino visual identity.

Doc sources: Settings

  • Settings screen matches Figma design specs
  • Toggle rows, segmented controls, and reset button styled with casino theme
  • Conditional Auto Hint / Insurance rows maintain table-aware visibility logic
  • Reset Game confirmation retains destructive styling with design polish

S23: Accessibility Layer

Comprehensive accessibility pass across the entire app — deferred from Phase D to Phase F so all UI surfaces are instrumented in a single, consistent sweep. Covers SpriteKit scene, game shell, betting, auto-hint, insurance, count peek, daily challenge, statistics, settings, store, and Game Center.

Doc sources: Technical Overview

  • Custom UIAccessibilityElement for each SpriteKit card position with descriptive values
  • Chip stack accessibility values updated on bet changes
  • SKLabelNode text scales based on system Dynamic Type preference
  • VoiceOver announcements for: deal, player BJ, dealer BJ, bust, win, loss, push
  • All SwiftUI action buttons and screens have correct accessibility traits and labels
  • Every Phase E screen (auto-hint, insurance, daily challenge, statistics, settings, store, Game Center) accessibility-audited

Dependency Graph

Build order flows left to right. Slices at the same level can be built in parallel.

Phase A (Core Engine)
  S01, S02, S03 ──→ S-FW (framework extraction)
  S-FW ──→ S04, S05, S06, S07, S08, S09, S10 (all built inside the package)
  S01 ──→ S02 ──→ S04 ──→ S07
  S03 ──→ S04
  S03 ──→ S05
  S03 ──→ S06
  S03 ──→ S09
  S01 ──→ S08
  S01-S06 ──→ S10

Phase B (Persistence)
  S03, S09 ──→ S11 ──→ S12

Phase C (ViewModels & Services)
  S13 (no deps, can start early)
  S10, S11, S12, S13 ──→ S14
  S12, S13 ──→ S15
  S11, S13 ──→ S16
  S13 ──→ S17
  S07, S09, S11 ──→ S18
  S03, S11, S13 ──→ S19

Phase D (UI Shell) - Design required
  S14 ──→ S20 ──→ S21
  S06, S14, S20 ──→ S22

Phase E (Feature Polish)
  S07, S14, S19, S21 ──→ S24
  S04, S14, S19, S21 ──→ S25
  S14, S19 ──→ S26
  S13, S14 ──→ S27
  S08, S14, S20 ──→ S28
  S16, S18, S21 ──→ S29
  S15, S21 ──→ S30
  S03, S14, S19, S21 ──→ S31
  S16, S21 ──→ S32
  S17, S21 ──→ S33

Phase F (Design & Polish)
  S21 ──→ S-DD
  S31 ──→ S-DS
  S20-S33 (all UI slices) ──→ S23

Parallelization opportunities:

  • Phase A: S01 and S03 start in parallel. After those, S02/S08 and S05/S06/S09 can parallelize.
  • Pre-design window: S01-S19, plus S27 and S26, can be executed before final UI design arrives.
  • UI-heavy endgame: S24/S25/S28/S29/S30/S31/S32/S33 can parallelize once S21 is complete.

Feature-to-Slice Mapping

Every documented feature maps to at least one implementation slice. Player-facing features map to UI/integration slices; rules-only features may remain logic-only.

FeatureEngine SlicesUI/Integration Slices
Dealer TablesS03 (table rules config)S14 (table switching), S21 (dealer selector)
Game CenterS17 (GameKit service)S33 (dashboard + leaderboard surfaces)
SettingsS11 (persistence), S19 (ViewModel)S31 (settings screen), S-DS (design refinement)
Credits & PricingS16 (StoreKit service)S32 (store screen)
IAP Credit SafetyS-IAP (Plans A–E)Transaction safety, bankroll backup, purchase support, admin panel
Daily ChallengeS18 (challenge logic)S29 (challenge UI)
ShufflingS01 (Shoe struct)S20 (shuffle animation)
StatisticsS12 (data models), S15 (ViewModel)S30 (statistics screen)
Player RankS09 (XP engine), S11 (persistence)S21 (rank bar)
Auto-DealS26 (timer logic)S21 (table controls/binding)
Haptic FeedbackS13 (protocol), S27 (service)S14 (event triggers), S31 (settings toggle)
InsuranceS04 (action validation)S19 (toggle), S25 (prompt UI)
Dealer Hits Soft 17S05 (dealer logic), S07 (strategy engine)S11 (persistence), S19 (settings toggle), S31 (settings screen)
Auto HintS07 (strategy engine)S24 (hint overlay)
Hand CountS26 (counter logic), S11 (persistence), S19 (toggle state)S21 (counter display), S31 (settings toggle)
Count PeekS08 (Hi-Lo engine)S28 (peek popover)

Architecture-to-Slice Mapping

Key architecture requirements from Technical Overview and Architecture Principles are explicitly covered below.

Architecture RequirementSlices
MVVM with dedicated feature ViewModels (GameViewModel, StoreVM, StatsVM, SettingsVM)S14, S15, S16, S19
Service layer protocol abstraction and dependency injectionS13, S16, S17, S27
SwiftData + CloudKit-safe schema and ModelActor write boundaryS11, S12, S14
Offline-first behavior and queued network-dependent operationsS16, S17, S32, S33
Centralized recoverable error surfacingS13, S14, S21
Performance notes (deferred framework startup, SpriteKit pause lifecycle)S16, S17, S20, S27
Accessibility bridge for SpriteKit + SwiftUI hybrid UIS23
Modularization (TrueCountEngine Swift Package boundary)S-FW

Status Legend

ColorStatusMeaning
GreyNot StartedDocumented but no code exists yet
AmberIn ProgressActive development, partially working
IndigoImplementedCode complete, functional in builds
GreenTestedVerified, stable, release-ready

How is this guide?

On this page