Example #1: Space Defender Game

Generating a Complete Game
with mkarchi 0.1.7

From
ClaudeClaude

This example demonstrates how mkarchi can generate a complex project structure with multiple files and complete source code. Simply copy the syntax below into a .txt file and run mkarchi apply.

Game Preview

Space Defender Screenshot 1
Space Defender Screenshot 2
Space Defender Screenshot 4
Space Defender Screenshot 3

How to Run

1
Generate Architecture

Copy the syntax below into a file named game.txt and run:

mkarchi apply game.txt

2
Play Game

cd mini-game
# Just open index.html in your browser
start index.html

Tip: Use a local server (like Live Server) for better experience.

game_structure.txt
mini-game/
├── index.html (begincontenu)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Space Defender - Mini Game</title>
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <div class="game-container">
        <div class="header">
            <h1>Space Defender</h1>
            <div class="score-board">
                <span class="label">Score:</span>
                <span id="score">0</span>
                <span class="label">Lives:</span>
                <span id="lives">3</span>
                <span class="label">Level:</span>
                <span id="level">1</span>
            </div>
        </div>
        
        <canvas id="gameCanvas" width="800" height="600"></canvas>
        
        <div class="controls">
            <button id="startBtn" class="btn btn-primary">Start Game</button>
            <button id="pauseBtn" class="btn btn-secondary" disabled>Pause</button>
            <button id="restartBtn" class="btn btn-warning" disabled>Restart</button>
        </div>
        
        <div class="instructions">
            <h3>How to Play</h3>
            <ul>
                <li>Use Arrow Keys or WASD to move your ship</li>
                <li>Press SPACE to shoot</li>
                <li>Destroy enemies to gain points</li>
                <li>Avoid enemy bullets and collisions</li>
                <li>Collect power-ups for special abilities</li>
            </ul>
        </div>
        
        <div id="gameOverModal" class="modal hidden">
            <div class="modal-content">
                <h2>Game Over!</h2>
                <p>Final Score: <span id="finalScore">0</span></p>
                <p>Level Reached: <span id="finalLevel">1</span></p>
                <button id="playAgainBtn" class="btn btn-primary">Play Again</button>
            </div>
        </div>
    </div>
    
    <script src="js/config.js"></script>
    <script src="js/utils.js"></script>
    <script src="js/entities.js"></script>
    <script src="js/player.js"></script>
    <script src="js/enemy.js"></script>
    <script src="js/powerup.js"></script>
    <script src="js/particle.js"></script>
    <script src="js/collision.js"></script>
    <script src="js/game.js"></script>
    <script src="js/main.js"></script>
</body>
</html>
(endcontenu)
│
├── css/
│   └── styles.css (begincontenu)
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    padding: 20px;
}

.game-container {
    background: rgba(255, 255, 255, 0.95);
    border-radius: 15px;
    padding: 30px;
    box-shadow: 0 10px 50px rgba(0, 0, 0, 0.3);
    max-width: 900px;
    width: 100%;
}

.header {
    text-align: center;
    margin-bottom: 20px;
}

.header h1 {
    color: #2c3e50;
    font-size: 2.5em;
    margin-bottom: 15px;
    text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
}

.score-board {
    display: flex;
    justify-content: center;
    gap: 30px;
    font-size: 1.2em;
    color: #34495e;
    font-weight: bold;
}

.score-board .label {
    color: #7f8c8d;
    font-weight: normal;
}

.score-board span:not(.label) {
    color: #e74c3c;
    font-size: 1.3em;
}

#gameCanvas {
    display: block;
    margin: 0 auto;
    background: #000;
    border: 3px solid #34495e;
    border-radius: 10px;
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}

.controls {
    display: flex;
    justify-content: center;
    gap: 15px;
    margin: 20px 0;
}

.btn {
    padding: 12px 30px;
    font-size: 1.1em;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.3s ease;
    font-weight: bold;
    text-transform: uppercase;
}

.btn:hover:not(:disabled) {
    transform: translateY(-2px);
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}

.btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.btn-primary {
    background: #3498db;
    color: white;
}

