about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--html/fps/game.js468
-rw-r--r--html/fps/index.html23
-rw-r--r--html/space/game.js8
-rw-r--r--html/space/gameState.js71
-rw-r--r--html/space/index.html1
-rw-r--r--html/space/input.js110
-rw-r--r--html/space/physics.js279
-rw-r--r--html/space/renderer.js202
8 files changed, 924 insertions, 238 deletions
diff --git a/html/fps/game.js b/html/fps/game.js
new file mode 100644
index 0000000..0a18d79
--- /dev/null
+++ b/html/fps/game.js
@@ -0,0 +1,468 @@
+// Game state management
+const GameState = {
+    player: {
+        x: 0,
+        y: 0,
+        angle: 0,
+        health: 100,
+        ammo: 10,
+        score: 0
+    },
+    level: {
+        width: 32,
+        height: 32,
+        map: [],
+        flag: { x: 0, y: 0 }
+    },
+    enemies: [],
+    items: [],
+    isGameOver: false,
+    gun: {
+        recoil: 0,
+        lastShot: 0,
+        muzzleFlash: 0
+    },
+    shots: []
+};
+
+// Level generation using a simple maze algorithm
+const generateLevel = () => {
+    const map = Array(GameState.level.height).fill().map(() => 
+        Array(GameState.level.width).fill(1)
+    );
+    
+    // Create a larger starting room
+    const startRoomSize = 5;
+    for (let y = 1; y < startRoomSize; y++) {
+        for (let x = 1; x < startRoomSize; x++) {
+            map[y][x] = 0;
+        }
+    }
+    
+    // Simple maze generation using depth-first search
+    const carveMaze = (x, y) => {
+        map[y][x] = 0;
+        const directions = [
+            [0, -2], [2, 0], [0, 2], [-2, 0]
+        ].sort(() => Math.random() - 0.5);
+        
+        for (const [dx, dy] of directions) {
+            const nx = x + dx;
+            const ny = y + dy;
+            if (nx > 0 && nx < GameState.level.width - 1 &&
+                ny > 0 && ny < GameState.level.height - 1 &&
+                map[ny][nx] === 1) {
+                map[y + dy/2][x + dx/2] = 0;
+                carveMaze(nx, ny);
+            }
+        }
+    };
+    
+    // Start maze generation from the edge of the starting room
+    carveMaze(startRoomSize, startRoomSize);
+    
+    // Place flag in a random open space (not in starting room)
+    const openSpaces = [];
+    for (let y = 0; y < GameState.level.height; y++) {
+        for (let x = 0; x < GameState.level.width; x++) {
+            if (map[y][x] === 0 && (x >= startRoomSize || y >= startRoomSize)) {
+                openSpaces.push({x, y});
+            }
+        }
+    }
+    const flagPos = openSpaces[Math.floor(Math.random() * openSpaces.length)];
+    GameState.level.flag = flagPos;
+    
+    // Place enemies in open spaces (not in starting room)
+    GameState.enemies = [];
+    for (let i = 0; i < 5; i++) {
+        const pos = openSpaces[Math.floor(Math.random() * openSpaces.length)];
+        GameState.enemies.push({
+            x: pos.x,
+            y: pos.y,
+            health: Math.floor(Math.random() * 4) + 2
+        });
+    }
+    
+    // Place items in open spaces (not in starting room)
+    GameState.items = [];
+    for (let i = 0; i < 10; i++) {
+        const pos = openSpaces[Math.floor(Math.random() * openSpaces.length)];
+        GameState.items.push({
+            x: pos.x,
+            y: pos.y,
+            type: Math.random() > 0.5 ? 'ammo' : 'health'
+        });
+    }
+    
+    GameState.level.map = map;
+    GameState.player.x = startRoomSize/2;
+    GameState.player.y = startRoomSize/2;
+    GameState.player.angle = 0;
+};
+
+// Player movement and controls
+const handlePlayerMovement = (keys) => {
+    const moveSpeed = 0.1;
+    const rotateSpeed = 0.05;
+    
+    if (keys.w) {
+        GameState.player.x += Math.sin(GameState.player.angle) * moveSpeed;
+        GameState.player.y += Math.cos(GameState.player.angle) * moveSpeed;
+    }
+    if (keys.s) {
+        GameState.player.x -= Math.sin(GameState.player.angle) * moveSpeed;
+        GameState.player.y -= Math.cos(GameState.player.angle) * moveSpeed;
+    }
+    if (keys.a) {
+        GameState.player.x -= Math.sin(GameState.player.angle - Math.PI/2) * moveSpeed;
+        GameState.player.y -= Math.cos(GameState.player.angle - Math.PI/2) * moveSpeed;
+    }
+    if (keys.d) {
+        GameState.player.x += Math.sin(GameState.player.angle - Math.PI/2) * moveSpeed;
+        GameState.player.y += Math.cos(GameState.player.angle - Math.PI/2) * moveSpeed;
+    }
+};
+
+// Enemy AI
+const updateEnemies = () => {
+    GameState.enemies = GameState.enemies.map(enemy => {
+        if (enemy.health <= 0) return null;
+        
+        const dx = GameState.player.x - enemy.x;
+        const dy = GameState.player.y - enemy.y;
+        const dist = Math.sqrt(dx * dx + dy * dy);
+        
+        if (dist < 0.5) {
+            GameState.player.health -= 10;
+            if (GameState.player.health <= 0) {
+                GameState.isGameOver = true;
+            }
+        } else if (dist < 5) {
+            // Check if path to player is clear
+            const steps = 10;
+            let canMove = true;
+            for (let i = 1; i <= steps; i++) {
+                const testX = enemy.x + (dx / dist) * (i / steps);
+                const testY = enemy.y + (dy / dist) * (i / steps);
+                if (GameState.level.map[Math.floor(testY)][Math.floor(testX)] === 1) {
+                    canMove = false;
+                    break;
+                }
+            }
+            
+            if (canMove) {
+                enemy.x += dx / dist * 0.05;
+                enemy.y += dy / dist * 0.05;
+            }
+        }
+        
+        return enemy;
+    }).filter(Boolean);
+};
+
+// Collision detection
+const checkCollisions = () => {
+    // Wall collisions with improved precision
+    const playerX = GameState.player.x;
+    const playerY = GameState.player.y;
+    const nextX = playerX + Math.sin(GameState.player.angle) * 0.1;
+    const nextY = playerY + Math.cos(GameState.player.angle) * 0.1;
+    
+    // Check all four corners of the player's collision box
+    const checkPoint = (x, y) => {
+        const gridX = Math.floor(x);
+        const gridY = Math.floor(y);
+        return GameState.level.map[gridY][gridX] === 1;
+    };
+    
+    const collisionBox = 0.2; // Player collision box size
+    
+    if (checkPoint(playerX + collisionBox, playerY + collisionBox) ||
+        checkPoint(playerX + collisionBox, playerY - collisionBox) ||
+        checkPoint(playerX - collisionBox, playerY + collisionBox) ||
+        checkPoint(playerX - collisionBox, playerY - collisionBox)) {
+        // Push player back to last valid position
+        GameState.player.x = Math.floor(GameState.player.x) + 0.5;
+        GameState.player.y = Math.floor(GameState.player.y) + 0.5;
+    }
+    
+    // Item collection
+    GameState.items = GameState.items.filter(item => {
+        const dx = GameState.player.x - item.x;
+        const dy = GameState.player.y - item.y;
+        if (Math.sqrt(dx * dx + dy * dy) < 0.5) {
+            if (item.type === 'ammo') {
+                GameState.player.ammo += 5;
+            } else {
+                GameState.player.health = Math.min(100, GameState.player.health + 25);
+            }
+            return false;
+        }
+        return true;
+    });
+    
+    // Flag collection
+    const dx = GameState.player.x - GameState.level.flag.x;
+    const dy = GameState.player.y - GameState.level.flag.y;
+    if (Math.sqrt(dx * dx + dy * dy) < 0.5) {
+        GameState.player.score++;
+        generateLevel();
+    }
+};
+
+// Rendering system
+const render = (ctx) => {
+    const canvas = ctx.canvas;
+    const width = canvas.width;
+    const height = canvas.height;
+    
+    // Clear screen
+    ctx.fillStyle = '#000';
+    ctx.fillRect(0, 0, width, height);
+    
+    // Draw ceiling
+    ctx.fillStyle = '#1a1a4a';
+    ctx.fillRect(0, 0, width, height/2);
+    
+    // Draw floor
+    ctx.fillStyle = '#4a2a00';
+    ctx.fillRect(0, height/2, width, height/2);
+    
+    // Draw walls and enemies using ray casting
+    const fov = Math.PI / 3;
+    const numRays = width;
+    const rayResults = [];
+    
+    for (let i = 0; i < numRays; i++) {
+        const rayAngle = GameState.player.angle - fov/2 + fov * i / numRays;
+        let distance = 0;
+        let hit = false;
+        let hitEnemy = null;
+        
+        while (!hit && distance < 20) {
+            distance += 0.1;
+            const testX = GameState.player.x + Math.sin(rayAngle) * distance;
+            const testY = GameState.player.y + Math.cos(rayAngle) * distance;
+            
+            // Check for wall hits
+            if (GameState.level.map[Math.floor(testY)][Math.floor(testX)] === 1) {
+                hit = true;
+            }
+            
+            // Check for enemy hits
+            if (!hit) {
+                hitEnemy = GameState.enemies.find(enemy => {
+                    const dx = testX - enemy.x;
+                    const dy = testY - enemy.y;
+                    return Math.sqrt(dx * dx + dy * dy) < 0.5;
+                });
+                if (hitEnemy) {
+                    hit = true;
+                }
+            }
+        }
+        
+        rayResults.push({
+            distance,
+            hitEnemy,
+            angle: rayAngle
+        });
+        
+        const wallHeight = height / (distance * Math.cos(rayAngle - GameState.player.angle));
+        const brightness = Math.max(0, 1 - distance / 20);
+        
+        if (hitEnemy) {
+            // Draw enemy
+            const enemyColor = Math.floor(brightness * 255);
+            ctx.fillStyle = `rgb(${enemyColor}, 0, 0)`;
+            ctx.fillRect(i, height/2 - wallHeight/2, 1, wallHeight);
+        } else {
+            // Draw wall
+            const wallColor = Math.floor(brightness * 100);
+            ctx.fillStyle = `rgb(0, ${wallColor}, 0)`;
+            ctx.fillRect(i, height/2 - wallHeight/2, 1, wallHeight);
+        }
+    }
+    
+    // Draw shots
+    const now = Date.now();
+    GameState.shots = GameState.shots.filter(shot => {
+        const age = now - shot.time;
+        if (age > 200) return false; // Remove shots older than 200ms
+        
+        const progress = age / 200;
+        const distance = progress * 20;
+        const x = GameState.player.x + Math.sin(shot.angle) * distance;
+        const y = GameState.player.y + Math.cos(shot.angle) * distance;
+        
+        // Convert world position to screen position
+        const dx = x - GameState.player.x;
+        const dy = y - GameState.player.y;
+        const angle = Math.atan2(dx, dy) - GameState.player.angle;
+        const screenX = (angle / fov + 0.5) * width;
+        
+        if (screenX >= 0 && screenX < width) {
+            ctx.fillStyle = '#ffff00';
+            ctx.fillRect(screenX, height/2, 2, 2);
+        }
+        
+        return true;
+    });
+    
+    // Draw gun
+    const gunY = height - 150;
+    const gunX = width/2;
+    const recoilOffset = Math.sin(GameState.gun.recoil * Math.PI) * 50; // Increased recoil range
+    
+    // Only draw gun if it's not in full recoil
+    if (GameState.gun.recoil < 0.8) {
+        // Gun body
+        ctx.fillStyle = '#333';
+        ctx.fillRect(gunX - 30, gunY + recoilOffset, 60, 90);
+        
+        // Gun barrel
+        ctx.fillStyle = '#222';
+        ctx.fillRect(gunX - 8, gunY - 30 + recoilOffset, 16, 60);
+        
+        // Muzzle flash
+        if (GameState.gun.muzzleFlash > 0) {
+            const flashSize = GameState.gun.muzzleFlash * 30;
+            ctx.fillStyle = `rgba(255, 255, 0, ${GameState.gun.muzzleFlash})`;
+            ctx.beginPath();
+            ctx.arc(gunX, gunY - 30 + recoilOffset, flashSize, 0, Math.PI * 2);
+            ctx.fill();
+        }
+    }
+    
+    // Draw crosshair
+    ctx.fillStyle = '#fff';
+    ctx.fillRect(width/2 - 5, height/2, 10, 1);
+    ctx.fillRect(width/2, height/2 - 5, 1, 10);
+    
+    // Draw HUD - only canvas-based
+    ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
+    ctx.fillRect(10, 10, 200, 100);
+    
+    ctx.fillStyle = '#fff';
+    ctx.font = '24px monospace';
+    ctx.fillText(`Health: ${GameState.player.health}`, 20, 45);
+    ctx.fillText(`Ammo: ${GameState.player.ammo}`, 20, 80);
+    ctx.fillText(`Score: ${GameState.player.score}`, 20, 115);
+    
+    // Draw enemy health bars
+    GameState.enemies.forEach(enemy => {
+        const dx = enemy.x - GameState.player.x;
+        const dy = enemy.y - GameState.player.y;
+        const angle = Math.atan2(dx, dy) - GameState.player.angle;
+        const screenX = (angle / fov + 0.5) * width;
+        
+        if (screenX >= 0 && screenX < width) {
+            const distance = Math.sqrt(dx * dx + dy * dy);
+            const height = canvas.height / (distance * Math.cos(angle));
+            const y = canvas.height/2 - height/2;
+            
+            // Health bar background
+            ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
+            ctx.fillRect(screenX - 10, y - 20, 20, 5);
+            
+            // Health bar
+            const healthPercent = enemy.health / 5; // Assuming max health is 5
+            ctx.fillStyle = `rgb(${255 * (1 - healthPercent)}, ${255 * healthPercent}, 0)`;
+            ctx.fillRect(screenX - 10, y - 20, 20 * healthPercent, 5);
+        }
+    });
+};
+
+// Game loop
+const gameLoop = (ctx) => {
+    if (GameState.isGameOver) {
+        ctx.fillStyle = '#fff';
+        ctx.font = '48px monospace';
+        ctx.fillText('GAME OVER', ctx.canvas.width/2 - 100, ctx.canvas.height/2);
+        return;
+    }
+    
+    // Update gun recoil and muzzle flash
+    if (GameState.gun.recoil > 0) {
+        GameState.gun.recoil -= 0.1;
+    }
+    if (GameState.gun.muzzleFlash > 0) {
+        GameState.gun.muzzleFlash -= 0.2;
+    }
+    
+    handlePlayerMovement(keys);
+    updateEnemies();
+    checkCollisions();
+    render(ctx);
+    
+    requestAnimationFrame(() => gameLoop(ctx));
+};
+
+// Input handling
+const keys = { w: false, a: false, s: false, d: false };
+document.addEventListener('keydown', e => {
+    if (e.key.toLowerCase() in keys) keys[e.key.toLowerCase()] = true;
+});
+document.addEventListener('keyup', e => {
+    if (e.key.toLowerCase() in keys) keys[e.key.toLowerCase()] = false;
+});
+
+document.addEventListener('mousemove', e => {
+    GameState.player.angle += e.movementX * 0.01;
+});
+
+document.addEventListener('click', () => {
+    if (GameState.player.ammo > 0) {
+        GameState.player.ammo--;
+        GameState.gun.recoil = 1;
+        GameState.gun.muzzleFlash = 1;
+        GameState.shots.push({
+            time: Date.now(),
+            angle: GameState.player.angle
+        });
+        
+        // Check for enemy hits with wall collision
+        const fov = Math.PI / 3;
+        const rayAngle = GameState.player.angle;
+        let distance = 0;
+        let hitEnemy = null;
+        let hitWall = false;
+        
+        while (!hitEnemy && !hitWall && distance < 20) {
+            distance += 0.1;
+            const testX = GameState.player.x + Math.sin(rayAngle) * distance;
+            const testY = GameState.player.y + Math.cos(rayAngle) * distance;
+            
+            // Check for wall hit first
+            if (GameState.level.map[Math.floor(testY)][Math.floor(testX)] === 1) {
+                hitWall = true;
+                break;
+            }
+            
+            // Then check for enemy hit
+            hitEnemy = GameState.enemies.find(enemy => {
+                const dx = testX - enemy.x;
+                const dy = testY - enemy.y;
+                return Math.sqrt(dx * dx + dy * dy) < 0.5;
+            });
+        }
+        
+        if (hitEnemy) {
+            hitEnemy.health--;
+        }
+    }
+});
+
+// Initialize game
+const init = () => {
+    const canvas = document.getElementById('gameCanvas');
+    canvas.width = window.innerWidth;
+    canvas.height = window.innerHeight;
+    const ctx = canvas.getContext('2d');
+    
+    generateLevel();
+    gameLoop(ctx);
+};
+
+init();
diff --git a/html/fps/index.html b/html/fps/index.html
new file mode 100644
index 0000000..a025fae
--- /dev/null
+++ b/html/fps/index.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Procedural FPS</title>
+    <style>
+        body {
+            margin: 0;
+            padding: 0;
+            overflow: hidden;
+            background-color: #000;
+        }
+        canvas {
+            display: block;
+        }
+    </style>
+</head>
+<body>
+    <canvas id="gameCanvas"></canvas>
+    <script type="module" src="game.js"></script>
+</body>
+</html>
diff --git a/html/space/game.js b/html/space/game.js
index 0a106cf..ecd7abc 100644
--- a/html/space/game.js
+++ b/html/space/game.js
@@ -10,10 +10,12 @@ let isRunning = true;
 
 // Initialize all systems
 function init() {
+    console.log('Initializing game...');
     initRenderer();
     initInput();
     initPhysics();
     initGameState();
+    console.log('Game initialized');
 }
 
 // Main game loop using requestAnimationFrame
