oneshotlm
Compare all models on this prompt →

Wolfenstein raycaster · deepseek-v4-flash-0731

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.

⚠ no runnable output

This one-shot run produced no runnable artifact.

timed out after 600000ms

The transcript below shows what the model did — read it to see why the one shot fell short.

transcript · 8 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
assistant
assistant
thinking
Let me build a Wolfenstein 3D style raycasting maze shooter. I'll write it all in a single index.html file with procedural textures, canvas rendering, WASD movement, mouse/arrow turning, and enemies.

Let me plan:
- Raycasting engine with a grid maze
- Procedural textures (bricks, stone, wood, etc.) generated on offscreen canvases
- Player with position, direction, plane (camera plane) - classic DDA algorithm
- Walls rendered via vertical stripes
- Floor/ceiling casting (raycasting on both floor and ceiling)
- Enemies - in Wolfenstein these are sprites. I'll do raycast-based sprite rendering: compute perpendicular distance of enemies, sort by distance, render as textured billboards.
- Shooting with mouse click or space, hitscan to enemies
- HUD with health, ammo, weapon sprite (procedurally drawn raygun)
- Mini-map maybe
- Muzzle flash
- Game states: start, playing, game over/victory

Let me build a complete, polished implementation.

Let me think about architecture:
- Maze generated procedurally. I'll generate a maze using recursive backtracker, then place enemies randomly in open cells (reachable). Ensure player has a weapon and enemies.

Let me write the code carefully.

Canvas size: I'll use full window, maybe fixed internal resolution lower for speed then scale. Use a modest resolution like width 960, height 540 scaled.

Raycasting DDA:
- posX, posY (player position as float in grid)
- dirX, dirY (direction vector)
- planeX, planeY (camera plane perpendicular)
- For each vertical stripe x: cameraX = 2*x/w - 1; rayDirX = dirX + planeX*cameraX; ...
- DDA with mapW=32, mapH=32.
- Compute lineHeight, draw wall stripe textured.

Texture per cell: store maze tile with texture variety. Colors for sides (shading by side: N/S darker, E/W lighter — classic).

Floor casting: raycast for each y (screen row below horizon) — project.

Sprites/enemies: Each enemy has x,y (in world), texture, state (alive, dying). Render by sorting by distance desc. Billboard transform.

Enemy AI: they move toward player, can see player. Simple chase. When in line of sight (no wall between) and close, move toward player. Maybe they shoot too — hitscan damage to player. Let's add shooter enemies with their own projectiles/hitscan every interval.

Weapon: a raygun drawn procedurally. Shooting triggers muzzle flash, hitscan along center ray, damages nearest enemy along a ray. I'll do a cone or center-line hitscan. Find enemy whose screen x is near center and within a range and line of sight.

Let me implement shooting: on fire, for each enemy, compute its screen position; if within some pixel margin of center, compute distance, and if line of sight clear and distance < something, hit with damage proportional to distance.

Health/ammo: health 100, ammo say 50, enemy hp.

Let me write the whole thing.

Let me structure:

```
<!DOCTYPE html>
<html>
<head>
<meta charset...>
<title>...</title>
<style>...</style>
</head>
<body>
<canvas id="c"></canvas>
<div id="overlay">...</div> // maybe HUD built in canvas
<script>
...everything...
</script>
</body>
</html>
```

I'll do HUD in canvas. Overlay div for start/gameover handled in canvas too with drawing. But pointer lock for mouse needed on canvas, so overlay in canvas may block. I'll handle start screen with a separate div that when clicked, starts and requests pointer lock.

Actually pointer lock: requestPointerLock on canvas. Mouse movement sets yaw. Use mousemove with movementX.

Let's allow arrow keys too.

Let me write.

Resolution: I'll use an internal buffer canvas of, say, 800x500, then draw scaled to display canvas. Simpler: single canvas sized to window, and compute wall columns across actual width. That's fine. But performance with procedural floor casting per row across full width—fine on modern browsers.

Let me use a fixed logical resolution for the 3D render (e.g., 480x360) for performance then upscale via CSS to fill window, with a separate overlay for HUD maybe. Actually simpler and polished: render at internal res, draw scaled with imageSmoothingEnabled false for authentic pixel look. HUD drawn on the display canvas after scaling? I'll draw 3D on internal canvas, scale it onto main canvas, then draw the weapon sprite & HUD on main canvas at full res.

Let me implement.

I'll write texture generation functions returning ImageData arrays (Uint32) directly for fast reads.

Textures generated into a Uint32Array of size TEX=64, squared. I'll make them once.

Let me define TEX=64.

Texture maker helpers: noise, brick, etc.

Let me plan textures array: an array of {wall:true/false} plus name. Define ~6 wall textures.

Walls: index into textures by tile value. Maze grid: use a 2D array of booleans wall. Assign each wall cell a texture index based on position.

I'll assign wall texture = ((x*7 + y*13) % numWallTextures) but maybe ensure neighboring variety. fine.

For texture sampling in wall rendering, use precomputed column data to avoid recompute. Since static, precompute texel column per wall texture? Simpler compute inline.

Let me write DDA per column (classic). For hit, get side, perpWallDist, wallX from camera. texX = wallX * TEX (floor). Draw vertical line sampling texture column with step. Apply shading per side.

Floor casting: for row y > horizonCenter, p = rowDist = (0.5*h) / (y - 0.5*h). This is for correctness depending on plane. Classic floor casting:

```
for y = horizonY+1 to h:
  rowDistance = (camHeight * (h/2)) / (y - h/2)
  // for each x:
  floorStepX = rowDistance*(rayDirX1-rayDirX0)/w
  ...
```

Wait standard: 
rowDistance = (0.5 * h) / (y - 0.5*h)
rayDirX0 = dirX - planeX; rayDirX1 = dirX + planeX
for each x: cellX = int(floorX) etc.
floorStepX = rowDistance * (rayDirX1 - rayDirX0) / w
fracX = x * floorStepX
floorX = posX + rowDistance * rayDirX0 ... 

Let me implement properly:

```
for (let y = drawEnd? ; y<h; y++) {
  const p = y - h/2;
  const posZ = (h/2) / p;
  const rowDist = posZ; // perspective
  // ray points at edges
  const stepX = posZ * (rayDirX1 - rayDirX0) / w;
  const stepY = posZ * (rayDirY1 - rayDirY0) / w;
  let floorX = posX + posZ * rayDirX0;
  let floorY = posY + posZ * rayDirY0;
  for x: {
     texX = (floorX - floor(floorX)) * TEX (as int)
     texY = ...
     sample floor texture at (texX, texY) but coordinate based on floorX-floorX lower
     put pixel
     floorX += stepX; floorY += stepY;
  }
}
```

This per-pixel is O(h*w). With 360 rows * columns. 480*360 = 172k pixels, fine.

I'll combine into reused buffer.

Now let me just write it. I'll be careful with typed arrays.

For drawing, I'll use a Uint32Array image buffer of size w*h, then putImageData. Then scale to display.

Let me implement colors as 0xAABBGGRR (little endian). Actually Uint32Array stores in machine byte order (little endian on most). I'll use a helper to build: (alpha<<24 | blue<<16 | green<<8 | red).

Texturing sample returns a Uint32 color from texture ImageData converted to Uint32Array.

Let me write texture generators:

- makeBrick: base red-brown, mortar lines.
- makeStone: gray noise, blocky.
- makeDarkStone: darker.
- makeWood: planks with grain.
- makeMetal: gray with rivets.
- makeEagle: blue with emblem.

Enemy texture: I'll draw a "guard" as a humanoid shape on a texture (sprite) — but Wolfenstein enemies are many frames. I'll make a single-frame zombie/humanoid with simple procedural drawing, and scale it as billboard. Use the texture and render as sprite column by column with zbuffer distance check.

Sprite rendering: for each sprite, transform relative position to camera space, if forward, compute screenX and size, draw vertical stripes sampling the sprite texture. Z-buffer check for occlusion.

Enemy sprite: I'll draw a distinctive creature (e.g., a red demon / soldier). Let me draw a humanoid: body, head, gun. In a 64x64 texture. To make it look OK, decent procedural pixel art. It will be enlarged maybe. Sprites drawn at size proportional.

Actually single sprite per enemy with slight animation (bobbing/sway). Good enough.

Let me also add muzzle flash animation for player weapon and recoil.

Weapon drawing: a raygun at bottom center, drawn procedurally on the display canvas. On fire, flash and recoil.

Let me code.

