- 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
5.7 KiB
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:
- Browser loads
index.htmlwhich importssrc/main.jsas module src/main.jscreates Phaser.Game instance with config- IntroScene is the first scene in the scene list, auto-starts
- Player interaction triggers scene transitions
Between-Scene Transitions:
- Current scene calls
this.scene.start(nextSceneKey, { inventory: this.inventory }) - Phaser stops current scene, starts next scene
- Next scene receives inventory data in
init(data)lifecycle method - Scene reads
data.inventoryand stores it locally - 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, implementscreate()for setup andupdate()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():
this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
Architecture analysis: 2026-02-04