.btn-primary:hover:not(:disabled) {
    background: #2980b9;
}

.btn-secondary {
    background: #95a5a6;
    color: white;
}

.btn-secondary:hover:not(:disabled) {
    background: #7f8c8d;
}

.btn-warning {
    background: #e67e22;
    color: white;
}

.btn-warning:hover:not(:disabled) {
    background: #d35400;
}

.instructions {
    background: #ecf0f1;
    padding: 20px;
    border-radius: 10px;
    margin-top: 20px;
}

.instructions h3 {
    color: #2c3e50;
    margin-bottom: 15px;
    font-size: 1.3em;
}

.instructions ul {
    list-style-position: inside;
    color: #34495e;
    line-height: 1.8;
}

.modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.8);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 1000;
}

.modal.hidden {
    display: none;
}

.modal-content {
    background: white;
    padding: 40px;
    border-radius: 15px;
    text-align: center;
    box-shadow: 0 10px 50px rgba(0, 0, 0, 0.5);
    animation: slideIn 0.3s ease;
}

@keyframes slideIn {
    from {
        transform: translateY(-50px);
        opacity: 0;
    }
    to {
        transform: translateY(0);
        opacity: 1;
    }
}

.modal-content h2 {
    color: #e74c3c;
    font-size: 2.5em;
    margin-bottom: 20px;
}

.modal-content p {
    color: #34495e;
    font-size: 1.3em;
    margin: 10px 0;
}

.modal-content span {
    color: #e74c3c;
    font-weight: bold;
    font-size: 1.5em;
}
(endcontenu)
│
├── js/
│   ├── config.js (begincontenu)
const CONFIG = {
    canvas: {
        width: 800,
        height: 600
    },
    
    player: {
        width: 40,
        height: 50,
        speed: 5,
        color: '#00ff00',
        bulletSpeed: 7,
        bulletWidth: 4,
        bulletHeight: 15,
        bulletColor: '#ffff00',
        fireRate: 250
    },
    
    enemy: {
        width: 35,
        height: 35,
        speed: 2,
        color: '#ff0000',
        spawnRate: 2000,
        bulletSpeed: 4,
        bulletWidth: 4,
        bulletHeight: 12,
        bulletColor: '#ff6600',
        fireRate: 1500,
        points: 10
    },
    
    powerup: {
        width: 25,
        height: 25,
        speed: 2,
        spawnRate: 15000,
        types: {
            RAPID_FIRE: {
                color: '#ffff00',
                duration: 5000
            },
            SHIELD: {
                color: '#00ffff',
                duration: 8000
            },
            MULTI_SHOT: {
                color: '#ff00ff',
                duration: 7000
            }
        }
    },
    
    particle: {
        count: 15,
        speed: 3,
        lifetime: 30,
        colors: ['#ff6b6b', '#feca57', '#48dbfb', '#ff9ff3', '#54a0ff']
    },
    
    game: {
        initialLives: 3,
        levelUpScore: 500,
        difficultyIncrease: 0.15
    }
};
(endcontenu)
│   │
│   ├── utils.js (begincontenu)
class Utils {
    static randomInt(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }
    
    static randomFloat(min, max) {
        return Math.random() * (max - min) + min;
    }
    
    static randomColor() {
        const colors = CONFIG.particle.colors;
        return colors[Math.floor(Math.random() * colors.length)];
    }
    
    static distance(x1, y1, x2, y2) {
        const dx = x2 - x1;
        const dy = y2 - y1;
        return Math.sqrt(dx * dx + dy * dy);
    }
    
    static clamp(value, min, max) {
        return Math.max(min, Math.min(max, value));
    }
    
    static lerp(start, end, t) {
        return start + (end - start) * t;
    }
}
(endcontenu)
│   │
│   ├── entities.js (begincontenu)
class Entity {
    constructor(x, y, width, height, color) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.color = color;
        this.alive = true;
    }
    
    draw(ctx) {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
    }
    
    update() {
        // To be overridden by subclasses
    }
    
    isOffScreen(canvasWidth, canvasHeight) {
        return this.x + this.width < 0 || 
               this.x > canvasWidth || 
               this.y + this.height < 0 || 
               this.y > canvasHeight;
    }
}