Enemy AI:
- Each enemy: {x,y (world float), tex, health, alive, state}, speed, shootCooldown, type.
- In update: compute dx,dy to player, dist.
- Check line of sight via DDA between enemy and player (sample along line, if hits wall before player -> blocked).
- If sees player: rotate enemy facing to player (not needed visually if single sprite), and move toward player (slide along walls). Every few seconds if within range & LoS, deal damage (hitscan), with screen flash.
- Bob movement causes items? keep simple.

Enemies shouldn't stack; apply simple separation.

Game flow: 
- Start screen: "MAZE STORM — Click to start (mouse controls)". Press M maybe to toggle mouse.
- Player has health 100, ammo infinite? Let's give ammo counter with near-infinite reload, or heat. I'll give ammo 200, pickups? Keep simple: ammo 150, kills restore? Let's just make ammo count and add ammo pickups (ammo boxes) as floor sprites. Also health packs. That's more complex but nice. I'll add pickup sprites (ammo, health) rendered as small sprites. Hmm, extra complexity. Let me include pickups since it adds gameplay.

Let me define sprite entities: type enemy or pickup. Each has x,y world, and rendering via sprite pipeline.

- Win when all enemies dead. Show victory. Die when health<=0 → game over.

Let me implement sprite pipeline generically over an array of renderable sprites (enemies + pickups).

zbuffer: array length w storing perpWallDist per column.

Let me now write everything.

I'll write code in the script. Let me be thorough but concise.

Let me define constants:
- MAP_W = 32, MAP_H = 32
- Tile size conceptual (integer spacing).
- Wall texture fade factors.

Maze generation: recursive backtracker producing a perfect maze on odd cells. Grid: all walls; carve passages. Then we have corridors of width 1. Player starts near entrance.

Generate maze:
```
function genMaze() {
  // map filled 1 (wall)
  map = new Uint8Array(MAP_W*MAP_H).fill(1);
  // carve from (1,1)
  const stack = [];
  let x=1, y=1; map[y*MAP_W+x]=0;
  ... recursive backtracker ...
}
```
Carve at odd/even. Standard: start (1,1), mark 0. Directions random, step 2. 

Enemies placed at random cells that are floor and far enough from player. Player at (1.5,1.5).

Let me ensure enough space. Maze corridors width 1 — enemies move along. Fine.

Pickups placed on some corridor cells.

Now let me code enemy textures. I'll make 3 enemy variants.

Procedural humanoid sprite drawing on 64x64 with transparency (alpha). I'll draw on a canvas 2D context, then get ImageData, convert to Uint32 (ignore alpha or keep). For sprite rendering keep full RGBA via Uint32Array and check alpha for transparent (270deg). Render bg or skip. I'll treat alpha<128 as transparent skip.

Let me just draw sprites via 2D canvas for authoring ease, then store as ImageData. Then in render, create a Uint32Array view? But ImageData data is Uint8ClampedArray; I can create a Uint32Array from buffer: `new Uint32Array(imagedata.data.buffer)` — works if not shared but it's fine for reads.

Alright.

Rendering sprites: classic Lodev algorithm. For each sprite: 
```
transformX = (dx*dirY - dy*dirX); // negative means behind
```
Wait correct: 
relativeX = spriteX - posX; relativeY = spriteY - posY;
transformX = planeX*relativeY - planeY*relativeX ... hmm let me use the invertMatrix approach.

Actually let me get it right from Lodev sprites:
```
double invDet = 1.0 / (planeX * dirY - dirX * planeY);
double transformX = invDet * (dirY * spriteX_rel - dirX * spriteY_rel);
double transformY = invDet * (-planeY * spriteX_rel + planeX * spriteY_rel);
int spriteScreenX = int((w/2) * (1 + transformX/transformY));
```
where spriteX_rel = spriteX - posX, spriteY_rel = spriteY - posY. transformY>0 in front.
If transformY <= 0 skip.
spriteHeight = abs(int(h / transformY)) / vMove... sizes scaled, using a SpriteSize factor. Lodev uses vMoveScreen, and treats coordinates in "world units" where each unit = texel/64? They multiply by scale. I'll set spriteScale = h / transformY, and draw sprite image scaled so that its height in px = spriteScale * (something). Since world coordinates in same units as walls, h/transformY gives px per world unit. Enemies ~0.7 world units tall. So height = h/transformY * 0.7? Actually wall height is h/perpDist (one world unit tall fills screen by design with camera). So sprite height in px = h/transformY * spriteWorldHeight. Use spriteWorldHeight ~0.8.

drawStartY = -height/2 + h/2; etc. Handle vertical & horizontal.

For each stripe from startX..endX clamp to [0,w), if transformY < zbuffer[x], sample texture column.

OK.

Now weapon drawing after 3D. Player gun drawn on display canvas with weapon sprite animation. I'll draw a raygun procedurally each frame in the overlay (display) canvas.

Let me define drawing of raygun: at bottom center, with bounce (walk bob) and recoil on shoot, muzzle flash.

Let me code it.

HUD: health bar, ammo, enemies remaining, compass. Crosshair center.

Let me now also handle fire: mouse down (while locked) and space. On fire, check hit on enemies: compute screen position & distance & LoS, choose nearest within gap< gapSize and distance < maxRange. Apply damage. ammo--, play muzzle.

Enemy damage to player: when enemy shoots, health -= dmg, red vignette flash.

Let me implement footstep? no audio (no assets / but could use WebAudio synthesized—allowed since no network). The spec says no external resources/network. WebAudio synth beeps allowed. I'll add simple synthesized sound effects via WebAudio (shoot beep, hit, enemy). That's a nice touch and self-contained. Let me add minimal.

Let me now write the file. This is large; I'll write it fully.

Let me define the render resolution: I'll render 3D at REN_W x REN_H. Let's choose 640x400 internal, upscaled to window. Actually let me compute based on a fixed 500 height and derive width for aspect. Simpler fixed: REN_W=640, REN_H=400. Display canvas fills window, scaled preserving aspect (letterbox). HUD drawn at display resolution.

Actually weapon should be drawn in display coordinates; scale accordingly. Fine.

Let me set up internal buffer as Uint32Array REN_W*REN_H, ImageData once.

Let me code texture sampling for walls: for column x across wall stripe, step = TEX/lineHeight; texPos increments. texX index into column. I'll precompute wall texture as Uint32Array TEX*TEX. Also store per texture.

Floor textures as Uint32.

Let me implement shading: shade = side===1 ? 1.0 : 0.7 (walls). Combine RGB: (r*shade,...). Precompute? per pixel compute shade may be slow but ok. I can multiply color by factor: c = (r*k)|((g*k)<<8)|((b*k)<<16)|alpha. Do inline.

To speed, precompute shaded versions of each texture? That doubles memory. I'll just compute per pixel: 
```
const s = side===0?0.75:1.0;
r=g=b multiply
```
Better precompute two lookup copies per texture: bright and dark. Precompute `texShade[i]` array [bright, dark] indexed by texture*2+side. Actually store pairs.

Let me precompute an array `wallTex` where each entry is TEX*TEX Uint32s, plus `wallDark` same. Then in render choose buffer by side. That's clean and fast.

Same for floor maybe no shading added (distance fog optional). I'll add distance fog for atmosphere: blend toward black based on rowDistance. Could too expensive per pixel but fine.

Actually to keep performance, skip floor fog or apply light fog by sampling via multiply with factor computed from rowDistance.

Let me keep floor simple without fog for perf. Add subtle fog on walls based on perpWallDist (distance-based darkening) to enhance depth. Compute factor = clamp(1 - perpDist/maxDist). Apply. That requires multiply per column (not per pixel row) — precompute a lookup table of shaded colors? Column uses various texture pixels. Could create per-column shading by sampling from a precomputed "faded" texture table for ~N distance buckets. Might be overkill.

I'll apply wall fog per column using per-pixel multiply but only wall column (h up to REN_H). Multiply cost similar to drawing anyway. Let me do simple: factor per column, and draw with brightness scaling using a small operation. I'll implement by reading tex pixel, splitting channels and multiply — a bit costly but only for wall pixels. Given REN 640x400, fine.

Alternatively precompute per column a darkened texture column lookup once per distance bucket. Eh. I'll just multiply.

Actually simpler: precompute a set of shaded variants? Too much. Multiply inline is fine on modern.

Let me just write it.

Let me define helper to make color: 
```
function rgb(r,g,b){ return (255<<24)|(b<<16)|(g<<8)|r; }
```

