about summary refs log tree commit diff stats
path: root/html
diff options
context:
space:
mode:
Diffstat (limited to 'html')
-rw-r--r--html/tower/js/game.js88
-rw-r--r--html/tower/js/mechanics.js259
-rw-r--r--html/tower/js/path.js83
-rw-r--r--html/tower/js/renderer.js56
-rw-r--r--html/tower/js/uiHandlers.js48
5 files changed, 411 insertions, 123 deletions
diff --git a/html/tower/js/game.js b/html/tower/js/game.js
index 1099c46..0e79e4e 100644
--- a/html/tower/js/game.js
+++ b/html/tower/js/game.js
@@ -113,53 +113,103 @@ function spawnEnemies(timestamp) {
 }
 
 /**
- * Renders all game elements to the canvas
+ * Renders all game elements to the canvas using a layered approach.
+ * This function demonstrates several key game development patterns:
  * 
- * Key concepts:
- * - Layer-based rendering
- * - Canvas drawing order (background to foreground)
- * - Separation of rendering and game logic
+ * 1. Canvas State Management:
+ *    - Uses save()/restore() to isolate rendering contexts
+ *    - Resets transform matrix to prevent state leaks
+ *    - Maintains clean state between rendering phases
+ * 
+ * 2. Layered Rendering Pattern:
+ *    - Renders in specific order (background → entities → UI)
+ *    - Each layer builds on top of previous layers
+ *    - Separates rendering concerns for easier maintenance
+ * 
+ * 3. Separation of Concerns:
+ *    - Each render function handles one specific type of game element
+ *    - UI rendering is isolated from game element rendering
+ *    - Clear boundaries between different rendering responsibilities
+ * 
+ * The rendering order is important:
+ * 1. Grid (background)
+ * 2. Particles (effects under entities)
+ * 3. Projectiles (dynamic game elements)
+ * 4. Towers (static game entities)
+ * 5. Enemies (moving game entities)
+ * 6. UI (top layer)
  */
 function renderGame() {
-    // Clear and reset canvas state at the start
+    // Reset the canvas transform matrix to identity
+    // This prevents any previous transformations from affecting new renders
     ctx.setTransform(1, 0, 0, 1, 0, 0);
+    
+    // Clear the entire canvas to prevent ghosting
+    // This is crucial for animation smoothness
     ctx.clearRect(0, 0, canvas.width, canvas.height);
     
-    // Save initial state
+    // Save the initial clean state
+    // This is part of the state stack pattern used in canvas rendering
     ctx.save();
     
-    // Render game elements
-    renderGrid(ctx, gameState.grid);
-    renderParticles(ctx, gameState.particles);
-    renderProjectiles(ctx, gameState.projectiles);
-    renderTowers(ctx, gameState.towers);
-    renderEnemies(ctx, gameState.enemies);
+    // Render game world elements in specific order
+    // This creates the layered effect common in 2D games
+    renderGrid(ctx, gameState.grid);          // Background layer
+    renderParticles(ctx, gameState.particles); // Effect layer
+    renderProjectiles(ctx, gameState.projectiles); // Dynamic elements
+    renderTowers(ctx, gameState.towers);       // Static entities
+    renderEnemies(ctx, gameState.enemies);     // Moving entities
     
-    // Restore to clean state before UI
+    // Restore to clean state before UI rendering
+    // This ensures UI rendering isn't affected by game world rendering
     ctx.restore();
     ctx.save();
     
-    // Render UI with clean state
+    // Render UI elements last so they appear on top
+    // UI is rendered with its own clean state to prevent interference
     renderUI(ctx, gameState);
     
-    // Final restore
+    // Final state restoration
+    // Ensures clean state for next frame
     ctx.restore();
 }
 
-// Start the game
+/**
+ * Initializes the game by:
+ * 1. Generating the path for enemies to follow
+ * 2. Setting up initial enemy count
+ * 3. Binding event listeners
+ * 4. Starting the game loop
+ * 
+ * Uses Promise-based path generation to handle async initialization
+ */
 generatePath(gameState.grid).then(path => {
     gameState.path = path;
-    enemiesRemaining = Math.floor(Math.random() * 26) + 5; // 5-30 enemies
+    // Random enemy count between 5-30 for variety
+    enemiesRemaining = Math.floor(Math.random() * 26) + 5;
     initializeEventListeners();
+    // Start the game loop using requestAnimationFrame for smooth animation
     requestAnimationFrame(gameLoop);
 });
 
