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
This commit is contained in:
134
.planning/codebase/ARCHITECTURE.md
Normal file
134
.planning/codebase/ARCHITECTURE.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# 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*
|
||||
205
.planning/codebase/CONCERNS.md
Normal file
205
.planning/codebase/CONCERNS.md
Normal file
@@ -0,0 +1,205 @@
|
||||
# Codebase Concerns
|
||||
|
||||
**Analysis Date:** 2026-02-04
|
||||
|
||||
## Architecture & State Management
|
||||
|
||||
**Fragile Inventory Passing System:**
|
||||
- Issue: Inventory object is manually passed between scenes via `data` parameter in every scene transition. No centralized state management.
|
||||
- Files: `src/scenes/IntroScene.js`, `src/scenes/ShipDeckScene.js`, `src/scenes/MapScene.js`, `src/scenes/HuntingScene.js`, `src/scenes/TransitionScene.js`
|
||||
- Impact: Each scene maintains its own copy of inventory. A player could lose progress if a scene fails to properly receive or pass inventory data. Adding new inventory items requires changes across all 5 scenes. Risk of inventory corruption during rapid scene transitions.
|
||||
- Fix approach: Create a centralized GameState or InventoryManager singleton that all scenes access. Example structure:
|
||||
```javascript
|
||||
class GameState {
|
||||
static instance = null;
|
||||
static getInstance() {
|
||||
if (!this.instance) this.instance = new GameState();
|
||||
return this.instance;
|
||||
}
|
||||
constructor() {
|
||||
this.inventory = { whaleOil: 0, fuel: 100, penguins: 0 };
|
||||
}
|
||||
}
|
||||
```
|
||||
Then all scenes reference `GameState.getInstance().inventory` instead of managing copies.
|
||||
|
||||
## Testing Coverage Gaps
|
||||
|
||||
**Unit Tests Don't Test Actual Scene Logic:**
|
||||
- What's not tested: Game logic tests in `tests/unit/game-logic.test.js` only test pure functions and simple calculations. They don't test the actual scene behavior, event handlers, or UI state changes.
|
||||
- Files: `tests/unit/game-logic.test.js`, `src/scenes/*.js`
|
||||
- Specific gaps:
|
||||
- No tests for barrel creation/destruction logic in ShipDeckScene
|
||||
- No tests for whale spawning, movement, health tracking
|
||||
- No tests for harpoon firing and collision detection
|
||||
- No tests for scene transition data passing
|
||||
- No tests for inventory display updates
|
||||
- Risk: Bugs in core game mechanics (whale health, fuel consumption, barrel positioning) can't be caught automatically. Changes to scene code could break functionality without detection.
|
||||
- Priority: High - Core game loop (hunting scene) is untested
|
||||
|
||||
**E2E Tests Use Hard-coded Click Positions:**
|
||||
- What's tested: `tests/e2e/game-flow.spec.js` relies on exact pixel coordinates for button clicks. Example: `canvas.click({ position: { x: 400, y: 400 } })`
|
||||
- Problem: Any change to UI layout, button positioning, or screen resolution will break these tests without actually breaking the game
|
||||
- Files: `tests/e2e/game-flow.spec.js` (lines 24, 40, 58, 66, 73, 95, 113-117, 125, 136)
|
||||
- Risk: Tests become maintenance burden; false positives when layout changes
|
||||
- Fix approach: Use Phaser's scene testing utilities or find elements by ID/class instead of pixel positions
|
||||
|
||||
**No Mobile Touch Testing:**
|
||||
- What's tested: E2E includes mobile viewport test but only checks canvas visibility and scaling, not touch interaction functionality
|
||||
- Files: `tests/e2e/game-flow.spec.js` (lines 144-173)
|
||||
- Missing: Tests for touch event handlers, multi-touch scenarios, long-press interactions
|
||||
- Risk: Touch controls may break without detection. Buttons may be non-responsive on actual devices.
|
||||
|
||||
## Performance & Complexity Issues
|
||||
|
||||
**HuntingScene is Large and Complex:**
|
||||
- Issue: Single 637-line file handles whale AI, harpoon physics, collision detection, camera effects, input management, and rendering
|
||||
- Files: `src/scenes/HuntingScene.js`
|
||||
- Specific problem areas:
|
||||
- Lines 316-398: Whale update logic duplicates movement calculation and bounds checking
|
||||
- Lines 434-450: Harpoon update is simple loop-over-array that could become O(n²) with many harpoons
|
||||
- Lines 453-489: Collision detection recalculates screen position every frame for every harpoon
|
||||
- Lines 607-630: Camera sway uses a `time.addEvent()` with permanent loop instead of native `update()` method
|
||||
- Impact: Difficult to debug, test, or modify. Camera sway timer creates memory leak potential (never cancelled). Whale movement becomes laggy with multiple whales.
|
||||
- Fix approach: Extract whale logic to separate `Whale` class, harpoons to `Harpoon` class, collision logic to separate method, use `update()` for camera instead of addEvent()
|
||||
|
||||
**Barrel Recreation is Inefficient:**
|
||||
- Issue: In `ShipDeckScene.js`, `updateInventoryDisplay()` calls `clearBarrels()` then recreates all barrels every time inventory changes (lines 294-297)
|
||||
- Files: `src/scenes/ShipDeckScene.js` (lines 225-297)
|
||||
- Impact: Visual flicker; hundreds of objects created/destroyed repeatedly. On low-end devices, could cause jank.
|
||||
- Fix approach: Reuse barrel objects or update only visual properties (fill color, scale) instead of destroying/recreating
|
||||
|
||||
**Graphics Objects Never Destroyed:**
|
||||
- Issue: Graphics objects created in multiple scenes are never destroyed - only drawn once
|
||||
- Files:
|
||||
- `src/scenes/IntroScene.js` (lines 82-98, 101-116): waves and ship drawn once
|
||||
- `src/scenes/HuntingScene.js` (lines 144-170): crosshair graphics.generateTexture() leaves original graphics object
|
||||
- `src/scenes/TransitionScene.js` (lines 286-301): ocean graphics never destroyed
|
||||
- Impact: Memory leak. Small issue now but accumulates with multiple playthroughs. Old graphics objects persist in memory even after scene changes.
|
||||
- Fix approach: Call `.destroy()` on graphics objects after `.generateTexture()` or scene cleanup
|
||||
|
||||
## Known Behavioral Issues
|
||||
|
||||
**Incomplete Features Referenced in Code:**
|
||||
- Issue: Code contains references to unimplemented scenes
|
||||
- Files: `src/scenes/MapScene.js` (lines 197, 207)
|
||||
- Problem: Pressing buttons to go to Antarctic or Port just returns to MapScene. Code comments say "Will change to 'AntarcticScene' when implemented" and "PortScene when implemented"
|
||||
- Impact: Two major gameplay areas not implemented. Players can't sell whale oil or gather penguins as intended
|
||||
- No fix needed for this sprint; just document that these scenes don't exist
|
||||
|
||||
**Penguin Cage Visibility Logic is Opaque:**
|
||||
- Issue: Penguin cage shown/hidden based on `inventory.penguins > 0` but there's no way in current code to acquire penguins
|
||||
- Files: `src/scenes/ShipDeckScene.js` (lines 83-94, 281-291)
|
||||
- Impact: Code path never executes. Feature is stub/placeholder.
|
||||
- Severity: Low - intentional incomplete feature, but makes code harder to understand
|
||||
|
||||
**Whale Diving Mechanic is Incomplete:**
|
||||
- Issue: Whales go transparent when diving but no actual "invulnerability" is enforced - collision detection still runs (line 461 checks `diving` but collision only prevented if whale is visible or alpha check)
|
||||
- Files: `src/scenes/HuntingScene.js` (lines 304-306, 333-342, 394-410, 460-463)
|
||||
- Risk: Harpoons might hit whale during dive in edge cases
|
||||
- Fix approach: Ensure collision detection returns early if `whale.getData('diving')`
|
||||
|
||||
## Security & Validation Issues
|
||||
|
||||
**No Inventory Bounds Checking:**
|
||||
- Issue: Inventory values can go negative or exceed max without validation
|
||||
- Files: All scene files, particularly `src/scenes/HuntingScene.js` (lines 586, 589)
|
||||
- Example problem: If fuel goes below 0, the display shows negative fuel and barrel count calculation breaks
|
||||
- Current safeguard: Line 547 checks `fuel < 2` before consuming, but nothing prevents other code paths from setting fuel to -5
|
||||
- Fix approach: Create Inventory class with setters that enforce bounds:
|
||||
```javascript
|
||||
class Inventory {
|
||||
setFuel(value) { this.fuel = Math.max(0, Math.min(100, value)); }
|
||||
}
|
||||
```
|
||||
|
||||
**Hard-coded Game Constants Scattered Throughout:**
|
||||
- Issue: Magic numbers for inventory limits, costs, and gameplay values are hard-coded in multiple files
|
||||
- Files:
|
||||
- Fuel max: `src/scenes/ShipDeckScene.js:276`, `src/scenes/MapScene.js:149`, `src/scenes/HuntingScene.js:234`
|
||||
- Oil max: `src/scenes/ShipDeckScene.js:277`, `src/scenes/MapScene.js:150`, `src/scenes/HuntingScene.js:235`
|
||||
- Whale health: `src/scenes/HuntingScene.js:292` (3 hits)
|
||||
- Fuel cost to process: `src/scenes/HuntingScene.js:547, 586` (2 fuel)
|
||||
- Barrel size calculations: `src/scenes/ShipDeckScene.js:105-165` (hardcoded ratios)
|
||||
- Impact: Changing game balance requires finding and updating 10+ locations. High risk of inconsistency.
|
||||
- Fix approach: Create `GameConstants.js` file:
|
||||
```javascript
|
||||
export const GAME_CONSTANTS = {
|
||||
INVENTORY: { MAX_FUEL: 100, MAX_OIL: 50, MAX_PENGUINS: 20 },
|
||||
WHALE: { HEALTH: 3, PROCESS_FUEL_COST: 2 },
|
||||
BARRELS: { FUEL_UNITS_PER_BARREL: 10, OIL_UNITS_PER_BARREL: 10 }
|
||||
};
|
||||
```
|
||||
|
||||
## Code Quality Issues
|
||||
|
||||
**Duplicate Inventory Initialization:**
|
||||
- Issue: Default inventory object defined in 5 different places
|
||||
- Files: `src/scenes/IntroScene.js:120-124`, `src/scenes/ShipDeckScene.js:6-10`, `src/scenes/HuntingScene.js:9`, `src/scenes/MapScene.js:10`, `src/scenes/TransitionScene.js:10`
|
||||
- Risk: If inventory structure changes, must update in all 5 places
|
||||
- Fix: One source of truth (GameState or constants)
|
||||
|
||||
**Inconsistent Data Passing Pattern:**
|
||||
- Issue: Scene init() method doesn't always match how data is received
|
||||
- Files: `src/scenes/TransitionScene.js` (line 10) uses OR operator for defaults but other scenes (ShipDeckScene line 15) use if check
|
||||
- Impact: Minor style inconsistency, slightly reduces readability
|
||||
|
||||
**No Error Handling for Scene Transitions:**
|
||||
- Issue: All `this.scene.start()` calls don't handle failures
|
||||
- Files: All scene files
|
||||
- Risk: If scene key is misspelled or doesn't exist, silently fails
|
||||
- Fix: Add error handling or validation
|
||||
|
||||
## Missing Features Blocking Full Gameplay
|
||||
|
||||
**No Penguin Collection Mechanic:**
|
||||
- What's missing: Antarctic Island scene doesn't exist, so penguins can't be collected
|
||||
- Blocks: Complete game loop where fuel can be managed through penguin burning
|
||||
- Files: Referenced in `src/scenes/MapScene.js:197` but scene doesn't exist
|
||||
|
||||
**No Port/Trading System:**
|
||||
- What's missing: Port scene doesn't exist, can't sell whale oil
|
||||
- Blocks: Economic gameplay loop and victory condition
|
||||
- Files: Referenced in `src/scenes/MapScene.js:207` but scene doesn't exist
|
||||
|
||||
**No Game Over or Win Condition:**
|
||||
- What's missing: No way to fail (fuel runs out) or win (enough whale oil collected)
|
||||
- Impact: Game has no clear objective or end state
|
||||
- Files: N/A - logic doesn't exist anywhere
|
||||
|
||||
**No Persistence:**
|
||||
- What's missing: Game state lost on page reload
|
||||
- Impact: Can't save/load progress
|
||||
- Not critical for prototype but important for release
|
||||
|
||||
## Scaling & Device Issues
|
||||
|
||||
**Hardcoded Screen Dimensions:**
|
||||
- Issue: Game assumes 800x600 canvas with many hardcoded position values
|
||||
- Files: `src/main.js:10-11`, all scene files
|
||||
- Example: `src/scenes/IntroScene.js:21` (text at x:400, y:150), `src/scenes/HuntingScene.js:139-140` (crosshair clamped to 0-800, 0-600)
|
||||
- Risk: Resizing game window breaks positioning. Mobile scaling works via Phaser but coordinates are still hardcoded
|
||||
- Fix: Use relative positioning or percentage-based coordinates
|
||||
|
||||
**Mobile Detection Uses navigator.userAgent:**
|
||||
- Issue: `src/scenes/HuntingScene.js:23` uses userAgent string matching
|
||||
- Risk: Can be spoofed, unreliable on some devices
|
||||
- Better approach: Use Phaser's `this.sys.game.device` API or check touch availability
|
||||
|
||||
## Testing Infrastructure Concerns
|
||||
|
||||
**Vitest Config Exposes Dev Server Publicly:**
|
||||
- Issue: `vitest.config.js:21-22` sets `host: '0.0.0.0'` allowing external connections
|
||||
- Files: `vitest.config.js`
|
||||
- Risk: In production, test server would be exposed to internet
|
||||
- Fix: Only use in development (check NODE_ENV)
|
||||
|
||||
**E2E Tests Have Long Arbitrary Waits:**
|
||||
- Issue: Tests use `waitForTimeout(1000)` and `waitForTimeout(2000)` instead of waiting for elements/state
|
||||
- Files: `tests/e2e/game-flow.spec.js` (almost every test)
|
||||
- Risk: Tests are slow and flaky; may timeout on slow devices but pass on fast ones
|
||||
- Fix: Use `waitForSelector()`, `waitForFunction()`, or Phaser's scene ready events
|
||||
|
||||
---
|
||||
|
||||
*Concerns audit: 2026-02-04*
|
||||
139
.planning/codebase/CONVENTIONS.md
Normal file
139
.planning/codebase/CONVENTIONS.md
Normal file
@@ -0,0 +1,139 @@
|
||||
# Coding Conventions
|
||||
|
||||
**Analysis Date:** 2026-02-04
|
||||
|
||||
## Naming Patterns
|
||||
|
||||
**Files:**
|
||||
- PascalCase for scene classes: `IntroScene.js`, `MapScene.js`, `HuntingScene.js`, `ShipDeckScene.js`, `TransitionScene.js`
|
||||
- kebab-case for test files: `game-logic.test.js`, `game-flow.spec.js`
|
||||
- camelCase for configuration files: `vitest.config.js`, `playwright.config.js`
|
||||
|
||||
**Functions:**
|
||||
- camelCase for all methods: `drawWaves()`, `createLocation()`, `updateInventoryDisplay()`, `spawnWhale()`, `hitWhale()`
|
||||
- Method names are descriptive and indicate action: `create*` for initialization, `update*` for state changes, `draw*` for graphics
|
||||
- Private-like pattern: methods starting with event handlers (`on*` callbacks) or utility methods
|
||||
|
||||
**Variables:**
|
||||
- camelCase for local variables and object properties: `whaleOil`, `currentWhale`, `inventory`, `crosshairX`, `swimSpeedX`
|
||||
- PascalCase for class names: `IntroScene`, `MapScene`, `HuntingScene`
|
||||
- SCREAMING_SNAKE_CASE for constants is not used; magic numbers are inline or stored as camelCase object properties
|
||||
- Abbreviated names in loops: `i`, `x`, `y` for coordinates
|
||||
|
||||
**Types:**
|
||||
- No TypeScript; vanilla JavaScript with JSDoc comments for complex logic
|
||||
- Object literals for data structures (e.g., inventory: `{ whaleOil: 0, fuel: 100, penguins: 0 }`)
|
||||
- No explicit type annotations; types inferred from usage context
|
||||
|
||||
## Code Style
|
||||
|
||||
**Formatting:**
|
||||
- No explicit formatter configured (no .prettierrc or similar found)
|
||||
- 4 spaces for indentation (observed consistently across all files)
|
||||
- Single statements per line; no cramping of expressions
|
||||
- Line length varies; some lines exceed 100 characters
|
||||
|
||||
**Linting:**
|
||||
- No ESLint or similar linting tool configured
|
||||
- No explicit style guide enforced; conventions followed naturally
|
||||
|
||||
## Import Organization
|
||||
|
||||
**Order:**
|
||||
1. Phaser framework imports: `import Phaser from 'phaser'`
|
||||
2. Scene exports: `export default class SceneName extends Phaser.Scene`
|
||||
3. Test framework imports: `import { describe, it, expect } from 'vitest'` and `import { test, expect } from '@playwright/test'`
|
||||
|
||||
**Path Aliases:**
|
||||
- No path aliases configured
|
||||
- Relative imports with `.js` extension explicit: `import IntroScene from './scenes/IntroScene.js'`
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Patterns:**
|
||||
- Defensive checks before operations: `if (this.currentWhale && this.currentWhale.getData('alive'))`
|
||||
- Boundary checking for game state: `if (this.inventory.fuel < 2)` before processing whale
|
||||
- No explicit error throwing; invalid states default to safe fallbacks
|
||||
- Scene transitions use `this.scene.start()` with null coalescing: `this.inventory = data.inventory || { whaleOil: 0, fuel: 100, penguins: 0 }`
|
||||
- Array bounds checking: loop guards with `.length` checks, array splice after removal
|
||||
|
||||
## Logging
|
||||
|
||||
**Framework:** console (implicit; not found in code)
|
||||
|
||||
**Patterns:**
|
||||
- No logging statements observed in source code
|
||||
- Game messaging via `showMessage()` method: text display in game UI
|
||||
- Debug output would likely use console.log if needed (not observed)
|
||||
|
||||
## Comments
|
||||
|
||||
**When to Comment:**
|
||||
- Method-level comments for non-obvious logic: `// Ocean blue background`, `// Draw decorative waves`
|
||||
- Inline comments for complex calculations: `// Can't hit whale while diving`, `// Keep within bounds`
|
||||
- Comment frequency is moderate; most code is self-documenting through naming
|
||||
|
||||
**JSDoc/TSDoc:**
|
||||
- No JSDoc comments found
|
||||
- Vanilla JavaScript with method names that describe intent
|
||||
|
||||
## Function Design
|
||||
|
||||
**Size:**
|
||||
- Methods range from 10-70 lines
|
||||
- Larger methods like `create()` (30+ lines) perform initialization with calls to smaller helper methods
|
||||
- Complex game logic broken into focused methods: `updateWhale()`, `updateHarpoons()`, `checkCollisions()`
|
||||
|
||||
**Parameters:**
|
||||
- Methods accept 0-3 parameters typically
|
||||
- Event handlers use single parameter (e.g., `pointerdown` callbacks)
|
||||
- Data passed through scene initialization: `this.scene.start('NextScene', { inventory: data })`
|
||||
|
||||
**Return Values:**
|
||||
- Mostly void/no return (Phaser scene lifecycle methods)
|
||||
- Some utility functions return boolean: `hasOwnProperty()` checks
|
||||
- Game state propagated through `this` context, not function returns
|
||||
|
||||
## Module Design
|
||||
|
||||
**Exports:**
|
||||
- Each scene file exports default class: `export default class SceneName extends Phaser.Scene`
|
||||
- All scenes imported into `src/main.js` as class references
|
||||
- Scene registration in Phaser config array: `scene: [IntroScene, ShipDeckScene, MapScene, TransitionScene, HuntingScene]`
|
||||
|
||||
**Barrel Files:**
|
||||
- No index.js or barrel files found
|
||||
- Each scene is independent; imports are explicit by filename
|
||||
|
||||
## Data Structures
|
||||
|
||||
**Object Literals:**
|
||||
- Inventory object: `{ whaleOil: 0, fuel: 100, penguins: 0 }`
|
||||
- Configuration objects: Phaser game config in `src/main.js`
|
||||
- Destination mapping in `TransitionScene.js`: `destinations` object with title, description, backgroundColor, visualType
|
||||
|
||||
**Phaser-Specific Patterns:**
|
||||
- `setData(key, value)` / `getData(key)` for storing state on game objects
|
||||
- Container objects with `add([children])` for grouping (e.g., whale body with parts)
|
||||
- Scene transitions with inventory passed as data parameter
|
||||
|
||||
## Common Patterns Observed
|
||||
|
||||
**Scene Lifecycle:**
|
||||
1. `constructor()`: Set scene key
|
||||
2. `init(data)`: Receive data from previous scene
|
||||
3. `create()`: Initialize scene graphics and setup
|
||||
4. `update()`: Game loop updates (only used in HuntingScene)
|
||||
|
||||
**UI Element Creation:**
|
||||
- Rectangle/circle/text created with `.add.rectangle()`, `.add.circle()`, `.add.text()`
|
||||
- Interactive zones created with `setInteractive()` and `.on('pointerX', callback)`
|
||||
- Hover/click feedback with `setScale()`, `setFillStyle()` updates
|
||||
|
||||
**Animation:**
|
||||
- Phaser tweens for smooth transitions: `this.tweens.add({ targets: obj, property: value, duration: ms })`
|
||||
- Sine/cosine wave patterns for natural movement: `Math.sin()`, `Math.cos()` for bobbing/sway
|
||||
|
||||
---
|
||||
|
||||
*Convention analysis: 2026-02-04*
|
||||
161
.planning/codebase/INTEGRATIONS.md
Normal file
161
.planning/codebase/INTEGRATIONS.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# External Integrations
|
||||
|
||||
**Analysis Date:** 2026-02-04
|
||||
|
||||
## APIs & External Services
|
||||
|
||||
**Not applicable** - No external APIs integrated. Game is fully self-contained.
|
||||
|
||||
## Data Storage
|
||||
|
||||
**Databases:**
|
||||
- Not applicable - No database required or used
|
||||
- Game state is managed in-memory during gameplay
|
||||
- State location: Passed via scene parameters in `src/main.js`
|
||||
|
||||
**File Storage:**
|
||||
- Local filesystem only - Assets would be bundled with application
|
||||
- No remote file storage configured
|
||||
- Asset directories (planned): `assets/sprites/`, `assets/backgrounds/`
|
||||
|
||||
**Caching:**
|
||||
- Browser caching only - Static assets cached by nginx (1 year TTL)
|
||||
- No server-side caching layer
|
||||
- Vite dev server handles hot module replacement during development
|
||||
|
||||
**State Management:**
|
||||
- Phaser Scene-based state management
|
||||
- Game state example from `src/scenes/IntroScene.js`:
|
||||
```javascript
|
||||
const inventory = {
|
||||
whaleOil: 0,
|
||||
fuel: 100,
|
||||
penguins: 0
|
||||
};
|
||||
this.scene.start('ShipDeckScene', { inventory: inventory });
|
||||
```
|
||||
- State passed between scenes as parameters
|
||||
- No persistence layer (state resets on page refresh)
|
||||
|
||||
## Authentication & Identity
|
||||
|
||||
**Not applicable** - No user authentication
|
||||
- Game is anonymous and stateless
|
||||
- No user accounts or login required
|
||||
- All players access the same game instance
|
||||
|
||||
## Monitoring & Observability
|
||||
|
||||
**Error Tracking:**
|
||||
- Not integrated
|
||||
- Console errors only (browser developer tools)
|
||||
- No remote error reporting configured
|
||||
|
||||
**Logs:**
|
||||
- Browser console logging only
|
||||
- Nginx access logs available in container at `/var/log/nginx/`
|
||||
- Docker container logs accessible via: `docker-compose logs -f`
|
||||
- Vite dev server logs to terminal
|
||||
|
||||
**Health Checks:**
|
||||
- Docker health check: `wget --quiet --tries=1 --spider http://127.0.0.1/`
|
||||
- Interval: 30 seconds
|
||||
- Timeout: 3 seconds
|
||||
- Retries: 3 before marking unhealthy
|
||||
- Start period: 5 seconds
|
||||
|
||||
## CI/CD & Deployment
|
||||
|
||||
**Hosting:**
|
||||
- Docker container on `node03.tricnet.de`
|
||||
- Served via Nginx (Alpine Linux)
|
||||
- Manual deployment via `deploy.sh`
|
||||
|
||||
**CI Pipeline:**
|
||||
- Not detected - No automated CI/CD system configured
|
||||
- Deployment process: Manual `./deploy.sh`
|
||||
- Uses rsync to sync files to node03
|
||||
- SSH to rebuild Docker container
|
||||
- Rebuilds docker-compose services
|
||||
|
||||
**Deployment Method:**
|
||||
- Deployment file: `deploy.sh`
|
||||
- Sync target: `tho@node03.tricnet.de:/home/tho/whalehunting/`
|
||||
- Excludes: `node_modules/`, `dist/`, `.git/`, `.DS_Store`
|
||||
- Build command: `docker-compose down && docker-compose up -d --build`
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
**Required env vars:**
|
||||
- None - Game requires no environment variables at runtime
|
||||
- Docker container runs with default environment
|
||||
|
||||
**Secrets location:**
|
||||
- Not applicable - No secrets, API keys, or credentials required
|
||||
- SSH key required for deployment (stored on developer machine)
|
||||
|
||||
**Development Environment:**
|
||||
- Game automatically runs on `http://localhost:5173` (Vite default)
|
||||
- Playwright configured to use `http://localhost:5173` as baseURL
|
||||
- No .env file needed for development
|
||||
|
||||
## Webhooks & Callbacks
|
||||
|
||||
**Incoming:**
|
||||
- Not applicable - No webhooks received
|
||||
|
||||
**Outgoing:**
|
||||
- Not applicable - No webhooks sent
|
||||
- Game makes no HTTP requests
|
||||
|
||||
## Network Requirements
|
||||
|
||||
**Development:**
|
||||
- Must be able to access `localhost:5173` (Vite dev server)
|
||||
- Must be able to access `localhost:5173` for Playwright E2E tests
|
||||
- Vitest UI server binds to `0.0.0.0:51204` (all interfaces)
|
||||
|
||||
**Production:**
|
||||
- Must be accessible on port 8880 (external Docker port)
|
||||
- Health checks require outbound HTTP to `http://127.0.0.1/` (internal to container)
|
||||
- No outbound internet access required from game runtime
|
||||
|
||||
## Data Flow
|
||||
|
||||
**Client-Side Only:**
|
||||
- All game logic runs in browser
|
||||
- No data sent to any backend or external service
|
||||
- Game state never persists (no save/load feature implemented)
|
||||
- Player actions: Click/tap interactions → Phaser input handlers → Scene state changes
|
||||
|
||||
**Example State Flow** (from `src/scenes/IntroScene.js`):
|
||||
1. User clicks "SET SAIL" button
|
||||
2. Button click handler creates inventory object
|
||||
3. Scene transitions: `this.scene.start('ShipDeckScene', { inventory })`
|
||||
4. ShipDeckScene receives inventory via init parameter
|
||||
5. Game continues with same inventory state
|
||||
|
||||
## Testing Infrastructure
|
||||
|
||||
**Unit Tests:**
|
||||
- Framework: Vitest 4.0.16
|
||||
- Environment: jsdom
|
||||
- Test directory: `tests/unit/`
|
||||
- Run: `npm run test` or `npm run test:ui` (with visual UI)
|
||||
- Coverage: `npm run test:coverage`
|
||||
|
||||
**E2E Tests:**
|
||||
- Framework: Playwright 1.57.0
|
||||
- Test directory: `tests/e2e/`
|
||||
- Browsers tested: Chromium, iPhone 12 (mobile)
|
||||
- Run: `npm run test:e2e` or `npm run test:e2e:ui`
|
||||
- Screenshots: Captured on failure only
|
||||
- Traces: Captured on first retry
|
||||
|
||||
**Test Configuration Files:**
|
||||
- `vitest.config.js` - Unit test setup
|
||||
- `playwright.config.js` - E2E test setup
|
||||
|
||||
---
|
||||
|
||||
*Integration audit: 2026-02-04*
|
||||
135
.planning/codebase/STACK.md
Normal file
135
.planning/codebase/STACK.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# Technology Stack
|
||||
|
||||
**Analysis Date:** 2026-02-04
|
||||
|
||||
## Languages
|
||||
|
||||
**Primary:**
|
||||
- JavaScript (ES6 modules) - All source code and configuration
|
||||
|
||||
## Runtime
|
||||
|
||||
**Environment:**
|
||||
- Node.js 20 (Alpine) - Development and build time
|
||||
- Browser (Chromium, Safari) - Runtime environment for game
|
||||
|
||||
**Package Manager:**
|
||||
- npm - Dependency management
|
||||
- Lockfile: `package-lock.json` (present)
|
||||
|
||||
## Frameworks
|
||||
|
||||
**Core:**
|
||||
- Phaser 3.80.1 - 2D game framework and physics engine
|
||||
- Used in: `src/main.js` and all scene files
|
||||
- Provides game loop, rendering, input handling, physics (arcade)
|
||||
|
||||
**Build/Dev:**
|
||||
- Vite 5.0.0 - Build tool and development server
|
||||
- Config: Not detected (uses Vite defaults)
|
||||
- Dev server: Port 5173 (standard)
|
||||
- Output directory: `dist/`
|
||||
|
||||
**Testing:**
|
||||
- Vitest 4.0.16 - Unit test framework
|
||||
- Config: `vitest.config.js`
|
||||
- Environment: jsdom (browser-like environment for testing)
|
||||
- UI: @vitest/ui 4.0.16 for visual test runner
|
||||
|
||||
- Playwright 1.57.0 - E2E testing framework
|
||||
- Config: `playwright.config.js`
|
||||
- Test directory: `tests/e2e/`
|
||||
- Browsers: Chromium, iPhone 12 (mobile simulation)
|
||||
- Screenshots: Captured on test failure
|
||||
|
||||
## Key Dependencies
|
||||
|
||||
**Critical:**
|
||||
- phaser (3.80.1) - Complete game development framework
|
||||
- Why it matters: Core engine for all game logic, rendering, and physics
|
||||
|
||||
**Development Only:**
|
||||
- @playwright/test (1.57.0) - E2E test runner with browser automation
|
||||
- @vitest/ui (4.0.16) - Visual UI for viewing test results
|
||||
- jsdom (27.3.0) - DOM implementation for testing in Node.js environment
|
||||
- vite (5.0.0) - Lightning-fast build tool and dev server
|
||||
- vitest (4.0.16) - Unit test framework built on Vite
|
||||
|
||||
## Configuration
|
||||
|
||||
**Environment:**
|
||||
- No environment variables required for runtime
|
||||
- Game runs entirely in browser with no backend dependencies
|
||||
|
||||
**Build:**
|
||||
- `vite.config.js` - Not present (uses defaults)
|
||||
- `playwright.config.js` - E2E test configuration
|
||||
- `vitest.config.js` - Unit test configuration with jsdom environment
|
||||
- Vite configured for module type: module (ES6)
|
||||
|
||||
## Platform Requirements
|
||||
|
||||
**Development:**
|
||||
- Node.js 20+
|
||||
- npm 8+ (included with Node 20)
|
||||
- Git (for version control)
|
||||
- Linux/macOS/Windows (any platform with Node.js)
|
||||
|
||||
**Production:**
|
||||
- Nginx web server (Alpine Linux image)
|
||||
- Docker (for containerized deployment)
|
||||
- Static file hosting (game is fully client-side)
|
||||
- No database required
|
||||
- No backend API required
|
||||
|
||||
## Build & Deployment
|
||||
|
||||
**Development:**
|
||||
```bash
|
||||
npm install # Install dependencies
|
||||
npm run dev # Start dev server on port 5173
|
||||
npm run test # Run unit tests
|
||||
npm run test:ui # Run tests with visual UI
|
||||
npm run test:e2e # Run Playwright E2E tests
|
||||
```
|
||||
|
||||
**Production:**
|
||||
```bash
|
||||
npm run build # Build to dist/ directory
|
||||
docker build -t whalehunting-game . # Build Docker image
|
||||
docker-compose up -d # Deploy with Docker Compose
|
||||
```
|
||||
|
||||
**Docker Stack:**
|
||||
- Base image: `nginx:alpine` (production serving)
|
||||
- Build stage: `node:20-alpine` (build application)
|
||||
- Port: 8880 (external), 80 (container)
|
||||
- Health checks: wget ping every 30s
|
||||
- Network: Docker bridge network `whalehunting-network`
|
||||
|
||||
**Deployment Target:**
|
||||
- Docker container on node03.tricnet.de
|
||||
- Deployed via rsync + SSH (see `deploy.sh`)
|
||||
- Game served at: `http://node03.tricnet.de:8880`
|
||||
|
||||
## Performance Optimizations
|
||||
|
||||
**Build:**
|
||||
- Vite provides fast module bundling
|
||||
- Production build is minified and optimized
|
||||
|
||||
**Runtime:**
|
||||
- Phaser uses WebGL/Canvas rendering (automatic selection via Phaser.AUTO)
|
||||
- Game configured with fixed dimensions (800x600) with responsive scaling
|
||||
- Responsive scaling mode: FIT with auto-centering
|
||||
- Min viewport: 320x240 (mobile support)
|
||||
- Arcade physics engine configured with no gravity (2D top-down view)
|
||||
|
||||
**Serving:**
|
||||
- Nginx configured with gzip compression
|
||||
- Static asset caching: 1 year (as noted in README)
|
||||
- Health checks ensure container availability
|
||||
|
||||
---
|
||||
|
||||
*Stack analysis: 2026-02-04*
|
||||
177
.planning/codebase/STRUCTURE.md
Normal file
177
.planning/codebase/STRUCTURE.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# Codebase Structure
|
||||
|
||||
**Analysis Date:** 2026-02-04
|
||||
|
||||
## Directory Layout
|
||||
|
||||
```
|
||||
whalehunting/
|
||||
├── src/ # Game source code
|
||||
│ ├── main.js # Phaser game initialization and configuration
|
||||
│ └── scenes/ # Game scene implementations
|
||||
│ ├── IntroScene.js
|
||||
│ ├── ShipDeckScene.js
|
||||
│ ├── MapScene.js
|
||||
│ ├── TransitionScene.js
|
||||
│ └── HuntingScene.js
|
||||
├── tests/ # Test suites
|
||||
│ ├── unit/ # Unit tests (Vitest)
|
||||
│ │ └── game-logic.test.js
|
||||
│ └── e2e/ # End-to-end tests (Playwright)
|
||||
│ └── game-flow.spec.js
|
||||
├── .planning/ # GSD planning documents
|
||||
│ └── codebase/ # Architecture analysis
|
||||
├── index.html # HTML entry point
|
||||
├── package.json # Dependencies and scripts
|
||||
├── vitest.config.js # Unit test configuration
|
||||
├── playwright.config.js # E2E test configuration
|
||||
├── nginx.conf # Web server config for deployment
|
||||
├── Dockerfile # Container image definition
|
||||
├── docker-compose.yml # Multi-container orchestration
|
||||
└── deploy.sh # Automated deployment script
|
||||
```
|
||||
|
||||
## Directory Purposes
|
||||
|
||||
**src/:**
|
||||
- Purpose: All game source code
|
||||
- Contains: Main game initialization and scene implementations
|
||||
- Key files: `main.js` is the entry point that configures Phaser
|
||||
|
||||
**src/scenes/:**
|
||||
- Purpose: Game scene implementations
|
||||
- Contains: Five scene classes, one per major game location/mode
|
||||
- Key files: IntroScene starts the game, HuntingScene has most complex logic
|
||||
|
||||
**tests/:**
|
||||
- Purpose: All test code separated from source
|
||||
- Contains: Unit tests and E2E tests in separate subdirectories
|
||||
- Key files: `game-logic.test.js` for game mechanics, `game-flow.spec.js` for user flows
|
||||
|
||||
**tests/unit/:**
|
||||
- Purpose: Logic testing without Phaser
|
||||
- Contains: Vitest tests for inventory calculations, fuel costs, barrel logic
|
||||
- Key files: `game-logic.test.js`
|
||||
|
||||
**tests/e2e/:**
|
||||
- Purpose: Full application flow testing
|
||||
- Contains: Playwright tests simulating user interactions on actual game canvas
|
||||
- Key files: `game-flow.spec.js`
|
||||
|
||||
**.planning/codebase/:**
|
||||
- Purpose: Analysis documents for code navigation
|
||||
- Contains: ARCHITECTURE.md, STRUCTURE.md, CONVENTIONS.md, TESTING.md, CONCERNS.md
|
||||
- Generated by: GSD mapping processes
|
||||
|
||||
## Key File Locations
|
||||
|
||||
**Entry Points:**
|
||||
- `index.html`: Browser loads this, contains game-container div and script import
|
||||
- `src/main.js`: Phaser game configuration and scene list initialization
|
||||
|
||||
**Configuration:**
|
||||
- `vitest.config.js`: Unit test runner with jsdom environment, port 51204 for UI server
|
||||
- `playwright.config.js`: E2E test runner with Chromium and iPhone 12 profiles
|
||||
- `package.json`: Dependencies (Phaser 3.80.1, Vite, Vitest, Playwright)
|
||||
- `nginx.conf`: Web server routing (not actively used in dev)
|
||||
- `docker-compose.yml`: Local dev: port 5173 for Vite server
|
||||
- `Dockerfile`: Production build with multi-stage for size optimization
|
||||
|
||||
**Core Logic:**
|
||||
- `src/scenes/IntroScene.js`: Game entry, starts with fuel=100, oil=0, penguins=0
|
||||
- `src/scenes/ShipDeckScene.js`: Inventory display, barrel visualization, penguin cage reveal
|
||||
- `src/scenes/MapScene.js`: Location selection (Hunting Grounds, Antarctic, Port)
|
||||
- `src/scenes/TransitionScene.js`: Atmospheric journey scenes, destination-specific visuals
|
||||
- `src/scenes/HuntingScene.js`: Core gameplay - whale spawning, harpoon mechanics, fuel consumption
|
||||
|
||||
**Testing:**
|
||||
- `tests/unit/game-logic.test.js`: Barrel calculations, inventory limits, fuel costs, whale health, crosshair clamping
|
||||
- `tests/e2e/game-flow.spec.js`: Full flows (intro→ship→map→hunting), mobile viewport, desktop scaling
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
**Files:**
|
||||
- PascalCase + Scene suffix: `IntroScene.js`, `ShipDeckScene.js`
|
||||
- camelCase for non-scene modules: Would apply if utilities existed
|
||||
- Test files: Matched source with `.test.js` or `.spec.js` suffix
|
||||
- Config files: kebab-case: `playwright.config.js`, `vitest.config.js`
|
||||
|
||||
**Directories:**
|
||||
- lowercase plural: `src/scenes/`, `tests/unit/`, `tests/e2e/`
|
||||
- camelCase for compound: Not currently used
|
||||
|
||||
**Class Names:**
|
||||
- PascalCase: `IntroScene`, `ShipDeckScene`, `MapScene`, `TransitionScene`, `HuntingScene`
|
||||
- Extend `Phaser.Scene` directly
|
||||
|
||||
**Methods:**
|
||||
- camelCase: `create()`, `update()`, `init()`, `createDeck()`, `createBarrels()`, `updateInventoryDisplay()`
|
||||
- Lifecycle methods (create, update) are Phaser conventions
|
||||
- Helper methods prefix with action: `create*()`, `update*()`, `show*()`, `draw*()`
|
||||
|
||||
**Variables:**
|
||||
- camelCase for instance: `this.inventory`, `this.currentWhale`, `this.harpoons`
|
||||
- camelCase for local: `barrelCount`, `swimSpeedX`, `healthPercent`
|
||||
- UPPERCASE for constants: `FUEL_COST = 2`, `MAX_HEALTH = 3`
|
||||
|
||||
**Game State Objects:**
|
||||
- Inventory structure: `{ whaleOil: number, fuel: number, penguins: number }`
|
||||
- Whale data stored via `setData()`: `health`, `alive`, `diving`, `swimSpeedX`, `swimSpeedY`, `direction`
|
||||
|
||||
## Where to Add New Code
|
||||
|
||||
**New Scene/Location:**
|
||||
1. Create `src/scenes/NewScene.js` extending Phaser.Scene
|
||||
2. Implement `init(data)` to receive inventory
|
||||
3. Implement `create()` for rendering
|
||||
4. Implement `update()` if frame-by-frame logic needed
|
||||
5. Call `this.scene.start('MapScene', { inventory: this.inventory })` to transition
|
||||
6. Add to scene list in `src/main.js` config array
|
||||
7. Add location marker in `MapScene.js` that routes to new scene
|
||||
|
||||
**New Game Mechanic:**
|
||||
- Hunting scene has most game logic: HuntingScene.js handles whale spawning, harpoon firing, collision detection, health tracking
|
||||
- Add mechanics as methods in relevant scene class
|
||||
- Store persistent state in `this.inventory` object
|
||||
- Display UI changes via `updateInventoryDisplay()` pattern
|
||||
|
||||
**Utilities (if needed):**
|
||||
- Create `src/utils/` directory for shared helpers
|
||||
- Example: `src/utils/inventory.js` for max capacity functions
|
||||
- Example: `src/utils/collision.js` for distance calculations
|
||||
- Import in scenes: `import { calculateBarrels } from '../utils/inventory.js';`
|
||||
|
||||
**New UI Component Pattern:**
|
||||
- Create methods in scene: `createInventoryDisplay()`, `createMessageBox()`
|
||||
- Return reference to element for later updates
|
||||
- Update via methods: `updateInventoryDisplay()`, `showMessage(text)`
|
||||
- Use semi-transparent rectangles for panels with `.setFillStyle(0x000000, 0.7)`
|
||||
|
||||
## Special Directories
|
||||
|
||||
**node_modules/:**
|
||||
- Purpose: Installed dependencies
|
||||
- Generated: Yes (via npm install)
|
||||
- Committed: No (.gitignore)
|
||||
|
||||
**dist/:**
|
||||
- Purpose: Vite production build output
|
||||
- Generated: Yes (via npm run build)
|
||||
- Committed: No (.gitignore)
|
||||
- Files: Optimized JS/CSS for deployment
|
||||
|
||||
**.git/:**
|
||||
- Purpose: Git repository metadata
|
||||
- Generated: Yes (git init)
|
||||
- Committed: Meta repository
|
||||
- Notable: Recent commits track feature additions and testing infrastructure
|
||||
|
||||
**.planning/:**
|
||||
- Purpose: GSD orchestration files and analysis documents
|
||||
- Generated: Yes (via /gsd commands)
|
||||
- Committed: Yes (tracked in git)
|
||||
- Structure: `codebase/` contains ARCHITECTURE.md, STRUCTURE.md, etc.
|
||||
|
||||
---
|
||||
|
||||
*Structure analysis: 2026-02-04*
|
||||
314
.planning/codebase/TESTING.md
Normal file
314
.planning/codebase/TESTING.md
Normal file
@@ -0,0 +1,314 @@
|
||||
# Testing Patterns
|
||||
|
||||
**Analysis Date:** 2026-02-04
|
||||
|
||||
## Test Framework
|
||||
|
||||
**Runner:**
|
||||
- Vitest 4.0.16 - Unit test runner
|
||||
- Playwright 1.57.0 - E2E test runner
|
||||
|
||||
**Config Files:**
|
||||
- Unit tests: `vitest.config.js`
|
||||
- E2E tests: `playwright.config.js`
|
||||
|
||||
**Run Commands:**
|
||||
```bash
|
||||
npm run test # Run unit tests (Vitest)
|
||||
npm run test:ui # Run tests with Vitest UI
|
||||
npm run test:coverage # Run tests with coverage report
|
||||
npm run test:e2e # Run E2E tests (Playwright)
|
||||
npm run test:e2e:ui # Run E2E tests with Playwright UI
|
||||
npm run test:all # Run all tests (unit + E2E)
|
||||
```
|
||||
|
||||
## Test File Organization
|
||||
|
||||
**Location:**
|
||||
- Unit tests: `tests/unit/` directory
|
||||
- E2E tests: `tests/e2e/` directory
|
||||
- Separate from source code (not co-located)
|
||||
|
||||
**Naming:**
|
||||
- Unit tests: `.test.js` suffix: `game-logic.test.js`
|
||||
- E2E tests: `.spec.js` suffix: `game-flow.spec.js`
|
||||
|
||||
**Structure:**
|
||||
```
|
||||
tests/
|
||||
├── unit/
|
||||
│ └── game-logic.test.js
|
||||
└── e2e/
|
||||
└── game-flow.spec.js
|
||||
```
|
||||
|
||||
## Unit Test Structure
|
||||
|
||||
**Framework:** Vitest with globals enabled
|
||||
|
||||
**Pattern from `tests/unit/game-logic.test.js`:**
|
||||
|
||||
```javascript
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
describe('Game Logic - Inventory Management', () => {
|
||||
describe('Barrel Calculations', () => {
|
||||
it('should calculate correct fuel barrel count', () => {
|
||||
const fuel = 100;
|
||||
const barrelCount = Math.ceil(fuel / 10);
|
||||
expect(barrelCount).toBe(10);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Test Organization:**
|
||||
- Top-level `describe()` blocks group by feature/system (e.g., "Game Logic - Inventory Management")
|
||||
- Nested `describe()` blocks organize related tests (e.g., "Barrel Calculations")
|
||||
- Individual `it()` blocks test single logical assertions
|
||||
- Test names are descriptive: "should [expected behavior]"
|
||||
|
||||
## E2E Test Structure
|
||||
|
||||
**Framework:** Playwright with page object patterns
|
||||
|
||||
**Pattern from `tests/e2e/game-flow.spec.js`:**
|
||||
|
||||
```javascript
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Whale Hunting Game - Main Flow', () => {
|
||||
test('should load the intro scene', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
const canvas = page.locator('canvas');
|
||||
await expect(canvas).toBeVisible();
|
||||
|
||||
await expect(page).toHaveTitle(/Whale Hunting/);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Test Organization:**
|
||||
- `test.describe()` blocks group related scenarios
|
||||
- Individual `test()` blocks test user flows
|
||||
- Setup patterns: `test.beforeEach()` for common navigation
|
||||
- Viewport configuration: `test.use()` for device-specific testing
|
||||
- Async/await pattern for all page interactions
|
||||
|
||||
## Mocking
|
||||
|
||||
**Framework:** None configured or used
|
||||
|
||||
**Patterns:**
|
||||
- No mocks found in unit tests
|
||||
- Tests verify pure calculation logic (Math.ceil, Math.min)
|
||||
- E2E tests work with actual running game instance
|
||||
|
||||
**What to Mock:**
|
||||
- Not applicable; unit tests use pure functions without external dependencies
|
||||
- Phaser framework is not mocked (games tested in browser context)
|
||||
|
||||
**What NOT to Mock:**
|
||||
- Scene transitions (tested via canvas visibility)
|
||||
- Phaser game instances (tested via E2E)
|
||||
|
||||
## Fixtures and Test Data
|
||||
|
||||
**Test Data:**
|
||||
```javascript
|
||||
// Direct inline values
|
||||
it('should calculate correct fuel barrel count', () => {
|
||||
const fuel = 100;
|
||||
const barrelCount = Math.ceil(fuel / 10);
|
||||
expect(barrelCount).toBe(10);
|
||||
});
|
||||
|
||||
// Inventory object template
|
||||
const inventory = { whaleOil: 0, fuel: 100, penguins: 0 };
|
||||
```
|
||||
|
||||
**Location:**
|
||||
- No shared fixture files; test data created inline within test functions
|
||||
- Inventory object structure repeated across multiple tests
|
||||
|
||||
## Coverage
|
||||
|
||||
**Configuration:**
|
||||
```javascript
|
||||
// vitest.config.js
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['text', 'html', 'lcov'],
|
||||
exclude: [
|
||||
'node_modules/',
|
||||
'dist/',
|
||||
'*.config.js',
|
||||
'tests/e2e/**'
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**View Coverage:**
|
||||
```bash
|
||||
npm run test:coverage
|
||||
# Creates HTML report in coverage/
|
||||
# View: coverage/index.html
|
||||
```
|
||||
|
||||
**Excluded from Coverage:**
|
||||
- E2E tests (`tests/e2e/**`)
|
||||
- Config files (`*.config.js`)
|
||||
- Dependencies and build output
|
||||
|
||||
## Test Types
|
||||
|
||||
**Unit Tests:**
|
||||
- Scope: Pure calculation logic (barrel counts, fuel consumption, bounds checking)
|
||||
- Approach: Direct function calls with known inputs
|
||||
- No DOM interaction; test game logic in isolation
|
||||
- Coverage: `tests/unit/game-logic.test.js`
|
||||
- Examples:
|
||||
- Barrel calculation: `Math.ceil(fuel / 10)`
|
||||
- Inventory limits: `Math.min(currentFuel + 10, maxFuel)`
|
||||
- Whale health: Health deduction logic
|
||||
- Mobile detection: User agent regex testing
|
||||
- Crosshair bounds: Clamp function testing
|
||||
|
||||
**Integration Tests:**
|
||||
- Not explicitly used
|
||||
- Closest: E2E tests that verify scene transitions
|
||||
|
||||
**E2E Tests:**
|
||||
- Scope: Complete user workflows (game startup to hunting)
|
||||
- Approach: Browser automation via Playwright
|
||||
- Tests: Canvas visibility, scene transitions, button clicks, viewport scaling
|
||||
- Coverage: `tests/e2e/game-flow.spec.js`
|
||||
- Desktop & mobile scenarios tested with viewport configuration
|
||||
- Examples:
|
||||
- "should load the intro scene"
|
||||
- "should navigate to hunting grounds"
|
||||
- "should work on mobile viewport"
|
||||
- "should scale properly on desktop"
|
||||
|
||||
## Common Patterns
|
||||
|
||||
**Async Testing (E2E):**
|
||||
```javascript
|
||||
test('should start game from intro scene', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
const canvas = page.locator('canvas');
|
||||
await canvas.click({ position: { x: 400, y: 400 } });
|
||||
|
||||
await page.waitForTimeout(1000);
|
||||
await expect(canvas).toBeVisible();
|
||||
});
|
||||
```
|
||||
|
||||
- `async ({ page })` destructures Playwright fixture
|
||||
- `await` on page navigation and interactions
|
||||
- `page.waitForTimeout()` for animation/transition delays
|
||||
- `page.locator()` for element selection
|
||||
|
||||
**Error Testing (Unit):**
|
||||
```javascript
|
||||
it('should not process whale without enough fuel', () => {
|
||||
let fuel = 1;
|
||||
const requiredFuel = 2;
|
||||
const canProcess = fuel >= requiredFuel;
|
||||
expect(canProcess).toBe(false);
|
||||
});
|
||||
```
|
||||
|
||||
- Boolean logic to test conditions
|
||||
- No exception throwing; test state validation
|
||||
|
||||
**Mobile Testing (E2E):**
|
||||
```javascript
|
||||
test.describe('Mobile Compatibility', () => {
|
||||
test.use({
|
||||
viewport: { width: 375, height: 667 },
|
||||
isMobile: true,
|
||||
});
|
||||
|
||||
test('should work on mobile viewport', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
const canvas = page.locator('canvas');
|
||||
await expect(canvas).toBeVisible();
|
||||
|
||||
const canvasBox = await canvas.boundingBox();
|
||||
expect(canvasBox?.width).toBeLessThanOrEqual(375);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
- `test.use()` sets viewport and device context
|
||||
- Tap interactions: `canvas.tap()`
|
||||
- BoundingBox assertions: verify canvas scaling
|
||||
|
||||
## Test Isolation
|
||||
|
||||
**Setup:**
|
||||
- E2E tests use `test.beforeEach()` for repeated navigation setup
|
||||
- No shared state between tests
|
||||
- Each test starts fresh from home page
|
||||
|
||||
**Teardown:**
|
||||
- Playwright automatically closes browser context between tests
|
||||
- No explicit cleanup required
|
||||
|
||||
## Configuration Details
|
||||
|
||||
**Vitest (`vitest.config.js`):**
|
||||
- Environment: jsdom (browser-like DOM)
|
||||
- Globals enabled: `describe`, `it`, `expect` available without imports
|
||||
- Include pattern: `tests/unit/**/*.test.js`
|
||||
- Server runs on port 51204 for Vitest UI
|
||||
|
||||
**Playwright (`playwright.config.js`):**
|
||||
- Projects: Chromium and mobile (iPhone 12)
|
||||
- Base URL: `http://localhost:5173` (dev server)
|
||||
- Test directory: `tests/e2e/`
|
||||
- Retries: 2 in CI, 0 locally
|
||||
- Screenshots: Only on failure
|
||||
- Trace: On first retry
|
||||
- Server: Runs `npm run dev` before tests
|
||||
|
||||
## Test Execution Flow
|
||||
|
||||
1. **Unit Tests (Vitest):**
|
||||
- Runs isolated game logic tests
|
||||
- Uses jsdom environment
|
||||
- No Phaser instance needed
|
||||
- Fast execution
|
||||
|
||||
2. **E2E Tests (Playwright):**
|
||||
- Starts dev server via `npm run dev`
|
||||
- Launches Chromium and mobile browsers
|
||||
- Navigates to `http://localhost:5173`
|
||||
- Performs user interactions
|
||||
- Verifies game state via canvas visibility
|
||||
- Slower execution but tests full stack
|
||||
|
||||
## Coverage Gaps
|
||||
|
||||
**Not Tested (Unit):**
|
||||
- Scene rendering and graphics creation
|
||||
- Phaser animation timing and tweens
|
||||
- Player input handling (mouse/touch)
|
||||
- Collision detection logic
|
||||
|
||||
**Not Tested (E2E):**
|
||||
- Detailed game mechanics (whale health, harpoon trajectory)
|
||||
- Inventory state persistence
|
||||
- Exact positioning of game elements
|
||||
- Performance under load
|
||||
|
||||
---
|
||||
|
||||
*Testing analysis: 2026-02-04*
|
||||
Reference in New Issue
Block a user