For shaded: 
```
function scale(c,k){ 
  const r=(c&255)*k; const g=((c>>>8)&255)*k; const b=((c>>>16)&255)*k;
  return (255<<24)|((b&255)<<16)|((g&255)<<8)|(r&255);
}
```

Now enemies render: replicate with optional fog? I'll just draw sprite with slight darkening by distance. Multiply inline per pixel.

OK let me write now.

Player movement: 
- forward/back W/S along dir vector. strafe A/D along perpendicular. Speed ~3.0 units/s, dt.
- Collision: check new position against map; if cell 0 (floor) and within radius, move. Use radius ~0.2. Check separately x and y to slide along walls.
- Turning: arrow keys rotate, mouse moves yaw (adds to angle), using rotation matrix.

Represent player dir by angle; recompute dir vector and plane from angle each frame. That's easiest. angle += yawRate*dt or mouse.

Mouse controls: rotational sensitivity; movementY changes pitch? We have vertical camera fixed (no pitch) but we could add slight pitch via view bob. Skip pitch; but store looking up/down minimal. Keep horizon center.

Mouse look: rotationX only.

Let me implement pointer lock: click on canvas start screen triggers game start + requestPointerLock. mousemove with movementX adds to angle when locked.

Pause: Esc releases lock automatically (browser). I'll detect lock loss → show paused overlay.

Firing: mousedown while locked, or Spacebar, or Ctrl.

Let me write final code.

Sprite world coordinates: enemies move in float world coords. Position in map array as floor for movement; ensure stays in path.

Enemy movement: direction toward player, try move with wall collision radius ~0.15.

Let me cap enemy speed ~1.2.

Let me code enemy "see" line of sight DDA: step along from enemy to player; check each grid cell for wall until reaching player cell. If wall found before reaching (within distance*... )-> blocked.

```
function los(x0,y0,x1,y1){
  const dx=x1-x0, dy=y1-y0; const len=Math.hypot(dx,dy);
  if(len<=0.01) return true;
  const steps=Math.ceil(len*8);
  for(let i=1;i<steps;i++){
    const fx=x0+dx*i/steps, fy=y0+dy*i/steps;
    if(map[Math.floor(fy)*MAP_W+Math.floor(fx)]) return false;
  }
  return true;
}
```

Good enough.

Enemy shoot: if sees player, dist<20, cooldown<=0 → player.health -= dmg(4..7); cooldown=1.5-2.5s random; spawn small flash. Sound.

Let me now write weapon markup for display.

I'll draw gun on display canvas after scaling internal buffer. Compute scale factor sx = dispW/REN_W. Draw gun at center bottom scaled.

Given complexity, let me draw gun in a way independent of resolution: compute cx = dispW/2. base y = dispH. gun width ~ dispH*0.6, etc. I'll draw with coordinates relative to dispH.

Recoil: when shooting, offset gun down/up by recoil which decays.

Muzzle flash: draw bright polygon at gun muzzle for a few frames.

Now, let me also add subtle screen shake on damage (vignette).

Let me now finalize and write the file.

I'll write the JS as a big IIFE.

Let me draft key update loop with requestAnimationFrame and fixed-ish dt clamped.

Enemy sprite texture drawing - I'll author a decent humanoid. Let me draw a "guard" figure:
- 64x64, transparent bg
- head circle at top
- shoulders/body
- legs
- a gun pointing toward viewer? Since billboard, facing viewer; draw front-facing soldier with gun raised.

Let me create function drawSoldier(ctx, palette). I'll draw a stylized soldier with helmet, face, body, arms holding a gun across chest. 64x64 might be small but scaled up.

Given enemies are ~0.8 world units and appear at up to h/transformY*0.8 px. At close range large, at far small. 64px texture scaled is pixelated—fits style.

Let me author with shapes using fillRect to create blocky soldier. Good.

Add per-enemy variant with palette color.

Let me write drawEnemySprite(type) returning offscreen canvas 64x64.

Also pickups: health cross sprite, ammo box.

Let me now write the code file. It'll be long.

Let me carefully write the full HTML.

I'll include:
- meta viewport
- CSS: fullscreen canvas, overlay, crosshair hidden.
- JS.

Let me write.

I need to double check floor casting row formula and ensure horizon at h/2. Player camHeight controls floor/ceiling split? With rowDistance = (0.5*h)/ (y - 0.5*h). Standard lodepad floor casting uses that with cameraHeight factor: rowDistance = cameraHeight * (h/2) / (y - h/2). I'll use camHeight=1.0. So rowDist = (h/2)/(y - h/2).

Then stepX = rowDist*(rayDirX1-rayDirX0)/w, stepY similar.
floorX = posX + rowDist*rayDirX0; floorY = posY + rowDist*rayDirY0.

For each x: 
cellX = floor(floorX); cellY=floor(floorY); texFx = floorX - cellX; texFy = floorY - cellY;
tx = int(texFx*TEX); ty=int(texFy*TEX);
if cellX<0||>=MAP_W||... sample floor/ceil texture by isWall.
// also alternate ceiling texture by (cellX& something)? Lodev uses texture based on (int(y)+int(x))&1 checkerboard to show motion. I'll do that: tx = int(texFy*TEX)+... Let me follow Lodev checkerboard: they compute tx = int(texFactor * (floorX - cellX)) etc and texture = (cellY + cellX) & 1. I'll do floorTexIndex based on ((cellY+cellX)&1) for nice checker, and sample.

Put pixel at (x,y). floorX+=stepX; floorY+=stepY.

Note: for ceiling (y<h/2) use ceilY = cellY+1, texFy = 1 - (floorY - cellY). Standard.

Only compute floor for lower half and mirror by symmetry to upper half (ceil) to save time: 
```
for(y=h/2; y<h; y++){ ... sample; img[ y*w+x ] = floor color; 
  // ceiling: use same y-distance
  // ceiling tex cellY+1, ty = TEX-1-ty
  img[(h-1-y)*w+x] = ceiling tex
}
```
Hmm mirror requires same cell mapping but with ceil cell above. Let me just compute both floor and ceiling in same inner loop as Lodev does (they do both for full column). I'll compute both.

Use floorTexture array of Uint32 for indices 0..7 (checker). I'll create 4 floor textures and 4 ceiling textures, alternate.

Let me just make checker index = (cellY+cellX)&1 → two floor textures and two ceiling textures.

I'll generate: floorTex[0], floorTex[1]; ceilTex[0], ceilTex[1].

Sample: floor index for actual cell; ceiling use different cell (cellY+1). I'll compute both cells in loop.

Let me implement inner:
```
for (let x=0; x<REN_W; x++){
  const flX = floorX - Math.floor(floorX); 
  const flY = floorY - Math.floor(floorY);
  let fx = (flX*TEX)|0; let fy = (flY*TEX)|0; if(fx>=TEX)fx=TEX-1; if(fy>=TEX)fy=TEX-1;
  const cellX=Math.floor(floorX), cellY=Math.floor(floorY);
  const fIdx=((cellX+cellY)&1);
  out[(y)*REN_W+x] = floorTex[fIdx][fy*TEX+fx];
  // ceiling
  const cy = cellY + 1;
  const fy2 = TEX-1-fy;
  const cIdx=((cellX+cy)&1);
  out[(REN_H-1-y)*REN_W+x] = ceilTex[cIdx][fy2*TEX+fx];
  floorX+=stepX; floorY+=stepY;
}
```
Wait fy for ceiling should use 1-flY of cell above; using TEX-1-fy approx okay.

This entire loop runs per row for rows h/2..h. Good.

But note: the floor casting must run before walls? Order: draw floor/ceiling for entire buffer first, then walls, then sprites. Yes.

Wall rendering draws over.

Let me now write it all.

Edge: y goes from h/2 to h (inclusive?). Use y = H2; y < REN_H; y++.

rowDist at y=H2 would be (H/2)/0 = inf → skip y=H2 (the exact horizon). Start y=H2+1. Set those single pixels? The horizon row will be partially covered by walls. Fine, leave y=H2 undefined color (0). Actually set to a sky/floor blend at exact horizon—negligible line. I'll just start H2 (rowDist infinite → big). Let me start at H2 and clamp rowDist? Better start y=H2+1 and separately fill y=H2 with floor top color. Minor. I'll fill y=H2 as ceiling bottom color basically. Eh, I'll do loop y from H2 to H-1 with rowDist computed, and for y==H2 set rowDist to a large finite like 1e9. Simple.

Let me now write initialize textures etc.

