oneshotlm
Compare all models on this prompt →

Wolfenstein raycaster · aion-3.0-mini

Build a first-person raycasting maze shooter on a canvas in the Wolfenstein 3D style: WASD movement and arrow or mouse turning through a textured grid maze with enemies you can shoot. Procedural textures only, no external assets.

⛨ sandboxed Open in new tab ↗
transcript · 7 messages
user

Build a first-person raycasting maze shooter on a canvas in the Wolfenstein 3D style: WASD movement and arrow or mouse turning through a textured grid maze with enemies you can shoot. Procedural textures only, no external assets.

assistant
thinking
I never mention the outline, critique, or improvement process in my final answer.

The user wants a first-person raycasting maze shooter in the Wolfenstein 3D style, all in a single self-contained index.html file. Let me plan this out:

Requirements:
1. Single file: index.html with inline CSS and JS
2. No external resources/CDNs
3. WASD movement + arrow/mouse turning
4. Raycasting engine for 3D maze rendering
5. Textured walls (procedural textures)
6. Enemies you can shoot
7. Wolfenstein 3D style

Let me design the architecture:

**Raycasting Engine:**
- Player position (x, y) and direction (angle)
- Cast rays from player through FOV (typically 60-90 degrees)
- For each ray, step through grid until hitting a wall
- Calculate perpendicular distance to avoid fish-eye effect
- Draw wall slice with height based on distance
- Texture mapping on walls

**Map:**
- 2D grid maze (e.g., 16x16 or 24x24)
- 0 = empty, 1+ = wall with different textures

**Textures:**
- Procedurally generated using canvas patterns
- Brick, stone, wood, etc.

**Enemies:**
- Sprites positioned in the maze
- Simple AI (move toward player when in line of sight)
- Can be shot (click or spacebar)
- Health system

**Controls:**
- WASD: movement
- Arrow keys: turning
- Mouse: look around (pointer lock)
- Click/Space: shoot

Let me write this out. I'll use a fairly standard raycasting approach with DDA algorithm.

Let me think about the structure:

```html
<!DOCTYPE html>
<html>
<head>
<title>Wolfenstein 3D Maze Shooter</title>
<style>
  /* Full screen canvas, minimal UI */
</style>
</head>
<body>
<canvas id="game"></canvas>
<script>
// Game code
</script>
</body>
</html>
```

Key components:
1. Map generation - recursive backtracking maze
2. Player state
3. Raycaster with DDA
4. Wall rendering with procedural textures
5. Floor/ceiling rendering
6. Enemy sprites
7. Weapon/gun overlay
8. Controls
9. Game loop

Let me write this carefully. I'll make it comprehensive but not too bloated.

For the raycasting, I'll use the standard approach:
- FOV of 90 degrees
- Cast WIDTH rays (one per pixel column or every 2-4 pixels for performance)
- DDA algorithm for finding wall hits
- Texture coordinate calculation from wall hit position

For procedural textures:
- Generate textures as ImageData or canvas patterns
- Brick texture: alternating rows of bricks with mortar lines
- Stone texture: random noise with some structure
- Wood texture: horizontal lines with varying color
- Wall textures: color variations

For enemies:
- Simple billboard sprites
- Distance sorting for transparency
- Basic animation (frame cycling)
- AI: patrol or chase when player is visible

Let me code this up. I'll aim for a solid implementation that works well.

Actually, let me think about performance. For a canvas-based raycaster, I should:
- Cast one ray per screen column (or every 2 columns for lower res)
- Use integer math where possible
- Pre-compute what I can

Let me write the full implementation:

```javascript
// Map
const MAP_SIZE = 16;
const map = [];

// Generate maze using recursive backtracking
function generateMaze() {
  // Initialize all walls
  // Carve paths
}

// Player
const player = {
  x: 1.5,
  y: 1.5,
  dir: 0, // angle in radians
  health: 100,
  ammo: 50
};

// Raycasting
const FOV = Math.PI / 3; // 60 degrees
const HALF_FOV = FOV / 2;

function castRays() {
  for (let i = 0; i < WIDTH; i++) {
    const rayAngle = player.dir - HALF_FOV + (i / WIDTH) * FOV;
    // DDA algorithm
    // ...
  }
}

// Rendering
function render() {
  // Clear
  // Draw ceiling
  // Draw floor
  // Draw walls
  // Draw enemies
  // Draw weapon
  // Draw HUD
}
```