class Bullet extends Entity {
    constructor(x, y, width, height, color, speed, direction = 'up') {
        super(x, y, width, height, color);
        this.speed = speed;
        this.direction = direction;
    }
    
    update() {
        if (this.direction === 'up') {
            this.y -= this.speed;
        } else {
            this.y += this.speed;
        }
    }
    
    draw(ctx) {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
        
        ctx.shadowBlur = 10;
        ctx.shadowColor = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
        ctx.shadowBlur = 0;
    }
}
(endcontenu)
│   │
│   ├── player.js (begincontenu)
class Player extends Entity {
    constructor(x, y) {
        super(x, y, CONFIG.player.width, CONFIG.player.height, CONFIG.player.color);
        this.speed = CONFIG.player.speed;
        this.bullets = [];
        this.lastFireTime = 0;
        this.fireRate = CONFIG.player.fireRate;
        this.hasShield = false;
        this.shieldEndTime = 0;
        this.hasRapidFire = false;
        this.rapidFireEndTime = 0;
        this.hasMultiShot = false;
        this.multiShotEndTime = 0;
    }
    
    move(direction, canvasWidth, canvasHeight) {
        switch(direction) {
            case 'left':
                this.x = Math.max(0, this.x - this.speed);
                break;
            case 'right':
                this.x = Math.min(canvasWidth - this.width, this.x + this.speed);
                break;
            case 'up':
                this.y = Math.max(0, this.y - this.speed);
                break;
            case 'down':
                this.y = Math.min(canvasHeight - this.height, this.y + this.speed);
                break;
        }
    }
    
    shoot(currentTime) {
        const actualFireRate = this.hasRapidFire ? this.fireRate / 2 : this.fireRate;
        
        if (currentTime - this.lastFireTime > actualFireRate) {
            if (this.hasMultiShot) {
                this.bullets.push(new Bullet(
                    this.x + this.width / 2 - CONFIG.player.bulletWidth / 2 - 15,
                    this.y,
                    CONFIG.player.bulletWidth,
                    CONFIG.player.bulletHeight,
                    CONFIG.player.bulletColor,
                    CONFIG.player.bulletSpeed,
                    'up'
                ));
                this.bullets.push(new Bullet(
                    this.x + this.width / 2 - CONFIG.player.bulletWidth / 2,
                    this.y,
                    CONFIG.player.bulletWidth,
                    CONFIG.player.bulletHeight,
                    CONFIG.player.bulletColor,
                    CONFIG.player.bulletSpeed,
                    'up'
                ));
                this.bullets.push(new Bullet(
                    this.x + this.width / 2 - CONFIG.player.bulletWidth / 2 + 15,
                    this.y,
                    CONFIG.player.bulletWidth,
                    CONFIG.player.bulletHeight,
                    CONFIG.player.bulletColor,
                    CONFIG.player.bulletSpeed,
                    'up'
                ));
            } else {
                this.bullets.push(new Bullet(
                    this.x + this.width / 2 - CONFIG.player.bulletWidth / 2,
                    this.y,
                    CONFIG.player.bulletWidth,
                    CONFIG.player.bulletHeight,
                    CONFIG.player.bulletColor,
                    CONFIG.player.bulletSpeed,
                    'up'
                ));
            }
            this.lastFireTime = currentTime;
        }
    }
    
    updatePowerUps(currentTime) {
        if (this.hasShield && currentTime > this.shieldEndTime) {
            this.hasShield = false;
        }
        if (this.hasRapidFire && currentTime > this.rapidFireEndTime) {
            this.hasRapidFire = false;
        }
        if (this.hasMultiShot && currentTime > this.multiShotEndTime) {
            this.hasMultiShot = false;
        }
    }
    
    update(canvasWidth, canvasHeight, currentTime) {
        this.bullets = this.bullets.filter(bullet => {
            bullet.update();
            return !bullet.isOffScreen(canvasWidth, canvasHeight);
        });
        
        this.updatePowerUps(currentTime);
    }
    
