Files
whalehunting/.planning/codebase/ARCHITECTURE.md
Thomas Richter 576799ae0e docs: map existing codebase
- STACK.md - Technologies and dependencies
- ARCHITECTURE.md - System design and patterns
- STRUCTURE.md - Directory layout
- CONVENTIONS.md - Code style and patterns
- TESTING.md - Test structure
- INTEGRATIONS.md - External services
- CONCERNS.md - Technical debt and issues
2026-02-04 23:16:04 +01:00

135 lines
5.7 KiB
Markdown

# Architecture
**Analysis Date:** 2026-02-04
## Pattern Overview
**Overall:** Scene-based state machine with linear progression through game states.
**Key Characteristics:**
- Phaser 3 game framework with arcade physics
- Scene-based architecture where each major game location is a self-contained scene
- Inventory as shared game state passed between scenes via scene data
- Input-driven gameplay with dual control schemes (mouse/keyboard and touch)
- Responsive scaling for mobile and desktop viewports
## Layers
**Presentation Layer (Scenes):**
- Purpose: Render game visuals and handle user interaction
- Location: `src/scenes/`
- Contains: Five scene classes extending Phaser.Scene
- Depends on: Phaser framework, Phaser graphics/text/physics utilities
- Used by: Main application entry point in `src/main.js`
**Game State Layer (Inventory):**
- Purpose: Track player progress across scenes (fuel, whale oil, penguins)
- Location: Passed as data object between scenes via `scene.start(nextScene, { inventory: ... })`
- Contains: Simple object with three numeric properties: `whaleOil`, `fuel`, `penguins`
- Depends on: Nothing
- Used by: All scenes read/modify inventory during gameplay
**Framework Configuration Layer:**
- Purpose: Initialize Phaser game with physics, scaling, scene list
- Location: `src/main.js`
- Contains: Phaser.Game configuration and setup
- Depends on: All scene classes
- Used by: Entry point for application startup
## Data Flow
**Game Startup:**
1. Browser loads `index.html` which imports `src/main.js` as module
2. `src/main.js` creates Phaser.Game instance with config
3. IntroScene is the first scene in the scene list, auto-starts
4. Player interaction triggers scene transitions
**Between-Scene Transitions:**
1. Current scene calls `this.scene.start(nextSceneKey, { inventory: this.inventory })`
2. Phaser stops current scene, starts next scene
3. Next scene receives inventory data in `init(data)` lifecycle method
4. Scene reads `data.inventory` and stores it locally
5. Scene's `create()` method renders UI with current inventory state
**Inventory State:**
- IntroScene initializes: `{ whaleOil: 0, fuel: 100, penguins: 0 }`
- ShipDeckScene receives and passes forward
- MapScene receives, displays, and passes forward
- TransitionScene modifies (deducts fuel if applicable) and passes forward
- HuntingScene receives, displays, modifies (fuel cost, oil gain, penguin discovery) and returns to MapScene
- Penguin discovery (penguins > 0) unlocks penguin cage UI in ShipDeckScene
## Key Abstractions
**Scene Class Pattern:**
- Purpose: Encapsulate game logic and rendering for a specific game state
- Examples: `src/scenes/IntroScene.js`, `src/scenes/ShipDeckScene.js`, `src/scenes/MapScene.js`, `src/scenes/TransitionScene.js`, `src/scenes/HuntingScene.js`
- Pattern: Each scene extends `Phaser.Scene`, implements `create()` for setup and `update()` for per-frame logic
**Interactive UI Elements:**
- Purpose: Handle pointer (mouse/touch) input for clickable objects
- Pattern: Rectangle or circle objects with `.setInteractive()` and `.on('pointerdown')` or `.on('pointerup')` listeners
- Examples in ShipDeckScene: wheel click to open map, barrel zones, penguin cage
- Examples in MapScene: location markers with hover effects and click handlers
- Examples in HuntingScene: crosshair positioning and firing
**Inventory Display Pattern:**
- Purpose: Show player resources in consistent UI
- Pattern: Text panel with semi-transparent background showing formatted resource strings
- Used in: ShipDeckScene, MapScene, HuntingScene
- Format: Multi-line text with labels and current/max values
**Message System Pattern:**
- Purpose: Communicate game state changes and feedback to player
- Pattern: Semi-transparent rectangle with text object, updated via `showMessage(text)` method
- Used in: ShipDeckScene, MapScene, TransitionScene, HuntingScene
## Entry Points
**Application Entry:**
- Location: `index.html`
- Triggers: Page load
- Responsibilities: Load HTML structure, import main.js as module, render into game-container div
**Game Initialization:**
- Location: `src/main.js`
- Triggers: Module import by index.html
- Responsibilities: Configure Phaser game (physics, scaling, resolution), instantiate Phaser.Game, list all scenes
**First Scene:**
- Location: `src/scenes/IntroScene.js`
- Triggers: Phaser auto-starts first scene in config array
- Responsibilities: Display title, draw decorative elements, show SET SAIL button, initialize inventory with defaults
## Error Handling
**Strategy:** Silent failures with user messaging; no error boundaries or try-catch blocks in current codebase.
**Patterns:**
- Fuel depletion check before whale processing (HuntingScene.killWhale): if fuel < 2, whale is discarded without processing
- Whale only spawns if no alive whale exists: `if (this.currentWhale && this.currentWhale.getData('alive')) return;`
- Inventory bounds clamped by Math.min/Math.ceil to prevent negative values
- Crosshair position clamped to screen bounds: `Phaser.Math.Clamp(value, 0, max)`
## Cross-Cutting Concerns
**Logging:** None implemented. Debug would require browser console.
**Validation:** Minimal; mostly relies on initial state setup and boundary clamping.
- Fuel: clamped to [0, 100] via Math.min operations
- Whale oil: clamped to [0, 50] via Math.min operations
- Penguins: clamped to [0, 20] via Math.min operations
- Crosshair X: `Phaser.Math.Clamp(x, 0, 800)`
- Crosshair Y: `Phaser.Math.Clamp(y, 0, 600)`
**Authentication:** Not applicable; single-player game.
**Device Detection:** Mobile detection via user agent regex in HuntingScene.create():
```javascript
this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
```
---
*Architecture analysis: 2026-02-04*