overrun/AGENTS.md

6.0 KiB

AGENTS.md - Agent Coding Guidelines

This file provides guidance for AI agents working on this codebase.

Project Overview

This is a Phaser 3 HTML game (Smash TV-style top-down arena shooter) built with vanilla JavaScript and ES6 modules. No build tools or bundlers are used — the game runs directly in the browser.

Running the Game

Since there is no bundler, serve the files with a local HTTP server (ES6 modules require HTTP, not file://):

npx serve .
# or
python3 -m http.server 8080
# or
./start_web.sh

Then open http://localhost:8080 (or whatever port) in a browser.

Build/Lint/Test Commands

This project has no build tools, no linting, and no test framework. It uses vanilla JavaScript with ES6 modules.

  • Run game: npx serve . or python3 -m http.server 8080 or ./start_web.sh
  • No lint command: Manually review code for style consistency
  • No test command: No tests exist; manually verify functionality in browser

Code Style Guidelines

General Principles

  • Keep code modular — each major concern in its own file/class
  • Use ES6 import/export for all inter-module dependencies
  • No TypeScript — plain JavaScript only
  • No bundlers (Webpack, Vite, etc.)

File Organization

js/
├── main.js              # Entry point, game config
├── scenes/              # Phaser scenes (IntroScene, GameScene, GameOverScene)
├── entities/            # Game entities (Player, enemies)
│   └── enemies/         # Enemy classes (BaseEnemy, ChaseEnemy, etc.)
├── systems/             # Game systems (WaveManager, SkillTree, XPSystem)
├── ui/                  # UI components (HUD, SkillTreeUI, Reticle)
└── data/                # JSON data files (zones.json, skillTree.json)

Naming Conventions

  • Classes: PascalCase (e.g., Player, WaveManager, GameScene)
  • Files: PascalCase with .js extension (e.g., Player.js, WaveManager.js)
  • Constants: UPPER_SNAKE_CASE (e.g., BULLET_SPEED, TURN_RATE_DEG)
  • Private methods: underscore prefix (e.g., _createAnims, _move)
  • Private fields: underscore prefix (e.g., _fireCooldown, _isMoving)

Imports/Exports

  • Use absolute paths from project root: import { Player } from '../entities/Player.js';
  • Group imports at top of file
  • Export classes as named exports: export class Player { ... }

Formatting

  • 2 spaces for indentation
  • No semicolons at statement end (optional in JS)
  • Use template literals for string interpolation: `Player at ${x}, ${y}`
  • Use const for all variables that don't change
  • Use let for mutable variables, avoid var

Code Structure

Class Structure Example

const CONSTANT_VALUE = 100;

export class MyClass {
  constructor(scene, x, y) {
    this.scene = scene;
    this.x = x;
    this.y = y;
    this._privateField = 0;
    this._setup();
  }

  _setup() {
    // initialization
  }

  update(delta) {
    this._updatePhysics(delta);
    this._updateAnimation();
  }

  _updatePhysics(delta) {
    // physics logic
  }

  _updateAnimation() {
    // animation logic
  }

  publicMethod() {
    // public API
  }

  destroy() {
    // cleanup
  }
}

Error Handling

  • No try/catch blocks required for simple operations
  • Use Phaser's built-in error handling where applicable
  • Log errors to console for debugging: console.warn('message') or console.error('message')
  • Validate inputs at function entry points when needed

Phaser-Specific Patterns

  • Extend Phaser classes: export class GameScene extends Phaser.Scene
  • Use this.scene reference to access scene in entity classes
  • Use this.add.* for creating game objects
  • Use this.physics.add.* for physics objects
  • Use this.events.emit() and this.events.on() for event-driven communication
  • Use Phaser's built-in groups: this.add.group(), this.physics.add.group()

Data Files (JSON)

  • Store game data in js/data/ directory
  • Examples: zones.json, skillTree.json
  • Load via: this.load.json('key', 'path') then this.cache.json.get('key')

Adding New Features

Adding a New Enemy Type

  1. Create new file in js/entities/enemies/
  2. Extend BaseEnemy or create new class
  3. Implement required methods: update(), takeDamage(), attack()
  4. Register in wave definitions (zones.json)

Adding a New Skill

  1. Add skill definition to js/data/skillTree.json
  2. Define node id, parent, effect (stat, add/multiply values)
  3. Implement effect logic in SkillTree.applyNode()

Adding a New Scene

  1. Create new file in js/scenes/
  2. Extend Phaser.Scene
  3. Implement preload(), create(), update() methods
  4. Add to scene array in js/main.js config

Important Patterns

Player Stats Object

this.stats = {
  speed: 200,
  damage: 20,
  fireRate: 1,
  damageReduction: 0,
  maxHp: 100,
};
  • Stats are modified by skill tree
  • Use getters/setters for x, y position from sprite

Event Communication

// Emitting events
this.events.emit('enemy-killed', { xp: 10 });
this.events.emit('level-up', newLevel);

// Listening events
this.events.on('enemy-killed', ({ xp }) => { ... });

Physics Collisions

this.physics.add.collider(playerSprite, enemyGroup);

Browser Testing

  • Open browser devtools (F12)
  • Use Console for logging and debugging
  • Use Network tab to verify asset loading
  • Use Elements tab to inspect game canvas

Common Issues

  • Modules not loading: Ensure running via HTTP server, not file://
  • Assets not loading: Check paths are relative to web root
  • Physics not working: Ensure physics config in game config and physics added to objects

Code Review Checklist

  • ES6 imports/exports used correctly
  • File naming follows PascalCase convention
  • Constants use UPPER_SNAKE_CASE
  • Private methods/fields use underscore prefix
  • No console.log in production code (use console.warn for warnings)
  • Code follows existing patterns in similar files
  • New files added to appropriate directory structure
  • JSON data files are valid