OverviewCode › R76
Code · blind round

R76 · Falling sand as free particles

blind round 3/8 local models answered

Answers below are anonymized and shuffled. Read, judge, pick a favourite — then scroll down and reveal the models.

2 of the 8 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. Which ones, and why, is spelled out in the reveal.

The reveal also holds a frontier reference on the same task (Claude Opus 5) — kept out of sight here so it cannot steer your judgement.

Show task
Create ONE self-contained HTML file (STRICT LIMIT: max 120 lines total) that simulates falling sand as 1500 FREE-MOVING PARTICLES with continuous positions on a <canvas>. Each grain has a floating-point position and velocity, falls under gravity, loses energy on impact and comes to rest on the growing pile, so a realistic angle of repose forms. No grid, no cells — continuous coordinates only. Show the number of grains at rest and the pile height. 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 — blind

Local models (Brain cluster) — identical prompt, anonymized order
MODEL Agemma4:26bDNF
No usable answer reached the harness (TIMEOUT). Counted as a did-not-finish.
MODEL Bllama3.1:8bDNF
No usable answer reached the harness (TIMEOUT). Counted as a did-not-finish.
MODEL Cqwen3.5:9bERRBLANKLIMFORMAT
Show code
```html
<!DOCTYPE html>
<html>
<body><canvas id="sandCanvas"></canvas><script>
const canvas = document.getElementById('sandCanvas');
const ctx = canvas.getContext('2d');
let W, H;

// Simulation Constants
const N_PARTICLES = 1500;
const GRAVITY = 0.3;
const DAMPING = 0.85; // Energy loss on impact
const PILE_LIMIT = 5; // Collision check radius (squared for performance)

let particles = [];
let isRunning = true;
let settledCount = 0;
let maxPileHeight = 0;

// Particle Structure: [x, y, vx, vy, active]
class Particle {
    constructor(x, y) {
        this.p = [x, y]; // Position
        this.v = [Math.random() * 2 - 1, Math.random() * -5]; // Velocity (some initial upward/lateral kick for variety)
        this.active = true;
    }

    update(dt) {
        if (!this.active) return;

        // Apply Gravity
        this.v[1] += GRAVITY * dt;

        // Update Position
        this.p[0] += this.v[0] * dt;
        this.p[1] += this.v[1] * dt;

        if (Math.abs(this.v[1]) > 0) {
            checkCollision();
        }
    }

    draw() {
        ctx.fillStyle = 'rgba(255, 165, 0', this.active ? ', 0.8)' : ', 1)';
        ctx.fillRect(this.p[0], this.p[1], 2, 2);
    }

    // Collision detection and settling logic (Simplified N-body interaction)
    checkCollision() {
        const x = this.p[0];
        const y = this.p[1];

        if (y > H - 5) { // Ground collision stop
            this.active = false;
            return true;
        }

        // Check against all other particles for collision
        for (let i = 0; i < particles.length; i++) {
            const p2 = particles[i];
            if (p2 === this || !p2.active) continue;

            const dx = x - p2.p[0];
            const dy = y - p2.p[1];
            const distSq = dx * dx + dy * dy;

            if (distSq < PILE_LIMIT && Math.abs(this.v[1]) > 0) {
                // Collision detected: Stop movement and settle
                this.active = false;
                p2.v[1] += GRAVITY * 0.1; // Give slight bounce to others
                this.v[1] = 0;
                this.v[0] *= DAMPING;

                // Adjust position slightly to rest on the surface
                const overlapDepth = PILE_LIMIT - Math.sqrt(distSq);
                this.p[1] += overlapDepth * 0.5; 
            }
        }
        return false;
    }
}

function initialize() {
    W = canvas.width = window.innerWidth * 0.95;
    H = canvas.height = window.innerHeight * 0.75;
    particles = [];
    settledCount = 0;
    maxPileHeight = 0;
    isRunning = true;

    for (let i = 0; i < N_PARTICLES; i++) {
        const startX = Math.random() * W * 0.8 + W * 0.1;
        const startY = H - 50 - Math.random() * 20; // Drop from above the canvas view
        particles[i] = new Particle(startX, startY);
    }
}

function updatePhysics(dt) {
    let settledThisFrame = 0;
    for (const p of particles) {
        if (p.active) {
            p.update(dt);
            // Check if the particle has fallen sufficiently far or stopped due to collision
            if (!p.checkCollision()) {
                // Simple check for settling: If vertical velocity is near zero AND it's not on the ground
                if (Math.abs(p.v[1]) < 0.5 && p.p[1] < H - 2) {
                    p.active = false;
                    settledThisFrame++;
                }
            }
        } else if (!p.active) {
             // Keep settled particles in place (they are part of the pile now)
        }
    }

    if (settledCount + settledThisFrame >= N_PARTICLES - 10) { // Check if almost all have settled
        isRunning = false;
        setTimeout(initialize, 2000); // Restart after a delay
    } else {
        settledCount += settledThisFrame;
    }

    // Update pile height metric
    maxPileHeight = Math.max(maxPileHeight, ...particles.map(p => p.p[1]));
}

function draw() {
    ctx.clearRect(0, 0, W, H);

    for (const p of particles) {
        if (p.active) {
            p.draw();
        } else {
            // Draw settled grains darker
            ctx.fillStyle = 'rgba(184, 134, 11', ', 1)';
            ctx.fillRect(p.p[0], p.p[1], 2, 2);
        }
    }

    // UI Overlay (Lines are kept simple for line count)
    ctx.fillStyle = 'white';
    ctx.font = '14px Arial';
    let yOffset = 20;
    ctx.fillText(`Grains At Rest: ${Math.floor(settledCount)} / ${N_PARTICLES}`, 10, yOffset);
    yOffset += 20;
    ctx.fillText(`Pile Height (Y): ${Math.round(H - maxPileHeight)}`, 10, yOffset);
}

function animate() {
    if (isRunning) {
        const dt = 1; // Time delta approximation
        updatePhysics(dt);
    }
    draw();
    requestAnimationFrame(animate);
}

window.addEventListener('resize', initialize);
initialize();
animate();
</script></body></html>
```
MODEL Dqwen3-coder:30bERRBLANKLIMFORMAT
Show code
```html
<!DOCTYPE html>
<html>
<head>
    <title>Continuous Sand Simulation</title>
    <style>body { margin: 0; background: #111; }</style>
</head>
<body>
<canvas id="sandCanvas"></canvas>
<script>
const canvas = document.getElementById('sandCanvas');
const ctx = canvas.getContext('2d');
let W, H;

function init() {
    W = window.innerWidth * 0.95;
    H = window.innerHeight * 0.8;
    canvas.width = W;
    canvas.height = H;
}
window.addEventListener('resize', init);
init();

const PARTICLE_COUNT = 1500;
let particles = [];
const GRAVITY = 9.8 / 60; // Adjusted for frame rate
const DAMPING = 0.85;     // Energy loss on impact
const MAX_VELOCITY = 20;

class Particle {
    constructor() {
        this.reset();
    }
    reset() {
        this.x = Math.random() * W * 0.3 + W * 0.1; // Start in a confined area
        this.y = -50;
        this.vx = (Math.random() - 0.5) * 5;
        this.vy = 0;
        this.r = 2;
    }

    update(pileHeight, pileMap) {
        if (this.isDead) return;

        // Apply gravity
        this.vy += GRAVITY;
        this.vx *= 0.98; // Air resistance
        this.x += this.vx;
        this.y += this.vy;

        let collisionY = pileHeight[Math.floor(this.x) % W];
        let groundCollision = false;

        // Collision detection with the "pile" structure or floor
        if (this.y >= collisionY - this.r * 2 && Math.abs(this.x - W / 2) < W/2) {
            this.vy *= -DAMPING; // Bounce and lose energy
            this.vx *= DAMPING;

            // If vertical velocity is small enough, settle down
            if (Math.abs(this.vy) < 0.5 && Math.abs(this.vx) < 0.1) {
                this.isDead = true; // Particle settles and becomes part of the pile
                return;
            }

            // Adjust position to sit exactly on the support plane
            this.y = collisionY[Math.floor(this.x)] - this.r * 2;
        } else if (this.y >= H - this.r) {
             this.isDead = true; // Hit floor
        }

        // Clamp position to canvas bounds
        this.x = Math.max(0, Math.min(W, this.x));
        if (this.y < 0) this.y = 0;
    }

    draw() {
        ctx.fillStyle = `rgba(139, 69, 19, ${Math.random() * 0.5 + 0.5})`;
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
        ctx.fill();
    }

    isDead = false; // Flag for settled particles
}

// Global map simulating the pile structure (stores Y coordinate at X)
let pileHeight = Array(Math.floor(W / 1)); 
let particleCountAtRest = 0;
let totalParticles = PARTICLE_COUNT;

function updateSimulation() {
    particles.forEach(p => p.update(pileHeight, null));

    // --- Pile Update Logic (Simplified support plane calculation) ---
    // On every frame, the pile height map should be updated by checking all settled particles
    const newPileHeight = Array(Math.floor(W / 1)).fill(H); // Initialize to floor level
    for (let i = 0; i < totalParticles; i++) {
        if (particles[i].isDead) {
            int x_idx = Math.min(Math.max(0, Math.floor(particles[i].x)), W - 1);
            newPileHeight[x_idx] = Math.min(newPileHeight[x_idx], particles[i].y + particles[i].r * 2);
        }
    }
    pileHeight = newPileHeight;

    // --- Particle Management & Reset ---
    let currentRestCount = 0;
    particles.forEach((p, i) => {
        if (p.isDead && !p.recycled) {
            currentRestCount++;
            p.recycled = true; // Mark as counted rest particle
        } else if (Math.random() < 0.01 || p.y > H + 50) { // Occasionally respawn or move out of bounds
             // If it settled, don't reset it unless needed for mass control
        }
    });

    particleCountAtRest = Math.min(totalParticles, currentRestCount);


    // --- Drawing & Looping ---
    ctx.clearRect(0, 0, W, H);

    particles.forEach((p, i) => {
        if (p.isDead && !p.recycled) {
            // If settled, keep drawing it slightly opaque but stationary
             ctx.fillStyle = 'rgba(139, 69, 19, 0.8)';
             ctx.beginPath();
             ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
             ctx.fill();

        } else {
            p.draw();
        }
    });


    // Info Display
    ctx.fillStyle = '#FFF';
    ctx.font = '16px monospace';
    ctx.fillText(`Resting Grains: ${particleCountAtRest}/${totalParticles}`, 10, 20);

    requestAnimationFrame(updateSimulation);
}

particles = [];
for (let i = 0; i < PARTICLE_COUNT; i++) {
    particles.push(new Particle());
}

// Start the simulation loop
updateSimulation();
</script>
</body>
</html>
```
MODEL Edeepseek-r1:14bDNF
No usable answer reached the harness (TIMEOUT). Counted as a did-not-finish.
MODEL Fqwen3:8bDNF
No usable answer reached the harness (ERR). Counted as a did-not-finish.
MODEL Gqwen3:14bBLANKLIM
Show code
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Continuous Sand Simulation</title>
    <style>body {margin:0;overflow:hidden;background:#111;}canvas {display:block;border:1px solid #333;}</style>
</head>
<body>
<canvas id="sandCanvas"></canvas>
<script>
const canvas = document.getElementById('sandCanvas');
const ctx = canvas.getContext('2d');
let W, H;
let particles = [];
let restingParticles = [];
let frameCount = 0;

function setup() {
    W = window.innerWidth * 0.95;
    H = window.innerHeight * 0.8;
    canvas.width = W;
    canvas.height = H;
    particles = [];
    restingParticles = [];
}

function init() {
    setup();
    for (let i = 0; i < 1500; i++) {
        particles.push({ x: Math.random() * W, y: -Math.random() * H, vx: 0, vy: 0 });
    }
    frameCount++;
}

function updatePhysics(p) {
    const G = 9.8 / 60; // Gravity scaled for frame rate
    const DAMPING = 0.7;
    let hit = false;

    // Apply gravity and movement
    p.vy += G;
    p.x += p.vx;
    p.y += p.vy;

    // Simple collision detection with the ground/pile structure
    for (const r of restingParticles) {
        if (Math.abs(r.x - p.x) < 10 && Math.abs(r.y - p.y) < 10) {
            hit = true;
            break;
        }
    }

    // If hitting the 'ground' or an existing particle, settle it
    if (p.y >= H * 0.9 || hit) {
        p.vy *= -DAMPING; // Bounce/loss of energy
        p.vx *= DAMPING;

        // Check for near-rest state
        if (Math.abs(p.vy) < 0.1 && Math.abs(p.vx) < 0.1 && p.y >= H * 0.9 - 5) {
            p.isResting = true;
        }
    }

    // If particle settles, transfer it to resting state and remove from active pool
    if (p.isResting) {
        restingParticles.push(Object.assign({}, p)); // Deep copy
        return false; // Indicates removal from active array
    }
    return true;
}

function update() {
    ctx.clearRect(0, 0, W, H);

    const activeParticles = [];
    let settledCount = 0;

    for (let i = 0; i < particles.length; i++) {
        const p = particles[i];
        if (!p.isResting) {
            // Apply slight lateral force for spreading
            p.vx += Math.sin(frameCount * 0.01 + i / 50) * 0.005;

            let keepActive = updatePhysics(p);
            if (keepActive) {
                activeParticles.push(p);
            } else {
                settledCount++;
            }
        }
    }
    particles = activeParticles;


    // Draw particles and rest pile
    ctx.fillStyle = '#555';
    for (const p of particles) {
        ctx.fillRect(p.x, p.y, 1, 1);
    }

    ctx.fillStyle = '#8a4d0e'; // Sand color
    for (const r of restingParticles) {
        ctx.beginPath();
        ctx.arc(r.x, r.y, 0.5, 0, Math.PI * 2);
        ctx.fill();
    }

    // Stats Display
    const restHeight = restingParticles.length > 0 ? Math.min(...restingParticles.map(p => p.y)) : H;
    document.getElementById('stats').innerHTML = `Resting Grains: ${restingParticles.length}<br>Pile Height: ${(H - restHeight).toFixed(1)}px`;

    requestAnimationFrame(update);
}

// Initialization and Runtime Management
window.onload = () => {
    const statsDiv = document.createElement('div');
    statsDiv.id = 'stats';
    statsDiv.style.color = '#ccc';
    document.body.appendChild(statsDiv);
    init();
};

</script>
<!-- The physics simulation logic implicitly handles the angle of repose by having particles settle only when they collide with an existing structure, reducing their energy until velocity approaches zero. -->
<div id="stats" style="position:absolute;top:10px;left:10px;color:#ccc;">Loading...</div>

</body>
</html>
No usable answer reached the harness (TIMEOUT). Counted as a did-not-finish.
Reveal the models— compare the answers first, then open. Names, blind scores and latencies are hidden until you do.

Who wrote what

Blind labelModelBlind scoreLatencyStatus
MODEL A gemma4:26b harness
MODEL B llama3.1:8b DNF
MODEL C qwen3.5:9b 43.5 sOK
MODEL D qwen3-coder:30b 22.9 sOK
MODEL E deepseek-r1:14b DNF
MODEL F qwen3:8b harness
MODEL G qwen3:14b 27.5 sOK
MODEL H mistral-small:24b DNF

Frontier reference — outside the blind field

These models answered the identical prompt outside the blind field. They are deliberately not scored and not part of the blind comparison — they are there so you can see where a frontier model lands on the same task.

Collected differently from the blind field: the local models run through a plain API harness, the frontier references through a context-free agent, one shot, no retries. Response times are therefore not comparable and are not shown. On two English tasks the reference answer came back in German — an artefact of that harness, flagged on the affected rounds.
Claude Opus 5frontier reference
Show code
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Falling Sand — 1500 Free Particles</title>
<style>
html,body{margin:0;height:100%;overflow:hidden;background:#080a0f;color:#e8e0cd;
font:12px/1.6 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
#wrap{position:fixed;inset:0;display:flex;align-items:center;justify-content:center}
canvas{background:radial-gradient(120% 90% at 50% 0%,#161b26,#0a0d13);border-radius:12px;
box-shadow:0 24px 70px #000c,inset 0 0 0 1px #ffffff10}
#hud{position:fixed;top:18px;left:50%;transform:translateX(-50%);display:flex;gap:22px;
align-items:center;padding:8px 16px;border-radius:999px;background:#0f131caa;
backdrop-filter:blur(6px);box-shadow:0 0 0 1px #ffffff14;letter-spacing:.06em;white-space:nowrap}
#hud b{color:#f0d79a;letter-spacing:.16em;font-weight:600}
#hud i{font-style:normal;color:#fff;font-variant-numeric:tabular-nums}
#hud span{color:#9aa3b4;text-transform:uppercase;font-size:11px}
</style>
</head>
<body>
<div id="wrap"><canvas id="c"></canvas></div>
<div id="hud"><b>FALLING SAND</b><span>grains <i id="tot">0</i>/1500</span>
<span>at rest <i id="rst">0</i></span><span>pile height <i id="hgt">0</i>px</span></div>
<script>
const cv=document.getElementById('c'),ctx=cv.getContext('2d');
const eT=document.getElementById('tot'),eR=document.getElementById('rst'),eH=document.getElementById('hgt');
const N=1500,R=2.6,D=5.2,G=1150,SUB=3,IT=2,VMAX=340,K=100003;
const SH=['#f6e7bb','#ecd497','#ddbb75','#cba55f','#b78c4b'];
let W=0,H=0,P=[],spawned=0,emitX=0,emitJ=0,doneT=0,age=0;
function fit(){const d=Math.min(devicePixelRatio||1,2);
W=Math.max(320,Math.min(innerWidth-30,960));H=Math.max(300,Math.min(innerHeight-30,660));
cv.style.width=W+'px';cv.style.height=H+'px';cv.width=W*d|0;cv.height=H*d|0;ctx.setTransform(d,0,0,d,0,0);}
function reset(){P=[];spawned=0;doneT=0;age=0;emitX=W*(0.34+Math.random()*0.32);emitJ=6+Math.random()*32;}
fit();reset();
addEventListener('resize',()=>{fit();reset();});
function collide(){
const m=new Map(),n=P.length;
for(let i=0;i<n;i++){const p=P[i],k=Math.floor(p.x/D)*K+Math.floor(p.y/D);
let a=m.get(k);if(!a)m.set(k,a=[]);a.push(i);}
for(let it=0;it<IT;it++)for(let i=0;i<n;i++){
const a=P[i],cx=Math.floor(a.x/D),cy=Math.floor(a.y/D);
for(let ox=-1;ox<2;ox++)for(let oy=-1;oy<2;oy++){
const bucket=m.get((cx+ox)*K+cy+oy);if(!bucket)continue;
for(let q=0;q<bucket.length;q++){const j=bucket[q];if(j<=i)continue;const b=P[j];
const dx=b.x-a.x,dy=b.y-a.y,d2=dx*dx+dy*dy;if(d2>=D*D||d2<1e-9)continue;
const d=Math.sqrt(d2),nx=dx/d,ny=dy/d,ov=D-d;a.sup=1;b.sup=1;
if(a.s&&b.s){if(ov>R*0.5){a.s=0;b.s=0;}continue;}
if(a.s&&ov>R*0.6)a.s=0;if(b.s&&ov>R*0.6)b.s=0;
const wa=a.s?0:1,wb=b.s?0:1,tw=wa+wb;if(!tw)continue;
const c=ov*0.75/tw;a.x-=nx*c*wa;a.y-=ny*c*wa;b.x+=nx*c*wb;b.y+=ny*c*wb;
const vn=(b.vx-a.vx)*nx+(b.vy-a.vy)*ny;
if(vn<0){const im=-1.08*vn/tw;a.vx-=nx*im*wa;a.vy-=ny*im*wa;b.vx+=nx*im*wb;b.vy+=ny*im*wb;}
const tx=-ny,ty=nx,ft=((b.vx-a.vx)*tx+(b.vy-a.vy)*ty)*0.5/tw;
a.vx+=tx*ft*wa;a.vy+=ty*ft*wa;b.vx-=tx*ft*wb;b.vy-=ty*ft*wb;}}}}
function physics(){
if(spawned<N)for(let i=0;i<10&&spawned<N;i++){spawned++;
P.push({x:emitX+(Math.random()-0.5)*emitJ,y:-R-Math.random()*70,vx:(Math.random()-0.5)*26,
vy:60+Math.random()*45,s:0,t:0,sup:0,g:Math.random()*5|0});}
const dt=1/(60*SUB);
for(let k=0;k<SUB;k++){
for(const p of P){if(p.s)continue;p.sup=0;p.vy+=G*dt;
const sp=Math.hypot(p.vx,p.vy);if(sp>VMAX){p.vx*=VMAX/sp;p.vy*=VMAX/sp;}
p.x+=p.vx*dt;p.y+=p.vy*dt;}
collide();
for(const p of P){if(p.s)continue;
if(p.y>H-R){p.y=H-R;if(p.vy>0)p.vy*=-0.1;p.vx*=0.55;p.sup=1;}
if(p.x<R){p.x=R;p.vx=Math.abs(p.vx)*0.25;}else if(p.x>W-R){p.x=W-R;p.vx=-Math.abs(p.vx)*0.25;}
if(p.sup&&p.vx*p.vx+p.vy*p.vy<6){if(++p.t>20){p.s=1;p.vx=0;p.vy=0;}}else p.t=0;}}
age++;}
function draw(){
ctx.clearRect(0,0,W,H);
let rest=0,top=H;
for(const p of P)if(p.s){rest++;if(p.y<top)top=p.y;}
const surf=rest?top-R:H,ph=rest?Math.round(H-surf):0;
for(let g=0;g<5;g++){ctx.fillStyle=SH[g];ctx.beginPath();
for(const p of P){if(p.g!==g)continue;ctx.moveTo(p.x+R,p.y);ctx.arc(p.x,p.y,R,0,6.28319);}ctx.fill();}
if(rest){ctx.strokeStyle='rgba(120,190,255,.32)';ctx.setLineDash([7,7]);ctx.lineWidth=1;
ctx.beginPath();ctx.moveTo(0,surf+.5);ctx.lineTo(W,surf+.5);ctx.stroke();ctx.setLineDash([]);
ctx.fillStyle='rgba(150,205,255,.65)';ctx.fillText(ph+' px',10,surf-6);}
ctx.strokeStyle='rgba(255,255,255,.14)';ctx.beginPath();
ctx.moveTo(0,H-.5);ctx.lineTo(W,H-.5);ctx.stroke();
eT.textContent=P.length;eR.textContent=rest;eH.textContent=ph;
if(spawned>=N&&(P.length-rest<=4||age>2600)){if(++doneT>80)reset();}else doneT=0;}
function loop(){physics();draw();requestAnimationFrame(loop);}
requestAnimationFrame(loop);
</script>
</body>
</html>