chess/planning/DEVELOPER_GUIDE.md
Christoph Wagner 5ad0700b41 refactor: Consolidate repository structure - flatten from workspace pattern
Restructured project from nested workspace pattern to flat single-repo layout.
This eliminates redundant nesting and consolidates all project files under version control.

## Migration Summary

**Before:**
```
alex/ (workspace, not versioned)
├── chess-game/ (git repo)
│   ├── js/, css/, tests/
│   └── index.html
└── docs/ (planning, not versioned)
```

**After:**
```
alex/ (git repo, everything versioned)
├── js/, css/, tests/
├── index.html
├── docs/ (project documentation)
├── planning/ (historical planning docs)
├── .gitea/ (CI/CD)
└── CLAUDE.md (configuration)
```

## Changes Made

### Structure Consolidation
- Moved all chess-game/ contents to root level
- Removed redundant chess-game/ subdirectory
- Flattened directory structure (eliminated one nesting level)

### Documentation Organization
- Moved chess-game/docs/ → docs/ (project documentation)
- Moved alex/docs/ → planning/ (historical planning documents)
- Added CLAUDE.md (workspace configuration)
- Added IMPLEMENTATION_PROMPT.md (original project prompt)

### Version Control Improvements
- All project files now under version control
- Planning documents preserved in planning/ folder
- Merged .gitignore files (workspace + project)
- Added .claude/ agent configurations

### File Updates
- Updated .gitignore to include both workspace and project excludes
- Moved README.md to root level
- All import paths remain functional (relative paths unchanged)

## Benefits

 **Simpler Structure** - One level of nesting removed
 **Complete Versioning** - All documentation now in git
 **Standard Layout** - Matches open-source project conventions
 **Easier Navigation** - Direct access to all project files
 **CI/CD Compatible** - All workflows still functional

## Technical Validation

-  Node.js environment verified
-  Dependencies installed successfully
-  Dev server starts and responds
-  All core files present and accessible
-  Git repository functional

## Files Preserved

**Implementation Files:**
- js/ (3,517 lines of code)
- css/ (4 stylesheets)
- tests/ (87 test cases)
- index.html
- package.json

**CI/CD Pipeline:**
- .gitea/workflows/ci.yml
- .gitea/workflows/release.yml

**Documentation:**
- docs/ (12+ documentation files)
- planning/ (historical planning materials)
- README.md

**Configuration:**
- jest.config.js, babel.config.cjs, playwright.config.js
- .gitignore (merged)
- CLAUDE.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-23 10:05:26 +01:00

20 KiB

Developer Guide - HTML Chess Game

Table of Contents

  1. Development Environment
  2. Project Structure
  3. Development Workflow
  4. Testing Strategy
  5. Debugging Guide
  6. Performance Optimization
  7. Code Style Guide
  8. Deployment
  9. Troubleshooting

Development Environment

Prerequisites

Required:

  • Modern web browser (Chrome 60+, Firefox 54+, Safari 10.1+, Edge 79+)
  • Text editor or IDE (VS Code recommended)
  • Git for version control

Optional:

  • Node.js (for local server and testing)
  • Browser dev tools extensions
  • Code formatters (Prettier recommended)

Initial Setup

1. Clone or Create Project

# Create new project
mkdir chess-game
cd chess-game

# Initialize git (optional)
git init

# Create project structure
mkdir -p {css,js/{game,pieces,moves,ui,utils},assets/pieces,tests/{unit,integration},docs}

2. Install Development Tools (Optional)

# Initialize npm (for testing framework)
npm init -y

# Install dev dependencies (optional)
npm install --save-dev \
    live-server \
    eslint \
    prettier \
    jest

3. Set Up Live Server

Option 1: Using Python

python3 -m http.server 8000

Option 2: Using Node.js

npx http-server -p 8000

Option 3: Using VS Code Extension

  • Install "Live Server" extension
  • Right-click index.html → "Open with Live Server"

4. Configure Editor

VS Code Settings (.vscode/settings.json):

{
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "javascript.preferences.quoteStyle": "single",
    "files.eol": "\n",
    "files.insertFinalNewline": true,
    "files.trimTrailingWhitespace": true
}