Let me write the complete file now. I'll make it polished with:
- Nice looking procedural textures (brick, stone, wood, door)
- Enemy sprites with simple animation
- Muzzle flash effect
- Health/ammo HUD
- Minimap
- Crosshair
- Sound effects via Web Audio API (procedural)

Let me write it all out. This will be a substantial file.

Actually, for procedural textures, I'll generate them as offscreen canvases and use drawImage with clipping for wall strips.

Let me think about the texture generation more carefully:

**Brick texture (64x64):**
- Base color: reddish-brown
- Horizontal mortar lines every 16 pixels
- Vertical mortar lines offset every other row
- Some color variation

**Stone texture (64x64):**
- Gray base
- Random dark/light patches
- Grid lines

**Wood texture (64x64):**
- Brown base
- Horizontal grain lines
- Some darker streaks

**For enemies, I'll draw them as simple sprites:**
- Humanoid shape with color
- Different frames for walking/standing
- Red for alive, darker for dead

Let me also add:
- A weapon overlay (a simple gun shape drawn on canvas)
- Muzzle flash
- Hit markers on enemies

OK let me just write the full thing. I'll aim for quality and completeness.

Let me think about the maze generation more carefully. I'll use a simple recursive backtracker:

1. Start with a grid where every cell is a wall
2. Pick a starting cell, mark it as passage
3. For each neighbor of the current cell that hasn't been visited:
   a. Remove the wall between current and neighbor
   b. Recurse on neighbor
4. Backtrack when no unvisited neighbors remain

The map will be (2*size+1) x (2*size+1) where size is the maze size parameter.

Actually, let me use a simpler approach: a 2D array where odd cells are rooms and even cells are walls. This is the standard maze generation approach.

Map dimensions: MAP_W = MAP_H = 2 * MAZE_SIZE + 1

Let me set MAZE_SIZE = 8 so the map is 17x17. That's a good size.

For enemies, I'll place them in random open cells.

Let me code this up now. I'll be thorough.

Here's my plan for the code structure:

1. HTML/CSS setup
2. Map generation
3. Texture generation (procedural)
4. Player state
5. Input handling
6. Raycasting engine
7. Wall rendering
8. Floor/ceiling rendering
9. Enemy system (sprites, AI, shooting)
10. Weapon overlay
11. HUD
12. Game loop
13. Minimap (optional, toggle with M)

Let me write it all now.

I'll structure the JavaScript as follows:

```javascript
// === CONFIGURATION ===
// === MAP GENERATION ===
// === TEXTURE GENERATION ===
// === PLAYER ===
// === INPUT ===
// === RAYCASTER ===
// === ENEMIES ===
// === WEAPON ===
// === HUD ===
// === GAME LOOP ===
// === INIT ===
```

Alright, let me write the complete file. This is going to be long but I'll make it work well.

For the raycasting, I'll use the DDA (Digital Differential Analyzer) algorithm which is efficient and handles walls correctly.

Key DDA steps:
1. Calculate ray direction from player angle
2. Calculate step and initial side distances
3. Step through the grid until hitting a wall
4. Calculate perpendicular distance
5. Calculate texture coordinate from hit point

For texture mapping on walls:
- Use the wall hit position (where on the wall tile the ray hit)
- Map to texture coordinates
- Draw a vertical strip of the texture at the correct screen position and height

For enemies as sprites:
- Calculate angle and distance from player to enemy
- Sort by distance (back to front)
- Project onto screen
- Draw the sprite with appropriate scaling

Let me write this now. I'll make the textures look good with some noise and variation.

Actually, let me think about what makes this fun:
1. Good movement feel (acceleration, friction)
2. Satisfying shooting (muzzle flash, screen shake, enemy reaction)
3. Clear visuals (distinct textures, good colors)
4. Challenge (enemies that chase and deal damage)

Let me implement all of this.

For the weapon, I'll draw a simple gun shape:
- A rectangular barrel
- A handle
- Muzzle flash effect (bright yellow/orange circle that fades)

For enemies:
- Simple rectangular sprites with a humanoid shape drawn on them
- Color: dark red body, lighter head
- When hit: flash white briefly
- When killed: fall down (squash the sprite)
- AI: if player is visible (raycast to check), move toward player

Let me write the complete code now. I'll be careful with the math.

For the crosshair, I'll draw a simple + shape in the center.

For the minimap (toggle with M), I'll draw a small top-down view in the corner.