    draw(ctx) {
        ctx.fillStyle = this.color;
        ctx.beginPath();
        ctx.moveTo(this.x + this.width / 2, this.y);
        ctx.lineTo(this.x, this.y + this.height);
        ctx.lineTo(this.x + this.width, this.y + this.height);
        ctx.closePath();
        ctx.fill();
        
        if (this.hasShield) {
            ctx.strokeStyle = '#00ffff';
            ctx.lineWidth = 3;
            ctx.beginPath();
            ctx.arc(this.x + this.width / 2, this.y + this.height / 2, 30, 0, Math.PI * 2);
            ctx.stroke();
        }
        
        this.bullets.forEach(bullet => bullet.draw(ctx));
    }
}
(endcontenu)
│   │
│   ├── enemy.js (begincontenu)
class Enemy extends Entity {
    constructor(x, y) {
        super(x, y, CONFIG.enemy.width, CONFIG.enemy.height, CONFIG.enemy.color);
        this.speed = CONFIG.enemy.speed;
        this.bullets = [];
        this.lastFireTime = 0;
        this.direction = 1;
        this.verticalSpeed = 0.5;
    }
    
    shoot(currentTime) {
        if (currentTime - this.lastFireTime > CONFIG.enemy.fireRate) {
            this.bullets.push(new Bullet(
                this.x + this.width / 2 - CONFIG.enemy.bulletWidth / 2,
                this.y + this.height,
                CONFIG.enemy.bulletWidth,
                CONFIG.enemy.bulletHeight,
                CONFIG.enemy.bulletColor,
                CONFIG.enemy.bulletSpeed,
                'down'
            ));
            this.lastFireTime = currentTime;
        }
    }
    
    update(canvasWidth, canvasHeight, currentTime) {
        this.x += this.speed * this.direction;
        this.y += this.verticalSpeed;
        
        if (this.x <= 0 || this.x + this.width >= canvasWidth) {
            this.direction *= -1;
        }
        
        if (Math.random() < 0.01) {
            this.shoot(currentTime);
        }
        
        this.bullets = this.bullets.filter(bullet => {
            bullet.update();
            return !bullet.isOffScreen(canvasWidth, canvasHeight);
        });
    }
    
    draw(ctx) {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
        
        ctx.fillStyle = '#ff6666';
        ctx.fillRect(this.x + 5, this.y + 10, 10, 10);
        ctx.fillRect(this.x + 20, this.y + 10, 10, 10);
        
        this.bullets.forEach(bullet => bullet.draw(ctx));
    }
}
(endcontenu)
│   │
│   ├── powerup.js (begincontenu)
class PowerUp extends Entity {
    constructor(x, y, type) {
        const config = CONFIG.powerup.types[type];
        super(x, y, CONFIG.powerup.width, CONFIG.powerup.height, config.color);
        this.type = type;
        this.speed = CONFIG.powerup.speed;
        this.rotation = 0;
        this.duration = config.duration;
    }
    
    update() {
        this.y += this.speed;
        this.rotation += 0.05;
    }
    
    draw(ctx) {
        ctx.save();
        ctx.translate(this.x + this.width / 2, this.y + this.height / 2);
        ctx.rotate(this.rotation);
        
        ctx.fillStyle = this.color;
        ctx.fillRect(-this.width / 2, -this.height / 2, this.width, this.height);
        
        ctx.strokeStyle = '#ffffff';
        ctx.lineWidth = 2;
        ctx.strokeRect(-this.width / 2, -this.height / 2, this.width, this.height);
        
        ctx.restore();
        
        ctx.shadowBlur = 15;
        ctx.shadowColor = this.color;
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
        ctx.shadowBlur = 0;
    }
}
(endcontenu)
│   │
│   ├── particle.js (begincontenu)
class Particle {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.vx = Utils.randomFloat(-CONFIG.particle.speed, CONFIG.particle.speed);
        this.vy = Utils.randomFloat(-CONFIG.particle.speed, CONFIG.particle.speed);
        this.life = CONFIG.particle.lifetime;
        this.maxLife = CONFIG.particle.lifetime;
        this.color = Utils.randomColor();
        this.size = Utils.randomInt(2, 5);
    }
    
    update() {
        this.x += this.vx;
        this.y += this.vy;
        this.life--;
        this.vx *= 0.98;
        this.vy *= 0.98;
    }
    
    draw(ctx) {
        const alpha = this.life / this.maxLife;
        ctx.fillStyle = this.color;
        ctx.globalAlpha = alpha;
        ctx.fillRect(this.x, this.y, this.size, this.size);
        ctx.globalAlpha = 1;
    }
    
    isDead() {
        return this.life <= 0;
    }
}