ESLint Config (.eslintrc.json):

{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": "eslint:recommended",
    "parserOptions": {
        "ecmaVersion": 12,
        "sourceType": "module"
    },
    "rules": {
        "indent": ["error", 4],
        "quotes": ["error", "single"],
        "semi": ["error", "always"]
    }
}

Prettier Config (.prettierrc):

{
    "singleQuote": true,
    "tabWidth": 4,
    "useTabs": false,
    "semi": true,
    "trailingComma": "es5"
}

Project Structure

Directory Organization

chess-game/
├── index.html              # Main entry point
├── package.json            # npm configuration (optional)
├── .gitignore              # Git ignore rules
├── .eslintrc.json          # ESLint configuration
├── .prettierrc             # Prettier configuration
│
├── css/                    # Stylesheets
│   ├── board.css          # Chess board styling
│   ├── pieces.css         # Piece styling
│   └── ui.css             # UI components
│
├── js/                     # JavaScript modules
│   ├── main.js            # Application entry point
│   │
│   ├── game/              # Game logic
│   │   ├── ChessGame.js   # Main game controller
│   │   ├── Board.js       # Board state management
│   │   └── GameState.js   # Game state and history
│   │
│   ├── pieces/            # Piece implementations
│   │   ├── Piece.js       # Base piece class
│   │   ├── Pawn.js        # Pawn logic
│   │   ├── Knight.js      # Knight logic
│   │   ├── Bishop.js      # Bishop logic
│   │   ├── Rook.js        # Rook logic
│   │   ├── Queen.js       # Queen logic
│   │   └── King.js        # King logic
│   │
│   ├── moves/             # Move validation
│   │   ├── MoveValidator.js    # Move validation
│   │   ├── MoveGenerator.js    # Legal move generation
│   │   └── SpecialMoves.js     # Special moves
│   │
│   ├── ui/                # UI components
│   │   ├── BoardRenderer.js    # Board rendering
│   │   ├── DragDropHandler.js  # Drag-and-drop
│   │   └── UIController.js     # UI state management
│   │
│   └── utils/             # Utilities
│       ├── notation.js    # Chess notation
│       ├── storage.js     # localStorage wrapper
│       └── helpers.js     # Helper functions
│
├── assets/                # Static assets
│   └── pieces/            # Piece images (SVG)
│       ├── white-king.svg
│       ├── white-queen.svg
│       └── ...
│
├── tests/                 # Test files
│   ├── unit/              # Unit tests
│   │   ├── Board.test.js
│   │   ├── pieces/
│   │   └── moves/
│   │
│   └── integration/       # Integration tests
│       └── gameplay.test.js
│
└── docs/                  # Documentation
    ├── README.md
    ├── IMPLEMENTATION_GUIDE.md
    ├── API_REFERENCE.md
    └── ...

Module Dependencies

main.js
  ├── ChessGame.js
  │   ├── Board.js
  │   ├── GameState.js
  │   └── MoveValidator.js
  │       ├── Piece.js (and subclasses)
  │       └── SpecialMoves.js
  │
  └── UIController.js
      ├── BoardRenderer.js
      └── DragDropHandler.js

Utilities (used everywhere):
  ├── notation.js
  ├── storage.js
  └── helpers.js

Development Workflow

1. Feature Development Cycle

# 1. Create feature branch (if using git)
git checkout -b feature/castling-logic

# 2. Write failing test first (TDD)
# Edit tests/unit/moves/SpecialMoves.test.js

# 3. Run tests
npm test

# 4. Implement feature
# Edit js/moves/SpecialMoves.js

# 5. Run tests until passing
npm test

# 6. Refactor if needed
# Clean up code, improve performance

# 7. Commit changes
git add .
git commit -m "feat: implement castling logic"

# 8. Merge to main
git checkout main
git merge feature/castling-logic

2. Daily Development Routine

Morning:

  1. Pull latest changes
  2. Review open issues
  3. Plan tasks for the day
  4. Set up development environment

During Development:

  1. Write test first (TDD)
  2. Implement minimal code to pass
  3. Refactor for quality
  4. Commit frequently
  5. Run full test suite periodically