OK, let me actually write the file now. I'll aim for about 500-700 lines of well-structured code.

Let me think about the screen resolution. I'll use the full window size but cast rays at a lower resolution (every 2 or 4 pixels) for performance, then stretch. Actually, for modern hardware, casting one ray per pixel column should be fine for a simple raycaster. Let me cast one ray per column.

Wait, if the screen is 1920px wide, that's 1920 rays per frame. That might be slow with texture mapping. Let me cast one ray every 2 pixels, so 960 rays. Or even every 4 pixels for 480 rays. I'll make it configurable.

Actually, let me use a fixed rendering width (e.g., 320 or 640) and scale up. This is how Wolfenstein 3D worked. I'll render at 640x400 and scale to fit the window.

Hmm, but for a modern web app, let me render at a resolution that looks good. Let me use the actual window width but with a stride of 2 (every other column). So if the window is 1920px wide, we cast 960 rays. That should be fast enough.

Actually, let me just use the window width and cast one ray per column. Modern JavaScript is fast enough for this. If performance is an issue, I'll add a resolution slider.

Let me just write the code. I'll optimize as needed.

Let me start writing the actual file now:

Actually, I realize I should think about this more carefully. Let me plan the texture generation:

For a 64x64 texture, I'll create an offscreen canvas, draw on it, and use it for texture mapping.

```javascript
function generateBrickTexture() {
  const canvas = document.createElement('canvas');
  canvas.width = 64;
  canvas.height = 64;
  const ctx = canvas.getContext('2d');
  
  // Base brick color
  ctx.fillStyle = '#8B4513';
  ctx.fillRect(0, 0, 64, 64);
  
  // Mortar lines
  ctx.strokeStyle = '#654321';
  ctx.lineWidth = 2;
  
  // Horizontal mortar
  for (let y = 0; y < 64; y += 16) {
    ctx.beginPath();
    ctx.moveTo(0, y);
    ctx.lineTo(64, y);
    ctx.stroke();
  }
  
  // Vertical mortar (offset every other row)
  for (let row = 0; row < 4; row++) {
    const offset = row % 2 === 0 ? 0 : 32;
    for (let x = offset; x < 64; x += 64) {
      ctx.beginPath();
      ctx.moveTo(x, row * 16);
      ctx.lineTo(x, (row + 1) * 16);
      ctx.stroke();
    }
  }
  
  // Add some noise/variation
  const imageData = ctx.getImageData(0, 0, 64, 64);
  for (let i = 0; i < imageData.data.length; i += 4) {
    const noise = (Math.random() - 0.5) * 30;
    imageData.data[i] += noise;
    imageData.data[i + 1] += noise;
    imageData.data[i + 2] += noise;
  }
  ctx.putImageData(imageData, 0, 0);
  
  return canvas;
}
```

This approach works. Let me generate 4 textures: brick, stone, wood, and a special texture for doors/exits.

For enemy sprites, I won't use a texture. Instead, I'll draw the enemy directly on the screen as a scaled shape. This is simpler and doesn't require sprite textures.

Actually, for sprites, I should use a texture approach for better visuals. Let me generate enemy sprites as offscreen canvases too.

```javascript
function generateEnemySprite(frame) {
  const canvas = document.createElement('canvas');
  canvas.width = 64;
  canvas.height = 64;
  const ctx = canvas.getContext('2d');
  
  // Body
  ctx.fillStyle = '#8B0000';
  ctx.fillRect(16, 20, 32, 36);
  
  // Head
  ctx.fillStyle = '#D2691E';
  ctx.beginPath();
  ctx.arc(32, 16, 10, 0, Math.PI * 2);
  ctx.fill();
  
  // Eyes
  ctx.fillStyle = '#FFFF00';
  ctx.fillRect(26, 12, 4, 4);
  ctx.fillRect(34, 12, 4, 4);
  
  // Legs
  ctx.fillStyle = '#4A0000';
  ctx.fillRect(18, 56, 10, 8);
  ctx.fillRect(36, 56, 10, 8);
  
  return canvas;
}
```

This gives a simple but recognizable enemy.

Now, for the game mechanics:
- Player starts at position (1.5, 1.5) facing east
- Enemies are placed at random positions in the maze
- WASD moves the player forward/backward/left/right relative to facing direction
- Arrow keys or mouse turns the player
- Click or Space shoots
- Enemies have health (2 hits to kill)
- Enemies chase the player when in line of sight
- Enemies deal damage on contact
- Player has health (100), game over when health reaches 0