Now let me consider performance: floor casting O(H*W) with some math + texture reads. 200*640=128k per frame, plus walls ~640 columns * up to 400 = also ~ that. Fine.

Alright writing.

Let me set REN_W=640, REN_H=400. H2=200.

Let me code mouse sensitivity default. Provide option keys.

Let me also implement the whole control/turn with angle.

Let me define:
```
let posX=1.5,posY=1.5, ang=0; // facing
```
dirX=Math.cos(ang), dirY=Math.sin(ang); planeX=-dirY*fovFactor; planeY=dirX*fovFactor; where fovFactor=0.66.

Rotation adds to ang.

Movement uses dir/perp vectors.

Now weapon: I'll draw a simple raygun.

Let me write final code now. I'll include robust texture generation.

Let me start writing the file.

I'll generate textures using 2D canvas 64x64.

makeTexture(drawFn) returns Uint32Array.

Let me write helper newTex(): create canvas, ctx, then drawFn(ctx), getImageData → build Uint32.

Also create sprite as {canvas, data(Uint32Array), w,h} for billboards. I'll keep canvas to draw directly? Easier to draw sprites via sampling ImageData columns. I'll convert to Uint32.

Now write.

For wall texture reading in stripe: I'll get tile texture index tIdx = mapping. The texture array `wallTex[tIdx]` bright and `wallTexDark[tIdx]`? I'll store `wallTex` list of Uint32 bright, and compute dark on the fly per column multiply... Actually to avoid multiply cost, precompute dark variant array `wallTexD` parallel list. When side===1 use bright, side===0 use dark. Good no multiply. Plus fog? skip wall fog or keep. I'll skip per-pixel fog to keep perf; instead precompute a mild dark already for one side; good enough.

Floor textures bright only.

Now write.

Let me also handle the crosshair & HUD on display canvas.

Muzzle flash & gun.

Let me code gun drawing function drawGun(ctx, dispW, dispH, state).

Let me define gunstate: recoil (0..1), bobPhase, firing flash frames.

Let me write all frames now. I think I have enough plan. Let me write the file.

For enemies count ~ e.g., 12. pickups: some health, some ammo.

Ammo mechanic: shoot costs 1 ammo; if 0, can't shoot (empty click). Ammo pickups give +20. Health +25.

Win detection: all enemies dead → show "MISSION COMPLETE" and let restart.

Player death → "YOU DIED".

Restart button / key R.

Start screen overlay with instructions. Let me use a div overlay that on click starts game.

Let me write it.

I'll compute weapon drawing coordinate in display pixels.

Let me write everything now in one write.

One more: pointer lock. On mousedown while not locked, don't fire (to avoid accidental). Fire requires locked. On start click requesting lock. Provide toggle key M to switch to arrow-only turn (unlock). 

Esc unlocks → show paused overlay "Click to resume".

Let me include key P/Pause checks.

Now writing.

Let me be careful: REN buffer indexing and putImageData.

Let me define:
```
const backBuf = new Uint32Array(REN_W*REN_H);
const img = ctx.createImageData(REN_W,REN_H);
const img32 = new Uint32Array(img.data.buffer);
```
Each frame copy backBuf into img32 then putImageData(display). Actually putImageData into internal then drawImage scaled. Let me have two contexts: renCtx (offscreen canvas REN size) and dispCtx (main canvas sized to window). 

Frame:
```
img32.set(backBuf);
renCtx.putImageData(img,0,0);
dispCtx.imageSmoothingEnabled=false;
dispCtx.drawImage(renCanvas, 0,0, dispW, dispH) // stretch to full window (fill)
```
I'll fill window fully (stretch) for immersion; aspect distortion slight but ok. Or preserve aspect letterbox. I'll do stretch to full — fine.

Size canvases on resize.

display canvas fills window; draw scaled render stretched; then HUD/gun drawn on top in display pixels; overlay for start/pause as DOM.

Note drawImage stretching 640x400 to e.g. 1920x1080 pixelated - fine.

For HUD text scaling, draw in display px.

Crosshair at disp center.

Gun drawn at bottom center disp px.

Let me now write the code. Given length I'll write carefully.

Let me write enemy AI and damage.

I'll now produce the file.

I'll include sound via WebAudio: functions beep(freq,dur,type,vol) generating oscillator. shoot: two quick blips descending. enemy hit: noise. player damage: low thud. enemy shoot: harsh. pickup: pleasant.

Let me implement a tiny helper.

Now writing the big file.

Let me define maze guard eq.

I'll write final. Let me carefully produce the JS.

For sprite rendering loop (sprites = enemies + pickups), I need per-entity screenZ (transformY) to sort descending.

Let me maintain global zbuffer REN_W filled during wall render with perpWallDist.

Sprite code per entity (as described). For texture sampling variable sprite width/height: prod.

Let me write.

Enemy facing/motion causes jitter? fine.

Let me write the movement collision: 
```
function tryMove(nx,ny){
  const rad=0.18;
  // check x separately
  if(!isWall(nx + (dirSignX?),...))
}
```
Standard: 
```
let nx = posX + moveX; let ny = posY + moveY;
// axis slide
if(!collide(nx, posY)) posX=nx;
if(!collide(posX, ny)) posY=ny;
```
collide checks grid cells overlapping a small box around (x,y): for the four corners x±r,y±r check wall. If any wall → blocked.

collide(x,y): 
```
const r=0.15;
const x0=Math.floor(x-r),x1=Math.floor(x+r),y0=Math.floor(y-r),y1=Math.floor(y+r);
for(gy=y0;gy<=y1;gy++)for(gx=x0;gx<=x1;gx++){ if(map[gy*MAP_W+gx]) return true;}
return false;
```
Bounds: keep within map 1..MAP_W-1; maze borders walls so fine; clamp indices.

Good.

Now firing hitscan: choose enemy within angle & range & LoS. Compute per enemy: 
```
const relX=e.x-posX, relY=e.y-posY;
const dist=hypot;
if(dist<range && los(posX,posY,e.x,e.y)){
  // angle between view dir and enemy direction
  const dotFwd = relX*dirX+relY*dirY; // >0 in front
  if(dotFwd>0){
    const angEnemy = Math.atan2(relY,relX); const angView=Math.atan2(dirY,dirX);
    let diff = angEnemy-angView; wrap to [-pi,pi];
    const spread = 0.05 + 0.5/dist; 
    if(Math.abs(diff)<spread){
       // candidate; choose smallest dist among hits
    }
  }
}
```
Hmm angle spread in radians small near center. But if mouse not locked maybe use center. Since crosshair center = view direction, this hits whatever is centered. Good.

Alternatively pick enemy whose screenX closest to center among those in front with LoS & dist<range. That's intuitive for crosshair. Let me compute screenX via transform and pick min |screenX-REN_W/2| under threshold. Better.

Let me implement using the sprite transform to get screenX, then threshold ~ 1.0 (deg). Use distance falloff damage.

Multiple enemies maybe; pick closest in threshold.

Damage: base 34 at close, scale down by dist: dmg = 34 * clamp(1,0.25) ... I'll do dmg = clamp(40/(1+dist*1.5), 12, 40). Enemy hp ~ 30-60. So 1-3 shots.

Enemy variants with hp.

Now player damage: enemy hits dmg 5-12, health cap 100; pickup heals.

Let me now write.

Alright, let me write the file completely now. It's big but one file.

I'll write carefully with correct syntax.

Let me produce it.

Also add minimap in HUD corner? Pixelate. Could add small map on a side. Nice to have. I'll add a small minimap rectangle top-left showing walls, player direction, enemies. Drawn in display HUD.

Let me include.

Now writing final.

I'll write the script.

Careful: typed array index `map[gy*MAP_W+gx]` returns number with "no-undefined" but typed arrays return undefined for OOB; guard.

Let me write.

For enemies list update including spawn labels.

I'll now produce the write command.

Let me also ensure star screen overlay styling nice with retro font (system monospace). No external fonts.

Let me write.

Given the size, I'll write in one go. Let me draft mentally then output.

I'll write now.

For rotate with turning keys: 
```
const rotSpeed = 2.6 * dt;
if(keys['ArrowLeft']) ang += rotSpeed;
if(keys['ArrowRight']) ang -= rotSpeed;
```
Mouse adds angDelta = -movementX * mouseSens * dt? Actually movementX per move event; accumulate per frame. I'll accumulate `rotAcc` from mousemove and apply per frame.

Let me store `mouseDx` accumulated; each frame ang += mouseDx * sens; reset to 0.