End of Day:

  1. Run full test suite
  2. Commit all changes
  3. Push to repository
  4. Update task tracker
  5. Document any blockers

3. Code Review Process

Before Requesting Review:

  • All tests passing
  • Code formatted and linted
  • No console errors
  • Documentation updated
  • Self-review completed

Review Checklist:

  • Code follows style guide
  • Tests are comprehensive
  • No performance regressions
  • Edge cases handled
  • Documentation accurate

Testing Strategy

Unit Testing

Framework: Jest (or your choice)

Test Structure:

// tests/unit/pieces/Rook.test.js
import { Rook } from '../../../js/pieces/Rook.js';
import { Board } from '../../../js/game/Board.js';

describe('Rook', () => {
    let board;

    beforeEach(() => {
        board = new Board();
        board.clear(); // Start with empty board
    });

    describe('getValidMoves', () => {
        it('should move vertically', () => {
            const rook = new Rook('white', {row: 4, col: 4});
            board.setPiece(4, 4, rook);

            const moves = rook.getValidMoves(board);
            const verticalMoves = moves.filter(m => m.col === 4);

            expect(verticalMoves.length).toBe(7);
        });

        it('should be blocked by friendly pieces', () => {
            const rook = new Rook('white', {row: 4, col: 4});
            const blockingPawn = new Pawn('white', {row: 4, col: 6});

            board.setPiece(4, 4, rook);
            board.setPiece(4, 6, blockingPawn);

            const moves = rook.getValidMoves(board);
            const rightMoves = moves.filter(m => m.row === 4 && m.col > 4);

            expect(rightMoves.length).toBe(1); // Only to col 5
        });

        it('should capture enemy pieces', () => {
            const rook = new Rook('white', {row: 4, col: 4});
            const enemyPawn = new Pawn('black', {row: 4, col: 6});

            board.setPiece(4, 4, rook);
            board.setPiece(4, 6, enemyPawn);

            const moves = rook.getValidMoves(board);
            const canCaptureEnemy = moves.some(m =>
                m.row === 4 && m.col === 6
            );

            expect(canCaptureEnemy).toBe(true);
        });
    });
});

Run Tests:

# Run all tests
npm test

# Run specific file
npm test -- Rook.test.js

# Run with coverage
npm test -- --coverage

# Watch mode
npm test -- --watch

Integration Testing

Test Complete Scenarios:

// tests/integration/gameplay.test.js
describe('Complete Game Scenarios', () => {
    it('should handle Scholar\'s Mate', () => {
        const game = new ChessGame();

        // Move sequence
        expect(game.makeMove(6, 4, 4, 4).success).toBe(true); // e4
        expect(game.makeMove(1, 4, 3, 4).success).toBe(true); // e5
        expect(game.makeMove(7, 5, 4, 2).success).toBe(true); // Bc4
        expect(game.makeMove(1, 1, 2, 2).success).toBe(true); // Nc6
        expect(game.makeMove(7, 3, 3, 7).success).toBe(true); // Qh5
        expect(game.makeMove(1, 6, 2, 5).success).toBe(true); // Nf6
        expect(game.makeMove(3, 7, 1, 5).success).toBe(true); // Qxf7#

        // Verify checkmate
        expect(game.status).toBe('checkmate');
        expect(game.winner).toBe('white');
    });

    it('should handle stalemate', () => {
        const game = new ChessGame();

        // Set up stalemate position
        game.board.fromFEN('7k/5Q2/6K1/8/8/8/8/8 b - - 0 1');

        expect(game.isStalemate('black')).toBe(true);
        expect(game.status).toBe('stalemate');
    });
});

Manual Testing Checklist

Before Each Release:

  • All piece types move correctly
  • Special moves work (castling, en passant, promotion)
  • Check detection accurate
  • Checkmate detection accurate
  • Stalemate detection accurate
  • UI responsive and intuitive
  • Save/load functionality works
  • Undo/redo works correctly
  • No console errors
  • Performance acceptable
  • Works in all target browsers

Debugging Guide

Browser Developer Tools

Console Debugging:

// Add debug logging
console.log('Move validation:', {
    piece: piece.type,
    from: {row: fromRow, col: fromCol},
    to: {row: toRow, col: toCol},
    valid: result
});