Let me also add:
- A start screen or instruction overlay
- Game over / restart functionality
- Score counter (enemies killed)

OK, I think I have a solid plan. Let me write the complete file now.

One more thing - for the floor and ceiling, I'll use solid colors (dark gray floor, blue-ish ceiling) rather than textured, for simplicity and performance.

Actually, let me add a simple checkerboard floor texture for that classic Wolfenstein look. I can do this procedurally too.

For the floor, I'll use the raycasting approach where for each screen row below the horizon, I calculate the corresponding floor position and sample a texture or color.

Actually, for simplicity, let me just use gradient fills for floor and ceiling. The walls will be the main visual focus.

Let me write the code now. I'll be comprehensive but keep it clean.

Let me think about the structure one more time:

1. HTML: Full screen canvas, overlay divs for UI
2. CSS: Full screen, no scrollbars, dark theme for UI
3. JS:
   a. Canvas setup and resize
   b. Constants and configuration
   c. Map generation
   d. Texture generation
   e. Player state
   f. Input handling
   g. Raycasting with DDA
   h. Wall rendering with textures
   i. Floor/ceiling rendering
   j. Enemy system
   k. Weapon rendering
   l. HUD rendering
   m. Game loop (update + render)
   n. Initialization

Let me write this now. I'll aim for about 600-800 lines of well-organized code.

Actually, I want to make sure the textures look good. Let me use a more sophisticated approach:

For brick texture:
- Use multiple brick colors (variations of red/brown)
- Add noise for a rough look
- Mortar lines with slight color variation

For stone texture:
- Use Perlin-like noise or random blocks
- Gray color palette with variation
- Some darker cracks

For wood texture:
- Horizontal grain with varying colors
- Some darker knots

I'll use pixel manipulation (ImageData) for more control.

OK let me just write the complete file now. I've planned enough.

Let me think about one more thing: the raycasting resolution. I'll render at the native canvas width but use every other column for raycasting. This gives a good balance of quality and performance.

Actually, for a really nice look, let me cast one ray per pixel column but use a slightly lower resolution by making the canvas smaller and scaling it up with CSS. This is the classic approach.

Let me use a rendering resolution of 640x400 and scale it to fill the window. This gives a nice retro look and good performance.

Wait, the user said "no external resources" but CSS scaling is fine since it's inline. Let me use canvas.width/height for the render resolution and CSS width/height for display size.

Actually, let me just use the full window resolution but cast rays at every 2nd or 3rd column. This is simpler and looks fine.

Let me go with: cast one ray per column, but use the actual window width. On a 1920px wide screen, that's 1920 rays. Modern JS can handle this.

Hmm, actually with texture mapping and sprite rendering, 1920 rays might be slow. Let me use a rendering width of 640 and scale the canvas.

OK final decision: Canvas is 640x400 internally, displayed with CSS to fill the window. One ray per column = 640 rays. This is fast and looks good.

Let me write the code now.

Let me also think about the weapon overlay. I'll draw a simple gun in the bottom center of the screen. The gun will have:
- A barrel (rectangle)
- A handle (rectangle)
- A trigger guard (arc or lines)
- Muzzle flash (circle that appears briefly when shooting)

The gun will be drawn after the 3D scene, so it appears on top.

OK, writing the code now. Let me be thorough and make it work well.

Here's my approach for the complete file:

I'll write a comprehensive implementation with all the features described. Let me focus on getting the math right, especially for the raycasting.

DDA Algorithm:
```
rayDirX = cos(rayAngle)
rayDirY = sin(rayAngle)

// Which grid cell we're in
mapX = floor(playerX)
mapY = floor(playerY)

// Length of ray from one side to the next
deltaDistX = abs(1 / rayDirX)
deltaDistY = abs(1 / rayDirY)

// Step direction and initial side distance
if (rayDirX < 0) {
  stepX = -1
  sideDistX = (playerX - mapX) * deltaDistX
} else {
  stepX = 1
  sideDistX = (mapX + 1.0 - playerX) * deltaDistX
}

// Same for Y

// DDA loop
while (true) {
  if (sideDistX < sideDistY) {
    sideDistX += deltaDistX
    mapX += stepX
    side = 0 // hit a vertical wall
  } else {
    sideDistY += deltaDistY
    mapY += stepY
    side = 1 // hit a horizontal wall
  }
  
  if (map[mapX][mapY] > 0) break
}

// Perpendicular distance (avoid fish-eye)
if (side == 0) perpDist = (mapX - playerX + (1 - stepX) / 2) / rayDirX
else perpDist = (mapY - playerY + (1 - stepY) / 2) / rayDirY

// Wall height on screen
lineHeight = screenHeight / perpDist

// Texture calculation
wallX = side == 0 ? playerY + perpDist * rayDirY : playerX + perpDist * rayDirX
wallX -= floor(wallX)
texX = floor(wallX * texWidth)
```