class ParticleSystem {
    constructor() {
        this.particles = [];
    }
    
    createExplosion(x, y) {
        for (let i = 0; i < CONFIG.particle.count; i++) {
            this.particles.push(new Particle(x, y));
        }
    }
    
    update() {
        this.particles = this.particles.filter(particle => {
            particle.update();
            return !particle.isDead();
        });
    }
    
    draw(ctx) {
        this.particles.forEach(particle => particle.draw(ctx));
    }
}
(endcontenu)
│   │
│   ├── collision.js (begincontenu)
class CollisionDetector {
    static checkCollision(rect1, rect2) {
        return rect1.x < rect2.x + rect2.width &&
               rect1.x + rect1.width > rect2.x &&
               rect1.y < rect2.y + rect2.height &&
               rect1.y + rect1.height > rect2.y;
    }
    
    static checkBulletEnemyCollisions(player, enemies, particleSystem, score) {
        let newScore = score;
        
        player.bullets.forEach(bullet => {
            enemies.forEach(enemy => {
                if (bullet.alive && enemy.alive && this.checkCollision(bullet, enemy)) {
                    bullet.alive = false;
                    enemy.alive = false;
                    particleSystem.createExplosion(
                        enemy.x + enemy.width / 2,
                        enemy.y + enemy.height / 2
                    );
                    newScore += CONFIG.enemy.points;
                }
            });
        });
        
        return newScore;
    }
    
    static checkEnemyBulletPlayerCollisions(player, enemies) {
        if (player.hasShield) {
            enemies.forEach(enemy => {
                enemy.bullets = enemy.bullets.filter(bullet => {
                    if (this.checkCollision(bullet, player)) {
                        return false;
                    }
                    return true;
                });
            });
            return false;
        }
        
        for (let enemy of enemies) {
            for (let bullet of enemy.bullets) {
                if (bullet.alive && this.checkCollision(bullet, player)) {
                    bullet.alive = false;
                    return true;
                }
            }
        }
        return false;
    }
    
    static checkEnemyPlayerCollisions(player, enemies) {
        if (player.hasShield) {
            return false;
        }
        
        for (let enemy of enemies) {
            if (enemy.alive && this.checkCollision(player, enemy)) {
                return true;
            }
        }
        return false;
    }
    
    static checkPowerUpPlayerCollisions(player, powerups, currentTime) {
        powerups.forEach(powerup => {
            if (powerup.alive && this.checkCollision(player, powerup)) {
                powerup.alive = false;
                
                switch(powerup.type) {
                    case 'RAPID_FIRE':
                        player.hasRapidFire = true;
                        player.rapidFireEndTime = currentTime + powerup.duration;
                        break;
                    case 'SHIELD':
                        player.hasShield = true;
                        player.shieldEndTime = currentTime + powerup.duration;
                        break;
                    case 'MULTI_SHOT':
                        player.hasMultiShot = true;
                        player.multiShotEndTime = currentTime + powerup.duration;
                        break;
                }
            }
        });
    }
}
(endcontenu)
│   │
│   ├── game.js (begincontenu)
class Game {
    constructor(canvas) {
        this.canvas = canvas;
        this.ctx = canvas.getContext('2d');
        this.width = CONFIG.canvas.width;
        this.height = CONFIG.canvas.height;
        
        this.player = new Player(
            this.width / 2 - CONFIG.player.width / 2,
            this.height - 100
        );
        
        this.enemies = [];
        this.powerups = [];
        this.particleSystem = new ParticleSystem();
        
        this.score = 0;
        this.lives = CONFIG.game.initialLives;
        this.level = 1;
        this.gameOver = false;
        this.paused = false;
        
        this.lastEnemySpawn = 0;
        this.lastPowerUpSpawn = 0;
        
        this.keys = {};
        
        this.setupEventListeners();
    }
    