// Use debugger statement
function makeMove(fromRow, fromCol, toRow, toCol) {
    debugger; // Execution will pause here
    const piece = this.board.getPiece(fromRow, fromCol);
    // ...
}

// Group related logs
console.group('Move Validation');
console.log('Piece:', piece);
console.log('Valid moves:', validMoves);
console.log('Target:', {toRow, toCol});
console.groupEnd();

Breakpoints:

  1. Open DevTools (F12)
  2. Go to Sources tab
  3. Find your file
  4. Click line number to set breakpoint
  5. Refresh page to trigger

Watch Expressions:

  • Add this.board.grid to watch
  • Add this.gameState.moveHistory to watch
  • Add this.currentTurn to watch

Common Issues and Solutions

Issue: Infinite Recursion in Check Detection

Problem:

// Bad: Causes infinite loop
function isMoveLegal(board, piece, toRow, toCol) {
    const validMoves = piece.getValidMoves(board); // Calls isMoveLegal again!
    // ...
}

Solution:

// Good: Separate concerns
function getValidMoves(board, piece) {
    // Get moves without check validation
}

function getLegalMoves(board, piece) {
    // Filter valid moves by check constraint
    return getValidMoves(board, piece)
        .filter(move => !leavesKingInCheck(board, piece, move));
}

Issue: Drag and Drop Not Working

Checklist:

  • Element has draggable="true"
  • Event listeners attached to correct elements
  • dataTransfer used correctly
  • preventDefault() called in dragover

Debug:

boardElement.addEventListener('dragstart', (e) => {
    console.log('Drag started:', e.target);
    console.log('Data:', e.dataTransfer.getData('text/plain'));
});

boardElement.addEventListener('dragover', (e) => {
    console.log('Drag over:', e.target);
    e.preventDefault(); // Don't forget this!
});

Issue: Pieces Not Rendering

Checklist:

  • CSS classes applied correctly
  • Grid layout configured
  • Z-index issues
  • Unicode symbols or images loading

Debug:

// Verify DOM structure
console.log('Board HTML:', boardElement.innerHTML);
console.log('Squares:', boardElement.querySelectorAll('.square').length);
console.log('Pieces:', boardElement.querySelectorAll('.piece').length);

Performance Profiling

Using Chrome DevTools:

  1. Open DevTools → Performance tab
  2. Click Record
  3. Perform action (e.g., make move)
  4. Stop recording
  5. Analyze timeline

Identify Bottlenecks:

  • Excessive DOM manipulation
  • Slow move validation
  • Memory leaks
  • Unnecessary re-renders

Solution:

// Before: Slow
function updateBoard() {
    boardElement.innerHTML = ''; // Triggers reflow
    for (let row = 0; row < 8; row++) {
        for (let col = 0; col < 8; col++) {
            // Create and append elements
        }
    }
}

// After: Fast
function updateBoard() {
    const fragment = document.createDocumentFragment();
    for (let row = 0; row < 8; row++) {
        for (let col = 0; col < 8; col++) {
            // Create elements and append to fragment
        }
    }
    boardElement.innerHTML = '';
    boardElement.appendChild(fragment); // Single reflow
}

Performance Optimization

Minimize DOM Manipulation

Use Document Fragments:

const fragment = document.createDocumentFragment();
// Add all elements to fragment
container.appendChild(fragment); // Single DOM update

Batch Updates:

// Bad: Multiple reflows
element.style.width = '100px';
element.style.height = '100px';
element.style.backgroundColor = 'red';

// Good: Single reflow
element.style.cssText = 'width: 100px; height: 100px; background-color: red;';

Memoize Expensive Calculations

class Piece {
    constructor() {
        this._validMovesCache = null;
        this._cacheValidUntil = null;
    }

    getValidMoves(board) {
        const boardHash = board.getHash();

        if (this._cacheValidUntil === boardHash) {
            return this._validMovesCache;
        }

        // Calculate moves
        this._validMovesCache = this.calculateValidMoves(board);
        this._cacheValidUntil = boardHash;

        return this._validMovesCache;
    }