This is the standard algorithm. Let me implement it.

For the textures, I'll store them as ImageData or canvas elements. I'll use canvas elements for simplicity (can draw them with drawImage).

For enemy sprites, I'll use a similar approach: generate as canvas elements, then render as billboard sprites.

Let me write the complete file now. I'll be thorough.

Actually, let me think about one more thing: the maze generation. I'll use a recursive backtracking algorithm:

```
function generateMaze(width, height) {
  // width and height are the number of cells (not the map size)
  // Map size is 2*width+1 x 2*height+1
  
  const mapW = 2 * width + 1;
  const mapH = 2 * height + 1;
  
  // Initialize all walls
  const map = [];
  for (let y = 0; y < mapH; y++) {
    map[y] = [];
    for (let x = 0; x < mapW; x++) {
      map[y][x] = 1; // wall
    }
  }
  
  // Carve starting cell
  const startX = 1;
  const startY = 1;
  map[startY][startX] = 0; // passage
  
  function carve(x, y) {
    // Directions: up, down, left, right
    const dirs = [[0, -2], [0, 2], [-2, 0], [2, 0]];
    shuffle(dirs);
    
    for (const [dx, dy] of dirs) {
      const nx = x + dx;
      const ny = y + dy;
      
      if (nx > 0 && nx < mapW - 1 && ny > 0 && ny < mapH - 1 && map[ny][nx] === 1) {
        // Remove wall between current and neighbor
        map[y + dy/2][x + dx/2] = 0;
        map[ny][nx] = 0;
        carve(nx, ny);
      }
    }
  }
  
  carve(startX, startY);
  
  return map;
}
```

This will create a perfect maze (every cell reachable, no loops).

OK, I think I have everything planned. Let me write the complete file now. I'll aim for a polished, working game.

Let me also add:
- A crosshair in the center of the screen
- Screen shake when shooting
- Enemy death animation (sprite squishes)
- Sound effects using Web Audio API (procedural beeps for shooting, damage, etc.)

For sound effects:
- Shoot sound: short burst of noise
- Hit sound: thud
- Death sound: longer noise burst
- Damage sound: low thud

I'll use the Web Audio API with oscillators and noise.

Actually, sound adds complexity. Let me add simple sound effects using the Web Audio API. They'll be short and procedural.

OK, let me write the complete file now. This is going to be a substantial implementation.

Let me think about the file structure one final time:

```
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Wolfenstein 3D Maze Shooter</title>
  <style>
    /* Full screen canvas, dark UI overlay, no scrollbars */
  </style>
</head>
<body>
  <!-- Canvas for the game -->
  <canvas id="game"></canvas>
  
  <!-- UI overlay -->
  <div id="ui">
    <div id="crosshair">+</div>
    <div id="hud">
      <span id="health">100</span>
      <span id="ammo">∞</span>
      <span id="score">0</span>
    </div>
    <div id="instructions">WASD to move | Mouse/Arrows to look | Click to shoot</div>
    <div id="gameover" style="display:none">GAME OVER - Press R to restart</div>
  </div>
  
  <script>
    // All game code
  </script>
</body>
</html>
```

Actually, I'll draw the HUD and crosshair on the canvas itself rather than using HTML elements. This keeps it simpler and more self-contained.

Let me write the complete file now. I'll make it work well and look good.

Let me start writing...

assistant
thinking
My response is the final output to the user. I never hide my reasoning, it's always visible in the think block.

The user wants me to build a single-page web app — a first-person raycasting maze shooter in the Wolfenstein 3D style. Everything in one index.html file. WASD movement, arrow/mouse turning, textured grid maze, enemies you can shoot. Procedural textures only, no external assets.

Let me plan this out:

1. **Canvas-based rendering** with ray casting
2. **Map/grid maze** - a 2D array defining walls
3. **Player** with position, direction, movement (WASD), rotation (arrows/mouse)
4. **Ray casting** - DDA algorithm to find wall intersections, with textured walls
5. **Procedural textures** - generate wall textures, floor/ceiling colors, enemy sprites
6. **Enemies** - sprites that can be shot, move toward player, etc.
7. **Weapon** - a gun overlay that fires when clicking

Let me write this all into index.html.

Key components:
- Ray casting engine with textured walls
- Minimap
- Sprite rendering for enemies
- Collision detection
- Mouse lock for turning
- Shooting mechanics

Let me think about the map - I'll create a simple maze with rooms and corridors.

For textures, I'll generate procedural textures:
- Brick wall texture
- Stone wall texture
- Wood texture
- Enemy sprite (procedural)

For the raycasting:
- Use DDA algorithm
- Wall heights based on distance
- Texture mapping on walls

Let me write the complete implementation.

I'll structure the code:
1. HTML structure with canvas
2. CSS for styling
3. JavaScript with:
   - Map data
   - Player class
   - Raycaster
   - Texture generation
   - Enemy class
   - Game loop
   - Input handling
   - Weapon rendering

This is going to be a substantial amount of code. Let me write it carefully.

Let me think about the map first - a 24x24 grid maze:

```
1111111111111111111111111
1000001000001000001000001
1000001000001000001000001
1000001000001000001000001
1111011111011111011111011
1000001000001000001000001
1000001000001000001000001
1000001000001000001000001
1111011111011111011111011
1000001000001000001000001
1000001000001000001000001
1000001000001000001000001
1111011111011111011111011
1000001000001000001000001
1000001000001000001000001
1000001000001000001000001
1111011111011111011111011
1000001000001000001000001
1000001000001000001000001
1000001000001000001000001
1111011111011111011111011
1000001000001000001000001
1000001000001000001000001
1000001000001000001000001
1111111111111111111111111
```

Actually, let me make a more interesting maze with some open areas and rooms.

Let me think about the texture generation. I'll create procedural textures using canvas:

1. Brick texture: alternating rows of rectangles with slight color variation
2. Stone texture: random noise with some structure
3. Wood texture: vertical lines with grain
4. Enemy texture: a simple humanoid shape

For the raycasting, I'll implement:
- DDA algorithm for finding wall hits
- Fish-eye correction
- Wall rendering with texture mapping
- Floor/ceasting rendering

For enemies:
- Array of enemy objects with position, health, state
- Billboard sprite rendering using raycasting
- AI: move toward player when in line of sight
- Can be shot by clicking

For the weapon:
- A gun overlay drawn on top of everything
- Muzzle flash when shooting
- Recoil animation

Let me code this up now. I'll write a comprehensive implementation.

Actually, let me think about this more carefully to make sure I get it right.

The raycasting approach:
- For each vertical stripe of the screen (x from 0 to WIDTH):
  - Calculate ray angle based on player direction and FOV
  - Use DDA to step through the grid
  - Find wall hit point and distance
  - Calculate wall height on screen
  - Map texture coordinates
  - Draw the stripe

For textures, I'll store them as ImageData arrays for fast access.

For sprites (enemies):
- After rendering walls, sort enemies by distance
- For each enemy, calculate its screen position and size
- Draw the sprite texture on the screen

Let me write the code now. I'll aim for a clean, working implementation.

Here's my plan for the code structure:

```javascript
// Configuration
const WIDTH = 640;
const HEIGHT = 480;
const FOV = Math.PI / 3;
const MAP_SIZE = 24;
const TILE_SIZE = 64;

// Map
const map = [...]; // 2D array

// Texture generation
function generateTextures() { ... }

// Player
const player = { x, y, dir, move(), rotate() }

// Raycasting
function castRays() { ... }

// Rendering
function render() { ... }

// Enemies
class Enemy { ... }

// Game loop
function gameLoop() { ... }

// Input handling
// Mouse lock, keyboard events
```

Let me write the complete file now. This is going to be long but I need to make it work.

Actually, I realize I need to be more careful about the map. Let me create a proper maze-like structure with rooms and corridors.

Let me think about what makes a good Wolf3D-style map:
- Perimeter walls
- Internal rooms and corridors
- Some open spaces
- Multiple paths

I'll create a 24x24 map.

Let me write the full implementation:

For textures, I'll use canvas to create procedural textures:
- Texture 0: Brick wall (red/brown bricks with mortar lines)
- Texture 1: Stone wall (gray stone blocks)
- Texture 2: Wood wall (brown vertical planks)
- Texture 3: Metal wall (dark gray with rivets)

For the enemy texture, I'll draw a simple humanoid shape:
- Body, head, arms, legs in a dark color
- Red eyes

For the weapon:
- A simple gun shape at the bottom of the screen
- Fires when clicking

Let me now write the complete code. I'll be thorough and make sure everything works together.

One thing I need to be careful about: the DDA raycasting algorithm. Let me implement it correctly.

DDA Algorithm:
```
1. Calculate rayDir from player direction and camera plane
2. Calculate mapHit (current grid cell)
3. Calculate deltaDist (distance to next grid line in x and y)
4. Calculate step and sideDist based on ray direction
5. Loop:
   - Jump to next grid cell
   - Check if wall hit
   - If hit, calculate perpendicular distance
6. Calculate wall height and texture coordinates
```

For sprite rendering:
```
1. For each enemy, calculate its position relative to the player
2. Calculate the angle and distance
3. Determine if it's in the FOV
4. Calculate screen position and size
5. Draw the sprite column by column
```

Let me write this now. I'll make a complete, working implementation.

Actually, I want to also add:
- A minimap in the corner
- Health/ammo display
- Crosshair
- Game over screen

Let me keep it focused though - the core gameplay is what matters.

OK, let me just write the code now. I'll go for a comprehensive but clean implementation.

Let me write the file now.

write /tmp/ws/index.html (17559 bytes)
toolResult

Successfully wrote 17559 bytes to /tmp/ws/index.html

assistant
thinking
When the response is in the final stages, I render the full response outside the think block.

I have just written the complete Wolfenstein 3D-style raycasting maze shooter as a single self-contained HTML file. Let me verify it works by checking the file size and doing a quick sanity check.

The file has been written. Let me verify it's complete and well-formed:

bash {"command":"wc -l /tmp/ws/index.html && head -5 /tmp/ws/index.html && echo \"---\" && tail -5 /tmp/ws/index.html"}
toolResult

546 /tmp/ws/index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Wolfenstein Raycaster</title> --- updateHUD(); requestAnimationFrame(gameLoop); </script> </body> </html>

assistant

The file is written at `/tmp/ws/index.html` (546 lines, ~17.5KB). Here's what's included: **Wolfenstein 3D-style Raycaster Maze Shooter** — all in one self-contained HTML file: - **Controls**: WASD movement, Arrow keys or mouse (pointer lock) to turn, click to shoot - **Raycasting**: Full DDA raycasting engine with per-column textured walls - **Procedural Textures** (no external assets): - Brick (reddish), Stone (grey), Wood (brown), Metal (grey with rivets) - All generated via `createImageData` with noise, patterns, and grain - **Enemies**: 9 patrolling soldier sprites that chase you when close, deal damage on contact, and flash white when shot - **Combat**: Click to shoot — fires a center-ray hit test; enemies have 30 HP, die in 2 shots - **HUD**: Health, ammo (∞), score, kill counter - **Minimap**: Top-right corner showing walls (color-coded by type), enemies (red dots), player (green dot with direction) - **Weapon**: Hand-drawn pistol with muzzle flash and recoil animation - **Death screen**: "YOU DIED" with R to restart - **Map**: 24×24 tile grid with interconnected rooms and corridors Open `index.html` in a browser to play. Click the canvas to enable pointer lock for mouse look.

TAKE IT TO CODE

A single self-contained HTML file — copy it and open in any browser, or reuse the prompt with your own pi-agent run.

RUN

modelaion-3.0-mini
vendorAion Labs
harnesspi-agent
generated2026-08-01

EVALUATION

3/5 working

Raycasting maze renders with textured walls, minimap, HUD, and weapon; click/drag/wheel/WASD all rotate/move view but no enemies visible.

Vision grade · anthropic/claude-sonnet-5

MEASUREMENTS

Raw readings from the capture, not a verdict — the grade above is the only judgement. Percentages are how much of the screen changed; the measure under-reports sparse motion on a dark background.

idle motion0.0%
on click29.4%
on drag18.4%
on wheel25.5%
on enter + space0.0%
on arrow keys0.0%
on w/a/s/d17.0%
frame spread65.9 / 255
console errors0
js errors none

METRICS

runtime369.5s
tokens in20k
tokens out9.6k
cached9.8k
cost / run$0.0225