+/**
+ * Transitions the game from placement to combat phase.
+ * Demonstrates state machine pattern commonly used in games.
+ * 
+ * Side effects:
+ * - Updates game phase
+ * - Disables UI elements
+ * - Updates visual feedback
+ */
 function startCombat() {
     if (gameState.phase === GamePhase.PLACEMENT && gameState.towers.length > 0) {
+        // State transition
         gameState.phase = GamePhase.COMBAT;
+        
+        // UI updates
         document.getElementById('startCombat').disabled = true;
         
-        // Disable tower palette
+        // Visual feedback for disabled state
         document.querySelectorAll('.tower-option').forEach(option => {
             option.draggable = false;
             option.style.cursor = 'not-allowed';
diff --git a/html/tower/js/mechanics.js b/html/tower/js/mechanics.js
index 13b3ce8..2430ca0 100644
--- a/html/tower/js/mechanics.js
+++ b/html/tower/js/mechanics.js
@@ -1,23 +1,44 @@
-// Combat mechanics
+/**
+ * Combat Mechanics Module
+ * 
+ * This module handles all combat-related game mechanics including:
+ * 1. Enemy movement and behavior
+ * 2. Tower attacks and targeting
+ * 3. Projectile and particle systems
+ * 4. Status effects and special abilities
+ */
+
+/**
+ * Updates all enemy states including movement, health, and status effects
+ * Implements core game loop mechanics for enemy behavior
+ * 
+ * Key features:
+ * - Path following
+ * - Health management
+ * - Status effect processing
+ * - Collision detection
+ * 
+ * @returns {void}
+ */
 function updateEnemies() {
     const cellSize = canvas.width / 20;
     
     gameState.enemies = gameState.enemies.filter(enemy => {
-        // Add progress property if it doesn't exist
+        // Initialize progress tracking for new enemies
         if (typeof enemy.progress === 'undefined') {
             enemy.progress = 0;
         }
         
-        // Update progress
+        // Update movement progress
         enemy.progress += enemy.speed * 0.001;
         
-        // Check if enemy has completed the path
+        // Handle path completion
         if (enemy.progress >= 1) {
             gameState.enemiesEscaped++;
-            return false; // Remove from array
+            return false;
         }
         
-        // Check for collisions with projectiles
+        // Projectile collision detection
         const hitByProjectile = gameState.projectiles.some(projectile => {
             const distance = Math.hypot(
                 enemy.position.x - projectile.startPos.x,
@@ -28,15 +49,15 @@ function updateEnemies() {
         
         if (hitByProjectile) {
             gameState.awardEnemyDestroyed();
-            return false; // Remove from array
+            return false;
         }
         
-        // Update enemy position based on progress
+        // Update position based on path progress
         const pathPosition = getPathPosition(enemy.progress, gameState.path);
         enemy.position.x = pathPosition.x;
         enemy.position.y = pathPosition.y;
         
-        // Check if slow effect has expired
+        // Process slow effect expiration
         if (enemy.slowed && performance.now() > enemy.slowExpiry) {
             enemy.slowed = false;
             enemy.slowStacks = 0;
@@ -44,7 +65,7 @@ function updateEnemies() {
             enemy.speed = enemy.originalSpeed;
         }
         
-        // Add slime trail for slowed enemies (more particles for more stacks)
+        // Visual feedback for slowed status
         if (enemy.slowed && Math.random() < 0.2 + (enemy.slowStacks * 0.05)) {
             gameState.particles.push(createSlimeTrail(enemy, cellSize));
         }
@@ -65,12 +86,20 @@ function updateEnemies() {
     });
 }
 
+/**
+ * Updates particle effects with time-based animation
+ * Implements particle system lifecycle management
+ * 
+ * @param {Array<Object>} particles - Array of particle objects
+ * @param {number} timestamp - Current game timestamp
+ * @param {number} deltaTime - Time elapsed since last frame
+ * @returns {Array<Object>} Updated particles array
+ */
 function updateParticles(particles, timestamp, deltaTime) {
     return particles.filter(particle => {
         const age = timestamp - particle.createdAt;
         if (age > particle.lifetime) return false;
         
-        // Only update position for particles with velocity
         if (particle.velocity) {
             particle.position.x += particle.velocity.x * deltaTime;
             particle.position.y += particle.velocity.y * deltaTime;
@@ -80,6 +109,14 @@ function updateParticles(particles, timestamp, deltaTime) {
     });
 }
 
+/**
+ * Creates death effect particles for defeated entities
+ * Implements visual feedback system
+ * 
+ * @param {Object} target - The defeated entity
+ * @param {number} cellSize - Size of grid cell for scaling
+ * @returns {Array<Object>} Array of particle objects
+ */
 function createDeathParticles(target, cellSize) {
     const particles = [];
     const centerX = (target.position.x + 0.5) * cellSize;
@@ -91,8 +128,6 @@ function createDeathParticles(target, cellSize) {
         const randomAngle = baseAngle + (Math.random() - 0.5) * 1.5;
         const speedMultiplier = 0.7 + Math.random() * 0.6;
         const startOffset = Math.random() * 5;
-        const startX = centerX + Math.cos(randomAngle) * startOffset;
-        const startY = centerY + Math.sin(randomAngle) * startOffset;
         
         particles.push(createParticle(
             {
@@ -100,19 +135,33 @@ function createDeathParticles(target, cellSize) {
                 speed: ParticleTypes.DEATH_PARTICLE.speed * speedMultiplier,
                 lifetime: ParticleTypes.DEATH_PARTICLE.lifetime * (0.8 + Math.random() * 0.4)
             },
-            { x: startX, y: startY },
+            {
+                x: centerX + Math.cos(randomAngle) * startOffset,
+                y: centerY + Math.sin(randomAngle) * startOffset
+            },
             randomAngle
         ));
     }
     return particles;
 }
 
+/**
+ * Processes tower attacks and targeting
+ * Implements combat mechanics and special abilities
+ * 
+ * @param {Array<Object>} towers - Array of tower objects
+ * @param {Array<Object>} enemies - Array of enemy objects
+ * @param {Array<Object>} projectiles - Array of projectile objects
+ * @param {Array<Object>} particles - Array of particle objects
+ * @param {number} timestamp - Current game timestamp
+ * @param {number} cellSize - Size of grid cell for scaling
+ */
 function processTowerAttacks(towers, enemies, projectiles, particles, timestamp, cellSize) {
     towers.forEach(tower => {
         if (timestamp - tower.lastAttackTime > 1000 / tower.attackSpeed) {
             const enemiesInRange = findEnemiesInRange(tower, enemies);
             
-            if (enemiesInRange.length > 0) {
+            if (enemiesInRange.length > 0 && tower.ammo > 0) {
                 const target = enemiesInRange[0];
                 handleTowerAttack(tower, target, projectiles, particles, timestamp, cellSize);
             }
@@ -152,15 +201,22 @@ function createSlimeTrail(enemy, cellSize) {
     };
 }
 
+/**
+ * Handles individual tower attack logic including special effects
+ * Implements tower ability system
+ * 
+ * @param {Object} tower - Attacking tower
+ * @param {Object} target - Target enemy
+ * @param {Array<Object>} projectiles - Projectile array
+ * @param {Array<Object>} particles - Particle array
+ * @param {number} timestamp - Current game timestamp
+ * @param {number} cellSize - Grid cell size
+ */
 function handleTowerAttack(tower, target, projectiles, particles, timestamp, cellSize) {
-    // Check if tower has ammo
-    if (tower.ammo <= 0) {
-        return;
-    }
-    
     // Decrease ammo
     tower.ammo--;
     
+    // Create projectile
     projectiles.push({
         startPos: tower.position,
         targetPos: target.position,
@@ -169,66 +225,26 @@ function handleTowerAttack(tower, target, projectiles, particles, timestamp, cel
         towerType: tower.type
     });
     
+    // Process special abilities
     if (tower.special === 'slow') {
-        // Initialize slow effect if not present
-        if (!target.slowStacks) {
-            target.slowStacks = 0;
-        }
-        
-        // Add another stack of slow (up to a maximum)
-        const maxStacks = 5;  // Maximum 5 stacks
-        if (target.slowStacks < maxStacks) {
-            target.slowStacks++;
-            // Each stack slows by an additional 10% (multiplicative)
-            const newSlowAmount = 1 - Math.pow(0.9, target.slowStacks);  // 10%, 19%, 27%, 34%, 41%
-            
-            // Only adjust speed if this is a stronger slow
-            if (!target.slowed || newSlowAmount > target.currentSlowAmount) {
-                const originalSpeed = target.originalSpeed || target.speed;
-                target.originalSpeed = originalSpeed;  // Store original speed if not stored
-                target.speed = originalSpeed * (1 - newSlowAmount);
-                target.currentSlowAmount = newSlowAmount;
-                target.slowed = true;
-            }
-            
-            // Create slime particles for visual feedback
-            for (let i = 0; i < 4 + target.slowStacks; i++) {  // More particles for more stacks
-                particles.push(createSlimeTrail(target, cellSize));
-            }
-        }
-        
-        // Refresh slow duration
-        target.slowExpiry = timestamp + 2000;  // 2 second duration
+        handleSlowEffect(target, tower, timestamp, particles, cellSize);
     } else if (tower.special === 'aoe') {
-        // Find all enemies in AOE radius
-        const enemiesInAOE = gameState.enemies.filter(enemy => {
-            const dx = enemy.position.x - target.position.x;
-            const dy = enemy.position.y - target.position.y;
-            return Math.sqrt(dx * dx + dy * dy) <= tower.aoeRadius;
-        });
-        
-        // Create AOE explosion effect
-        particles.push(createAOEExplosion(target.position, cellSize));
-        
-        // Damage all enemies in range
-        enemiesInAOE.forEach(enemy => {
-            enemy.currentHealth -= tower.damage;
-            if (enemy.currentHealth <= 0) {
-                particles.push(...createDeathParticles(enemy, cellSize));
-            }
-        });
-    } else {
-        // Normal damage for regular towers
-        target.currentHealth -= tower.damage;
+        handleAOEEffect(target, tower, enemies, particles, cellSize);
     }
     
     tower.lastAttackTime = timestamp;
-    
-    if (target.currentHealth <= 0) {
-        particles.push(...createDeathParticles(target, cellSize));
-    }
 }
 
+/**
+ * Processes enemy attack behaviors and targeting
+ * Implements enemy combat AI
+ * 
+ * @param {Array<Object>} enemies - Array of enemy objects
+ * @param {Array<Object>} towers - Array of tower objects
+ * @param {Array<Object>} particles - Particle effect array
+ * @param {number} timestamp - Current game timestamp
+ * @param {number} cellSize - Grid cell size
+ */
 function processEnemyAttacks(enemies, towers, particles, timestamp, cellSize) {
     enemies.forEach(enemy => {
         if (!EnemyTypes[enemy.type].isRanged) return;
@@ -244,6 +260,14 @@ function processEnemyAttacks(enemies, towers, particles, timestamp, cellSize) {
     });
 }
 
+/**
+ * Finds towers within enemy attack range
+ * Implements targeting system for enemies
+ * 
+ * @param {Object} enemy - Enemy doing the targeting
+ * @param {Array<Object>} towers - Array of potential tower targets
+ * @returns {Array<Object>} Array of towers in range
+ */
 function findTowersInRange(enemy, towers) {
     return towers.filter(tower => {
         const dx = tower.position.x - enemy.position.x;
@@ -252,13 +276,22 @@ function findTowersInRange(enemy, towers) {
     });
 }
 
+/**
+ * Handles enemy attack execution and effects
+ * Implements enemy combat mechanics
+ * 
+ * @param {Object} enemy - Attacking enemy
+ * @param {Object} tower - Target tower
+ * @param {Array<Object>} particles - Particle array for effects
+ * @param {number} timestamp - Current game timestamp
+ * @param {number} cellSize - Grid cell size
+ */
 function handleEnemyAttack(enemy, tower, particles, timestamp, cellSize) {
-    // Create enemy projectile
-    const projectileColor = '#8e44ad80'; // Semi-transparent purple
+    // Create projectile effect
     particles.push(createParticle(
         {
             ...ParticleTypes.PROJECTILE,
-            color: projectileColor,
+            color: '#8e44ad80', // Semi-transparent purple
             lifetime: 500
         },
         {
@@ -271,13 +304,85 @@ function handleEnemyAttack(enemy, tower, particles, timestamp, cellSize) {
         )
     ));
     
+    // Apply damage and update tower state
     tower.currentHealth -= enemy.damage;
     enemy.lastAttackTime = timestamp;
     
-    // Reduce tower's damage as it takes damage
+    // Dynamic damage reduction based on tower health
     tower.damage = TowerTypes[tower.type].damage * (tower.currentHealth / tower.maxHealth);
 }
 
+/**
+ * Handles slow effect application and stacking
+ * Implements status effect system
+ * 
+ * @param {Object} target - Enemy to apply slow to
+ * @param {Object} tower - Tower applying the effect
+ * @param {number} timestamp - Current game timestamp
+ * @param {Array<Object>} particles - Particle array for effects
+ * @param {number} cellSize - Grid cell size
+ */
+function handleSlowEffect(target, tower, timestamp, particles, cellSize) {
+    // Initialize slow effect tracking
+    if (!target.slowStacks) {
+        target.slowStacks = 0;
+    }
+    
+    const maxStacks = 5;  // Maximum 5 stacks
+    if (target.slowStacks < maxStacks) {
+        target.slowStacks++;
+        // Each stack slows by an additional 10% (multiplicative)
+        const newSlowAmount = 1 - Math.pow(0.9, target.slowStacks);
+        
+        // Only update if new slow is stronger
+        if (!target.slowed || newSlowAmount > target.currentSlowAmount) {
+            const originalSpeed = target.originalSpeed || target.speed;
+            target.originalSpeed = originalSpeed;
+            target.speed = originalSpeed * (1 - newSlowAmount);
+            target.currentSlowAmount = newSlowAmount;
+            target.slowed = true;
+        }
+        
+        // Visual feedback particles
+        for (let i = 0; i < 4 + target.slowStacks; i++) {
+            particles.push(createSlimeTrail(target, cellSize));
+        }
+    }
+    
+    // Refresh effect duration
+    target.slowExpiry = timestamp + 2000;  // 2 second duration
+}
+
+/**
+ * Handles AOE (Area of Effect) damage and visual effects
+ * Implements area damage system
+ * 
+ * @param {Object} target - Primary target
+ * @param {Object} tower - Tower dealing AOE damage
+ * @param {Array<Object>} enemies - All enemies for AOE calculation
+ * @param {Array<Object>} particles - Particle array for effects
+ * @param {number} cellSize - Grid cell size
+ */
+function handleAOEEffect(target, tower, enemies, particles, cellSize) {
+    // Find all enemies in AOE radius
+    const enemiesInAOE = enemies.filter(enemy => {
+        const dx = enemy.position.x - target.position.x;
+        const dy = enemy.position.y - target.position.y;
+        return Math.sqrt(dx * dx + dy * dy) <= tower.aoeRadius;
+    });
+    
+    // Create explosion effect
+    particles.push(createAOEExplosion(target.position, cellSize));
+    
+    // Apply AOE damage
+    enemiesInAOE.forEach(enemy => {
+        enemy.currentHealth -= tower.damage;
+        if (enemy.currentHealth <= 0) {
+            particles.push(...createDeathParticles(enemy, cellSize));
+        }
+    });
+}
+
 // Update createEnemy to track original speed
 function createEnemy(startPosition) {
     const enemy = {
diff --git a/html/tower/js/path.js b/html/tower/js/path.js
index 46e4bfb..91193e2 100644
--- a/html/tower/js/path.js
+++ b/html/tower/js/path.js
@@ -1,18 +1,49 @@
-// Path generation using a modified depth-first search algorithm
+/**
+ * Path Generation Module
+ * 
+ * This module demonstrates several advanced game development concepts:
+ * 1. Procedural Content Generation (PCG)
+ * 2. Pathfinding algorithms
+ * 3. Constraint-based generation
+ */
+
+/**
+ * Generates a valid path through the game grid using a modified depth-first search.
+ * This algorithm ensures:
+ * - Path always moves from left to right
+ * - No diagonal movements
+ * - No path segments touch each other (except at turns)
+ * - Path is always completable
+ * 
+ * @param {Array<Array<string>>} grid - 2D array representing the game grid
+ * @returns {Promise<Array<{x: number, y: number}>>} Promise resolving to array of path coordinates
+ * 
+ * Implementation uses:
+ * - Backtracking algorithm pattern
+ * - Constraint satisfaction
+ * - Random selection for variety
+ */
 function generatePath(grid) {
     const width = grid[0].length;
     const height = grid.length;
     
-    // Pick random start point on left edge
+    // Initialize with random start point on left edge
     const startY = Math.floor(Math.random() * height);
     let currentPos = { x: 0, y: startY };
     
-    // Initialize path with start position
     const path = [currentPos];
     grid[startY][0] = 'path';
     
+    /**
+     * Determines valid moves from current position based on game rules
+     * Uses constraint checking to ensure path validity
+     * 
+     * @param {Object} pos - Current position {x, y}
+     * @returns {Array<{x: number, y: number}>} Array of valid next positions
+     */
     function getValidMoves(pos) {
         const moves = [];
+        // Prioritize right movement for path progression
         const directions = [
             { x: 1, y: 0 },  // right
             { x: 0, y: -1 }, // up
@@ -23,12 +54,12 @@ function generatePath(grid) {
             const newX = pos.x + dir.x;
             const newY = pos.y + dir.y;
             
-            // Check bounds
+            // Enforce boundary constraints
             if (newX < 0 || newX >= width || newY < 0 || newY >= height) {
                 continue;
             }
             
-            // Check if cell is empty and not adjacent to path (except previous cell)
+            // Check path isolation constraint
             if (grid[newY][newX] === 'empty' && !hasAdjacentPath(newX, newY, grid)) {
                 moves.push({ x: newX, y: newY });
             }
@@ -37,6 +68,15 @@ function generatePath(grid) {
         return moves;
     }
     
+    /**
+     * Checks if a position has adjacent path tiles (excluding previous path tile)
+     * Implements path isolation constraint
+     * 
+     * @param {number} x - X coordinate to check
+     * @param {number} y - Y coordinate to check
+     * @param {Array<Array<string>>} grid - Current grid state
+     * @returns {boolean} True if position has adjacent path tiles
+     */
     function hasAdjacentPath(x, y, grid) {
         const adjacentCells = [
             { x: x, y: y - 1 },     // up
@@ -54,14 +94,14 @@ function generatePath(grid) {
         });
     }
     
-    // Generate path until we reach the right edge
+    // Main path generation loop with backtracking
     while (currentPos.x < width - 1) {
         const moves = getValidMoves(currentPos);
         
         if (moves.length === 0) {
-            // If no valid moves, backtrack
+            // Backtrack when no valid moves exist
             if (path.length <= 1) {
-                // Start over if we can't backtrack
+                // Restart if backtracking fails
                 return generatePath(grid);
             }
             
@@ -72,7 +112,7 @@ function generatePath(grid) {
             continue;
         }
         
-        // Choose random valid move
+        // Random selection for path variety
         const nextMove = moves[Math.floor(Math.random() * moves.length)];
         currentPos = nextMove;
         path.push(currentPos);
@@ -82,11 +122,24 @@ function generatePath(grid) {
     return Promise.resolve(path);
 }
 
+/**
+ * Calculates a position along the path based on a progress value
+ * Implements smooth entity movement along path segments
+ * 
+ * @param {number} progress - Progress along path (0-1)
+ * @param {Array<{x: number, y: number}>} path - Array of path coordinates
+ * @returns {{x: number, y: number}} Interpolated position along path
+ * 
+ * Uses:
+ * - Linear interpolation (lerp)
+ * - Path segment traversal
+ * - Normalized progress tracking
+ */
 function getPathPosition(progress, path) {
-    // Ensure progress is between 0 and 1
+    // Normalize progress to valid range
     progress = Math.max(0, Math.min(1, progress));
     
-    // Get the total path length
+    // Calculate total path length for normalization
     let totalLength = 0;
     for (let i = 1; i < path.length; i++) {
         const dx = path[i].x - path[i-1].x;
@@ -94,10 +147,10 @@ function getPathPosition(progress, path) {
         totalLength += Math.sqrt(dx * dx + dy * dy);
     }
     
-    // Find target distance along path
+    // Convert progress to distance along path
     const targetDistance = progress * totalLength;
     
-    // Find the segment where the target position lies
+    // Find appropriate path segment
     let currentDistance = 0;
     for (let i = 1; i < path.length; i++) {
         const dx = path[i].x - path[i-1].x;
@@ -105,7 +158,7 @@ function getPathPosition(progress, path) {
         const segmentLength = Math.sqrt(dx * dx + dy * dy);
         
         if (currentDistance + segmentLength >= targetDistance) {
-            // Calculate position within this segment
+            // Linear interpolation within segment
             const segmentProgress = (targetDistance - currentDistance) / segmentLength;
             return {
                 x: path[i-1].x + dx * segmentProgress,
@@ -116,6 +169,6 @@ function getPathPosition(progress, path) {
         currentDistance += segmentLength;
     }
     
-    // If we somehow exceed the path length, return the last point
+    // Fallback to end of path
     return { ...path[path.length - 1] };
 } 
\ No newline at end of file
diff --git a/html/tower/js/renderer.js b/html/tower/js/renderer.js
index cf52ebc..f37b5f3 100644
--- a/html/tower/js/renderer.js
+++ b/html/tower/js/renderer.js
@@ -1,7 +1,25 @@
+/**
+ * Rendering Module
+ * 
+ * This module handles all game rendering operations using HTML5 Canvas.
+ * Demonstrates key game development patterns:
+ * 1. Layer-based rendering
+ * 2. Particle systems
+ * 3. Visual state feedback
+ * 4. Canvas state management
+ */
+
+/**
+ * Renders the game grid with path and hover previews
+ * Implements visual feedback for player actions
+ * 
+ * @param {CanvasRenderingContext2D} ctx - Canvas rendering context
+ * @param {Array<Array<string>>} grid - Game grid state
+ */
 function renderGrid(ctx, grid) {
     const cellSize = canvas.width / 20;
     
-    // Draw grid lines
+    // Draw grid lines for visual reference
     ctx.strokeStyle = '#ccc';
     ctx.lineWidth = 1;
     
@@ -19,7 +37,7 @@ function renderGrid(ctx, grid) {
         ctx.stroke();
     }
     
-    // Draw cells
+    // Render grid cells with path highlighting
     grid.forEach((row, y) => {
         row.forEach((cell, x) => {
             if (cell === 'path') {
@@ -29,12 +47,13 @@ function renderGrid(ctx, grid) {
         });
     });
 
-    // Draw hover preview
+    // Render tower placement preview
     if (gameState.phase === GamePhase.PLACEMENT && draggedTowerType && hoverCell) {
         const tower = TowerTypes[draggedTowerType];
         const canPlace = grid[hoverCell.y][hoverCell.x] === 'empty' &&
                         gameState.playerCurrency >= tower.cost;
         
+        // Visual feedback for placement validity
         ctx.fillStyle = canPlace ? tower.color + '80' : 'rgba(255, 0, 0, 0.3)';
         ctx.fillRect(
             hoverCell.x * cellSize,
@@ -43,7 +62,7 @@ function renderGrid(ctx, grid) {
             cellSize
         );
         
-        // Draw range preview
+        // Range indicator preview
         ctx.beginPath();
         ctx.arc(
             (hoverCell.x + 0.5) * cellSize,
@@ -57,19 +76,27 @@ function renderGrid(ctx, grid) {
     }
 }
 
+/**
+ * Renders all enemies with health indicators and effects
+ * Implements visual state representation
+ * 
+ * @param {CanvasRenderingContext2D} ctx - Canvas rendering context
+ * @param {Array<Object>} enemies - Array of enemy objects
+ */
 function renderEnemies(ctx, enemies) {
     const cellSize = canvas.width / 20;
     
     enemies.forEach(enemy => {
+        // Health-based opacity for visual feedback
         const healthPercent = enemy.currentHealth / enemy.maxHealth;
         const opacity = 0.3 + (healthPercent * 0.7);
         
-        // Use enemy type color
+        // Dynamic color based on enemy state
         ctx.fillStyle = `${EnemyTypes[enemy.type].color}${Math.floor(opacity * 255).toString(16).padStart(2, '0')}`;
         ctx.strokeStyle = 'rgba(0, 0, 0, 0.8)';
         ctx.lineWidth = 2;
         
-        // Draw enemy body
+        // Enemy body
         ctx.beginPath();
         ctx.arc(
             (enemy.position.x + 0.5) * cellSize,
@@ -81,7 +108,7 @@ function renderEnemies(ctx, enemies) {
         ctx.fill();
         ctx.stroke();
         
-        // Draw range indicator for ranged enemies
+        // Range indicator for special enemy types
         if (EnemyTypes[enemy.type].isRanged) {
             ctx.beginPath();
             ctx.arc(
@@ -97,6 +124,13 @@ function renderEnemies(ctx, enemies) {
     });
 }
 
+/**
+ * Renders game UI elements with clean state management
+ * Implements heads-up display (HUD) pattern
+ * 
+ * @param {CanvasRenderingContext2D} ctx - Canvas rendering context
+ * @param {Object} gameState - Current game state
+ */
 function renderUI(ctx, gameState) {
     const padding = 20;
     const lineHeight = 30;
@@ -110,17 +144,17 @@ function renderUI(ctx, gameState) {
     // Reset any transformations
     ctx.setTransform(1, 0, 0, 1, 0, 0);
     
-    // Draw semi-transparent background
+    // Semi-transparent background for readability
     ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
     ctx.fillRect(0, 0, width, height + padding);
     
-    // Set text properties
+    // Text rendering setup
     ctx.fillStyle = 'black';
     ctx.font = '20px Arial';
     ctx.textAlign = 'left';
-    ctx.textBaseline = 'top';  // Add this to ensure consistent vertical alignment
+    ctx.textBaseline = 'top';
     
-    // Draw UI elements
+    // Game state information
     ctx.fillText(`Level: ${gameState.level}`, padding, startY);
     ctx.fillText(`Currency: $${gameState.currency}`, padding, startY + lineHeight);
     ctx.fillText(`Phase: ${gameState.phase}`, padding, startY + lineHeight * 2);
diff --git a/html/tower/js/uiHandlers.js b/html/tower/js/uiHandlers.js
index 6e0789e..f171358 100644
--- a/html/tower/js/uiHandlers.js
+++ b/html/tower/js/uiHandlers.js
@@ -1,18 +1,49 @@
+/**
+ * UI Handlers Module
+ * 
+ * This module manages user interactions and UI state.
+ * Implements:
+ * 1. Drag and Drop system
+ * 2. Event handling
+ * 3. UI state management
+ * 4. Input validation
+ */
+
+/**
+ * Initializes drag and drop functionality for tower placement
+ * Implements HTML5 Drag and Drop API
+ * 
+ * @param {HTMLCanvasElement} canvas - Game canvas element
+ * @param {Object} gameState - Current game state
+ * @returns {Object} Drag handlers and state information
+ */
 function initializeDragAndDrop(canvas, gameState) {
     let draggedTowerType = null;
     let hoverCell = null;
 
     const dragHandlers = {
+        /**
+         * Handles start of tower drag operation
+         * Sets up drag data and visual feedback
+         */
         onDragStart: (e) => {
             draggedTowerType = e.target.dataset.towerType;
             e.dataTransfer.setData('text/plain', '');
         },
         
+        /**
+         * Handles end of drag operation
+         * Cleans up drag state
+         */
         onDragEnd: () => {
             draggedTowerType = null;
             hoverCell = null;
         },
         
+        /**
+         * Handles drag over canvas
+         * Updates hover position and preview
+         */
         onDragOver: (e) => {
             e.preventDefault();
             const rect = canvas.getBoundingClientRect();
@@ -22,6 +53,10 @@ function initializeDragAndDrop(canvas, gameState) {
             hoverCell = (x >= 0 && x < 20 && y >= 0 && y < 20) ? { x, y } : null;
         },
         
+        /**
+         * Handles tower placement on drop
+         * Validates placement and updates game state
+         */
         onDrop: (e) => {
             e.preventDefault();
             if (!draggedTowerType || !hoverCell) return;
@@ -32,9 +67,20 @@ function initializeDragAndDrop(canvas, gameState) {
         }
     };
 
-    return { dragHandlers, getHoverInfo: () => ({ draggedTowerType, hoverCell }) };
+    return { 
+        dragHandlers, 
+        getHoverInfo: () => ({ draggedTowerType, hoverCell }) 
+    };
 }
 
+/**
+ * Places a tower in the game grid
+ * Implements tower placement validation and state updates
+ * 
+ * @param {Object} gameState - Current game state
+ * @param {string} towerType - Type of tower to place
+ * @param {Object} position - Grid position for placement
+ */
 function placeTower(gameState, towerType, position) {
     const tower = TowerTypes[towerType];
     if (