@@ -29,9 +31,15 @@ function gameLoop(timestamp) {
     updateGameState(deltaTime);
     render();
 
+    // Debug output
+    if (Math.random() < 0.01) { // Only log occasionally to avoid spam
+        console.log('Game loop running, deltaTime:', deltaTime);
+    }
+
     requestAnimationFrame(gameLoop);
 }
 
 // Start the game
+console.log('Starting game...');
 init();
 requestAnimationFrame(gameLoop);
\ No newline at end of file
diff --git a/html/space/gameState.js b/html/space/gameState.js
index 85f56b0..620bc1f 100644
--- a/html/space/gameState.js
+++ b/html/space/gameState.js
@@ -6,11 +6,14 @@ import { getPlayerState } from './physics.js';
 const planets = [];
 const enemyShips = [];
 const projectiles = [];
+let lastEnemySpawn = 0;
 
 // Space dimensions
 const SPACE_SIZE = 10000;  // Increased from implicit 2000
 const PLANET_DISTANCE = 5000;  // Increased from 1000
 const ENEMY_SPAWN_DISTANCE = 3000;  // Increased from 500
+const ENEMY_SPAWN_INTERVAL = 5000; // 5 seconds
+const MAX_ENEMIES = 5;
 
 // Initialize game state
 export function initGameState() {
@@ -27,6 +30,11 @@ export function initGameState() {
         color: '#e74c3c'
     });
 
