# Architecture > Last Updated: 2026-03-31T00:00:00.000Z ## Overview | Attribute | Value | |-----------------|--------------------------------------------------------| | **Language** | TypeScript (ES2020 target, strict mode) | | **Type** | 2D card game — Scopone Scientifico | | **Framework** | Phaser 3.87+ (scene-based game engine) | | **Bundler** | Vite 5 | | **Native** | Capacitor 8.3 (Android) | | **Resolution** | 1280 × 720, FIT scaling with auto-center | ## Project Structure ``` scopone-phaser/ ├── src/ │ ├── main.ts # Phaser.Game bootstrap + config │ ├── game/ │ │ ├── types.ts # Card, Suit, Player, GameState, TeamScore, ScoreBreakdown, PRIMIERA_VALUES │ │ ├── engine.ts # Deck build, shuffle, capture logic, applyMove, scoring, primiera │ │ └── ai.ts # Heuristic AI: chooseMove, scoreCapture, scoreDump │ └── scenes/ │ ├── BootScene.ts # Asset loading (atlas, card back image) │ ├── MenuScene.ts # Start menu with rules summary │ └── GameScene.ts # Main game: rendering, turn management, effects, audio ├── index.html # Entry point, Italian locale, green felt background ├── public/ # Static assets (atlas.json, atlas.png, retro.png) ├── android/ # Capacitor Android native shell ├── package.json ├── tsconfig.json ├── vite.config.ts └── capacitor.config.ts ``` ## Key Directories | Directory | Purpose | |--------------------|----------------------------------------------------------------| | `src/game/` | Domain logic — types, game engine, AI (no Phaser dependency) | | `src/scenes/` | Phaser scenes — rendering, input, effects, audio | | `public/` | Static assets served by Vite (card atlas, card back) | | `android/` | Capacitor-generated Android project (Gradle, Java) | | `prompts/` | JIRA agent pipeline artifacts | ## Design Patterns | Pattern | Where | |-----------------------------|--------------------------------------------------------------------| | **Scene lifecycle** | BootScene → MenuScene → GameScene (Phaser scene graph) | | **Immutable state updates** | `applyMove()` deep-clones `GameState` before mutation | | **Heuristic scoring** | AI evaluates all legal moves with weighted feature scores | | **Separation of concerns** | `game/` has no Phaser imports; `scenes/` bridges game ↔ rendering | | **Procedural audio** | Web Audio API oscillators + delay reverb — no audio files | No explicit GoF patterns (singleton, factory, observer, DI) detected. ## Key Components ### `types.ts` — Domain Types - `Card { suit, value, id }` — 40-card Napoletane deck (suits: bastoni, coppe, denara, spade; values 1-10) - `GameState` — full round state: 4 players, table, current player, team scores, round tracking - `TeamScore` — per-team stats: cards, scope, denari, settebello, primiera, round/total points - `ScoreBreakdown` — which team won each scoring category - `PRIMIERA_VALUES` — lookup table for primiera card values ### `engine.ts` — Game Logic - `buildDeck()` / `shuffle()` — Fisher-Yates 40-card deck - `createInitialState()` — deals 10 cards per player, empty table (Scopone Scientifico rules) - `findCaptures(played, table)` — direct value match (mandatory) or subset-sum combinations - `applyMove(state, player, card, captureChoice)` — immutable state transition, scopa detection, end-of-round scoring - `calculateScores()` / `scoreRound()` — carte, denari, settebello, primiera, scope points - `calcPrimiera(pile)` — best card per suit using `PRIMIERA_VALUES` - `teamOf(playerIdx)` — team assignment: 0+2 = Team A, 1+3 = Team B ### `ai.ts` — Heuristic AI - `chooseMove(state, playerIdx)` — evaluates all legal moves (captures + dumps) - `scoreCapture()` — weighted: scopa (+500), settebello (+300), denari (+50 each), card count, primiera value, opponent threat - `scoreDump()` — avoids giving opponents scopa (-400), prefers low-value non-denari, penalises dumping 7s and aces ### `GameScene.ts` — Main Scene (~1340 lines) - Four-player layout: South (human), West/East (AI, rotated ±90°), North (AI partner) - Deal animation with staggered tweens - Card selection with postFX glow pulse - Capture highlighting with multiple-choice UI - Particle effects: capture burst, scopa explosion, settebello flash, denari shimmer, primiera glow, card trails, victory confetti - Camera shake + flash on scopa and settebello - Live score bar with animated counter updates - Think bar progress indicator during AI turns - Procedural background music (oscillator drone + triangle melody + chord stabs) - Round-end summary panel and game-over screen ## Dependencies ### Production | Package | Version | Purpose | |----------------------|----------|--------------------------------------| | `phaser` | ^3.87.0 | 2D game engine | | `@capacitor/core` | ^8.3.0 | Capacitor runtime | | `@capacitor/cli` | ^8.3.0 | Capacitor CLI | | `@capacitor/android` | ^8.3.0 | Android platform plugin | ### Development | Package | Version | Purpose | |---------------|---------|--------------------------| | `typescript` | ^5.0.0 | TypeScript compiler | | `vite` | ^5.0.0 | Dev server and bundler | ## Module Organisation ``` main.ts ──→ BootScene ──→ MenuScene ──→ GameScene │ ├── game/engine (createInitialState, applyMove, findCaptures, ...) ├── game/ai (chooseMove) └── game/types (Card, GameState, ...) ``` `game/` modules are pure logic with no framework coupling. `scenes/` imports from `game/` but never vice versa. ## Data Flow 1. `createInitialState()` builds shuffled deck, deals 10 cards each, empty table 2. `GameScene.nextTurn()` detects current player: human → enable input; AI → delay + `chooseMove()` 3. `applyMove()` returns new `GameState` + capture result + scopa flag 4. `GameScene.executeMove()` animates: card flight → capture burst → pile collection 5. `updateScoreBar()` reflects live team stats with animated counter tweens 6. When all hands empty → `calculateScores()` → round-end overlay 7. First team to 11 points → game-over screen → optional restart ## Build System | Command | Action | |--------------------|--------------------------------------------| | `npm run dev` | `vite` — dev server on port 3000 | | `npm run build` | `tsc && vite build` — compile + bundle to `dist/` | | `npm run preview` | `vite preview` — preview production build | | `tsc --noEmit` | Type-check only (no test framework) |