sens ~ 0.0022.

Vertical mouse ignored.

Now code.

Let me write gun.

I'll define gun colors metallic.

Let me write drawGun:
```
function drawGun(disp, W, H, s){
  const cx=W/2;
  const bob = s.bob; // -1..1
  const recoil = s.recoil;
  const gw = H*0.62, gh = H*0.55;
  const gx0 = cx - gw*0.30, gy = H*0.78 + bob*bobWalkAmp + recoil*H*0.06;
  ... draw rectangles ...
}
```
I'll draw a raygun: body, barrel, grip, glow. Add muzzle flash circle when s.flash>0.

Let me implement moderately.

Also crosshair: small cross.

Weapon might look simple; fine.

Now HUD text draw with font monospace bold.

Let me write.

Time to output the file.

I'll write the entire index.html.

Let me also make sure to handle restart (R key) resets enemies & player.

Let me define init() to create maze, enemies, pickups, reset stats.

On game over show overlay with message; clicking restart.

I'll manage state var: 'start','playing','paused','over'(gameover or victory). Overlays.

Let me code overlays as DOM div: #overlay containing innerHTML depending on state, always covers. Actually I'll have a single #overlay with dynamic text and a click handler. When state 'playing', hide overlay. When pointerlock lost and state playing → set paused show overlay.

Click on overlay: 
- if start → init(), state playing, requestLock.
- if paused → resume lock, state playing.
- if over → init(), playing, requestLock.

Let me implement requestLock on canvas element.

Edge: requestPointerLock may fail; still allow playing with arrows if not locked. I'll set mouseActive = locked.

Alright writing now for real.

Let me define constants and init.

I'll write the JS top-down logically.

Given complexity, let me now write.

I will produce a fairly long file. Let me write it.

I'll build a complete Wolfenstein 3D-style raycasting maze shooter. Let me create the single self-contained HTML file.

assistant
thinking
Let me build a Wolfenstein 3D style raycasting maze shooter as requested. This is a substantial single-page app. Let me plan the architecture:

1. **Map**: A grid maze with walls (1), floor space (0), and pickups/enemies placed procedurally.
2. **Raycasting**: DDA algorithm for rendering textured walls with distance-based shading/fog.
3. **Textures**: Procedural textures generated via canvas — brick, stone, wood, etc.
4. **Player**: WASD movement, collision, mouse/arrow turning.
5. **Enemies**: Sprites (bilboards) rendered via raycasting sprite projection, animated, shootable.
6. **Weapon**: A gun that renders in foreground, fires projectiles/hitscan.
7. **Floor/ceiling**: gradient rendering.

Let me write a comprehensive implementation. I'll write it all into one index.html file.

Let me think about the rendering carefully:

**Raycasting core**: For each screen column x, cast a ray through the grid. DDA gives wall hit distance and side. Then project wall slice.

**Camera plane** for ray direction: dirX, dirY (player direction), planeX, planeY (camera plane perpendicular).

For screen x from 0 to width:
- cameraX = 2*x/width - 1
- rayDirX = dirX + planeX*cameraX
- rayDirY = dirY + planeY*cameraX

**DDA**: mapX, mapY = player's map pos. deltaDistX/Y given rayDir. stepX/Y and sideDistX/Y. Loop until hit. Determine side (0 = x-side, 1 = y-side). perpWallDist.

**Wall height**: lineHeight = height / perpWallDist. Draw slice.

**Texture mapping**: wallX = hit point fractional coordinate. texX = wallX * texWidth. Add texture vertical coordinate stepping.

**Sprite rendering** for enemies: compute transform with inverse camera matrix, project onto camera plane, draw columns.

**Z-buffer**: store perpWallDist per column for sprite depth testing.

Let me construct the map as a maze generated with recursive backtracking, then fill walls=1, floor=0. Place enemies in open cells.

Let me define tiles:
- 0 = floor
- 1 = wall
- Various wall texture types maybe via tile value: 1-5 different wall texture types.

Actually let me use tile numbers to select wall texture: tile value = texture index. Generate maze with walls as specific textures.

Let me plan textures:
- brick red
- stone blue-gray
- wood
- mossy brick
- metal/rust
- unique green (eagle), like blue (column), etc. (nice Wolfenstein flair)

I'll generate textures procedurally on offscreen canvases.

**Enemies**: draw as sprites with simple shapes — procedurally generated enemy sprites (like an ugly soldier). I'll generate enemy sprite canvases with body, head, gun. Animate by walking. Also damage flash.

Let me write procedural enemy sprite generation. Might be simpler to draw enemy directly on the wall/scanline projection using its sprite canvas.

I'll generate enemy textures on offscreen canvases at multiple animation frames.

**Shooting**: hitscan. On fire, cast a ray and check along the ray for enemy intersections. Simplest: check center column z-buffer distance, compute enemy transform at screen, if enemy within a tolerance of center x and within z-buffer range, hit.

Actually simpler: raycast and find if an enemy is hit. Let me do: frame fire effect, muzzle flash, and determine hit by checking enemies — compute each enemy's transformed position; if it falls near screen center and perp distance close to z-buffer at that column (i.e., not occluded by wall), it's hit.

Let me just do: for hitting, cast ray from player through center. For each enemy not dead, compute perpendicular distance and whether the ray intersects the enemy's screen rectangle around center. Check wall occlusion using z-buffer at center column.

I'll keep it reasonably simple but functional.

**Enemy AI**: Chase player when within a range/line of sight. Move toward player, collide with walls. When close, attack (deal damage). Player has health, enemies have health.

**HUD**: health, ammo, weapon, minimap, crosshair, game over / win state.

Let me also add falling/avoid — player collision with walls.

Let me write the code. This will be long. Let me be careful and write complete working code.

Let me structure the JS:

```js
const CV = document.getElementById('c');
const CX = CV.getContext('2d');
```

Sizes: canvas 960x480 maybe. Let me use width=960 height=540. ImageData-based rendering for performance (pixel buffer per column). Actually using putImageData each frame is efficient. I'll render walls directly into an ImageData then draw sprites overlaid? Sprites need per-pixel with texture and shading; easier to use drawImage with sprite slices per column.

Approach: 
- Render walls into ImageData buffer (48x24 texture per tile region). For each column, iterate scanlines, set color.
- Then set imgData -> putImageData.
- Draw sprites using ctx.drawImage cropping slices.

But sprites need z-buffer occlusion by walls — fine since walls drawn first. But sprite vs sprite occlusion — I can sort sprites far-to-near and draw with z-buffer.

For a solid GameBoy-ish approach, draw sprites per column manually into the ImageData too, then putImageData once. That's most correct but slow-ish. Let me do wall rendering into ImageData, putImageData once, then draw sprites with drawImage slice-per-column using the z-buffer. Since walls already drawn, sprite depth vs wall handled naturally. For multiple enemies overlapping, sort far to near.

Let me do that.

Grid size: say 24x24 maze built with recursive backtracker where walls are odd cells... Actually standard maze generation on an odd grid: create NxN of all walls, carve paths.

Let me generate a maze: mazeW=11, mazeH=11 (odd) so paths are corridors width varying. Hmm for Wolfenstein feel we want rooms and corridors. A maze gives corridors. Let me do a maze of size cells = e.g., 14x10 populated with rooms plus corridors.

Simplest robust: recursive backtracker on grid where cells are separated by walls. Grid dims: cols=25, rows=25 total cells each 1 unit. Use cell size in map units... Actually let me make map where each "cell" is 1x1 and maze corridors carved at path width... complicated.

Let me use a simpler approach: 
- Grid of N x M where generation uses a cell array.
- mazeGrid: 2*N+1 x 2*M+1. N=M=9 => 19x19. carves 1-wide corridors. That's fine, corridors width 1. Maybe I want wider. 

Alternatively use "thick" maze: carve in a grid where every maze cell maps to 3x3 map tiles (corridor 3 wide). That gives spacious corridors.

Let me do: each maze cell = 3x3 tiles. Maze occupies cells. Map size = (2*MW-1)*cellSize...

Hmm, let me keep it clean: recursive backtracker moving by 1 cell producing corridors 1-wall-thick. Then widen by using a scale factor so corridors appear ~2-3 tiles wide? Not straightforward.

Simplicity: I'll build a maze with the recursive backtracker at a base grid, then "thicken" walls into blocks? I'll just accept 1-unit-wide corridors but set player movement radius small, textures make it look fine. Actually enemy density in 1-wide corridors is restrictive.