+    // Reset other state
+    enemyShips.length = 0;
+    projectiles.length = 0;
+    lastEnemySpawn = Date.now();
+
     // Create initial enemy ships
     for (let i = 0; i < 5; i++) {
         createEnemyShip();
@@ -56,8 +64,28 @@ function createEnemyShip() {
 
 // Update game state
 export function updateGameState(deltaTime) {
+    const currentTime = Date.now();
     const player = getPlayerState();
+    
+    // Spawn enemies
+    if (currentTime - lastEnemySpawn > ENEMY_SPAWN_INTERVAL && 
+        enemyShips.length < MAX_ENEMIES) {
+        spawnEnemy();
+        lastEnemySpawn = currentTime;
+    }
+    
+    // Update projectiles
+    projectiles.forEach((projectile, index) => {
+        projectile.position.x += projectile.velocity.x * deltaTime;
+        projectile.position.y += projectile.velocity.y * deltaTime;
+        projectile.position.z += projectile.velocity.z * deltaTime;
 
+        // Remove if too old
+        if (currentTime - projectile.createdAt > 5000) {
+            projectiles.splice(index, 1);
+        }
+    });
+    
     // Update enemy ships
     enemyShips.forEach((ship, index) => {
         // Move ships
@@ -85,28 +113,10 @@ export function updateGameState(deltaTime) {
     if (inputState.fireSecondary) {
         createProjectile('secondary');
     }
-
-    // Update projectiles
-    projectiles.forEach((projectile, index) => {
-        projectile.position.x += projectile.velocity.x * deltaTime;
-        projectile.position.y += projectile.velocity.y * deltaTime;
-        projectile.position.z += projectile.velocity.z * deltaTime;
-
-        // Remove projectiles that are too far away
-        const distance = Math.sqrt(
-            Math.pow(projectile.position.x - player.position.x, 2) +
-            Math.pow(projectile.position.y - player.position.y, 2) +
-            Math.pow(projectile.position.z - player.position.z, 2)
-        );
-
-        if (distance > SPACE_SIZE/2) {
-            projectiles.splice(index, 1);
-        }
-    });
 }
 
 // Create a new projectile
-function createProjectile(type) {
+export function createProjectile(type) {
     const player = getPlayerState();
     const speed = type === 'primary' ? 10 : 7.5;  // Reduced from 20/15
     const damage = type === 'primary' ? 25 : 10;
@@ -124,7 +134,28 @@ function createProjectile(type) {
             y: sinX * speed,
             z: cosY * cosX * speed
         },
-        damage
+        damage,
+        createdAt: Date.now()
+    });
+}
+
+// Spawn a new enemy ship
+function spawnEnemy() {
+    const angle = Math.random() * Math.PI * 2;
+    const distance = ENEMY_SPAWN_DISTANCE;
+    
+    enemyShips.push({
+        position: {
+            x: Math.cos(angle) * distance,
+            y: 0,
+            z: Math.sin(angle) * distance
+        },
+        velocity: {
+            x: (Math.random() - 0.5) * 0.5,
+            y: (Math.random() - 0.5) * 0.5,
+            z: (Math.random() - 0.5) * 0.5
+        },
+        health: 100
     });
 }
 
diff --git a/html/space/index.html b/html/space/index.html
index 52dffa0..9db977d 100644
--- a/html/space/index.html
+++ b/html/space/index.html
@@ -16,6 +16,7 @@
     </style>
 </head>
 <body>
+    <canvas id="gameCanvas"></canvas>
     <script type="module" src="game.js"></script>
 </body>
 </html>
\ No newline at end of file
diff --git a/html/space/input.js b/html/space/input.js
index dadecb9..19ea56c 100644
--- a/html/space/input.js
+++ b/html/space/input.js
@@ -1,16 +1,9 @@
-// Input module using keyboard controls
-const keys = {
-    w: false,
-    a: false,
-    s: false,
-    d: false,
-    ArrowUp: false,
-    ArrowDown: false,
-    ArrowLeft: false,
-    ArrowRight: false,
-    ' ': false, // space
-    e: false
-};
+// Input handling module
+import { updatePlayerControls } from './physics.js';
+
+let keys = {};
+let mouseX = 0;
+let mouseY = 0;
 
 // Input state that other modules can read
 export const inputState = {
@@ -24,48 +17,67 @@ export const inputState = {
 
 // Initialize input handlers
 export function initInput() {
-    window.addEventListener('keydown', handleKeyDown);
-    window.addEventListener('keyup', handleKeyUp);
-}
+    // Keyboard event listeners
+    document.addEventListener('keydown', (e) => {
+        keys[e.key.toLowerCase()] = true;
+    });
 
-// Update input state based on current key presses
-export function updateInput() {
-    // Reset input state
-    inputState.thrust = 0;
-    inputState.strafe = 0;
-    inputState.yaw = 0;
-    inputState.pitch = 0;
-    inputState.firePrimary = false;
-    inputState.fireSecondary = false;
+    document.addEventListener('keyup', (e) => {
+        keys[e.key.toLowerCase()] = false;
+    });
 
-    // Thrust controls (W/S)
-    if (keys.w) inputState.thrust = 1;   // Forward thrust
-    if (keys.s) inputState.thrust = -1;  // Backward thrust
+    // Mouse movement for heading
+    document.addEventListener('mousemove', (e) => {
+        // Calculate mouse position relative to center of canvas
+        const canvas = document.querySelector('canvas');
+        const rect = canvas.getBoundingClientRect();
+        const centerX = rect.left + rect.width / 2;
+        const centerY = rect.top + rect.height / 2;
+        
+        mouseX = (e.clientX - centerX) / (rect.width / 2);
+        mouseY = (e.clientY - centerY) / (rect.height / 2);
+    });
 
-    // Strafe controls (A/D)
-    if (keys.a) inputState.strafe = -1;  // Left strafe
-    if (keys.d) inputState.strafe = 1;   // Right strafe
+    // Mouse click for primary weapon
+    document.addEventListener('mousedown', (e) => {
+        if (e.button === 0) { // Left click
+            keys['fire'] = true;
+        }
+    });
 
-    // Rotation controls (Arrow keys)
-    if (keys.ArrowLeft) inputState.yaw = -1;
-    if (keys.ArrowRight) inputState.yaw = 1;
-    if (keys.ArrowUp) inputState.pitch = -1;
-    if (keys.ArrowDown) inputState.pitch = 1;
+    document.addEventListener('mouseup', (e) => {
+        if (e.button === 0) { // Left click
+            keys['fire'] = false;
+        }
+    });
 
-    // Weapons
-    if (keys[' ']) inputState.firePrimary = true;
-    if (keys.e) inputState.fireSecondary = true;
-}
+    // E key for secondary weapon
+    document.addEventListener('keydown', (e) => {
+        if (e.key.toLowerCase() === 'e') {
+            keys['secondary'] = true;
+        }
+    });
 
-// Event handlers
-function handleKeyDown(e) {
-    if (keys.hasOwnProperty(e.key)) {
-        keys[e.key] = true;
-    }
+    document.addEventListener('keyup', (e) => {
+        if (e.key.toLowerCase() === 'e') {
+            keys['secondary'] = false;
+        }
+    });
 }
 
-function handleKeyUp(e) {
-    if (keys.hasOwnProperty(e.key)) {
-        keys[e.key] = false;
-    }
+// Update controls based on current input state
+export function updateInput() {
+    const controls = {
+        thrust: keys[' '] || false, // Space bar for thrust
+        up: keys['w'] || false,     // W for upward strafe
+        down: keys['s'] || false,   // S for downward strafe
+        left: keys['a'] || false,   // A for left strafe
+        right: keys['d'] || false,  // D for right strafe
+        fire: keys['fire'] || false,
+        secondary: keys['secondary'] || false,
+        mouseX,
+        mouseY
+    };
+
+    updatePlayerControls(controls);
 } 
\ No newline at end of file
diff --git a/html/space/physics.js b/html/space/physics.js
index 6b71601..d4dfe55 100644
--- a/html/space/physics.js
+++ b/html/space/physics.js
@@ -1,5 +1,6 @@
 // Physics module for handling movement and collisions
 import { inputState } from './input.js';
+import { createProjectile } from './gameState.js';
 
 // Constants
 const MAX_THRUST = 0.5;        // Reduced from 2
@@ -8,113 +9,245 @@ const DECELERATION = 0.001;    // Reduced from 0.01
 const BASE_ROTATION_SPEED = 0.001;  // Reduced from 0.005
 const ROTATION_ACCELERATION = 0.0005; // Reduced from 0.002
 const ROTATION_DECELERATION = 0.0002; // Reduced from 0.001
+const MOUSE_SENSITIVITY = 0.03; // Increased from 0.01 for sharper turns
+const MAX_SPEED = 1.0; // Maximum speed in any direction
+
+// Weapon constants
+export const PRIMARY_COOLDOWN = 100; // ms between primary shots
+export const SECONDARY_COOLDOWN = 2000; // ms between secondary shots
+export const PRIMARY_BURST_COUNT = 3; // Number of shots in primary burst
+export const PRIMARY_BURST_DELAY = 50; // ms between burst shots
 
 // Player state
-const player = {
+let playerState = {
     position: { x: 0, y: 0, z: 0 },
     velocity: { x: 0, y: 0, z: 0 },
-    rotation: { x: 0, y: 0, z: 0 },
-    rotationSpeed: { x: 0, y: 0 }  // Added for smooth rotation
+    rotation: { x: 0, y: 0 },
+    thrust: 0,
+    strafe: 0,
+    weapons: {
+        primary: {
+            lastFired: 0,
+            burstCount: 0,
+            burstTimer: 0
+        },
+        secondary: {
+            lastFired: 0
+        }
+    }
 };
 
 // Initialize physics
 export function initPhysics() {
     // Reset player state
-    player.position = { x: 0, y: 0, z: 0 };
-    player.velocity = { x: 0, y: 0, z: 0 };
-    player.rotation = { x: 0, y: 0, z: 0 };
-    player.rotationSpeed = { x: 0, y: 0 };
+    playerState.position = { x: 0, y: 0, z: 0 };
+    playerState.velocity = { x: 0, y: 0, z: 0 };
+    playerState.rotation = { x: 0, y: 0 };
+    playerState.thrust = 0;
+    playerState.strafe = 0;
 }
 
-// Helper function to apply force in a direction
-function applyForce(direction, magnitude, deltaTime) {
-    const force = {
-        x: direction.x * magnitude * deltaTime,
-        y: direction.y * magnitude * deltaTime,
-        z: direction.z * magnitude * deltaTime
-    };
-    
-    player.velocity.x += force.x;
-    player.velocity.y += force.y;
-    player.velocity.z += force.z;
+// Helper function to limit speed in a direction
+function limitSpeed(velocity, maxSpeed) {
+    const speed = Math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y + velocity.z * velocity.z);
+    if (speed > maxSpeed) {
+        const scale = maxSpeed / speed;
+        velocity.x *= scale;
+        velocity.y *= scale;
+        velocity.z *= scale;
+    }
 }
 
-// Update physics
-export function updatePhysics(deltaTime) {
-    // Update rotation speed based on input
-    if (inputState.yaw !== 0) {
-        player.rotationSpeed.y += inputState.yaw * ROTATION_ACCELERATION * deltaTime;
+// Update player controls
+export function updatePlayerControls(controls) {
+    // Handle thrust (space bar)
+    if (controls.thrust) {
+        playerState.thrust = Math.min(playerState.thrust + THRUST_ACCELERATION, MAX_THRUST);
     } else {
-        // Smoothly decelerate rotation
-        player.rotationSpeed.y *= (1 - ROTATION_DECELERATION * deltaTime);
+        // Apply deceleration when no thrust input
+        if (playerState.thrust > 0) {
+            playerState.thrust = Math.max(playerState.thrust - DECELERATION, 0);
+        }
     }
 
-    if (inputState.pitch !== 0) {
-        player.rotationSpeed.x += inputState.pitch * ROTATION_ACCELERATION * deltaTime;
+    // Handle vertical strafing (W/S)
+    if (controls.up) {
+        playerState.verticalStrafe = Math.min(playerState.verticalStrafe + THRUST_ACCELERATION, MAX_THRUST);
+    } else if (controls.down) {
+        playerState.verticalStrafe = Math.max(playerState.verticalStrafe - THRUST_ACCELERATION, -MAX_THRUST);
     } else {
-        // Smoothly decelerate rotation
-        player.rotationSpeed.x *= (1 - ROTATION_DECELERATION * deltaTime);
+        // Apply deceleration when no vertical strafe input
+        if (playerState.verticalStrafe > 0) {
+            playerState.verticalStrafe = Math.max(playerState.verticalStrafe - DECELERATION, 0);
+        } else if (playerState.verticalStrafe < 0) {
+            playerState.verticalStrafe = Math.min(playerState.verticalStrafe + DECELERATION, 0);
+        }
+    }
+
+    // Handle horizontal strafing (A/D)
+    if (controls.left) {
+        playerState.horizontalStrafe = Math.min(playerState.horizontalStrafe + THRUST_ACCELERATION, MAX_THRUST);
+    } else if (controls.right) {
+        playerState.horizontalStrafe = Math.max(playerState.horizontalStrafe - THRUST_ACCELERATION, -MAX_THRUST);
+    } else {
+        // Apply deceleration when no horizontal strafe input
+        if (playerState.horizontalStrafe > 0) {
+            playerState.horizontalStrafe = Math.max(playerState.horizontalStrafe - DECELERATION, 0);
+        } else if (playerState.horizontalStrafe < 0) {
+            playerState.horizontalStrafe = Math.min(playerState.horizontalStrafe + DECELERATION, 0);
+        }
+    }
+
+    // Handle mouse-based rotation with smoothing
+    const targetRotationY = controls.mouseX * MOUSE_SENSITIVITY;
+    const targetRotationX = controls.mouseY * MOUSE_SENSITIVITY;
+    
+    // Smooth rotation using lerp with faster response
+    playerState.rotation.y += (targetRotationY - playerState.rotation.y) * 0.2;
+    playerState.rotation.x += (targetRotationX - playerState.rotation.x) * 0.2;
+
+    // Clamp pitch rotation
+    playerState.rotation.x = Math.max(-Math.PI/2, Math.min(Math.PI/2, playerState.rotation.x));
+
+    // Handle weapons with cooldowns
+    const currentTime = Date.now();
+    
+    // Primary weapon (burst fire)
+    if (controls.fire) {
+        const primary = playerState.weapons.primary;
+        if (currentTime - primary.lastFired >= PRIMARY_COOLDOWN && primary.burstCount === 0) {
+            primary.burstCount = PRIMARY_BURST_COUNT;
+            primary.burstTimer = currentTime;
+            firePrimaryWeapon();
+            primary.lastFired = currentTime;
+        }
     }
 
-    // Apply rotation based on current rotation speed
-    player.rotation.y += player.rotationSpeed.y * BASE_ROTATION_SPEED * deltaTime;
-    player.rotation.x += player.rotationSpeed.x * BASE_ROTATION_SPEED * deltaTime;
+    // Secondary weapon (single shot with cooldown)
+    if (controls.secondary && currentTime - playerState.weapons.secondary.lastFired >= SECONDARY_COOLDOWN) {
+        fireSecondaryWeapon();
+        playerState.weapons.secondary.lastFired = currentTime;
+    }
 
-    // Calculate forward and right vectors based on current rotation
-    const cosY = Math.cos(player.rotation.y);
-    const sinY = Math.sin(player.rotation.y);
-    const cosX = Math.cos(player.rotation.x);
-    const sinX = Math.sin(player.rotation.x);
+    // Handle burst fire timing
+    const primary = playerState.weapons.primary;
+    if (primary.burstCount > 0 && currentTime - primary.burstTimer >= PRIMARY_BURST_DELAY) {
+        firePrimaryWeapon();
+        primary.burstCount--;
+        primary.burstTimer = currentTime;
+    }
+}
 
-    // Forward vector (in the direction the ship is facing)
+// Update physics
+export function updatePhysics(deltaTime) {
+    // Calculate forward and right vectors based on rotation
     const forward = {
-        x: sinY * cosX,
-        y: sinX,
-        z: cosY * cosX
+        x: Math.sin(playerState.rotation.y) * Math.cos(playerState.rotation.x),
+        y: -Math.sin(playerState.rotation.x),
+        z: Math.cos(playerState.rotation.y) * Math.cos(playerState.rotation.x)
     };
 
-    // Right vector (perpendicular to forward)
     const right = {
-        x: cosY,
+        x: Math.cos(playerState.rotation.y),
         y: 0,
-        z: -sinY
+        z: -Math.sin(playerState.rotation.y)
     };
 
-    // Apply thrust in the direction the ship is facing
-    if (inputState.thrust !== 0) {
-        applyForce(forward, inputState.thrust * THRUST_ACCELERATION, deltaTime);
-    }
+    const up = { x: 0, y: 1, z: 0 };
 
-    // Apply strafing force
-    if (inputState.strafe !== 0) {
-        applyForce(right, inputState.strafe * THRUST_ACCELERATION, deltaTime);
-    }
+    // Apply thrust in forward direction
+    const thrustVelocity = {
+        x: forward.x * playerState.thrust * deltaTime,
+        y: forward.y * playerState.thrust * deltaTime,
+        z: forward.z * playerState.thrust * deltaTime
+    };
 
-    // Apply damping to simulate space friction (very slight)
-    const currentSpeed = Math.sqrt(
-        player.velocity.x * player.velocity.x +
-        player.velocity.y * player.velocity.y +
-        player.velocity.z * player.velocity.z
-    );
-
-    if (currentSpeed > 0) {
-        const speedDamping = 1 - (DECELERATION * deltaTime);
-        player.velocity.x *= speedDamping;
-        player.velocity.y *= speedDamping;
-        player.velocity.z *= speedDamping;
-    }
+    // Apply horizontal strafe
+    const horizontalStrafeVelocity = {
+        x: right.x * playerState.horizontalStrafe * deltaTime,
+        y: 0,
+        z: right.z * playerState.horizontalStrafe * deltaTime
+    };
+
+    // Apply vertical strafe
+    const verticalStrafeVelocity = {
+        x: 0,
+        y: up.y * playerState.verticalStrafe * deltaTime,
+        z: 0
+    };
+
+    // Add velocities
+    playerState.velocity.x += thrustVelocity.x + horizontalStrafeVelocity.x + verticalStrafeVelocity.x;
+    playerState.velocity.y += thrustVelocity.y + horizontalStrafeVelocity.y + verticalStrafeVelocity.y;
+    playerState.velocity.z += thrustVelocity.z + horizontalStrafeVelocity.z + verticalStrafeVelocity.z;
+
+    // Limit total speed
+    limitSpeed(playerState.velocity, MAX_SPEED);
+
+    // Apply velocity to position
+    playerState.position.x += playerState.velocity.x * deltaTime;
+    playerState.position.y += playerState.velocity.y * deltaTime;
+    playerState.position.z += playerState.velocity.z * deltaTime;
+
+    // Apply friction/drag
+    const drag = 0.99;
+    playerState.velocity.x *= drag;
+    playerState.velocity.y *= drag;
+    playerState.velocity.z *= drag;
+}
+
+// Weapon firing
+function firePrimaryWeapon() {
+    const forward = {
+        x: Math.sin(playerState.rotation.y) * Math.cos(playerState.rotation.x),
+        y: -Math.sin(playerState.rotation.x),
+        z: Math.cos(playerState.rotation.y) * Math.cos(playerState.rotation.x)
+    };
 
-    // Update position
-    player.position.x += player.velocity.x * deltaTime;
-    player.position.y += player.velocity.y * deltaTime;
-    player.position.z += player.velocity.z * deltaTime;
+    createProjectile({
+        position: { ...playerState.position },
+        velocity: {
+            x: forward.x * 10 + playerState.velocity.x,
+            y: forward.y * 10 + playerState.velocity.y,
+            z: forward.z * 10 + playerState.velocity.z
+        },
+        type: 'primary'
+    });
 }
 
-// Get player state for rendering
+function fireSecondaryWeapon() {
+    const forward = {
+        x: Math.sin(playerState.rotation.y) * Math.cos(playerState.rotation.x),
+        y: -Math.sin(playerState.rotation.x),
+        z: Math.cos(playerState.rotation.y) * Math.cos(playerState.rotation.x)
+    };
+
+    createProjectile({
+        position: { ...playerState.position },
+        velocity: {
+            x: forward.x * 5 + playerState.velocity.x,
+            y: forward.y * 5 + playerState.velocity.y,
+            z: forward.z * 5 + playerState.velocity.z
+        },
+        type: 'secondary'
+    });
+}
+
+// Get current player state
 export function getPlayerState() {
+    return playerState;
+}
+
+// Get weapon cooldown states
+export function getWeaponStates() {
+    const currentTime = Date.now();
     return {
-        position: { ...player.position },
-        rotation: { ...player.rotation },
-        velocity: { ...player.velocity }
+        primary: {
+            cooldown: Math.max(0, PRIMARY_COOLDOWN - (currentTime - playerState.weapons.primary.lastFired)),
+            burstCount: playerState.weapons.primary.burstCount
+        },
+        secondary: {
+            cooldown: Math.max(0, SECONDARY_COOLDOWN - (currentTime - playerState.weapons.secondary.lastFired))
+        }
     };
 } 
\ No newline at end of file
diff --git a/html/space/renderer.js b/html/space/renderer.js
index 6af271d..04646cf 100644
--- a/html/space/renderer.js
+++ b/html/space/renderer.js
@@ -1,14 +1,22 @@
 // Renderer module using HTML5 Canvas
-import { getPlayerState } from './physics.js';
+import { getPlayerState, getWeaponStates } from './physics.js';
 import { getGameState } from './gameState.js';
 
+// Import weapon constants
+import {
+    PRIMARY_COOLDOWN,
+    SECONDARY_COOLDOWN,
+    PRIMARY_BURST_COUNT,
+    PRIMARY_BURST_DELAY
+} from './physics.js';
+
 let canvas;
 let ctx;
 let width;
 let height;
 
 // Star field
-const stars = [];
+let starfield = [];  // Declare starfield array
 const NUM_STARS = 2000;  // Increased from 1000
 const STAR_FIELD_DEPTH = 20000;  // Increased from 2000
 
@@ -24,60 +32,33 @@ const TARGET_LOCK_THRESHOLD = 20; // Pixels from center to consider locked
 
 // Initialize the renderer
 export function initRenderer() {
-    canvas = document.createElement('canvas');
-    document.body.appendChild(canvas);
+    console.log('Initializing renderer...');
+    canvas = document.getElementById('gameCanvas');
     ctx = canvas.getContext('2d');
     
-    // Make canvas fullscreen
-    function resize() {
-        width = window.innerWidth;
-        height = window.innerHeight;
-        canvas.width = width;
-        canvas.height = height;
-    }
-    
-    window.addEventListener('resize', resize);
-    resize();
+    // Set canvas size
+    width = canvas.width = window.innerWidth;
+    height = canvas.height = window.innerHeight;
     
-    // Initialize star field
-    for (let i = 0; i < NUM_STARS; i++) {
-        stars.push({
-            x: (Math.random() - 0.5) * width * 4,  // Increased spread
-            y: (Math.random() - 0.5) * height * 4, // Increased spread
-            z: Math.random() * STAR_FIELD_DEPTH,
-            size: Math.random() * 2
-        });
-    }
+    // Initialize starfield
+    console.log('Creating starfield with', NUM_STARS, 'stars...');
+    starfield = Array.from({ length: NUM_STARS }, () => ({
+        x: (Math.random() - 0.5) * STAR_FIELD_DEPTH,
+        y: (Math.random() - 0.5) * STAR_FIELD_DEPTH,
+        z: Math.random() * STAR_FIELD_DEPTH,
+        size: Math.random() * 2 + 1
+    }));
+    console.log('Starfield initialized');
 }
 
 // Project 3D point to 2D screen coordinates
-function projectPoint(point, player) {
-    // Calculate relative position to player
-    const relativeX = point.x - player.position.x;
-    const relativeY = point.y - player.position.y;
-    const relativeZ = point.z - player.position.z;
-
-    // Apply player rotation
-    const cosY = Math.cos(player.rotation.y);
-    const sinY = Math.sin(player.rotation.y);
-    const cosX = Math.cos(player.rotation.x);
-    const sinX = Math.sin(player.rotation.x);
-
-    // Rotate around Y axis (yaw)
-    let rotatedX = relativeX * cosY - relativeZ * sinY;
-    let rotatedZ = relativeX * sinY + relativeZ * cosY;
-
-    // Rotate around X axis (pitch)
-    let rotatedY = relativeY * cosX - rotatedZ * sinX;
-    rotatedZ = relativeY * sinX + rotatedZ * cosX;
-
-    // Project to screen
-    if (rotatedZ <= 0) return null; // Behind camera
-
-    const scale = 1000 / rotatedZ;
+function projectPoint(x, y, z) {
+    if (z <= 0) return null; // Behind camera
+    
+    const scale = 2000 / z; // Increased scale factor
     return {
-        x: width/2 + rotatedX * scale,
-        y: height/2 + rotatedY * scale,
+        x: width/2 + x * scale,
+        y: height/2 + y * scale,
         scale
     };
 }
@@ -88,7 +69,7 @@ function getTargetLock(player, gameState) {
     const centerY = height / 2;
     
     for (const ship of gameState.enemyShips) {
-        const projected = projectPoint(ship.position, player);
+        const projected = projectPoint(ship.x - player.x, ship.y - player.y, ship.z - player.z);
         if (projected) {
             const distance = Math.sqrt(
                 Math.pow(projected.x - centerX, 2) +
@@ -135,8 +116,8 @@ function drawRadar(player, gameState, targetLock) {
     
     // Draw planets
     gameState.planets.forEach(planet => {
-        const dx = (planet.position.x - player.position.x) * RADAR_SCALE;
-        const dy = (planet.position.z - player.position.z) * RADAR_SCALE;
+        const dx = (planet.x - player.x) * RADAR_SCALE;
+        const dy = (planet.z - player.z) * RADAR_SCALE;
         const distance = Math.sqrt(dx * dx + dy * dy);
         
         if (distance < RADAR_RADIUS) {
@@ -154,8 +135,8 @@ function drawRadar(player, gameState, targetLock) {
     
     // Draw enemy ships
     gameState.enemyShips.forEach(ship => {
-        const dx = (ship.position.x - player.position.x) * RADAR_SCALE;
-        const dy = (ship.position.z - player.position.z) * RADAR_SCALE;
+        const dx = (ship.x - player.x) * RADAR_SCALE;
+        const dy = (ship.z - player.z) * RADAR_SCALE;
         const distance = Math.sqrt(dx * dx + dy * dy);
         
         if (distance < RADAR_RADIUS) {
@@ -181,18 +162,18 @@ function drawSpeedIndicator(player, targetLock) {
     ctx.fillStyle = targetLock ? TARGET_LOCK_COLOR : HUD_COLOR;
     ctx.font = '14px monospace';
     
-    // Calculate speed
+    // Calculate speed from velocity components
     const speed = Math.sqrt(
-        player.velocity.x * player.velocity.x +
-        player.velocity.y * player.velocity.y +
-        player.velocity.z * player.velocity.z
+        player.vx * player.vx +
+        player.vy * player.vy +
+        player.vz * player.vz
     );
     
     // Draw speed
     ctx.fillText(`Speed: ${speed.toFixed(2)}`, 20, height - 40);
     
-    // Draw direction
-    const direction = Math.atan2(player.velocity.x, player.velocity.z);
+    // Draw direction (using x and z components for heading)
+    const direction = Math.atan2(player.vx, player.vz);
     ctx.fillText(`Heading: ${(direction * 180 / Math.PI).toFixed(1)}°`, 20, height - 20);
     
     ctx.restore();
@@ -255,6 +236,39 @@ function drawTargetingReticle(player, gameState) {
     ctx.restore();
 }
 
+// Draw weapon cooldown indicators
+function drawWeaponCooldowns() {
+    const weaponStates = getWeaponStates();
+    ctx.save();
+    ctx.fillStyle = HUD_COLOR;
+    ctx.font = '14px monospace';
+
+    // Primary weapon cooldown (bottom left)
+    const primaryCooldown = weaponStates.primary.cooldown / PRIMARY_COOLDOWN;
+    ctx.fillText('Primary:', 20, height - 80);
+    ctx.fillStyle = `rgba(0, 255, 0, ${primaryCooldown})`;
+    ctx.fillRect(20, height - 70, 100, 10);
+    ctx.strokeStyle = HUD_COLOR;
+    ctx.strokeRect(20, height - 70, 100, 10);
+
+    // Secondary weapon cooldown (bottom left, below primary)
+    const secondaryCooldown = weaponStates.secondary.cooldown / SECONDARY_COOLDOWN;
+    ctx.fillStyle = HUD_COLOR;
+    ctx.fillText('Secondary:', 20, height - 50);
+    ctx.fillStyle = `rgba(0, 255, 0, ${secondaryCooldown})`;
+    ctx.fillRect(20, height - 40, 100, 10);
+    ctx.strokeStyle = HUD_COLOR;
+    ctx.strokeRect(20, height - 40, 100, 10);
+
+    // Draw burst indicator for primary weapon
+    if (weaponStates.primary.burstCount > 0) {
+        ctx.fillStyle = HUD_COLOR;
+        ctx.fillText(`Burst: ${weaponStates.primary.burstCount}`, 20, height - 20);
+    }
+
+    ctx.restore();
+}
+
 // Main render function
 export function render() {
     const player = getPlayerState();
@@ -262,49 +276,44 @@ export function render() {
     const targetLock = getTargetLock(player, gameState);
 
     // Clear canvas
-    ctx.fillStyle = 'black';
-    ctx.fillRect(0, 0, width, height);
+    ctx.fillStyle = '#000000';
+    ctx.fillRect(0, 0, canvas.width, canvas.height);
     
-    // Draw star field
-    ctx.fillStyle = 'white';
-    stars.forEach(star => {
+    // Draw starfield
+    let starsRendered = 0;
+    starfield.forEach(star => {
         // Calculate star position relative to player
-        const relativeX = star.x - player.position.x;
-        const relativeY = star.y - player.position.y;
-        const relativeZ = star.z - player.position.z;
-
+        let relativeX = star.x - player.x;
+        let relativeY = star.y - player.y;
+        let relativeZ = star.z - player.z;
+        
         // Apply player rotation
-        const cosY = Math.cos(player.rotation.y);
-        const sinY = Math.sin(player.rotation.y);
-        const cosX = Math.cos(player.rotation.x);
-        const sinX = Math.sin(player.rotation.x);
-
-        // Rotate around Y axis (yaw)
-        let rotatedX = relativeX * cosY - relativeZ * sinY;
-        let rotatedZ = relativeX * sinY + relativeZ * cosY;
-
-        // Rotate around X axis (pitch)
-        let rotatedY = relativeY * cosX - rotatedZ * sinX;
-        rotatedZ = relativeY * sinX + rotatedZ * cosX;
-
-        // Project to screen
-        if (rotatedZ <= 0) return; // Behind camera
-
-        const scale = STAR_FIELD_DEPTH / rotatedZ;
-        const x = width/2 + rotatedX * scale;
-        const y = height/2 + rotatedY * scale;
-        const size = star.size * scale;
+        let rotatedX = relativeX * Math.cos(player.rotation) - relativeY * Math.sin(player.rotation);
+        let rotatedY = relativeX * Math.sin(player.rotation) + relativeY * Math.cos(player.rotation);
+        let rotatedZ = relativeZ;
         
-        if (x >= 0 && x <= width && y >= 0 && y <= height) {
-            ctx.beginPath();
-            ctx.arc(x, y, size, 0, Math.PI * 2);
-            ctx.fill();
+        // Project to screen coordinates
+        if (rotatedZ > 0) {
+            const projected = projectPoint(rotatedX, rotatedY, rotatedZ);
+            if (projected) {
+                const brightness = Math.min(1, 2000 / rotatedZ);
+                ctx.fillStyle = `rgba(255, 255, 255, ${brightness})`;
+                ctx.beginPath();
+                ctx.arc(projected.x, projected.y, star.size * brightness, 0, Math.PI * 2);
+                ctx.fill();
+                starsRendered++;
+            }
         }
     });
+    
+    // Debug output
+    if (Math.random() < 0.01) { // Only log occasionally to avoid spam
+        console.log('Stars rendered:', starsRendered);
+    }
 
     // Draw planets
     gameState.planets.forEach(planet => {
-        const projected = projectPoint(planet.position, player);
+        const projected = projectPoint(planet.x - player.x, planet.y - player.y, planet.z - player.z);
         if (projected) {
             const radius = planet.radius * projected.scale;
             ctx.fillStyle = planet.color;
@@ -316,7 +325,7 @@ export function render() {
 
     // Draw enemy ships
     gameState.enemyShips.forEach(ship => {
-        const projected = projectPoint(ship.position, player);
+        const projected = projectPoint(ship.x - player.x, ship.y - player.y, ship.z - player.z);
         if (projected) {
             const size = 20 * projected.scale;
             ctx.fillStyle = '#ff0000';
@@ -331,7 +340,7 @@ export function render() {
 
     // Draw projectiles
     gameState.projectiles.forEach(projectile => {
-        const projected = projectPoint(projectile.position, player);
+        const projected = projectPoint(projectile.x - player.x, projectile.y - player.y, projectile.z - player.z);
         if (projected) {
             const size = 3 * projected.scale;
             ctx.fillStyle = projectile.type === 'primary' ? '#ffff00' : '#00ffff';
@@ -345,4 +354,5 @@ export function render() {
     drawRadar(player, gameState, targetLock);
     drawSpeedIndicator(player, targetLock);
     drawTargetingReticle(player, gameState);
+    drawWeaponCooldowns();
 } 
\ No newline at end of file