Overview › Code › R93
Code · blind round

R93 · Rotating wireframe height field

blind round 9/11 local models answered

Every answer below carries the name of the model that wrote it. Blind refers to the scoring: the review was done without knowing which model produced which answer — the published result names them.

2 of the 11 local models delivered nothing through our test harness in this round — for reasons that lie with our setup, not with the models. Those cards are marked DNF like any other, but they are not evidence about those models — the reason is noted on the card itself.

Show task
Create ONE self-contained HTML file (STRICT LIMIT: max 7000 characters in total — this is a budget on characters, not on lines, so removing line breaks does not help) that draws a rotating 3D height field on a <canvas>: build a grid of heights from a smooth mathematical function that changes over time, project every grid point in perspective while the whole surface rotates, and draw the mesh rows and columns from back to front so nearer rows cover the ones behind them. Show the grid size and the rotation angle. Use only the 2D canvas context — no WebGL, no libraries. Smooth requestAnimationFrame animation, NO user input, starts immediately and keeps running (restart with a fresh random instance when finished). No external libraries, no comments needed. Output ONLY the HTML file content, nothing else.

The answers

Local models (Brain cluster) — identical prompt, shuffled order (the sequence is not a ranking)
mistral-small:24bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Rotating Height Field</title><style>body{margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #000; color: #fff; font-family: Arial, sans-serif;}#info{position: absolute; top: 20px; left: 20px; z-index: 1;}</style>
</head><body>
<div id="info"></div><canvas id="canvas" width="800" height="600"></canvas><script>const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');let angle = 0;
function drawHeightField() {ctx.clearRect(0, 0, canvas.width, canvas.height);ctx.fillStyle = 'white';ctx.font = '16px Arial';
ctx.fillText(`Grid Size: 50x50`, 10, 20);
ctx.fillText(`Rotation Angle: ${angle.toFixed(2)}°`, 10, 40);
const numPointsX = 50; const numPointsZ = 50;
const gridSize = 80; let minY = Infinity, maxY = -Infinity;
let vertices = [];
for (let z = 0; z < numPointsZ; z++) { for (let x = 0; x < numPointsX; x++) {
let y = Math.sin(x / 10 + angle) * Math.cos(z / 10 + angle);
minY = Math.min(minY, y); maxY = Math.max(maxY, y);
vertices.push({x, y, z});
}}const heightScale = (maxY - minY) / canvas.height;ctx.lineWidth = 2;
for (let z = 0; z < numPointsZ - 1; z++) { for (let x = 0; x < numPointsX; x++) {
let v1 = vertices[z * numPointsX + x];
let v2 = vertices[(z + 1) * numPointsX + x];drawLine(v1, v2, gridSize);
}}for (let z = 0; z < numPointsZ; z++) { for (let x = 0; x < numPointsX - 1; x++) {
let v1 = vertices[z * numPointsX + x];
let v2 = vertices[z * numPointsX + x + 1];drawLine(v1, v2, gridSize);
}}function drawLine(v1, v2, size) {const screenX1 = canvas.width / 2 + (v1.z - v1.x) * Math.cos(angle) * size;
const screenY1 = canvas.height / 2 + (v1.y - v1.z) * size; const screenX2 = canvas.width / 2 + (v2.z - v2.x) * Math.cos(angle) * size;
const screenY2 = canvas.height / 2 + (v2.y - v2.z) * size;ctx.beginPath();
ctx.moveTo(screenX1, screenY1); ctx.lineTo(screenX2, screenY2);
ctx.strokeStyle = 'rgba(0, 255, 0, 0.8)';ctx.stroke();}angle += 0.01;
if (angle >= 360) angle = 0;requestAnimationFrame(drawHeightField);}
drawHeightField();
</script>
</body>
</html>
```
qwen3:14bERRBLANKFORMAT
Show code
```html
<!DOCTYPE html>
<html><head><title>Rotating 3D Height Field</title></head><body style="background: #000; margin: 0; display: flex; justify-content: center; align-items: center; min-height: 100vh;"><canvas id="c" width="800" height="600" style="border: 1px solid #333;"></canvas><script>const c=document.getElementById('c');const ctx=c.getContext('2d');let W=c.width,H=c.height;let N=40;let s=Math.random()*2*Math.PI;let a=0;function h(x,y){return Math.sin(x*0.1)*Math.cos(y*0.1)+Math.sin((x+y)/5)};function draw(){ctx.clearRect(0,0,W,H);ctx.fillStyle='#333';ctx.fillRect(0,0,W,H);const scale=W/(N-1);let points=[];for(let i=0;i<N;i++){for(let j=0;j<N;j++){let x=(i-N/2)*scale*0.5,y=(j-N/2)*scale*0.5,z=h(x,y);points.push({x:x,y:y,z:z});}}ctx.strokeStyle='#666';ctx.lineWidth=1;let p=[];const angle_a = a*0.01;for(let i=0;i<N;i++){for(let j=0;j<N;j++){let x=(i-N/2)*scale*0.5,y=(j-N/2)*scale*0.5,z=h(x,y);// Rotate coordinates: Yaw (around Y) and Pitch (around X)
let rx = x*Math.cos(angle_a)-z*Math.sin(angle_a);
let rz=x*Math.sin(angle_a)+z*Math.cos(angle_a);
// Simple projection assuming viewing direction is along Z' axis (or a combination)
// Let's use standard rotation: X -> X', Y -> Y', Z -> Z'
// Yaw (rotation around Y): x'=x*cos, z'=z*cos; y'=y + x*sin*tan(angle_a) - z*sin*tan(angle_a)*cos? Too complex.

// Standard 3D rotation for visualization: Rotate based on angle 'a'
let cosA=Math.cos(angle_a);
let sinA=Math.sin(angle_a);
let px = x*cosA-z*sinA;
let pz=x*sinA+z*cosA;

// Now we treat (px, y, pz) as the new coordinates.
// Projection: screenX = (p/d + cameraX)/(p+d), screenY = ...
let dx=W/(2*Math.sqrt(1+(x*x)+(y*y)+(z*z))); // Perspective factor

// Simplified pseudo-perspective projection for drawing the grid lines
for(let i=0;i<N;i++){
    for(let j=0;j<N;j++){
        let x=(i-N/2)*scale*0.5,y=(j-N/2)*scale*0.5,z=h(x,y);
        // Rotate the point (x, y, z) by angle 'a' around the Y axis (vertical plane rotation)
        let nx = x*Math.cos(angle_a)-z*Math.sin(angle_a);
        let nz=x*Math.sin(angle_a)+z*Math.cos(angle_a);
        // Point is (nx, y, nz). Projecting onto the XY plane for simplicity of drawing lines.
        let sx = W/2 * (1 + Math.cos(angle_a)*((i-N/2)/N) - Math.sin(angle_a)*z*0.1);
        let sy = H/2 * (1 + ((j-N/2)/N));

        // Store vertices for depth sorting: {x, y, z, i, j}
        p.push({
            sx: W*(i/(N-1))-W/(2*Math.sqrt(1+(x*x)+(y*y)+z*z)), // Dummy pseudo-perspective calculation
            sy: H*(j/(N-1))-H/(2*Math.sqrt(1+(x*x)+(y*y)+z*z)),
            depth: Math.sqrt(x*x+y*y+z*z),
            i: i, j: j
        });
    }
}

// --- Simplified Drawing (No complex depth sorting, just drawing projected lines) ---
ctx.beginPath();
for(let j=0;j<N;j++){ // Rows (Y direction)
    ctx.moveTo((j-N/2)*scale*0.5+W/2, H-(j-N/2)*scale*0.5);
    for(let i=0;i<N;i++){ // Columns (X direction)
        // Calculate projected coordinates for the line segment end point
        let x=(i-N/2)*scale*0.5,y=(j-N/2)*scale*0.5,z=h(x,y);
        let cosA=Math.cos(angle_a), sinA=Math.sin(angle_a);

        // Simple pseudo-projection based on rotation for visual effect
        let sx = W * (i/(N-1)) + Math.cos(angle_a)*x*0.1 - Math.sin(angle_a)*z*0.1;
        let sy = H - H*(j/(N-1));

        ctx.lineTo(sx, sy);
    }
}
// --- End Simplified Drawing ---

ctx.stroke();

ctx.fillStyle='#FFF';
ctx.font='14px Arial';
ctx.fillText(`Grid Size: ${N}x${N}`, 10, 20);
ctx.fillText(`Rotation Angle: ${(a/Math.PI*180).toFixed(0)}°`, 10, 40);

requestAnimationFrame(draw);
</script></body></html>
```
qwen3:8bharness
No answer reached us (ERR) — and the reason lies with our setup, not with the model: reasoning consumed the entire token budget and the answer stayed empty; the gateway rejects budgets above 3000 tokens Counted as a did-not-finish, but it is not evidence about this model.
qwen3-coder:30bBLANK
Show code
<!DOCTYPE html>
<html>
<head>
<title>Rotating Height Field</title>
<style>
body { background: #000; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
canvas { border: 1px solid #333; }
#info { color: white; font-family: monospace; position: absolute; top: 10px; left: 10px; background: rgba(0,0,0,0.5); padding: 8px;}
</style>
</head>
<body>

<canvas id="canvas" width="600" height="600"></canvas>
<div id="info">Grid Size: 40x40 | Angle: 0 rad</div>

<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const infoDisplay = document.getElementById('info');

let A = 10; // Amplitude multiplier for height function
let GRID_SIZE = 40;
let SCALE = 30 / (GRID_SIZE - 1); // Scale factor for mapping grid units to canvas pixels
let rotationAngle = 0;
const CAMERA_DISTANCE = 50;

function getHeight(i, j) {
    return A * Math.sin(i / 4) * Math.cos(j / 4);
}

// Project a world point (x, y, z) onto the screen
function project(x, y, z) {
    const projectedZ = z + CAMERA_DISTANCE;
    if (projectedZ < 1) return null;
    return {
        x: x / projectedZ * SCALE,
        y: y / projectedZ * SCALE,
        z: projectedZ // Use Z for sorting depth
    };
}

function drawFrame(angle) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    infoDisplay.innerHTML = `Grid Size: ${GRID_SIZE}x${GRID_SIZE} | Angle: ${(angle * 180 / Math.PI).toFixed(1)} deg`;

    // --- Drawing Mesh Lines ---
    
    // We will draw all lines (rows and columns) and store them with their depth for sorting.
    let segments = [];

    for (let j = 0; j < GRID_SIZE; j++) {
        for (let i = 0; i < GRID_SIZE - 1; i++) {
            // 1. Horizontal lines (Rows: connecting (i, j) to (i+1, j))
            const z1 = getHeight(i, j);
            const z2 = getHeight(i + 1, j);
            
            const p1_h = project(i, j, z1);
            const p2_h = project(i + 1, j, z2);

            if (p1_h && p2_h) {
                // Depth sorting key: average Z depth of the segment
                segments.push({ 
                    p1: p1_h, p2: p2_h, depth: (p1_h.z + p2_h.z) / 2, type: 'H' 
                });
            }

            // 2. Vertical lines (Columns: connecting (i, j) to (i, j+1))
            const z3 = getHeight(i, j);
            const z4 = getHeight(i, j + 1);
            
            const p1_v = project(i, j, z3);
            const p2_v = project(i, j + 1, z4);

            if (p1_v && p2_v) {
                segments.push({ 
                    p1: p1_v, p2: p2_v, depth: (p1_v.z + p2_v.z) / 2, type: 'V' 
                });
            }
        }
    }

    // Sort segments by increasing Z depth (farthest to nearest, so drawing order is back-to-front)
    segments.sort((a, b) => a.depth - b.depth);

    // Draw sorted segments
    ctx.lineWidth = 1;
    for (const seg of segments) {
        ctx.strokeStyle = `rgba(100, 255, 100, ${Math.max(0.3, Math.min(1, 1 - (seg.depth / (CAMERA_DISTANCE * 2))))})`;
        ctx.beginPath();
        ctx.moveTo(seg.p1.x, seg.p1.y);
        ctx.lineTo(seg.p2.x, seg.p2.y);
        ctx.stroke();
    }
}

function animate() {
    rotationAngle += 0.03; // Rotation speed
    drawFrame(rotationAngle);
    requestAnimationFrame(animate);
}

// Start the animation immediately
animate();

</script>
</body>
</html>
gemma4:26bharness
No answer reached us (THIN) — and the reason lies with our setup, not with the model: reasoning consumed the entire token budget (3 min 28 s, zero characters of answer); larger budgets are refused by the gateway Counted as a did-not-finish, but it is not evidence about this model.
qwen3.5:9bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html>
<body><canvas id="c"></canvas><script>
const c = document.getElementById('c');
const ctx = c.getContext('2d');

let W = 800;
let H = 600;
c.width = W;
c.height = H;

let GRID_SIZE = 25; // NxN grid
let STEP = 1.0;

// Camera/Scene parameters
const CAMERA_DISTANCE = 8.0;
const SCALE = 0.3;

let time = 0;
let angleX = 0;
let angleY = 0;
let lastTime = 0;

function setup() {
    time = Math.random() * 100;
    angleX = Math.PI / 4 + Math.random() * Math.PI / 2;
    angleY = Math.random() * Math.PI;
    lastTime = performance.now();
}

// Smooth height function: H(x, z)
function getHeight(x, z, t) {
    let h = Math.sin(x * 0.5 + t * 0.2) * Math.cos(z * 0.3 + t * 0.1);
    return h * 0.8; 
}

// Project (x, y, z) to screen coordinates (x', y')
function project(p) {
    let x = p[0];
    let y = p[1] + p[2]; // Height acts as Y relative to ground plane
    let z = p[2];

    // Rotate point around X and Y axes
    let tempX = x * Math.cos(angleY) - z * Math.sin(angleY);
    let tempZ = x * Math.sin(angleY) + z * Math.cos(angleY);

    let rx = tempX;
    let ry = y;
    let rz = tempZ;

    // Rotate around X axis (pitch)
    let pitch_x = rx;
    let pitch_y = ry * Math.cos(angleX) - rz * Math.sin(angleX);
    let pitch_z = ry * Math.sin(angleX) + rz * Math.cos(angleX);

    // Rotate around Y axis (yaw)
    let finalX = pitch_x * Math.cos(angleY) - pitch_z * Math.sin(angleY);
    let finalY = pitch_y;
    let finalZ = pitch_x * Math.sin(angleY) + pitch_z * Math.cos(angleY);

    // Perspective projection
    let scaleFactor = CAMERA_DISTANCE / (CAMERA_DISTANCE + finalZ);
    
    return { 
        x: W / 2 + finalX * scaleFactor, 
        y: H / 2 - finalY * scaleFactor, // Y is inverted on canvas
        z: finalZ * scaleFactor, 
        depth: finalZ // Used for sorting/depth check
    };
}

// Main drawing function
function draw(t) {
    ctx.clearRect(0, 0, W, H);
    ctx.fillStyle = '#112233';
    ctx.fillRect(0, 0, W, H);

    let points = [];
    let depthMap = {}; // Store projected depth for sorting

    // Calculate all grid point positions and store their projections
    for (let i = 0; i < GRID_SIZE; i++) {
        for (let j = 0; j < GRID_SIZE; j++) {
            let x = (j - GRID_SIZE / 2) * STEP;
            let z = (i - GRID_SIZE / 2) * STEP;
            let h = getHeight(x, z, t);

            // P: [x, y, z] relative to origin. Note height is added to the Y coordinate.
            let p = [x, h, z]; 
            let proj = project(p);
            
            points.push({ x: proj.x, y: proj.y, depth: proj.depth });
            depthMap[`${i},${j}`] = proj;
        }
    }

    // --- Drawing Mesh Edges (The core complexity) ---
    ctx.strokeStyle = 'rgba(100, 255, 200, 0.7)';
    ctx.lineWidth = 1;

    let edgesToDraw = [];

    // 1. Collect all adjacent point pairs (edges)
    for (let i = 0; i < GRID_SIZE; i++) {
        for (let j = 0; j < GRID_SIZE; j++) {
            // Edge to the right (+X direction)
            if (j + 1 < GRID_SIZE) {
                edgesToDraw.push({ p1: depthMap[`${i},${j}`], p2: depthMap[`${i},${j+1}`] });
            }
            // Edge in front (+Z direction)
            if (i + 1 < GRID_SIZE) {
                edgesToDraw.push({ p1: depthMap[`${i},${j}`], p2: depthMap[`${i+1},${j}`] });
            }
        }
    }

    // 2. Sorting Edges by Depth (Painter's Algorithm approximation)
    // We sort edges based on the average depth of their endpoints.
    edgesToDraw.sort((a, b) => {
        const avgDepthA = (a.p1.depth + a.p2.depth) / 2;
        const avgDepthB = (b.p1.depth + b.p2.depth) / 2;
        return Math.abs(avgDepthB - avgDepthA); // Draw farthest first (largest difference means more depth variation, but sorting by magnitude of distance from viewer is key). Simple sort on the average Z component works well enough for visualization.
    });

    // 3. Draw Sorted Edges
    edgesToDraw.forEach(edge => {
        ctx.beginPath();
        ctx.moveTo(edge.p1.x, edge.p1.y);
        ctx.lineTo(edge.p2.x, edge.p2.y);
        ctx.stroke();
    });

    // --- Display Info ---
    ctx.fillStyle = '#aaa';
    ctx.font = '14px Courier New';
    ctx.fillText(`Grid: ${GRID_SIZE}x${GRID_SIZE}`, 10, 20);
    ctx.fillText(`Angle X (Pitch): ${(angleX * 180 / Math.PI).toFixed(1)}°`, 10, 40);
    ctx.fillText(`Angle Y (Yaw): ${(angleY * 180 / Math.PI).toFixed(1)}°`, 10, 60);
}

// Animation Loop
function animate(timestamp) {
    const deltaTime = timestamp - lastTime;
    lastTime = timestamp;
    time += deltaTime * 0.005; // Smooth passage of time for height change

    angleX = Math.sin(time * 0.1) * (Math.PI / 3);
    angleY = Math.cos(time * 0.08) * (Math.PI / 2);

    draw(time);
    requestAnimationFrame(animate);
}

setup();
requestAnimationFrame(animate);
</script></body></html>
```
deepseek-r1:14bERRBLANKFORMAT
Show code
```html
<!DOCTYPE html>
<html><body style="background:#000;margin:0;display:flex;justify-content:center;align-items:center;height:100vh">
<canvas id=c width=800 height=600></canvas>
<div id=s>Size: 50x40</div>
<div id=a>Angle: 0°</div>

<script>
let c=document.getElementById('c'),ctx=c.getContext('2d');
const w=c.width,h=c.height,g=50,j=40,f=600,t=0,ro=0;
let dx=new Array(g),dy=new Array(j);

function init(){for(let i=0;i<g;i++)dx[i]=(i/g-0.5)*w*2; 
  for(let j=0;j<40;j++) dy[j]=(j/39-1)*h*f/(j.length*.5);}

function project(x,y,z){
  let xp=x/f + z/(f*y) * x, yp=y/f + z/(f*y)*y;
  return{xp:xp*0.5*w+0.5*w,yp:yp*0.5*h+0.5*h};}

function smooth(points){
  for(let i=1;i<points.length-1;i++) 
    points[i]= (points[i-1]+points[i+1])/2;
  return points;}

let render=()=>{
  ctx.fillStyle='#111';ctx.fillRect(0,0,w,h);
  let data=[[...Array(g)].map((_,i)=>Math.sin(i/g*t*4 +ro) * 
    Math.cos(j.map((_,j)=>Math.sin(j/39*t*3 +ro)))*2+2)], 
   [...Array(g)].map(_=>[...Array(40)] )];
  let grid=[],lines=[[[]], [[]]];
  for(let i=0;i<g;i++)for(let j=0;j<40;j++){ 
    data[i][j]=Math.sin(i/g*t*3-ro/2) * Math.cos(j/39*t*5 +ro)*
      (Math.sin(ro)+2)/3;
    let x=i, y=j/40*w*.1, z=data[i][j];
    grid.push({x,y,z});
  }
  for(let i=0;i<g;i++)for(let j=0;j<40;){ 
    lines[0][i].push(project(grid[i*40+j].x/grid.length*2,
      grid[i*40+j].y,grid[i*40+j].z));j++}
  for(let i=0;i<g;i++)for(let j=1;j<40;){ 
    lines[1][i].push(project(grid[i+g*j].x, grid[i+g*j].y,
      grid[i+g*j].z));j++}
  let sort=(a,b)=>b.z-a.z;
  for(let i=0;i<g;i++)lines[0][i].sort(sort);
  for(let j=0;j<40;j++)lines[1][j].sort(sort);
  ctx.strokeStyle='#fff';ctx.lineWidth=.5;
  for(let i=0;i<g;i++){ 
    lines[1][i].forEach(l=>{if(l.x&&l.y) 
      ctx.beginPath(), ctx.moveTo(lines[0][i][0]||l.x,lines[0][i][0]||l.y);
        lines[0][i].find(m=>m.x).x==undefined?
          (ctx.lineTo(l.x,l.y),ctx.stroke()):(null);});
    lines[0][i].forEach((p,k)=>{k<lines[0][i].length-1&&
      ctx.beginPath(),ctx.moveTo(p.x,p.y), 
      ctx.lineTo(lines[0][i][k+1].x,lines[0][i][k+1].y),
      ctx.stroke();})}
  for(let j=0;j<40;j++){ 
    lines[1][j].forEach((p,k)=>{k<lines[1][j].length-1&&
      ctx.beginPath(),ctx.moveTo(p.x,p.y), 
      ctx.lineTo(lines[1][j][k+1].x,lines[1][j][k+1].y),
      ctx.stroke();})}
  t+=.03;ro=(ro+1)%360;
  document.getElementById('s').textContent=`Size: ${g}x${40}`;
  document.getElementById('a').textContent=`Angle: ${~~(ro%360)}°`;
}

init();
smooth(dx);smooth(dy);
function animate(){render();requestAnimationFrame(animate);}
animate();
</script>
</body></html>
```
llama3.1:8bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>3D Height Field</title>
<style>
body { background-color: #f0f0f0; }
canvas { border: 1px solid black; }
</style>
</head>

<body onload='start();'>
<canvas id='c' width='600' height='400'></canvas>
<script>
var c = document.getElementById('c');
var ctx = c.getContext('2d');

var w = c.width;
var h = c.height;

var g = 24; // grid size
var rot = 0; // rotation angle

function s(x, y) {
	var r = Math.pow(Math.sin(y), 3)*Math.cos(Math.sin(x));
	return r*(w/2)+w/2;
}

function d() {
	ctx.clearRect(0, 0, w, h);

	// Draw grid
	for (var i=0; i<g; i++) {
		var y = Math.floor(h/g*i);
		ctx.beginPath();
		ctx.moveTo(s(i*3.14159/g, 1+rot), y);
		for (var j=1; j<=g; j++)
			ctx.lineTo(s(j*3.14159/g+rot, 1+i), h-j*y/g);
		ctx.stroke();

		var x = Math.floor(w/g*i);
		ctx.beginPath();
		ctx.moveTo(x, s(1+i, rot));
		for (var j=0; j<=g; j++)
			ctx.lineTo(s(j*3.14159/g+rot, 2+i), h-h/j*g);
		ctx.stroke();
	}

	// Draw points
	var ps = [];
	for (var x=0; x<w; x++) {
		for (var y=0; y<h; y++) {
			ps.push({x:x, y:y});
		}
	}
	var pps = [];
	for (var i=0; i<ps.length; i++)
		if ((i%1)<0.01)
			pps.push(ps[i]);
	ctx.fillStyle='rgba(0, 0, 255, 0.5)';
	ctx.beginPath();
	for (var i=0; i<pps.length; i++) {
		var x = pps[i].x;
		var y = pps[i].y;
		if (i==0)
			ctx.moveTo(x, y);
		else
			ctx.lineTo(x, y);
	}
	ctx.closePath();
	ctx.fill();

	ctx.font="14px Arial";
	ctx.fillStyle='black';
	ctx.fillText("Grid size: "+g+", Rotation angle: "+rot.toFixed(2)+"°", 10, h-20);

	requestAnimationFrame(d);
}

function start() {
	d();
	setInterval(function(){ rot+=0.01; }, 1000/60);
	setInterval(function(){ g=Math.floor(Math.random()*50+1); }, 20000);
}
</script>
</body>
</html>
```
deepseek-r1:32bERRBLANKMINIFIEDFORMAT
Show code
```html
<!DOCTYPE html><html><body style="background:#000;margin:0;display:flex;flex-direction:column;align-items:center"><div id=o style="color:white;font-family:sans-serif"></div><canvas id=c width=600 height=400></canvas><script>
const c=document.getElementById('c'),ctx=c.getContext('2d'),w=600,h=400,N=20;let t=0,grid=[],rot=0;
function init(){grid=[];for(let x=-10;x<=10;x++)for(let y=-10;y<=10;y++){const s=Math.random()*0.5+0.5;grid.push({x:x,y:y,z:Math.sin(x*2+t)+Math.cos(y*2+t)+Math.sin(t/5)*1.5,s:s})}draw();}
function draw(){ctx.fillStyle='#000';ctx.fillRect(0,0,w,h);rot+=0.02;t=rot*Math.PI/6;grid.forEach(p=>{const x=p.x,y=p.y,z=p.z+Math.sin(y*2+t)*1.5;sx=(x+y)/3*50+300,sy=(-y+z)*40+200;});
let lines=[];for(let i=0;i<N-1;i++){let row=i*N,points=[];for(let j=0;j<N;j++)points.push({x:grid[row+j].sx,y:grid[row+j].sy,z:grid[row+j].z});lines.push(...[...Array(N)].map((_,k)=>({start:points[k],end:points[k+1]})))}for(let i=0;i<N-1;i++){let col=i,points=[];for(let j=0;j<N;j++)points.push({x:grid[col+j*N].sx,y:grid[col+j*N].sy,z:grid[col+j*N].z});lines.push(...[...Array(N)].map((_,k)=>({start:points[k],end:points[k+1]})))}
ctx.strokeStyle='#fff';ctx.lineWidth=0.5;lines.sort((a,b)=>b.start.z-a.start.z);lines.forEach(l=>{ctx.beginPath();ctx.moveTo(l.start.x,l.start.y);ctx.lineTo(l.end.x,l.end.y);ctx.stroke()});
document.getElementById('o').innerHTML=`Grid: ${N}x${N} | Angle: ${(rot*180/Math.PI).toFixed(1)}°`;if(rot>2*Math.PI)init();}
init();function animate(){draw();requestAnimationFrame(animate);}animate();
</script></body></html>
```
qwq:32bSTATLIM
Show code
<think>

Okay, let's tackle this problem. The user wants an HTML file that uses a 2D canvas to display a rotating 3D height field. The grid should be built from a smooth mathematical function that changes over time. Each grid point needs to be projected in perspective, and the surface should rotate. Also, the mesh rows and columns should be drawn from back to front so that nearer parts cover the ones behind. Plus, we need to show the grid size and rotation angle, and it should loop with a new random instance each time. All without any libraries, just plain JS and Canvas 2D.

Hmm, first, I need to structure the HTML file. Since it has to be self-contained, the entire code will be in one HTML file. The canvas element should be there, and all the JavaScript inside script tags.

Starting with the canvas setup. The canvas element should have an id so we can reference it. Then, in the script, I'll get the canvas and its 2D context. The grid size can be a variable, maybe 20x20. The user mentioned showing grid size, so that variable should stay accessible.

Next, the rotation. The surface needs to rotate over time. So, we can track the current rotation angles for x and y axes. Maybe using angles that change per frame. The rotation should be smooth, so using requestAnimationFrame is essential here. The rotation angle will be displayed, so we'll need to update that in the canvas or in a separate element. Since it's a 2D canvas, maybe we can draw the text on the same canvas.

The height field is a grid of points, each with a z value determined by a function. The function needs to be smooth and time-dependent. Maybe something like combining sine waves or other periodic functions to create a smooth terrain. Let me think: for each point (x, y), the height could be a function of (x*t, y*t) where t is time, so it changes over time. Or maybe using a function that's a combination of sines with different frequencies.

Wait, for the height function, perhaps using a function like Math.sin(x * time + a) * Math.cos(y * time + b) where a and b are offsets. The time component will make it change over time. The parameters can be adjusted to control the smoothness and movement. Also, adding some randomness here might help in varying the terrain each time.

Now, the projection. Since it's a 3D to 2D projection in perspective, we need to apply some projection matrix. Since it's 2D context, we can't use WebGL matrices, so we have to handle the coordinates manually. Each point (x, y, z) needs to be transformed into 2D screen coordinates considering rotation and perspective.

The steps for each frame would be:

1. Clear the canvas.
2. Update the rotation angle based on time.
3. Calculate the current time (maybe using performance.now() or a counter).
4. For each grid point, compute its 3D position (x, y, z) where z is the height determined by the function.
5. Apply the rotation to the point (around some axis? Maybe x and y axes? The rotation might need to be around a central point, so translating to origin, rotating, then translating back).
6. Project the rotated 3D point to 2D using perspective. Perspective projection formulas: something like (x/(z + d), y/(z + d)) where d is a distance for perspective. Need to adjust the projection parameters for better visuals.
7. Sort the points by depth so that closer ones are drawn over farther ones. Since it's a grid, perhaps sorting rows based on their depth. Since the grid is 2D, maybe the depth can be determined by a function that depends on the rotated position. Alternatively, for each row or column, compute their average distance and sort them accordingly. Wait, the problem says "draw the mesh rows and columns from back to front". So, the mesh is made of lines connecting grid points, so perhaps we can iterate over the grid in order of depth, drawing each row and column in that order. But how to compute the depth for each row or column?

Alternatively, since it's a grid, each row (fixed y) or column (fixed x) can be sorted based on their z-coordinate? Or perhaps the z-coordinate after rotation? Hmm, this is tricky. Since the projection is perspective, the depth isn't straightforward. Maybe the depth can be determined by the distance from the viewer along the z-axis after rotation. So for each row (fixed y?), compute the z-coordinate of the center of the row, and sort rows by that z-coordinate. Then, draw the rows from back to front. Similarly for columns? Or maybe rows and columns are drawn in the order of their sorted depth.

Alternatively, perhaps each vertex's depth can be calculated, and then the entire grid is drawn in order from back to front. But that might be computationally intensive for a grid of 20x20. Maybe instead, for each row in the grid, compute a representative depth (like the average z-coordinate of the row's points after rotation) and sort the rows by that depth. Then, draw each row's lines in that order. Similarly for columns. But rows and columns are different, so maybe separate sorting for rows and columns? Or maybe columns are part of the rows?

Hmm, perhaps it's easier to render all rows and columns, but for each row (a horizontal line in the grid), we can process them from back to front. To do that, for each row (fixed y-coordinate in the original grid), compute its depth (distance from viewer), then sort all rows by this depth. Then, draw each row's lines in that order. Similarly for columns (fixed x-coordinate), determine their depth and sort them. But how precisely?

Alternatively, since the grid is a 2D array, for each cell (x, y), we can compute the projected 2D coordinates and then decide the order based on, say, the z-coordinate (after rotation but before projection). Because in perspective projection, the closer a point is along the camera's z-axis, the larger it appears, but for ordering, we can sort based on the negative z value (since lower z is closer? Wait, need to define the coordinate system).

Let me think about coordinate systems. Let me define the camera's position such that the rotation is around the center of the grid. So, each grid point (x, y, z) is relative to the center. Then, rotation matrices can be applied. The projection would take those rotated points and map them to 2D.

Suppose the grid is centered at (0,0,0). Each point's position is (dx, dy, dz), where dx ranges from -width/2 to width/2, similarly for dy. Then, applying rotation around the x and y axes, then projecting.

The projection formula could be:

After rotation, a point (x, y, z) is transformed. Then, perspective projection can be done by dividing by the z-component plus some distance (to avoid division by zero). So projected x and y would be something like:

projectedX = (rotatedX * (viewDistance + rotatedZ)) / (viewDistance) 

Wait, maybe:

Let’s define a viewing distance D. The projected coordinates would be:

projectedX = (x / (rotatedZ + D)) * scale + canvasWidth/2

projectedY = (y / (rotatedZ + D)) * scale + canvasHeight/2 ?

Hmm, perhaps. But exact formulas might need adjusting. Alternatively, the perspective projection can be handled with a simple division based on the depth.

Alternatively, maybe using a simple orthographic projection with some perspective scaling. Let me look up the perspective projection equations.

Alternatively, the standard way is:

For a point in 3D space (x, y, z), rotated, then projected to 2D:

The projection matrix for perspective would involve dividing by the z coordinate. But since we have to do this manually, let's say:

After rotation, the point is (x, y, z). The screen coordinates are computed as:

screenX = (x * perspectiveDistance) / (z + perspectiveDistance) + centerX;

screenY = (y * perspectiveDistance) / (z + perspectiveDistance) + centerY;

Where perspectiveDistance is a parameter that controls the perspective effect. That might work. The idea is that as z approaches -perspectiveDistance, the projection goes to infinity; so we need to avoid that. So the Z component should be kept positive or at a certain distance.

Alternatively, perhaps I need to set up the coordinates so that the rotated Z is positive to see the objects. Let me think through the steps:

First, for each grid point (i, j):

- Compute its original coordinates. Let's say the grid is from -halfGridSize to +halfGridSize in both x and y directions. The grid has gridSize points, so each step is 1 unit (for simplicity). Wait, but the grid size is N x N where N is the grid size variable.

Wait, maybe it's better to represent the grid as a grid of points with indices from 0 to grid_size-1 in both x and y. The actual coordinates can be scaled so that the grid is centered and spaced properly.

Suppose grid_size is 20, so each grid point (i, j) has coordinates:

x = (i - (grid_size-1)/2) * scale

y = (j - (grid_size-1)/2) * scale

scale could be, say, 1 for simplicity, but might need to be adjusted based on the canvas size.

But the actual 3D coordinates would be (x, y, z), where z is the height.

The height z is given by some function f(x, y, t), where t is time. For example, z = Math.sin(x * 0.1 + t) * Math.cos(y * 0.1 + t) * amplitude. The parameters can be adjusted so that the height varies smoothly over time.

Then, apply rotation. The rotation is around the center of the grid, so first translate each point to the origin, rotate, then translate back?

Wait, no, the rotation is applied to the entire grid as it's rotating around some axes. Let's define two angles, angleX and angleY, which change over time. These angles control the rotation around the X and Y axes.

The rotation matrices can be applied to each point's coordinates (x, y, z).

Wait, actually, to rotate around the X axis:

The rotation matrix for an angle α around X is:

[1, 0, 0]

[0, cosα, -sinα]

[0, sinα, cosα]

Similarly, for rotation around Y axis with angle β:

[cosβ, 0, sinβ]

[0, 1, 0]

[-sinβ, 0, cosβ]

So, to apply both rotations, we need to multiply the two matrices. The order of rotations matters. Probably, first rotate around X, then Y, or vice versa.

Alternatively, apply a combined rotation. But for simplicity, perhaps the code can first rotate around X, then Y, or the other way. Let me think: perhaps the rotation angles are added incrementally each frame.

The rotation angles (angleX and angleY) are updated each frame by some delta. The delta is based on elapsed time, so that the rotation is smooth.

Once rotated, the points are projected onto 2D.

After applying the rotations, each point's new coordinates (x', y', z') will determine its position in screen coordinates.

The projection step is crucial here. To get perspective, we can use a formula similar to:

screenX = (x' * (distance + z')) / (distance + z') ? No, that might not be right. Wait, maybe:

Let me think of the projection as looking along the z-axis. The perspective projection can be done by dividing by the z component plus a distance. For example:

projectedX = (x' * perspectiveDistance) / (z' + perspectiveDistance) + centerX;

projectedY = (y' * perspectiveDistance) / (z' + perspectiveDistance) + centerY;

Where perspectiveDistance is a value that sets the distance of the virtual camera from the scene. This way, as z' increases (moving away), the division makes the projected coordinates smaller, giving perspective.

Alternatively, using a simpler approach where:

projectedX = (x' * (projectionFactor)) / (z' + projectionDepth) 

But scaling and centering are important. The parameters need to be tuned so that the grid fits the canvas.

Now, the order of drawing is important. To have the back rows cover the front, we need to draw from back to front. Since each row (fixed j) is horizontal, perhaps we can sort rows by their depth (z-coordinate) and draw them in that order. Wait, but each row's depth varies across its columns. Alternatively, the depth for a row can be determined by the z-coordinate of its center point. For example, for row j, pick the central x-coordinate (the middle of the row) and compute the z value there. Then, sort rows based on their z value. The rows with lower z (further away) are drawn first, and higher z (closer) are drawn later, covering the previous ones.

Alternatively, since the projection includes z', maybe the depth is determined by the z' coordinate after rotation but before projection. Or perhaps the distance from the viewer can be estimated by the negative z' component (assuming that the viewer is looking along the negative z' axis). So, for each point, the depth is 1/(z' + D), where D is a constant to prevent division by zero. To order rows, we can compute an average depth for the row and sort the rows accordingly.

Hmm, perhaps for each row (fixed y in the grid), compute the average z' of the points in that row, then sort the rows by the z' such that rows with lower z' (farther) come first. But how exactly?

Alternatively, maybe sort each row by the sum of the z-components of its points, and sort in order from lowest to highest. The rows with the lowest sum are drawn first.

Alternatively, since each row's points are along a horizontal line, the middle point might be representative of the row's depth. So, for each row j, compute the z-coordinate of the center point (i = grid_size/2), then sort the rows based on that z-coordinate. The rows with lower z (farther) are drawn first.

This might work as an approximation.

Once the rows are sorted, we can loop through them in order and draw each row's horizontal line and vertical lines (columns) for that row.

Wait, but the problem says to draw both rows and columns. So, each row is a horizontal line between its left and right points, and each column is a vertical line between its top and bottom points. So, for each row, after sorting, we can draw all its horizontal lines, and then also draw its vertical lines? Or perhaps draw all rows first in sorted order, then all columns? No, because columns also need to be ordered depth-wise.

Alternatively, for both rows and columns, sort them based on their depth and draw in order. But rows and columns are different, so perhaps process rows first, then columns in sorted order. Or maybe process each row and column together.

Hmm, perhaps it's better to process rows first in the sorted order, drawing their horizontal lines, and then process columns in their own sorted order, drawing their vertical lines. But need to ensure that columns are also ordered back to front.

Alternatively, the entire grid's lines can be considered as a collection of lines, each with their average depth, and sorted all together. But that might be more complex.

Alternatively, for the rows, sorted by row depth, and for each row, draw all horizontal lines (each row is one horizontal line per row?), then draw the columns (vertical lines) in their own sorted order.

Alternatively, perhaps the rows can be drawn in order, which takes care of horizontal lines, and then the columns can be drawn in their own order, sorted by their own depth. But this might have some overlapping issues.

Hmm, this part is a bit tricky. The user instruction says "draw the mesh rows and columns from back to front so nearer rows cover the ones behind them." So the rows and columns must be drawn in such an order that the closer lines are on top.

Perhaps the rows are drawn from back to front, so each row's horizontal lines are drawn, with later rows (closer) overlapping the earlier ones. The columns, which are vertical lines, need to be drawn similarly. But how to handle their depth?

Maybe the columns can be sorted individually, but that's time-consuming. Alternatively, for the columns, since they are vertical, their depth can be determined by their central point's depth. So for each column i, compute the center point's depth, sort the columns in order, and draw them similarly.

Alternatively, since rows and columns are separate, perhaps the rows are drawn first in row order, columns are drawn in column order, but each column is sorted based on their depth. But that might require more computational steps.

Alternatively, maybe the code can sort rows by their depth and draw their horizontal lines in that order. Then, for the columns, sort them by their depth and draw their vertical lines in that order. The key is that all horizontal lines from a row are drawn before or after the columns, depending on which is closer.

Alternatively, process each row, drawing its horizontal lines, and also its vertical lines (columns) in the correct order. Wait, but columns span multiple rows, so that complicates things.

Alternatively, perhaps the code should process each row in order, and for each row, draw its horizontal line and then draw the vertical lines (columns) at each point. Wait, but vertical lines are part of the columns. Hmm, this is getting too tangled.

Maybe the simplest approach is to first draw all the horizontal lines (rows) in sorted order, and then draw all vertical lines (columns) in their own sorted order. Since columns are vertical, their depth might depend on their x-coordinate. Let's say for each column, the depth is the average of all points along that column's z after rotation. Then, sort the columns by that depth and draw them in order.

This way, rows are drawn in row order, covering appropriately, and then columns are drawn in column order, covering appropriately.

Alternatively, the columns could be part of the rows, so drawing the rows first (horizontal lines) and then the columns (vertical lines) in their own order. The columns might overlap with previous rows but since they are drawn later, they would be on top where they should be.

Alternatively, perhaps the code can process the entire grid, and for every line segment (row or column), compute the average or some representative depth, and then sort all line segments from back to front and draw them in that order. But that would involve a lot of lines and sorting.

Alternatively, since the rows are horizontal and columns vertical, maybe the rows and columns can be sorted independently as two separate groups.

Let me try to outline the steps:

1. Compute the rotation angles based on time.

2. For each point (i,j) in the grid:

   a. Compute its 3D coordinates (x, y, z).

   b. Apply rotation to get (x', y', z').

3. For each row (fixed j):

   a. Compute the depth of the row (e.g., average z' of all points in the row, or midpoint's z').

   b. Sort rows in order from farthest (lowest z') to closest (highest z').

4. Draw all rows (horizontal lines) in this sorted order.

   a. For each row j:

      i. Find the two endpoints (leftmost and rightmost points in the row).

      ii. Project these endpoints to screen coordinates.

      iii. Draw a line between them.

5. For each column (fixed i):

   a. Compute the depth of the column (e.g., average z' of all points in the column, or midpoint's z').

   b. Sort columns in order from farthest to closest.

6. Draw all columns (vertical lines) in this sorted order.

   a. For each column i:

      i. Find the two endpoints (top and bottom points in the column).

      ii. Project to screen coordinates.

      iii. Draw a line between them.

This way, rows are drawn first in order, then columns in their own order. However, there may still be overlaps where columns are drawn on top of rows or vice versa, but since rows are drawn first and columns later, the columns will be on top. But columns might need to be behind some parts. Hmm.

Alternatively, perhaps the order should be columns first then rows? Not sure.

Alternatively, separate the processing of horizontal and vertical lines, but ensure that lines closer to the viewer are drawn later, thus on top. So rows sorted back to front, columns sorted back to front.

Alternatively, perhaps the rows and columns should be all considered as line segments, sorted by their depth, and drawn in order. However, this would require sorting all line segments, which might be computationally intensive but manageable for a grid of 20x20.

Wait, for a grid of 20x20, there are 20 rows (each row is 20 points but each row has 19 horizontal lines between points? Or each row is a single line connecting the first and last point of the row?). Wait, the problem says "mesh rows and columns", so likely each row is a horizontal line connecting all points in the row, and each column is a vertical line connecting all points in the column. So each row is a single horizontal line segment per row? No, each row would consist of horizontal lines between consecutive points along the row? Or is each row's horizontal line the full row from one side to the other?

Probably, each row is a single horizontal line spanning the entire row, so for row j, the line connects the first and last point of the row. Similarly for columns.

So, for rows: there are N rows (each with N points), so N horizontal lines, each spanning the entire row.

Similarly, there are N columns (each with N points), so N vertical lines, each spanning the entire column.

Therefore, there are 2*N lines total. So sorting all of them and drawing in order is feasible.

So the approach would be:

- For each row line:

   - Compute its depth (e.g., average z' of all points in the row, or the midpoint's z').

- For each column line:

   - Compute its depth similarly.

- Combine all lines (rows and columns) into a list.

- Sort the list from back to front based on depth.

- Draw each line in sorted order.

This way, all lines are drawn correctly, with closer lines on top.

This is probably the most accurate method, though it requires some computation.

Now, moving to coding steps:

Variables needed:

- grid_size (like 20)

- center_x and center_y to compute screen coordinates.

- rotation angles (angleX and angleY), which are updated each frame.

- time-based delta for smooth rotation.

Projection parameters:

- perspectiveDistance (distance from camera to projection plane?)

- scaling factors to fit the grid into the canvas.

Now, in pseudocode:

Initialize grid_size and other parameters.

In setup():

    canvas size, set up context.

In draw():

    clear canvas.

    compute current angleX and angleY based on time.

    create a list of all line segments (rows and columns).

    for each row j in 0..grid_size-1:

        compute all points of row j, apply rotation, get their (x', y', z').

        compute the depth of row j (e.g., average z' or midpoint's z').

        create a row_line object with endpoints (first and last projected points) and depth.

    for each column i in 0..grid_size-1:

        compute all points of column i, apply rotation...

        compute depth similarly.

        create column_line object with endpoints (top and bottom projected points) and depth.

    combine all lines into a list.

    sort the lines by depth (back to front): from lower z' (farther) to higher z' (closer). So sort in ascending order of depth.

    for each line in sorted list:

        draw the line between its endpoints.

But how exactly to compute the projected endpoints?

Wait, each line is a horizontal row or vertical column line. For example, a row j has points from i=0 to i=grid_size-1, so the endpoints are the first and last points in the row. To find their projected screen coordinates, we can compute their (x', y', z') after rotation, then project them using the projection formula, then convert to screen coordinates.

So, for each row j:

   first point is (i=0, j), last point is (i=grid_size-1, j)

   compute their rotated coordinates and project.

Similarly for columns.

Alternatively, to compute the endpoints' screen positions:

For a row, the two endpoints are (min_x, y_j) and (max_x, y_j). But in 3D coordinates, the actual coordinates depend on the grid's layout.

Wait, perhaps first define the 3D coordinates for each point:

Let's define the grid points as follows:

Each point (i, j) has:

x = (i - (grid_size-1)/2) * scale_x

y = (j - (grid_size-1)/2) * scale_y

z = height_function(i, j, current_time)

Wait, but the height is a function over x and y, so maybe:

x and y are the grid's local coordinates. To simplify, we can set scale_x and scale_y to 1, so the grid spans from -grid_size/2 to +grid_size/2 in x and y dimensions.

Then, the height z can be something like:

z = Math.sin(x * 0.2 + t) * Math.cos(y * 0.2 + t) * amplitude;

where t is time in seconds.

But the exact function is up to the user, as long as it varies smoothly.

The rotation is applied to each point (x, y, z):

First rotate around X axis by angleX, then around Y axis by angleY.

The rotation matrices:

For X rotation:

x' = x

y' = y * cos(angleX) - z * sin(angleX)

z' = y * sin(angleX) + z * cos(angleX)

For Y rotation:

x'' = x' * cos(angleY) + z' * sin(angleY)

y'' = y'

z'' = -x' * sin(angleY) + z' * cos(angleY)

So the total rotation is first X then Y.

Then, after both rotations, the coordinates (x'', y'', z'') are the rotated coordinates.

Then, we project:

// perspective projection: assuming a camera looking along the negative Z axis.

// The projection can be done using:

// screenX = (x'' * perspectiveDistance) / (z'' + perspectiveDistance) + centerX

// screenY = (y'' * perspectiveDistance) / (z'' + perspectiveDistance) + centerY

Wait, but need to ensure that z'' + perspectiveDistance is not zero. The perspectiveDistance is a positive constant (e.g., 100).

Alternatively, maybe use a different projection formula. Let me think.

Let me set the projection parameters:

Let’s set the perspective distance (camera to projection plane) as a fixed value, say 100.

The screen coordinates can be derived as follows:

Let’s define the screen width and height as canvas dimensions.

Let’s assume the canvas has width=canvasWidth, height=canvasHeight.

The center of the screen is (canvasWidth/2, canvasHeight/2).

The projection formulas could be:

// After rotation, the coordinates are (x_rot, y_rot, z_rot)

// Perspective projection:

var factor = perspectiveDistance / (z_rot + perspectiveDistance);

screenX = centerX + x_rot * factor;

screenY = centerY + y_rot * factor;

This way, as the object moves away along the Z axis (z_rot increases), factor decreases, making the projected points smaller.

Wait, but if the object is behind the camera (z_rot < -perspectiveDistance), then division by zero / negative can occur. To avoid that, we can clamp z_rot + perspectiveDistance to be positive.

Alternatively, we need to ensure that for our grid, the z_rot values don't go too negative.

Alternatively, perhaps use a simple orthographic projection for simplicity? But the user asked for a 3D effect so perspective is better.

Alternatively, maybe use a different projection approach.

Alternatively, to make it simple for now, let's assume:

We can first apply rotation, then project using:

screenX = (x'' * projectionScale) + centerX;

screenY = (y'' * projectionScale) + centerY;

But this is orthographic. To add perspective, perhaps:

screenX = (x'' / (z'' + perspectiveDistance)) * scale + centerX;

screenY = (y'' / (z'' + perspectiveDistance)) * scale + centerY;

But the exact implementation requires some constants.

In any case, the key steps are:

1. For each point, compute rotated coordinates.

2. Project to 2D screen coordinates with perspective.

Now, putting this into code:

First, set up some variables:

const grid_size = 20;

const centerX = canvas.width/2;

const centerY = canvas.height/2;

const perspectiveDistance = 200; // arbitrary value to control perspective effect

const projectionScale = 50; // scaling factor for the projection.

var angleX = 0;

var angleY = 0;

const rotationSpeed = 0.01;

var lastTime = 0;

function animate() {

    const time = performance.now();

    const deltaTime = time - lastTime;

    lastTime = time;

    angleX += rotationSpeed * deltaTime;

    angleY += rotationSpeed * deltaTime;

    // compute all points

    var lines = [];

    // compute rows and columns

    for(var j=0; j<grid_size; j++) {

        // get first and last points of row j

        var rowPoints = [];

        var firstPoint = getProjectedPoint(0, j);

        var lastPoint = getProjectedPoint(grid_size-1, j);

        // create a line object for the row

        lines.push({

            type: 'row',

            start: firstPoint,

            end: lastPoint,

            depth: (firstPoint.z + lastPoint.z)/2 // average z?

        });

    }

    for(var i=0; i<grid_size; i++) {

        var firstPoint = getProjectedPoint(i, 0);

        var lastPoint = getProjectedPoint(i, grid_size-1);

        lines.push({

            type: 'column',

            start: firstPoint,

            end: lastPoint,

            depth: (firstPoint.z + lastPoint.z)/2

        });

    }

    // sort lines by depth (back to front)

    lines.sort( (a,b) => a.depth - b.depth );

    // clear canvas and draw lines

    ctx.clearRect(0,0,canvas.width, canvas.height);

    for(var line of lines) {

        ctx.beginPath();

        ctx.moveTo(line.start.x, line.start.y);

        ctx.lineTo(line.end.x, line.end.y);

        ctx.stroke();

    }

    requestAnimationFrame(animate);

}

function getProjectedPoint(i,j) {

    // compute 3D coordinates

    var x = (i - (grid_size-1)/2) * 10; // scale_x = 10

    var y = (j - (grid_size-1)/2) * 10;

    var z = Math.sin(x * 0.1 + angleX) * Math.cos(y * 0.1 + angleY) * 20;

    // rotate around X and Y axes

    var angleX_rad = angleX * (Math.PI/180); // assuming angles are in degrees?

    var angleY_rad = angleY * (Math.PI/180);

    // rotate X first

    var y1 = y * Math.cos(angleX_rad) - z * Math.sin(angleX_rad);

    var z1 = y * Math.sin(angleX_rad) + z * Math.cos(angleX_rad);

    // rotate Y

    var x1 = x * Math.cos(angleY_rad) + z1 * Math.sin(angleY_rad);

    var z2 = -x * Math.sin(angleY_rad) + z1 * Math.cos(angleY_rad);

    // now x1, y1, z2 are rotated coordinates

    // perspective projection

    var factor = perspectiveDistance / (z2 + perspectiveDistance);

    var screen_x = centerX + x1 * factor * projectionScale;

    var screen_y = centerY + y1 * factor * projectionScale;

    // return the projected coordinates and the z value (for depth sorting)

    return {

        x: screen_x,

        y: screen_y,

        z: z2 // using z2 as depth (since lower z2 means closer?)

    };

}

Wait, but here the depth sorting is based on z2, which is the rotated Z coordinate after both rotations. However, the perspective is based on z2. The depth for sorting should be based on the actual distance from the camera. For perspective projection, the depth can be represented by the z2 coordinate, but since we are using a perspective formula, the actual depth in 3D space is z2. To sort back to front:

- Objects with lower z2 (closer to the camera, since if z2 is negative, they are in front of the projection plane).

Wait, perhaps the depth for sorting should be the negative of z2, so that closer objects (lower z2) are drawn later.

Wait, let's think:

Suppose z2 is the rotated Z coordinate.

- If z2 is very large (far away), the projected points will be small and towards the center.

- If z2 is negative (behind the projection plane?), but depending on the perspectiveDistance.

Wait, perhaps it's better to compute the actual distance from the camera, but that might complicate.

Alternatively, the depth for sorting can be the z2 value, but since in the perspective formula, the projected position depends on 1/(z2 + perspectiveDistance). So if we want to sort from far to near (back to front), we can sort based on increasing z2 + perspectiveDistance. Because when z2 is small (closer), z2 + perspectiveDistance is smaller, so the object is closer.

Wait, no:

Wait, if z2 is the distance along the Z axis after rotation.

Assuming the camera is at (0,0,0), looking along the negative Z axis.

Thus, the objects with higher z2 (more in the positive Z direction) are farther away.

Thus, to sort back to front, we should sort the lines in increasing order of (z2 + perspectiveDistance). Because:

- A point with z2 = 10 is farther than z2 = 5.

Thus, to draw back to front, sort lines by their z2 in ascending order.

Hence, in the depth field of the line objects, we can set depth = z2, and sort in ascending order.

Thus in getProjectedPoint(), the z value returned is z2.

Then in the line object, depth is the average of the two endpoints' z2.

Wait, but for a row line, the two endpoints may have different z2 values. So the average might not be the best. Alternatively, take the average of the midpoint's z2? Or perhaps compute the midpoint's coordinates.

Alternatively, compute the midpoint in 3D space and use its z2 as the depth for the line.

Alternatively, to simplify, take the average of the two endpoints' z2.

In the code above, for a row line, the depth is (firstPoint.z + lastPoint.z)/2.

Similarly for columns.

Thus, with this setup, the lines will be sorted by their depth, and drawn from back to front.

However, there might be some artifacts because the lines are straight and the depth is an average, but it should give a reasonable result.

Testing this code might require adjusting the perspectiveDistance and projectionScale to get a good visual effect.

Also, note that the initial rotation angles may be in degrees, but in JavaScript Math functions use radians, so the angleX and angleY variables in the getProjectedPoint() function are converted to radians.

Wait, in the animate() function, are angleX and angleY in degrees or radians?

The code currently has:

var angleX = 0;

var angleY = 0;

The rotationSpeed is 0.01, which if it's degrees per millisecond, but multiplied by deltaTime (milliseconds), so:

angleX += rotationSpeed * deltaTime;

If rotationSpeed is in degrees per millisecond, then with 0.01 degrees per millisecond, over 1 second (1000 ms), it would rotate 10 degrees.

Alternatively, maybe it's better to use radians.

Perhaps better to use radians for all angle calculations.

Let me adjust:

Set rotationSpeed in radians per millisecond:

const rotationSpeed = 0.0003; // e.g., 0.18 degrees per millisecond.

But maybe better to compute the delta in seconds.

Wait, the deltaTime is in milliseconds, so converting to seconds:

deltaTime_seconds = deltaTime / 1000;

Thus:

angleX += rotationSpeed * (deltaTime/1000);

where rotationSpeed is in radians per second.

Thus, setting rotationSpeed to 0.1 radians per second (approx 5.7 degrees/s):

const rotationSpeed = 0.1; // radians per second

Then:

angleX += rotationSpeed * (deltaTime / 1000);

Similarly for angleY.

This way, the rotation speed is properly in radians per second.

This adjustment is important for correct rotation.

So revising the variables and functions accordingly.

Also, need to ensure that the projectionScale and perspectiveDistance are set such that the grid fits on the canvas.

Probably need to experiment with the parameters.

Additionally, in getProjectedPoint(), the X and Y coordinates are computed as:

var x = (i - (grid_size-1)/2) * 10;

This spreads the grid out over a 10 units per grid step, so for grid_size=20, the maximum i is 19, so:

x ranges from (- (19 - (20-1)/2 )) ?

Wait, for i=0:

x = (0 - (19)/2)*10 = (-9.5)*10 = -95

For i=19: x = (19 - 9.5)*10 = 9.5 *10= 95

Thus, the grid extends from -95 to +95 in x and y.

The projectionScale and perspectiveDistance need to be set so that the projected points fit the canvas.

Suppose the canvas is 800x600:

centerX = 400, centerY = 300.

projectionScale: higher value would make the grid larger on the screen.

perspectiveDistance: controls how much perspective is applied. A smaller value gives a stronger perspective effect.

Perhaps start with:

perspectiveDistance = 200,

projectionScale = 3.

But need to test.

Also, in the z calculation:

var z = Math.sin(x * 0.1 + angleX) * Math.cos(y * 0.1 + angleY) * 20;

This creates a wave-like pattern in the z coordinate, which adds some 3D effect.

Alternatively, using a different function for z, such as a heightmap.

Overall, the code should create an animated 3D grid with rotating perspective, where lines are drawn back to front based on their depth.
command-r:35bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        margin: 0;
      }
      canvas {
        display: block;
      }
    </style>
  </head>
  <body>
    <canvas id="canvas"></canvas>

    <script>
      const canvas = document.getElementById("canvas");
      const ctx = canvas.getContext("2d");

      function smoothStep(edge0, edge1, x) {
        let t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));
        return t * t * (3 - 2 * t);
      }

      function lerp(a, b, ratio) {
        return a + (b - a) * ratio;
      }

      function drawGrid(gridSize, angle, time) {
        const halfWidth = gridSize / 2;

        ctx.clearRect(0, 0, canvas.width, canvas.height);

        for (let x = -halfWidth; x <= halfWidth; x++) {
          for (let y = -halfWidth; y <= halfWidth; y++) {
            const height = Math.sin((x * time + angle) / gridSize) * 30;

            const projectedX =
              canvas.width / 2 +
              150 *
                (x / halfWidth *
                  smoothStep(-1, -0.95, 1 - y / halfWidth - 0.05));
            const projectedY =
              150 * (y / halfWidth) * Math.cos(angle) +
              canvas.height / 2;

            ctx.fillStyle = `hsl(${(x + halfWidth) * 4}, 80%, ${
                lerp(0, y > -halfWidth ? 70 : 30, (y + halfWidth) / gridSize)
            }%)`;
            ctx.fillRect(projectedX, projectedY - height / 2, 1, height);
          }
        }
      }

      function animate() {
        let time = 0;
        const angle = Math.PI / 6 * Math.sin(Date.now() / 500) % (Math.PI / 4);

        drawGrid(30, angle, time++);

        requestAnimationFrame(animate);
      }

      animate();
    </script>
  </body>
</html>
```
Outside the Brain cluster — same task, same character budget, collected through their own tooling (response times not comparable)
Claude Opus 5frontier referenceOK
Show code
<!doctype html>
<html><head><meta charset="utf-8"><title>Rotating wireframe height field</title>
<style>
html,body{margin:0;height:100%;background:#05070e;overflow:hidden}
canvas{display:block;width:100vw;height:100vh}
#hud{position:fixed;left:12px;top:11px;font:13px ui-monospace,monospace;color:#a9e6ff;
background:rgba(5,7,14,.6);padding:5px 9px;border-radius:5px}
</style></head><body>
<canvas id="c"></canvas><div id="hud">grid</div>
<script>
const cv=document.getElementById('c'),g=cv.getContext('2d'),hud=document.getElementById('hud');
let W,H,cx,cy;
function fit(){W=cv.width=innerWidth;H=cv.height=innerHeight;cx=W/2;cy=H*.56}
fit();addEventListener('resize',fit);

const N=34,SP=26,F=560,CAMZ=680,TILT=.62;

function height(x,y,t){
  const d=Math.sqrt(x*x+y*y);
  return Math.sin(d*.055-t*1.9)*46/(1+d*.012)
       + Math.sin(x*.07+t*.8)*13
       + Math.cos(y*.06-t*.6)*13;
}

let t0=0;
function frame(tm){
  if(!t0)t0=tm;
  const t=(tm-t0)/1000, ang=t*.35;
  g.fillStyle='#05070e';g.fillRect(0,0,W,H);

  const ca=Math.cos(ang),sa=Math.sin(ang);
  const ct=Math.cos(TILT),st=Math.sin(TILT);
  const P=[];
  for(let j=0;j<N;j++){
    P.push([]);
    for(let i=0;i<N;i++){
      const wx=(i-(N-1)/2)*SP, wy=(j-(N-1)/2)*SP;
      const h=height(wx,wy,t);
      const rx=wx*ca-wy*sa, ry=wx*sa+wy*ca;
      const y2=ry*ct-h*st, z=ry*st+h*ct+CAMZ;
      const k=F/z;
      P[j].push([cx+rx*k, cy+y2*k, z, h]);
    }
  }

  // Reihen von HINTEN nach VORN: die Zeichenreihenfolge selbst verdeckt.
  const order=[];
  for(let j=0;j<N;j++){
    let d=0;for(let i=0;i<N;i++)d+=P[j][i][2];
    order.push([j,d/N]);
  }
  order.sort((a,b)=>b[1]-a[1]);

  for(const [j] of order){
    for(let i=0;i<N-1;i++){
      const a=P[j][i],b=P[j][i+1];
      const lift=(a[3]+b[3])/2;
      g.strokeStyle='hsl('+(196-lift*.9)+',85%,'+(38+lift*.42)+'%)';
      g.lineWidth=1.05;
      g.beginPath();g.moveTo(a[0],a[1]);g.lineTo(b[0],b[1]);g.stroke();
    }
    if(j<N-1)for(let i=0;i<N;i++){
      const a=P[j][i],b=P[j+1][i];
      g.strokeStyle='rgba(90,170,220,.34)';
      g.lineWidth=.8;
      g.beginPath();g.moveTo(a[0],a[1]);g.lineTo(b[0],b[1]);g.stroke();
    }
  }

  hud.textContent='grid '+N+'×'+N+'  ·  rotation '+(ang%6.2832).toFixed(2)+' rad';
  requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
</script></body></html>
GPT-5.5 (Codex)frontier referenceOKMINIFIED
Show code
<!doctype html><html><head><meta charset=utf-8><title>Height Field</title><style>html,body{margin:0;height:100%;overflow:hidden;background:#07090d;color:#dce7ff;font:14px system-ui}canvas{display:block;width:100vw;height:100vh}#i{position:fixed;left:14px;top:12px;background:#0009;padding:8px 10px;border:1px solid #3b465b;border-radius:6px;white-space:pre}</style></head><body><canvas id=c></canvas><div id=i></div><script>
const c=document.getElementById("c"),x=c.getContext("2d"),i=document.getElementById("i");
let W,H,DPR,pts,n=38,seed,life,start=0;
function R(){seed=Math.random()*9;life=18000+Math.random()*9000;pts=[];for(let z=0;z<n;z++)for(let q=0;q<n;q++)pts.push({x:(q/(n-1)-.5)*7,z:(z/(n-1)-.5)*7,y:0});start=performance.now()}
function S(){DPR=Math.min(devicePixelRatio||1,2);W=c.width=innerWidth*DPR;H=c.height=innerHeight*DPR;x.setTransform(DPR,0,0,DPR,0,0);W=innerWidth;H=innerHeight}
function h(a,b,t){return 1.1*Math.sin(a*1.7+t+seed)+.65*Math.cos(b*2.2-t*.8)+.45*Math.sin((a*a+b*b)*.42-t*1.5)}
function p(P,A,B){let ca=Math.cos(A),sa=Math.sin(A),cb=Math.cos(B),sb=Math.sin(B),X=P.x*ca-P.z*sa,Z=P.x*sa+P.z*ca,Y=P.y*cb-Z*sb;Z=P.y*sb+Z*cb+10;let s=Math.min(W,H)*.72/Z;return{x:W/2+X*s,y:H*.56-Y*s,z:Z}}
function line(a){x.beginPath();for(let k=0;k<a.length;k++){let m=a[k];k?x.lineTo(m.x,m.y):x.moveTo(m.x,m.y)}x.stroke()}
function F(now){if(now-start>life)R();let t=(now-start)/1000,A=t*.38+seed,B=.78+.22*Math.sin(t*.27+seed),rows=[],cols=[];x.fillStyle="#07090d";x.fillRect(0,0,W,H);for(let z=0;z<n;z++){let r=[];for(let q=0;q<n;q++){let P=pts[z*n+q];P.y=h(P.x,P.z,t);r.push(p(P,A,B))}rows.push(r)}for(let q=0;q<n;q++){let cc=[];for(let z=0;z<n;z++)cc.push(rows[z][q]);cols.push(cc)}let all=rows.concat(cols).map(a=>({a,d:a.reduce((s,v)=>s+v.z,0)/a.length})).sort((u,v)=>v.d-u.d);x.lineWidth=1.15;x.strokeStyle="#7ee7ff";x.shadowBlur=8;x.shadowColor="#1db6ff";for(const o of all)line(o.a);x.shadowBlur=0;x.strokeStyle="#eef7ff55";x.lineWidth=.6;for(const o of all)line(o.a);i.textContent="grid "+n+" x "+n+"\nangle "+((A*180/Math.PI)%360).toFixed(1)+" deg";requestAnimationFrame(F)}
addEventListener("resize",S);S();R();requestAnimationFrame(F);
</script></body></html>
Claude Sonnet 5frontier referenceOK
Show code
<!DOCTYPE html><html><head><meta charset="utf8"><title>Height Field</title><style>
body{margin:0;background:#04060b;overflow:hidden}canvas{display:block}
#i{position:fixed;top:8px;left:8px;color:#8fd;font:14px monospace}
</style></head><body><canvas id="c"></canvas><div id="i"></div><script>
const cv=document.getElementById('c'),ctx=cv.getContext('2d');
function resize(){cv.width=innerWidth;cv.height=innerHeight}
resize();addEventListener('resize',resize);
const GS=32;
let ang=0,t=0,seedA,seedB,seedC,frame=0;
function init(){
  seedA=Math.random()*10; seedB=Math.random()*10; seedC=Math.random()*10;
  ang=0; t=0; frame=0;
}
init();
function heightAt(x,y,time){
  const d=Math.sqrt(x*x+y*y);
  return Math.sin(d*0.35-time+seedA)*22 + Math.cos(x*0.22+time*0.7+seedB)*14 + Math.sin(y*0.25-time*0.5+seedC)*14;
}
function project(x,y,z,cx,cy,scale,ca,sa,cb,sb){
  let y1=y*ca - z*sa, z1=y*sa + z*ca;
  let x2=x*cb + z1*sb, z2=-x*sb + z1*cb;
  const camZ=380;
  const zz=z2+camZ;
  const f=380/zz;
  return [cx + x2*f*scale, cy + y1*f*scale, zz];
}
function loop(){
  ctx.fillStyle='#04060b';
  ctx.fillRect(0,0,cv.width,cv.height);
  ang+=0.006; t+=0.02; frame++;
  const cx=cv.width/2, cy=cv.height/2;
  const ca=Math.cos(ang*0.6), sa=Math.sin(ang*0.6);
  const cb=Math.cos(ang), sb=Math.sin(ang);
  const scale=Math.min(cv.width,cv.height)/(GS*3.2);
  const half=GS/2;
  const pts=[];
  for(let j=0;j<GS;j++){
    pts.push([]);
    for(let i=0;i<GS;i++){
      const x=(i-half)*6, y=(j-half)*6;
      const h=heightAt(x,y,t);
      pts[j].push(project(x,h,y,cx,cy,scale,ca,sa,cb,sb));
    }
  }
  const lines=[];
  for(let j=0;j<GS;j++){
    let z=0; for(let i=0;i<GS;i++) z+=pts[j][i][2];
    lines.push({type:'r',idx:j,z:z/GS});
  }
  for(let i=0;i<GS;i++){
    let z=0; for(let j=0;j<GS;j++) z+=pts[j][i][2];
    lines.push({type:'c',idx:i,z:z/GS});
  }
  lines.sort((a,b)=>b.z-a.z);
  ctx.lineWidth=1.2;
  for(const ln of lines){
    ctx.beginPath();
    if(ln.type==='r'){
      for(let i=0;i<GS;i++){
        const p=pts[ln.idx][i];
        if(i===0) ctx.moveTo(p[0],p[1]); else ctx.lineTo(p[0],p[1]);
      }
    } else {
      for(let j=0;j<GS;j++){
        const p=pts[j][ln.idx];
        if(j===0) ctx.moveTo(p[0],p[1]); else ctx.lineTo(p[0],p[1]);
      }
    }
    const depth=Math.max(0,Math.min(1,(ln.z-200)/500));
    ctx.strokeStyle='rgba('+Math.floor(80+150*(1-depth))+','+Math.floor(220-60*depth)+',255,'+(0.25+0.6*(1-depth)).toFixed(2)+')';
    ctx.stroke();
  }
  ctx.fillStyle='#8fd';ctx.font='14px monospace';
  ctx.fillText('grid: '+GS+'x'+GS,10,20);
  ctx.fillText('angle: '+(ang%(Math.PI*2)).toFixed(2),10,38);
  if(frame>2400) init();
  requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
</script></body></html>
Claude Haiku 4.5frontier referenceOKMINIFIED
Show code
<!DOCTYPE html><html><head><meta charset="utf-8"><style>body{margin:0;background:#000;overflow:hidden}#c{display:block}#i{position:absolute;top:5px;left:5px;color:#0f0;font-family:monospace;font-size:12px}</style></head><body><canvas id="c"></canvas><div id="i"></div><script>const c=document.getElementById('c'),ctx=c.getContext('2d'),i=document.getElementById('i');c.width=800;c.height=600;const G=20;function h(x,y,t){return Math.sin(x/10+t/500)*Math.cos(y/10+t/500)*10}function rx(p,a){let c=Math.cos(a),s=Math.sin(a);return[p[0],p[1]*c-p[2]*s,p[1]*s+p[2]*c]}function ry(p,a){let c=Math.cos(a),s=Math.sin(a);return[p[0]*c+p[2]*s,p[1],-p[0]*s+p[2]*c]}function prj(p){return[400+p[0]/Math.max(0.1,p[2])*100,300+p[1]/Math.max(0.1,p[2])*100]}function dr(){ctx.fillStyle='#000';ctx.fillRect(0,0,800,600);let t=Date.now();let ax=t/3000,ay=t/2000;let gr=[];for(let y=0;y<=G;y++){let row=[];for(let x=0;x<=G;x++){let hv=h(x*5-50,y*5-50,t);let p=[x*5-50,hv,y*5-50];p=ry(rx(p,ax),ay);p[2]+=20;row.push(p)}gr.push(row)}ctx.strokeStyle='#0f0';ctx.lineWidth=0.5;for(let y=G;y>0;y--){for(let x=0;x<G;x++){let p1=prj(gr[y][x]);let p2=prj(gr[y][x+1]);let p3=prj(gr[y-1][x+1]);let p4=prj(gr[y-1][x]);ctx.beginPath();ctx.moveTo(p1[0],p1[1]);ctx.lineTo(p2[0],p2[1]);ctx.lineTo(p3[0],p3[1]);ctx.lineTo(p4[0],p4[1]);ctx.closePath();ctx.stroke()}}i.textContent=`Grid: ${G}x${G} Angle: ${(ay*180/Math.PI).toFixed(0)}°`}setInterval(dr,50);</script></body></html>
Results at a glance— every model in this round with score, response time and status.

Who wrote what

ModelBlind scoreLatencyStatus
mistral-small:24b —128.7 sOK
qwen3:14b —30.5 sOK
qwen3:8b ——harness
qwen3-coder:30b —29.6 sOK
gemma4:26b ——harness
qwen3.5:9b —50.8 sOK
deepseek-r1:14b —69.1 sOK
llama3.1:8b —125.7 sOK
deepseek-r1:32b —289.3 sOK
qwq:32b —279.6 sOK
command-r:35b —294.3 sOK