    invalidateCache() {
        this._validMovesCache = null;
        this._cacheValidUntil = null;
    }
}

Debounce UI Updates

function debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
        const later = () => {
            clearTimeout(timeout);
            func(...args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
}

// Usage
const updateUI = debounce(() => {
    renderer.renderBoard(game.board, game.gameState);
}, 100);

Optimize Event Handlers

Use Event Delegation:

// Bad: Many listeners
squares.forEach(square => {
    square.addEventListener('click', handleClick);
});

// Good: Single listener
boardElement.addEventListener('click', (e) => {
    const square = e.target.closest('.square');
    if (square) {
        handleClick(square);
    }
});

Code Style Guide

Naming Conventions

Variables:

// camelCase for variables and functions
const currentTurn = 'white';
const isKingInCheck = true;

function makeMove(from, to) { }

Classes:

// PascalCase for classes
class ChessGame { }
class MoveValidator { }

Constants:

// UPPER_SNAKE_CASE for constants
const MAX_MOVES = 500;
const DEFAULT_FEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';

Private Members:

// Prefix with underscore
class Piece {
    constructor() {
        this._cachedMoves = null;
    }
}

File Organization

One class per file:

// Good: Rook.js
export class Rook extends Piece {
    // ...
}

// Bad: pieces.js with all pieces
export class Rook { }
export class Bishop { }
export class Knight { }

Related functions can be grouped:

// utils/helpers.js
export function clamp(value, min, max) { }
export function isInBounds(row, col) { }
export function getOppositeColor(color) { }

Documentation

JSDoc Comments:

/**
 * Validates if a move is legal according to chess rules
 *
 * @param {Board} board - The current board state
 * @param {Piece} piece - The piece to move
 * @param {number} toRow - Target row (0-7)
 * @param {number} toCol - Target column (0-7)
 * @param {GameState} gameState - Current game state
 * @returns {boolean} True if move is legal
 */
static isMoveLegal(board, piece, toRow, toCol, gameState) {
    // ...
}

Error Handling

Use descriptive errors:

// Good
if (!piece) {
    throw new Error(`No piece found at position (${row}, ${col})`);
}

// Bad
if (!piece) {
    throw new Error('Invalid');
}

Return result objects:

function makeMove(from, to) {
    if (!isValid) {
        return {
            success: false,
            error: 'Invalid move: piece cannot move there'
        };
    }

    return {
        success: true,
        move: executedMove
    };
}

Deployment

Pre-Deployment Checklist

  • All tests passing
  • No console errors
  • Code minified (optional)
  • Assets optimized
  • Browser compatibility tested
  • Performance acceptable
  • Documentation updated

Build Process (Optional)

If using build tools:

# Install build tools
npm install --save-dev webpack webpack-cli

# Create webpack.config.js
# Build for production
npm run build

Static Hosting

GitHub Pages:

# Create gh-pages branch
git checkout -b gh-pages

# Push to GitHub
git push origin gh-pages

# Access at: https://username.github.io/chess-game

Netlify:

  1. Connect GitHub repository
  2. Set build command (if any)
  3. Set publish directory
  4. Deploy

Vercel:

npm install -g vercel
vercel deploy

Performance Optimization for Production

Minify CSS/JS:

# CSS
npx cssnano css/board.css > dist/board.min.css

# JS
npx terser js/main.js -o dist/main.min.js

Optimize Images:

  • Use SVG for piece images (scalable)
  • Compress PNG/JPG if used
  • Use appropriate formats

Enable Compression:

# .htaccess for Apache
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/css application/javascript
</IfModule>

Troubleshooting

Common Errors

"Uncaught TypeError: Cannot read property 'grid' of undefined"

  • Board not initialized
  • Check constructor calls
  • Verify import statements

"Maximum call stack size exceeded"

  • Infinite recursion
  • Check move validation logic
  • Verify event listener cleanup

Drag and drop not working

  • Check draggable attribute
  • Verify event listeners
  • Call preventDefault() in dragover

Getting Help

  1. Check documentation
  2. Review API reference
  3. Search existing issues
  4. Ask specific questions with code samples

Next: See HANDOFF_CHECKLIST.md for implementation timeline