    setupEventListeners() {
        document.addEventListener('keydown', (e) => {
            this.keys[e.key] = true;
            
            if (e.key === ' ') {
                e.preventDefault();
                if (!this.paused && !this.gameOver) {
                    this.player.shoot(Date.now());
                }
            }
        });
        
        document.addEventListener('keyup', (e) => {
            this.keys[e.key] = false;
        });
    }
    
    spawnEnemy(currentTime) {
        const spawnRate = CONFIG.enemy.spawnRate * Math.pow(0.95, this.level - 1);
        
        if (currentTime - this.lastEnemySpawn > spawnRate) {
            const x = Utils.randomInt(0, this.width - CONFIG.enemy.width);
            this.enemies.push(new Enemy(x, -CONFIG.enemy.height));
            this.lastEnemySpawn = currentTime;
        }
    }
    
    spawnPowerUp(currentTime) {
        if (currentTime - this.lastPowerUpSpawn > CONFIG.powerup.spawnRate) {
            const x = Utils.randomInt(0, this.width - CONFIG.powerup.width);
            const types = Object.keys(CONFIG.powerup.types);
            const randomType = types[Utils.randomInt(0, types.length - 1)];
            this.powerups.push(new PowerUp(x, -CONFIG.powerup.height, randomType));
            this.lastPowerUpSpawn = currentTime;
        }
    }
    
    handleInput() {
        if (this.keys['ArrowLeft'] || this.keys['a'] || this.keys['A']) {
            this.player.move('left', this.width, this.height);
        }
        if (this.keys['ArrowRight'] || this.keys['d'] || this.keys['D']) {
            this.player.move('right', this.width, this.height);
        }
        if (this.keys['ArrowUp'] || this.keys['w'] || this.keys['W']) {
            this.player.move('up', this.width, this.height);
        }
        if (this.keys['ArrowDown'] || this.keys['s'] || this.keys['S']) {
            this.player.move('down', this.width, this.height);
        }
    }
    
    updateLevel() {
        const newLevel = Math.floor(this.score / CONFIG.game.levelUpScore) + 1;
        if (newLevel > this.level) {
            this.level = newLevel;
            CONFIG.enemy.speed = 2 + (this.level * CONFIG.game.difficultyIncrease); 
        }
    }
    
    update() {
        if (this.paused || this.gameOver) return;
        
        const currentTime = Date.now();
        
        this.handleInput();
        
        this.player.update(this.width, this.height, currentTime);
        
        this.spawnEnemy(currentTime);
        this.spawnPowerUp(currentTime);
        
        this.enemies.forEach(enemy => {
            enemy.update(this.width, this.height, currentTime);
        });
        
        this.powerups.forEach(powerup => {
            powerup.update();
        });
        
        this.enemies = this.enemies.filter(enemy => {
            return enemy.alive && !enemy.isOffScreen(this.width, this.height);
        });
        
        this.powerups = this.powerups.filter(powerup => {
            return powerup.alive && !powerup.isOffScreen(this.width, this.height);
        });
        
        this.player.bullets = this.player.bullets.filter(b => b.alive);
        this.enemies.forEach(enemy => {
            enemy.bullets = enemy.bullets.filter(b => b.alive);
        });
        
        this.score = CollisionDetector.checkBulletEnemyCollisions(this.player, this.enemies, this.particleSystem, this.score);
        
        const hitByBullet = CollisionDetector.checkEnemyBulletPlayerCollisions(this.player, this.enemies);
        const hitByEnemy = CollisionDetector.checkEnemyPlayerCollisions(this.player, this.enemies);
        
        if (hitByBullet || hitByEnemy) {
            this.handlePlayerHit();
        }
        
        CollisionDetector.checkPowerUpPlayerCollisions(this.player, this.powerups, currentTime);
        
        this.particleSystem.update();
        this.updateLevel();
    }
    