Let me make corridors wider by a post-step: after generating base maze (odd grid), replace each carved `floor` cell and its neighborhood... no.

Alternative method producing naturally wide rooms: 
1. Start with all walls.
2. Random walk "cave" carving: carve a random path, with probability to randomly jump to a random location. This makes open map with rooms. Good for a shooter.

Random-walk carve: choose random point, random walk carving nearby cells for ~2000 steps, occasionally teleport to random location. The result is open rooms with pillars of walls remaining. That actually looks good and plays well. Let me use that but ensure connectivity (random walk is connected since it's a walk).

Then assign wall textures around. Also carve the perimeter border walls thick.

Since it's random walk with teleports, connectivity holds along the walk path. Good enough.

Let me design map:
- MW=64, MH=48 tiles. All tiles = 1 (wall with varied textures).
- Random walk carving: start at center, walk many steps carving 0, teleport periodically. Avoid carving edges (border walls). Carve with some thickness (carve a 2x2 or cross) to make open areas.

I'll carve using a "brush" cross to make wider corridors.

Player spawn at center. Place ~10 enemies in random floor cells. Place pickups (ammo, health) too.

Textures: I'll create an array of texture canvas, index by tile value: value 1..t = brick, stone, wood, moss, metal, eagle. Randomize wall texture per wall tile.

To keep texture tiling visually nice, each tile samples its own texture based on tile value.

Let me define getPixel for wall rendering reading from offscreen texture canvases via getImageData (precomputed into arrays for speed).

Actually reading getImageData each frame is slow but we do per-pixel. Better: precompute texture as Uint32Array (RGBA) per texture. Then in render loop build Uint32 buffer.

Let me do:
- textures: array of {w, h, data: Uint32Array}
- Build each via canvas 2D.

Wall rendering per column:
```
rayDirX/Y, dda...
lineHeight, startY, endY
wallX frac -> texX
texStep = texH/lineHeight (as float) 
texPos = (startY - h/2 + lineHeight/2) * texStep
for y in [startY..endY]:
   texY = int(texPos) & (texH-1); texPos+=texStep
   color = texData[texY*tw + texX]
   shade based on side and distance
   buffer[y*W+x] = shaded color
```

I'll precompute darkening by distance in bands. To keep speed, I'll compute shade factors.

Let me cap lineHeight for perf? Wall slices per column ~ lineHeight up to screen height. Fine.

For shading, compute a single factor per column (based on side and perpWallDist) and multiply RGB of each pixel. Multiplying per pixel per column. Acceptable.

Floor/ceiling: I'll fill with a vertical gradient first (ceiling dark blue-top, floor brown-near). Actually floor casting would be nicer but heavy. Let me do a simple gradient fill then walls over. Add fog gradient. That's acceptable aesthetically.

Better: do actual floor casting for the "floor texture" look? It's heavy. I'll do a gradient + subtle horizontal scanline floor texture? Keep gradient.

Let me fill background: ceiling gradient (dark) upper half, floor gradient (ground) lower half. Then draw wall slices.

Sprite rendering:
```
invDet = 1/(planeX*dirY - dirX*planeY)
transformX = invDet*(dirY*spriteX - dirX*spriteY)
transformY = invDet*(-planeY*spriteX + planeX*spriteY)  // depth
screenX = (W/2)*(1+transformX/transformY)
spriteScreenX = int(spriteX) ...
vMove = 0
spriteHeight = abs(int(H/transformY))
spriteWidth = abs(int(H/transformY))
spriteStartY = -spriteHeight/2 + H/2 + vMove (use actual projection height)
spriteStartX = -spriteWidth/2 + screenX
for stripe:
   if transformY>0 and stripe in [0,W]:
      if transformY < zbuffer[stripe]:
         draw column
```

Use drawImage cropping from sprite texture canvas, scaled to spriteHeight/spriteWidth.

For enemies, I want them standing properly. Use sprite texture canvas of enemy, with transparency. Column from texture: source x = stripeX. Draw slice to dest x = spriteStartX+stripe, height scaled.

Let me generate enemy sprite on canvas ~ 64x92 (width 64 height 92) with transparent bg. Draw soldier: helmet, head (skin), torso (green/dark), gun. 2 frames (legs). Also hit/flash variant.

Since drawImage needs preserving aspect, set spriteW in terms of width 64, height 92: project width = spriteWidth64 = H/spriteY*(64/viewplane?)... In standard raycaster, spriteWidth=abs(H/transformY) assumes square texture. For non-square, scale: draw slice height = (textureH/textureW)*spriteWidth. Let me compute dest height = spriteWidth * (texH/texW). I'll handle.

Let me just draw per-stripe using drawImage: 
```
srcY=0, srcH=texH, srcX=stripe, srcW=1
destX=spriteStartX+stripe, destW=1, destH=spriteHeight, destY=spriteStartY
```
where spriteStartY uses textureHeight normalized feet-at-horizon. Compute: drawW = spriteWidth (=H/transformY roughly, but scale so feet~ground): Let me treat projection using aspect: standard approach handles square. For height-proportions, I'll set the enemy's on-screen size as height = k/transformY and width = height*(texW/texH). Compute vMoveShift for feet at horizon line = H/2. Since feet should be at floor horizon (centroid of screen). For standing sprites feet at horizon: drawY.bottom = H/2 (horizon at center). So destY = (H/2) - drawH. Actually with vMove=0 center maps... whatever, draw sprite centered with feet at H/2. I'll place feet at screen H/2 (horizon). But floor gradient horizon is at H/2. Good.

Let me set destHeight = abs(H/transformY) * (texH/texW) ... then width = destHeight*texW/texH. Hmm circular. Let me define: onScreenWidth = H/transformY (pixels) (for texW wide texture). onScreenHeight = onScreenWidth * texH / texW. Then draw each column of height onScreenHeight.

Sprite feet bottom at horizon = H/2. Top = H/2 - onScreenHeight.

But actually feet should be below horizon if floor extends. Standard raycaster centers sprite vertically (feet at bottom of projection). Simplest: center them so feet are at H/2 + vMove. I'll set vMove so feet sit near bottom of the cell... It looks fine to center with feet at H/2.

Let me just center sprite vertically at H/2 (like classic). Good enough visually.

Shooting: hitscan from center. Determine hit:
- Use center column zbuffer: wallDist at W/2.
- For each alive enemy, compute transform at center ray: 
  ```
  invDet...
  transformX/Y for enemy
  if transformY>0:
     screenX for enemy at center ray (cameraX=0 => rayDir = dir). 
  ```
  Actually to check hit, compute the enemy's perpendicular distance transformY (depth). If transformY < wallDistAtCenter (unblocked) and enemy is near center line (|transformX| small relative to depth -> within sprite width at that depth) -> hit.
  
  Simpler: enemy at depth d, half-width on screen = (onScreenWidth/2)/... Let me compute screenX of enemy projected onto camera including cameraX for center = 0: screenPos = (W/2)*(1+transformX/transformY). The center is W/2. Enemy hit if |screenPos - W/2| < halfWidthScreen where halfWidthScreen = (onScreenWidth/2). And transformY < zbufferCenter. Then choose nearest hit.

I'll implement that.

Timing: use requestAnimationFrame with delta time, movement speed units/sec.

Let me also add falling... subtract gravity just visual bob. Keep simple: view bob based on movement for style.

Weapon render: draw a gun at bottom-right in screen space each frame, with muzzle flash on fire, recoil. Procedural gun canvas pre-rendered.

HUD overlay: crosshair, health bar, ammo, kills, minimap (small canvas top-left), messages.

Let me now also handle enemies shooting back: when line of sight and within range, enemy "shoots" player reducing health (projectile shown as sprite). I'll add a visual tracer. Keep basic.

Game states: playing, gameover, win. Restart with key R or button.

Let me write it all now.

Let me be mindful of performance: imageData per frame with W*H writes for background+walls. Resolution: maybe render at lower internal res and scale up? To keep crisp but performant, I'll render at full canvas but keep grids moderate and cap lineHeight. Modern browsers handle 960x540 easily. I'll go 960x560? Let me use 960x540.

Actually 960x540 * per frame buffer ~ 518k pixels, ~ fine for 60fps.

Let me code textures generator. I'll write functions to draw each texture into a canvas.

Textures (64x64):
1. Brick: red brick pattern with mortar lines.
2. Stone: gray blocks.
3. Wood: planks horizontal brown.
4. Mossy brick: green tint over brick.
5. Metal: riveted metal gray.
6. Eagle: like Wolfenstein final secret — blue eagle on red. Fun.
7. Column / mixed.

Enemy sprite: I'll draw on a canvas. Let me draw a simple bipedal trooper with helmet.

Let me write the code now. I'll aim for clarity and correctness.

For minimap colors, fine.

Let me handle keyboard: track keys state. WASD movement. Arrow keys turn; mouse: use pointer lock for turning (button to lock). Also on-screen button to lock pointer. Mouse click fires.

Let me implement pointer lock on canvas click, mouse move to turn. Fire on click (also mouse locked click fires). Provide fallback: also 'F' or space to shoot if not pointer-locked.

Let me structure events.

Now write everything.

Let me define constants and get going. I'll write the file.

Let me carefully write the whole index.html.

I'll write concise but complete code. Let me produce it.

For the maze random walk, ensure not trapping in border. Carve area from x in [2, MW-3], y in [2, MH-3]. Brush carve cross: set 5x5? Too much. Use brush radius pattern: carve the current cell plus cross neighbors of a 3x3? Let me carve a plus: cells (x,y),(x±1,y),(x,y±1) set floor, occasionally. To make open halls, carve 3x3 block sometimes.

Let me implement:
```
function carve(x,y){ if in bounds set 0 }
walk: px,py center. for i<steps:
  d = dir random; move.
  carve 3x3 around (x,y) -> open rooms-ish. But carving 3x3 at 64x48 gives big open areas quickly. Maybe carve plus/cross.
```
I want decent open areas for fights. Let me carve a 3x3 block at each step => wide rooms. With 64x48 map that's fine, plenty of wall left. Let me do carve3x3 with random teleports (to create multiple rooms). This yields roomy T-shaped corridors. Good.

But connectivity: random walk in this scheme — when teleport to a random new location, that area becomes connected via future steps? Actually teleport breaks path; carving continues from that new cell, and eventually cells overlap, connecting. Not guaranteed but typically connects because later steps wander over. Radio connections fine.

Let me not overthink; random-walk carve 3x3 blocks from start, plus random teleports. Result looks like a dungeon. Good.

Also place a few isolated pillar regions retained as walls.

Now code.

Let me get texture data as Uint32Array. I'll make helper: makeTex(64,64, drawFunc) returns {canvas, data}. Put imageData from canvas getImageData.

For enemy sprites, I'll make canvas and use as texture for drawImage directly (not typed array).

Alright writing.

Fog/distance shading: factor F = clamp(1 - perpWallDist/maxdist, min, 1). Multiply RGB.

Let me implement shade for pixel: since Uint32 abgr little-endian layout. Canvas ImageData pixel bytes are RGBA. In buffer Uint32, value = a<<24|b<<16|g<<8|r. Multiplying channels: extract r,g,b.

Let me write shade helper inline:
```
r = px & 255; g=(px>>8)&255; b=(px>>16)&255;
r=int(r*f); ... 
px2 = (0xFF<<24)|(b<<16)|(g<<8)|r;
```
Wait endianness: buffer[i] = data[i] as Uint32; data is RGBA bytes little-endian -> value = R | G<<8 | B<<16 | A<<24. So to write: value = (a<<24)|(b<<16)|(g<<8)|r. Yes.

I'll precompute texture arrays endian accordingly.

Now, floor/ceiling fill: fill entire buffer rows with gradient colors directly (as Uint32). Then draw walls overwriting.

Ceiling rows 0..H/2: gradient from dark to slightly lighter at horizon. Floor rows H/2..H: gradient from dark floor to lighter/checkered near. I'll add checker floor pattern for depth feel by alternating? Let me add a simple horizontal moving checker for floor using a pseudo pattern: row parity + column parity scaled. Nice depth cue. I'll do: for floor, checker based on (y) and distance dp: Actually simpler: use constant shade bands by y.

Let me just do gradient plus subtle per-column darkening for depth: floorBrightness increases with row (far is bright). Add fog: far rows (just below horizon) = horizon color (bridge to wall fog). It's fine.

Let me reduce complexity: 
- ceiling: fill rows with color from top (0,0,40) to horizon (120,120,160).
- floor: from horizon (near) (90,70,50) to bottom bright (160,140,110). Adds grounded feel.

Good enough.

Now write code.

Weapon draw: I'll create a gun canvas, draw two hands holding a pistol/rifle at bottom right, and draw with recoil offset and muzzle flash alpha.

Now finalize enemies list: {x (float in unit), y, alive, hp, texFrames[], frame, state('idle','walk','attack'), range, attackCd, deadTimer, flash}.

Enemy AI update:
- dist to player.
- if dist < sightRange and hasLOS -> chase (move toward) unless too close; face player.
- if dist < attackRange -> attack: every attackCd seconds, deal damage to player with probability, play muzzle.
- bob/anim frames by movement/time.

LOS: raycast from player? I'll do simple: for enemy to attack/see, require straight-line LOS: march a DDA from enemy toward player checking walls. Let me implement LOS check by sampling along the segment.

hasLOS(a, b): step along a->b checking tiles; if any wall return false.

Movement: move enemy toward player with dx,dy normalized, check collision with walls (probe next cell), collide with other enemies? skip.

Player death -> game over screen. All enemies dead -> win message.

Shooting: ammo limited, weapon pistol (infinite) plus maybe shotgun? Keep pistol. Add ammo count, pickups.

Let me include pickups: health and ammo crates rendered as sprites in the scene (small). Player walking over collects.

Let me implement pickups as simple sprites (drawn like enemies). I'll render them each frame with the same sprite projection. Keep small set.

Alright, let me also add sound? No external. Could generate via WebAudio oscillator for gunshot/beep. Nice touch. I'll add simple WebAudio blips (gunshot = noise). Procedural sound is allowed (no external assets). Let me add a tiny audio using AudioContext noise burst. I'll implement but guard errors (must be after user gesture; pointer lock click triggers). Keep minimal.

Let me write the file now.

I'll keep JS organized. Let me write.

Note: For rendering enemy sprites into scene, I need the zbuffer array length = canvas width (double buffer? I'll use self.bufZ Int32Array(W)).

Let me code rendering function step by step.

Let me now write everything out. This is a big file but let me go.

I'll set canvas 960x540.

Let me define these globals:
```
const W=960,H=540;
```
Player: posX,posY (float), dirX,dirY, planeX,planeY. fov ~66°, plane length ~0.66.

Start dir up (0,-1), plane (0.66,0). Actually facing north neg y.

Movement speed 2.2 cells/s run (shift sprint), turn speed 2.6 rad/s.

Let me write final file.

For the weapon drawing, I'll place gun anchored bottom-right, pivot to mouse? Keep static center firing.

Let me now write.

I'll implement pointer lock turning: on mousemove dx, rotate.

Rotation function: rotate(dirX,dirY,planeX,planeY, angle) -> new dir/plane via cos/sin.

Let me code.

For sprite drawing column-max: clamp stripes within screen.

Alright, writing the whole thing.

I'll compute per-frame array reused.

Let me write the HTML/CSS too: minimal styling, centered canvas, title, controls overlay, HUD arranged inside canvas via JS drawing (I'll draw HUD into canvas top-left etc.). Crosshair center.

Let me write final.

One more: draw order for sprites sorted far->near by transformY.

Also player bob: viewBobbing adds small vertical offset to all rendering (draw wall slices shifted). I'll incorporate as an offset added to projected startY. For background fill ignore bob (fine) or shift too. I'll shift wall/draw and sprites by bob for effect. Actually shifting sprites too requires adding to destY. I'll apply bobY to both. Hmm background gradient fixed means walls shift revealing mismatch at top/bottom edges by small amount (bob is small, <8px). Acceptable. Actually better: also draw walls a bit taller than screen to avoid gaps. I'll just keep bob subtle (≤3px). Fine.

Let me write now, final code.

Let me define enemy sprite generation carefully to look decent: 48x72.

Draw soldier:
- shadow ellipse at feet.
- legs animated (two frames: legs together, legs apart) — lower half.
- torso: dark olive jacket, ammo belt.
- arms and a gun pointing at viewer (forward).
- head with helmet.

I'll draw with simple shapes, plus an idle/hit overlay (red tint when flash).

For frames, I'll produce 2 frame canvases. For anim, alternate when moving.

Let me write drawEnemy(ctx, frame) producing 48x72 canvas. Position: draw feet at bottom near y=70.

Let me just produce.

Now, code time. Writing the file.

I need to be careful with the random generator — use Math.random fine.

Let me write.

Also add overlay screen "Click / press to start" that initiates audio + pointer lock.

Let me produce the final index.html.

Given length, I'll write in one write call.

Let me carefully draft the JS to avoid syntax errors.

I'll write the map generation:
```
const MW=56, MH=44;
map = Array(MH).fill().map(()=>Array(MW).fill(1));
fill borders already 1.
function inb(x,y){return x>1&&x<MW-2&&y>1&&y<MH-2;}
function carve(x,y){ for dy-1..1 for dx-1..1 if inb -> map[y+dy][x+dx]=0; }
startx=MW>>1, starty=MH>>1.
for steps until enough carved (target ~55% floor): random walk.
```
I'll run walk with teleports, count floor ratio; stop when FLOOR_RATIO met.

Let me implement walk:
```
let cy=starty,cx=startx; carve(cx,cy);
const dirs=[[1,0],[-1,0],[0,1],[0,-1]];
let floorCount=count0();
while(floorCount < MW*MH*0.5){
  if(Math.random()<0.04){ cx=rand inb x; cy=rand inb y; }
  let d=dirs[(Math.random()*4)|0];
  cx+=d[0]*2; cy+=d[1]*2; // step 2 to keep wall gaps? maybe step1
  if(!inb(cx,cy)){cx=startx;cy=starty;}
  carve(cx,cy);
  floorCount=...
}
```
Carving 3x3 each step will quickly fill. I'll tune ratio 0.55. Counting every iteration is expensive-ish (MH*MW=2464) times maybe thousands — fine.

Actually recompute floorCount each loop iteration: acceptable.

But carving 3x3 blocks with step covering ensures open. Let me keep brush small (3x3) and target ratio ~0.5.

Doorways? skip.

Now enemies placed at random floor cells at least distance from player.

Spawn enemies count ~ (MH*MW*ratio)/  ~ let's say 12.

Pickups: a few health (green cross) and ammo.

Let me set enemy sprite positions to cell centers (x+0.5, y+0.5).

Player spawn at center floor cell (startx+0.5, starty+0.5). Ensure floor there.

Alright.

Now the render loop using ImageData. Let me create Int32 zBuffer and Float? zbuffer = new Float32Array(W)? distances can exceed int range fine, use Float32Array.

Line rendering inner y loop: for performance set buffer indices.

Let me code carefully.

```
let data = new Uint32Array(W*H);
let img = ctx.createImageData(W,H);
let imgU8 = new Uint8ClampedArray(img.data.buffer); // 4 bytes per px
// We write directly via Uint32 view on same buffer
let buf = new Uint32Array(img.data.buffer);
```
Then at end: ctx.putImageData(img,0,0). Good — buf and img.data share buffer.

Wait Uint32Array on img.data.buffer — img.data is Uint8ClampedArray of length W*H*4. Creating Uint32Array view with same buffer works. Good, but need alignment: buffer start aligned 4 bytes, yes.

Now background fill loop over all pixels: for i in 0..W*H-1 set buf[i]=col(i). The row y = i/W, x=i%W. For gradient per row compute cross-row color at start of each row to save compute: compute per row ceiling color, per row floor color, then fill that whole row? Ceiling rows share same color entire row (no shading per column) => cheap and looks flat. But depth cue lost. Acceptable. Slight improvement: add subtle checkboard on floor via (x>>3 ^ y>>3)&1 offset brightness. Cheap since row loop can do per-pixel but cheap op. Let me include checker only on floor for depth.

Row setup:
```
for(i=0;i<W*H;i++){
  y=(i/W)|0; x=i%W;
  ...
}
```
i%W is division per pixel — slightly slow but fine at 518k.

Let me compute y then inner x loop:
```
let c=0, y=0;
for(y=0;y<H;y++){
  let cycol;
  if(y<H/2){ ceiling gradient color cyan-ish }
  else { floor gradient + checker }
  // fill row
  for(x=0;x<W;x++){ buf[c++]=color; }
}
```
Compute color once per row, with checker adjust per pixel in floor:
```
if(floor){ let chk=( (x>>2)+(y>>2) )&1; color = base + chk*delta; }
```
Modify per pixel slightly. Fine.

Then walls overwrite with shades.

Let me now write shade computation per column factor f = 1 - fogdepth where fogdepth=perpWallDist/MIN(maxFog, ...). Actually classic: darker with distance. f = max(0.15, 1 - perp/ 12.0); then multiply side shading: if side==1 f*=0.7.

Apply to each pixel rgb. Extract via shifts.

Now write.

I'll write the whole file now.

Let me also add ceiling/floor don't need Z. Good.

For performance of putImageData at 60fps each frame building 518k pixels plus draws — okay.

Let me finalize code and write.

Weapon and HUD drawn with ctx after putImageData (2d overlays).

Let me write the file.

I need to make sure to handle sprite draws clipped. drawImage with per column single-pixel slice is costly if many enemies/columns. With ~12 enemies each ~spriteWidth columns, total maybe 12*spriteWidth. spriteWidth max ~H when very close. Sum could be up to 12*H columns = 6480 drawImage calls worst case. That might be heavy but only when enemies close. Acceptable-ish. To optimize, I could draw via ImageData too but complexity high. Keep drawImage; likely fine.

Actually per-stripe drawImage is the standard approach. Fine.

Let me also implement enemy walk anim and death fade (draw then fade alpha, remove after timer; collide no).

Now write.

Let me define classes/functions in order:

1. Canvas setup, audio
2. Texture generation
3. Enemy sprite generation
4. Game state init (map gen, player, enemies, pickups)
5. Input handlers
6. Update
7. Render (walls, sprites, weapons, HUD)
8. Main loop

Let me write it all.

For the LOS check function:
```
function hasLOS(x0,y0,x1,y1){
  const dx=x1-x0, dy=y1-y0; const dist=Math.hypot(dx,dy);
  const steps=Math.ceil(dist*4);
  for(let s=1;s<steps;s++){
    const t=s/steps;
    const px=x0+dx*t, py=y0+dy*t;
    if(map[(py|0)] && map[(py|0)][(px|0)]===1) return false;
  }
  return true;
}
```
Map bounds: ensure within. Since inside borders, fine.

But sampling might miss thin walls; use steps=dist*8.

Enemy attack: if hasLOS and dist<3.5 -> attack with cooldown, deal damage if line unblocked (use hasLOS). Player health reduce ~8-14.

Now player collision with walls: attempt move x then y separately:
```
function tryMove(nx,ny,r){
  const hw=0.25; // half width size of player ~ 0.22
  // corner checks
  if(!solid(nx+hw,ny) && !solid(nx-hw,ny)) posX=nx;
  if(!solid(nx,ny+hw) && !solid(nx,ny-hw)) posY=ny;
}
function solid(x,y){ const mx=(x|0),my=(y|0); if(map[my]&&map[my][mx]) return true; return false; }
```
r not used; keep hw 0.2. Actually fudge: use margin 0.1 from wall. Fine.

Let me finalize and write. I'll write now.

Let me handle the case map cells out of bounds (shouldn't happen since borders are walls).

Pickups render similar to sprites: small boxes. I'll generate pickup sprites (health pack, ammo crate) canvases.

Now write file.

Given the size, let me just write it.

I'll double-check the sky/horizon: W*=960, H*=540. horizon H/2=270.

Let me write the code now.

For the weapon/gun, I'll generate a canvas 200x180 and draw a pistol silhouetted black/dark with hands. Draw at bottom right each frame with recoil offset when firing and muzzle flash circle near muzzle.

Crosshair: draw small circle + cross center.

HUD:
- top-left: minimap (render map scaled to ~140x110) with player cone and enemies as dots, pickups.
- bottom-left: health bar, armor? just health + kills count + ammo.
- bottom-right: "Armed" text etc.
- messages center for pickups/kills.

Let me draw minimap each frame.

OK writing now, final.

Let me write out carefully. I'll produce the complete file.
bash {"command":"cd /workspace && ls -la && node -v 2>/dev/null || echo \"no node\""}
toolResult

toolResult

total 4 drwxrwxrwx 2 node node 64 Jul 31 18:31 . drwxr-xr-x 1 root root 4096 Jul 31 18:31 .. v24.18.0

assistant

TAKE IT TO CODE

This run produced no artifact — reuse the prompt with a different model or your own pi-agent run.

RUN

modeldeepseek-v4-flash-0731
vendorDeepSeek
harnesspi-agent
generated2026-07-31

METRICS

runtime
tokens in1.6k
tokens out8.2k
cached0
cost / run$0.0291