# Architecture > Last Updated: 2026-04-02T19:05:00.000Z ## Overview | Attribute | Value | |-----------|-------| | Primary language | TypeScript | | Secondary language | Java (Capacitor Android shell) | | Project type | Browser card game with Android packaging | | Framework | Phaser 3.87.0 | | Tooling | Vite 5, TypeScript 5.x, Capacitor 8.3 | | Runtime layout | 1280 x 720, `Phaser.Scale.FIT`, centered in `#game` | | Build command | `npm run build` | | Test command | `npx tsc --noEmit` | The repository is a TypeScript-first Scopone Scientifico implementation. The web client contains the real game logic and presentation. The Android tree is a Capacitor wrapper with a custom immersive `MainActivity`. ## Project Structure ```text scopone-phaser/ |- src/ | |- main.ts | |- game/ | | |- types.ts | | |- engine.ts | | |- card-tracker.ts | | |- ai.ts | | |- ai-worker-protocol.ts | | |- ai-worker-client.ts | | `- ai.worker.ts | `- scenes/ | |- BootScene.ts | |- MenuScene.ts | `- GameScene.ts |- public/ |- android/ |- docs/ |- prompts/ |- package.json |- tsconfig.json |- vite.config.ts `- capacitor.config.ts ``` ## Key Directories | Directory | Purpose | |-----------|---------| | `src/game/` | Framework-independent rules, scoring, imperfect-information tracking, and AI search | | `src/scenes/` | Phaser scene lifecycle, UI, animation, effects, and round orchestration | | `public/` | Static web assets consumed by Phaser loaders | | `android/` | Capacitor Android project, Gradle config, and immersive activity wrapper | | `docs/` | Architecture, code style, findings, and cache metadata | | `prompts/` | JIRA pipeline artifacts and iteration state | ## Design Patterns No explicit GoF patterns were detected in the source or by semantic search. Observed architectural patterns in the current codebase: | Pattern | Where it appears | |---------|------------------| | Scene-based flow | `BootScene -> MenuScene -> GameScene` via Phaser scene registration | | Functional core / imperative shell | `src/game/` stays free of Phaser imports, while `src/scenes/` owns rendering and input | | Clone-before-mutate state transitions | `applyMove()` clones `GameState` before applying move effects | | Worker offload with fallback | `AIWorkerClient` runs heavy AI inside `ai.worker.ts` and falls back to in-thread `chooseMove()` if worker startup or messaging fails | | Determinization search | Master AI samples hidden hands before alpha-beta evaluation | | Message-based progress reporting | Worker and main thread exchange typed request/result/progress messages through `ai-worker-protocol.ts` | ## Key Components ### `src/main.ts` - Bootstraps `Phaser.Game`. - Registers `BootScene`, `MenuScene`, and `GameScene`. - Installs a one-shot fullscreen request handler on first user interaction. ### `src/game/types.ts` - Defines the game model: `Card`, `Capture`, `Player`, `GameState`, `TeamScore`, `ScoreBreakdown`. - Encodes difficulty tiers as `'beginner' | 'advanced' | 'master'`. - Stores the `PRIMIERA_VALUES` lookup table. ### `src/game/engine.ts` (371 lines) - Builds and shuffles the 40-card deck. - Creates the initial round state for four players. - Implements capture selection rules: single direct matches take priority; subset sums are considered only when no direct match exists. - Applies moves immutably, detects scopas, assigns leftover table cards, and computes round scores. ### `src/game/card-tracker.ts` (89 lines) - Tracks seen cards across a round without exposing hidden hands directly. - Computes unseen cards from `played + myHand + table`. - Supplies probability helpers used by the AI for value-based inference. ### `src/game/ai.ts` - Exposes `chooseMove()` as an async entry point. - Implements three difficulty levels: - `beginner`: noisy heuristic play. - `advanced`: stronger heuristics with race awareness, partner setup, and card-tracker inference. - `master`: determinization plus alpha-beta search with dynamic time budgets, batching, and progress callbacks. - Uses `yieldToBrowser()` between master-search batches so Phaser can repaint the think bar. ### `src/game/ai-worker-protocol.ts` - Defines the typed message contract between the main thread and the worker. - Serializes requests around `GameState`, `Difficulty`, `PlayerIndex`, tracker snapshots, progress, results, and worker-safe errors. ### `src/game/ai-worker-client.ts` - Wraps the worker lifecycle behind the same `chooseMove()` API the scene needs. - Creates module workers with `new Worker(new URL('./ai.worker.ts', import.meta.url), { type: 'module' })`. - Streams progress callbacks back into `GameScene` and degrades to direct `chooseMove()` execution when workers are unavailable. ### `src/game/ai.worker.ts` - Rehydrates `CardTracker` from a snapshot, delegates move selection to `chooseMove()`, and posts progress/result/error messages back to the scene thread. - Keeps the expensive `master` search off the main rendering thread when worker support is available. ### `src/scenes/BootScene.ts` - Loads the card atlas and card-back texture. - Shows a simple progress bar and transitions into the menu. ### `src/scenes/MenuScene.ts` - Renders the title screen and rules summary. - Lets the player choose `beginner`, `advanced`, or `master` difficulty. - Starts `GameScene` with the selected difficulty in scene data. ### `src/scenes/GameScene.ts` - Owns the match loop, HUD, think bar, card interaction, animation, FX, audio, and round transitions. - Uses `CardTracker` to record played and captured cards after each move. - Instantiates `AIWorkerClient`, bridges async AI progress into a visible top-of-screen think bar, and disposes worker resources on scene shutdown. - Handles end-of-round overlays and full-match restart flow. ### `android/app/src/main/java/com/phaser/scopa/MainActivity.java` - Extends `BridgeActivity`. - Forces immersive mode by hiding status and navigation bars whenever the window gains focus. ## Dependencies ### JavaScript production dependencies | Package | Version | Purpose | |---------|---------|---------| | `phaser` | `^3.87.0` | Game engine | | `@capacitor/core` | `^8.3.0` | Capacitor runtime | | `@capacitor/cli` | `^8.3.0` | Capacitor tooling | | `@capacitor/android` | `^8.3.0` | Android platform integration | ### JavaScript development dependencies | Package | Version | Purpose | |---------|---------|---------| | `typescript` | `^5.0.0` | Type-checking and TS compilation for builds | | `vite` | `^5.0.0` | Dev server and bundling | ### Android / Gradle dependencies | Dependency | Source | Purpose | |------------|--------|---------| | `com.android.tools.build:gradle:8.13.0` | `android/build.gradle` | Android build plugin | | `com.google.gms:google-services:4.4.4` | `android/build.gradle` | Optional Google services integration | | `androidx.appcompat:appcompat` | `android/app/build.gradle` | Android UI compatibility | | `androidx.coordinatorlayout:coordinatorlayout` | `android/app/build.gradle` | Android layout support | | `androidx.core:core-splashscreen` | `android/app/build.gradle` | Splash screen support | | `junit:junit` | `android/app/build.gradle` | JVM-side Android tests | | `androidx.test.ext:junit` | `android/app/build.gradle` | Instrumented Android testing | | `androidx.test.espresso:espresso-core` | `android/app/build.gradle` | Android UI testing | ## Module Organization ```text main.ts -> BootScene -> MenuScene -> GameScene -> engine.ts -> ai.ts -> ai-worker-client.ts -> ai-worker-protocol.ts -> ai.worker.ts -> ai.ts -> card-tracker.ts -> types.ts ``` Dependencies are one-directional at the application level: - `src/game/` imports only from sibling game modules. - `src/scenes/` imports from `src/game/`. - `src/game/` never imports Phaser. ## Data Flow 1. `main.ts` creates the Phaser app and registers all scenes. 2. `BootScene` loads assets, then starts `MenuScene`. 3. `MenuScene` passes the chosen difficulty into `GameScene`. 4. `GameScene.create()` initializes a new `CardTracker`, creates the initial `GameState`, and animates the opening deal. 5. On each turn: - Human turns use click-driven selection and capture highlighting. - AI turns call `AIWorkerClient.chooseMove(state, playerIdx, difficulty, tracker, onProgress)`. 6. `AIWorkerClient` posts a typed request into `ai.worker.ts`; if worker setup fails, it falls back to in-thread `chooseMove()`. 7. `chooseMove()` either returns immediately for heuristic tiers or performs batched master search while reporting `AIDecisionProgress`. 8. Worker progress messages drive `GameScene.updateThinkBar()` until a result is posted back. 9. `GameScene.executeMove()` applies the move, updates the tracker, animates the result, refreshes the HUD, and advances the round. 10. When all hands are empty, `engine.ts` finalizes scoring and `GameScene` displays the round summary or final match screen. ## Build System | Command | Source | Purpose | |---------|--------|---------| | `npm run dev` | `package.json` | Starts the Vite development server on port 3000 and opens the browser | | `npm run build` | user-provided build command | Runs `tsc && vite build` and writes web output to `dist/` | | `npm run preview` | `package.json` | Serves the built app locally via Vite preview | | `npx tsc --noEmit` | user-provided test command | Type-checks the TypeScript codebase without emitting files |