    handlePlayerHit() {
        this.lives--;
        this.particleSystem.createExplosion(
            this.player.x + this.player.width / 2,
            this.player.y + this.player.height / 2
        );
        
        this.player.x = this.width / 2 - CONFIG.player.width / 2;
        this.player.y = this.height - 100;
        
        this.enemies = [];
        this.player.bullets = [];
        
        if (this.lives <= 0) {
            this.gameOver = true;
        }
    }
    
    draw() {
        this.ctx.fillStyle = '#000000';
        this.ctx.fillRect(0, 0, this.width, this.height);
        
        this.ctx.fillStyle = '#ffffff';
        for(let i=0; i<20; i++) {
             let x = (Date.now() / 50 * (i+1) + i*100) % this.width;
             let y = (i * 40) % this.height;
             this.ctx.fillRect(x, y, 2, 2);
        }

        this.player.draw(this.ctx);
        
        this.enemies.forEach(enemy => enemy.draw(this.ctx));
        this.powerups.forEach(powerup => powerup.draw(this.ctx));
        this.particleSystem.draw(this.ctx);
        
        if (this.paused) {
            this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
            this.ctx.fillRect(0, 0, this.width, this.height);
            this.ctx.fillStyle = '#ffffff';
            this.ctx.font = '30px Arial';
            this.ctx.textAlign = 'center';
            this.ctx.fillText('PAUSED', this.width / 2, this.height / 2);
        }
    }
}
(endcontenu)
│   │
│   ├── main.js (begincontenu)
document.addEventListener('DOMContentLoaded', () => {
    const canvas = document.getElementById('gameCanvas');
    const scoreEl = document.getElementById('score');
    const livesEl = document.getElementById('lives');
    const levelEl = document.getElementById('level');
    
    const startBtn = document.getElementById('startBtn');
    const pauseBtn = document.getElementById('pauseBtn');
    const restartBtn = document.getElementById('restartBtn');
    
    const gameOverModal = document.getElementById('gameOverModal');
    const finalScoreEl = document.getElementById('finalScore');
    const finalLevelEl = document.getElementById('finalLevel');
    const playAgainBtn = document.getElementById('playAgainBtn');
    
    let game = null;
    let animationId = null;
    let isGameRunning = false;

    function initGame() {
        game = new Game(canvas);
        updateUI();
        startBtn.disabled = true;
        pauseBtn.disabled = false;
        restartBtn.disabled = false;
        gameOverModal.classList.add('hidden');
        isGameRunning = true;
        gameLoop();
    }

    function gameLoop() {
        if (!isGameRunning) return;

        game.update();
        game.draw();
        updateUI();

        if (game.gameOver) {
            handleGameOver();
        } else {
            animationId = requestAnimationFrame(gameLoop);
        }
    }

    function updateUI() {
        if (!game) return;
        scoreEl.textContent = game.score;
        livesEl.textContent = game.lives;
        levelEl.textContent = game.level;
    }

    function handleGameOver() {
        isGameRunning = false;
        cancelAnimationFrame(animationId);
        finalScoreEl.textContent = game.score;
        finalLevelEl.textContent = game.level;
        gameOverModal.classList.remove('hidden');
        
        pauseBtn.disabled = true;
        restartBtn.disabled = true;
    }

    startBtn.addEventListener('click', () => {
        if (!isGameRunning) initGame();
    });

    pauseBtn.addEventListener('click', () => {
        if (game && !game.gameOver) {
            game.paused = !game.paused;
            pauseBtn.textContent = game.paused ? 'Resume' : 'Pause';
        }
    });

    restartBtn.addEventListener('click', () => {
        if (animationId) cancelAnimationFrame(animationId);
        initGame();
        pauseBtn.textContent = 'Pause';
    });

    playAgainBtn.addEventListener('click', () => {
        initGame();
        pauseBtn.textContent = 'Pause';
    });
});
(endcontenu)

Total length: ~750 lines • Uses mkarchi 0.1.7 syntax tags