OverviewPhysics Lab › R23
Physics Lab

R23 · Pendulum wave

Archive round — this round predates the blind-first layout, so answers appear with model names attached. Newer rounds keep the models anonymous until you reveal them.
scored 11/13 models answered
Show task
Create ONE self-contained HTML file (STRICT LIMIT: max 100 lines total) that shows a pendulum wave on a <canvas>: exactly 15 pendulums side by side, each with a slightly different length so their periods differ and they drift in and out of phase, producing the classic traveling-wave and snake patterns before realigning. Draw strings and bobs, animate with requestAnimationFrame. No external libraries, no comments needed. Output ONLY the HTML file content, nothing else.

Answers

Local (Brain cluster)
gemma4:26b DNF / pending DNF (infra)
DNF — infrastructure: 9/10 rounds ended in provider errors; its only completed round, R28, scored 8.5
qwen3-coder:30b15.3 sOK★ 8.5/10
Show code
```html
<!DOCTYPE html>
<html>
<head>
<title>Traveling Pendulum Wave</title>
<style>body {margin:0;display:flex;justify-content:center;align-items:center;height:100vh;background:#222;}canvas {border:1px solid #333;}</style>
</head>
<body>
<canvas id="pendulumCanvas"></canvas>
<script>
const canvas = document.getElementById('pendulumCanvas');
const ctx = canvas.getContext('2d');

canvas.width = 800;
canvas.height = 400;

const N = 15; // Number of pendulums
const LOOP_LENGTH = 70;
const BOB_SIZE = 10;
const DAMPING = 0.999;

let startTime = performance.now();

function animate(timestamp) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    const elapsed = (timestamp - startTime) / 1000;

    for (let i = 0; i < N; i++) {
        let bobX, bobY;
        // Physics approximation for coupled oscillator wave: position modulated by index 'i' and time 'elapsed'.
        // The phase difference (Math.sin(...) / Math.cos(...)) creates the traveling wave effect.
        // Modulating frequencies based on 'i' creates unique periods.
        const amp = 60 + i * 1; // Amplitude increases slightly with index
        const freqA = i * 0.15 + (i % 3) * 0.2;
        const freqB = 1.5 - i * 0.08;

        // Calculate sag/oscillation for the bob relative to its hanging point
        const offsetX = Math.sin(freqA * elapsed + i * 0.5) * amp;
        const offsetY = (Math.cos(freqB * elapsed + i * 0.3)) * amp / 2;

        bobX = i * (canvas.width - BOB_SIZE * 2) / (N - 1);
        bobY = canvas.height - LOOP_LENGTH - offsetY; // bob is displaced vertically
        
        const anchorY = canvas.height - LOOP_LENGTH;
        
        // Draw string/rod connection (anchor point to bob)
        ctx.strokeStyle = '#aaa';
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.moveTo(bobX, anchorY); // Attachment point is slightly higher than true hang point for visual tension
        ctx.lineTo(bobX + offsetX * (N - 1) / N * 0.8, Math.min(canvas.height - LOOP_LENGTH, anchorY) - offsetY);
        ctx.stroke();

        // Draw bob
        ctx.fillStyle = 'rgba(80, 80, 255, 0.9)';
        ctx.strokeStyle = '#444';
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.arc(bobX + offsetX * (N - 1) / N * 0.8, Math.min(canvas.height - LOOP_LENGTH, anchorY) - offsetY - BOB_SIZE/2 , BOB_SIZE/2, 0, Math.PI * 2);
        ctx.fill();
        ctx.stroke();
    }

    requestAnimationFrame(animate);
}

requestAnimationFrame(animate);
</script>
</body>
</html>
```
qwen3.5:9b10.4 sOK★ 8.5/10
Show code
<!DOCTYPE html>
<html><head><title>Pendulum Wave</title></head><body style="display:flex; justify-content:center; align-items:center; background: #000;"><canvas id="c" width="800" height="400" style="border:1px solid #333;"></canvas><script>
const c=document.getElementById('c');
const ctx=c.getContext('2d');
let t=0;

function draw() {
    ctx.clearRect(0, 0, c.width, c.height);
    const numPendulums = 15;
    const spacing = (c.width - 50) / (numPendulums + 1);
    const pivotY = 20;

    for (let i=0; i<numPendulums; i++) {
        const x=(i+1)*spacing;
        // Period modulation: different base frequencies/lengths
        const lengthScale = 30 + (i * 2); 

        // Traveling wave equation with damping and phase shift based on index (i)
        const angle = Math.sin((t*0.5 + i*0.5 * i / numPendulums)) * 0.8;
        
        // Calculate bob coordinates
        const bobX = x;
        const bobY = pivotY + lengthScale * (1 - Math.cos(angle));

        // Draw string (Pivot to Bob)
        ctx.strokeStyle='#AAAAAA';
        ctx.lineWidth=1;
        ctx.beginPath();
        ctx.moveTo(x, pivotY);
        ctx.lineTo(bobX, bobY);
        ctx.stroke();

        // Draw bob (Circle)
        const bobRadius = 5;
        ctx.fillStyle='#6666FF';
        ctx.beginPath()
        ctx.arc(bobX, bobY, bobRadius, 0, Math.PI*2);
        ctx.fill();

    }
    t += 0.1;
    requestAnimationFrame(draw);
}

draw();
</script></body></html>
qwen3:14b15.3 sOK★ 8.5/10
Show code
```html
<!DOCTYPE html>
<html>
<head><title>Pendulum Wave Simulation</title></head>
<body><canvas id="c"></canvas><script>
let c = document.getElementById('c');
let ctx = c.getContext('2d', {alpha: false});

const N = 15;
const LANGLEN = 300;
const GRAVITY = 9.8;
const K = 0.02; // Coupling Constant
const h = 1;     // Distance between bobs

c.width = 700; c.height = 450;

let l = [];
let x_angle = Array(N).fill(Math.PI / 6);
let y_angle = Array(N).fill(Math.PI / 6); // Slopes
let mass = Array(N).fill(1);
let len = Array(N).fill(LANGLEN * (0.9 + Math.random() * 0.2));

for(let i=0; i<N; i++){
    l[i] = len[i];
}

function updatePhysics() {
    for(let i=0; i<N; i++){
        if (i > 0) x_angle[i] -= K * Math.sin(y_angle[i - 1]) / l[i];
    }
    x_angle[0] += K * Math.sin(Math.PI/2);

    for(let i=0; i<N; i++){
        y_angle[i] = x_angle[i] + ((GRAVITY / (l[i] * l[i])) * 0.1) * (x_angle[i]-Math.PI/2);
        y_angle[i] += (x_angle[i] - y_angle[i]); // Simple spring damping
    }
}

function draw() {
    ctx.fillStyle = 'rgba(0,0,0,0.1)';
    ctx.fillRect(0, 0, c.width, c.height);
    
    for(let i=0; i<N; i++){
        const x_bob = (i === 0) ? 20 : ((i-1)/(N-1)) * (c.width - 40) + 20;
        const y_bob = c.height - 50;

        // Draw string/arm connection (Simplified linear approximation for performance)
        ctx.strokeStyle = '#333';
        ctx.beginPath();
        ctx.moveTo(x_bob, y_bob);
        ctx.lineTo(Math.sin(x_angle[i]) * 50 + x_bob, Math.cos(x_angle[i]) * 40 + h);
        ctx.stroke();

        // Draw bobs (circular)
        const bb_x = Math.sin(x_angle[i]) * 100 + c.width/2 - i*35;
        const bb_y = Math.cos(x_angle[i]) * 40 + h + (c.height-50)*0.1 * Math.sin(x_angle[i]);

        ctx.fillStyle = '#cc3333';
        ctx.beginPath();
        ctx.arc(bb_x, bb_y, 8, 0, 2*Math.PI);
        ctx.fill();
    }
}

function animate() {
    updatePhysics();
    draw();
    requestAnimationFrame(animate);
}
animate();
</script></body></html>
```
qwen3:8b DNF / pending DNF (infra)
DNF — infrastructure: 10/10 requests returned status 500
llama3.111.3 sERRBLANK★ 1/10
Show code
```html
<!DOCTYPE html>
<html>
<head>
<style>
body { background-color: #f0f0f0; }
</style>
</head>
<body>
<canvas id="screen" width="600" height="200"></canvas>

<script>
document.addEventListener("DOMContentLoaded", init);
var ctx = document.getElementById('screen').getContext2D();

function init() {
  var pendulums = [], count=15, dx = (document.body.getBoundingClientRect().width - 10) / count;
  for(var i=0; i<count; i++) { 
    pendulums.push(new Pendulum(i*dx,150,Math.random()*100+20));
  }
  loop(pendulums);
}

class Pendulum {
  constructor(x,y,len) {
    this.x = x;
    this.y = y;
    this.len = len;
    this.angle = Math.PI / 2;
  }
  draw() {
    ctx.lineCap = "round";
    ctx.lineWidth = 1.5;
    ctx.strokeStyle = "#808080";
    ctx.beginPath();
    ctx.arc(this.x, this.y,3,0,Math.PI*2);
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(this.x,this.y);
    let px = this.x + this.len * Math.cos(this.angle), py = this.y + this.len * -Math.sin(this.angle);
    ctx.lineTo(px,py);
    ctx.stroke();
  }
  update() {
    this.angle-=0.02;
    if (this.angle<-Math.PI/2) { 
      this.angle += 2*Math.PI; // "reset" pendulum
    }

    this.x+=0.5 * Math.sin(this.angle +Math.PI/4) / this.len;
  }
}

function loop(pendulums) {
  let current = new Date().getTime();
  ctx.clearRect(0, 0, document.body.getBoundingClientRect().width,200);
  for(let pendulum of pendulums) { 
    pendulum.update();
    pendulum.draw();
  }
  requestAnimationFrame(loop.bind(null,pendulums));
}
</script>
</body>
</html>
```
deepseek-r124.1 sERRBLANK★ 1/10
Show code
```html
<!DOCTYPE html>
<html><head><canvas id="c"></canvas><style>canvas{position:fixed;top:-20;left:0;width:100vw;height:95vh;background:#343;}</style></head>
<body>
    <script>
    const c = document.getElementById('c'), ctx = c.getContext('2d');
    let w = c.width = window.innerWidth, h = c.height = window.innerHeight + 30;

    const pendulums = [];
    const g = 1, pi = Math.PI;
    let ang = 0;

    // setup
    for(let i=0; i<15; i++) {
        const p = {
            x: w/2 + (w * i)/(cols-1),
            y: h - 150,
            len: 40 + i*3,
            angle: 0,
            velocity: 0,
            swinging: true
        }
        pendulums.push(p);
    }

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

        pendulums.forEach((p) => {

            // string from top to mass position
            const yTop = h - c.scrollHeight; 
            const xMid = p.x;
            
            ctx.beginPath();
            ctx.strokeStyle = 'white';
            ctx.lineWidth = 2;

            if(p.swinging) {
                ctx.moveTo(xMid, yTop);
                ctx.lineTo(p.x, p.y);
            }

            //bob and mass points
            ctx.fillStyle = '#fff';
            pendulums.forEach((p) => {
                const xB = p.x;
                const yB = p.y || h-150;
                if(yB < h-10) { 
                    ctx.beginPath();
                    ctx.arc(xB - 1, yB, 2, 0, pi * 2);
                    ctx.fill();
                }
            });

            //wave form
            pendulums.forEach((b,i) => {
                const nextI = (i+1)%pendulums.length;
                if(i && b.swinging) {
                    const xA = b.x, yA = h-150;
                    const xB = pendulums[i+1].x, yB = pendulums[i+1].y;
                    ctx.beginPath();
                    ctx.moveTo(xA, yA);
                    ctx.lineTo(xB*.7 + (xA*.3), (yB + yA)/5);
                    ctx.lineTo(xA, yA>10 ? yA-20 : yA);
                }
            });

        });
        ctx.stroke();

        // physics
        pendulums.forEach(p => {
            if(Math.sin(ang) > 0.8 && Date.now() % (pi*2*5)>pi && p.swinging) ang += g/100;
            p.velocity += Math.sin(ang)*g / 4;
            p.angle += p.velocity;
            p.y = p.len * Math.sin(p.angle) + h - 150;

        });

        requestAnimationFrame(draw);
    }

    window.addEventListener('resize', () => {
        w = c.width = window.innerWidth, h = c.height = window.innerHeight +30;
        pendulums.forEach(p => { p.x *= (w/c.width); });
    });

    draw();
    </script>
</body></html>
```
mistral-small66.3 sOK★ 8.5/10
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>Pendulum Wave</title>
    <style>
        canvas { background: #fff; display: block; margin: 20px auto; }
    </style>
</head>
<body>
<canvas id="pendulums" width="800" height="600"></canvas>
<script>
function pendulumWave() {
    const canvas = document.getElementById('pendulums');
    const ctx = canvas.getContext('2d');
    let lastTime = 0;

    const numPendulums = 15;
    const pendulumLengths = Array.from({ length: numPendulums }, (_, i) => 30 * (numPendulums - i));
    const pivotX = canvas.width / 2;
    const amplitudes = pendulumLengths.map(l => l * 0.8);

    function animate(time) {
        if (!lastTime) lastTime = time;
        const deltaTime = time - lastTime;

        ctx.clearRect(0, 0, canvas.width, canvas.height);
        for (let i = 0; i < numPendulums; i++) {
            const length = pendulumLengths[i];
            const amplitude = amplitudes[i];
            let angle = Math.sin(time / 100 + i * 2.4) * amplitude;
            ctx.beginPath();
            ctx.moveTo(pivotX, 50);
            ctx.lineTo(pivotX + (length * Math.cos(angle)), 50 - (length * Math.sin(angle)));
            ctx.stroke();

            const pendulumColor = `rgba(179, ${32+6*i}, 8, 1)`;
            ctx.fillStyle = pendulumColor;

            ctx.beginPath();
            ctx.arc(pivotX + (length * Math.cos(angle)), 50 - (length * Math.sin(angle)), 10, 0, 2 * Math.PI);
            ctx.fill();

        }
        lastTime = time;
        requestAnimationFrame(animate);
    }

    requestAnimationFrame(animate);
}

pendulumWave();
</script>
</body>
</html>
```
Cloud
GPT-5.5 (codex)16.6 sOK★ 8.5/10
Show code
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Pendulum Wave</title>
<style>
html,body{margin:0;height:100%;overflow:hidden;background:#071018}
canvas{display:block;width:100%;height:100%}
</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
const c=document.getElementById("c"),x=c.getContext("2d");
let W,H,DPR;
function size(){
  DPR=devicePixelRatio||1;
  W=c.width=innerWidth*DPR;
  H=c.height=innerHeight*DPR;
  c.style.width=innerWidth+"px";
  c.style.height=innerHeight+"px";
  x.setTransform(DPR,0,0,DPR,0,0);
}
addEventListener("resize",size);size();
const n=15,g=9.81,base=2.15,step=.035,amp=.34;
const p=Array.from({length:n},(_,i)=>({
  k:i,
  T:base+i*step,
  hue:190+i*9
}));
function draw(t){
  t/=1000;
  const w=innerWidth,h=innerHeight;
  x.clearRect(0,0,w,h);
  const top=h*.15,span=w*.82,gap=span/(n-1),ox=w*.09;
  x.lineWidth=1.5;
  for(const q of p){
    const L=(g*(q.T/(2*Math.PI))**2)*90;
    const px=ox+q.k*gap,py=top;
    const a=amp*Math.sin(2*Math.PI*t/q.T);
    const bx=px+Math.sin(a)*L,by=py+Math.cos(a)*L;
    x.strokeStyle="rgba(170,210,230,.55)";
    x.beginPath();x.moveTo(px,py);x.lineTo(bx,by);x.stroke();
    const r=Math.max(7,Math.min(15,gap*.18));
    const grad=x.createRadialGradient(bx-r*.35,by-r*.45,2,bx,by,r);
    grad.addColorStop(0,`hsl(${q.hue},95%,78%)`);
    grad.addColorStop(1,`hsl(${q.hue},75%,42%)`);
    x.fillStyle=grad;
    x.beginPath();x.arc(bx,by,r,0,7);x.fill();
  }
  x.fillStyle="rgba(230,245,255,.8)";
  x.fillRect(w*.06,top-3,w*.88,6);
  requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
</script>
</body>
</html>
Claude HaikuOK★ 8.5/10
Show code
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Pendulum</title><style>body{margin:0;background:#000}</style></head><body><canvas id="c"></canvas><script>
const c=document.getElementById('c'),x=c.getContext('2d'),W=900,H=500;
c.width=W;c.height=H;const n=15,g=980;
const pends=Array(n).fill().map((_, i)=>{const L=50+i*8;return{L,amp:0.5,T:2*Math.PI*Math.sqrt(L/g),cx:W/(n+1)*(i+1),cy:80};});
let t=0;function loop(){t+=0.016;x.fillStyle='#000';x.fillRect(0,0,W,H);
for(let i=0;i<n;i++){const p=pends[i],th=p.amp*Math.sin(2*Math.PI*t/p.T),bx=p.cx+p.L*Math.sin(th),by=p.cy+p.L*Math.cos(th);
x.strokeStyle='#08f';x.lineWidth=1.5;x.beginPath();x.moveTo(p.cx,p.cy);x.lineTo(bx,by);x.stroke();
x.fillStyle='#0ff';x.beginPath();x.arc(bx,by,4,0,2*Math.PI);x.fill();}requestAnimationFrame(loop);}loop();
</script></body></html>
Claude SonnetOK★ 8.5/10
Show code
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Pendulum Wave</title>
<style>html,body{margin:0;background:#0b0b16;overflow:hidden}canvas{display:block}</style>
</head><body>
<canvas id="c"></canvas>
<script>
const cv=document.getElementById('c'), ctx=cv.getContext('2d');
function resize(){cv.width=innerWidth; cv.height=innerHeight;}
resize(); addEventListener('resize',resize);
const N=15, g=900, theta0=0.55;
const pends=[];
for(let i=0;i<N;i++){
  const L=140+i*9, T=2*Math.PI*Math.sqrt(L/g);
  pends.push({L,T,hue:(i*24)%360});
}
const start=performance.now();
function frame(now){
  const t=(now-start)/1000;
  ctx.fillStyle='rgba(11,11,22,0.25)';
  ctx.fillRect(0,0,cv.width,cv.height);
  const marginX=cv.width*0.07, spacing=(cv.width*0.86)/(N-1), anchorY=70;
  for(let i=0;i<N;i++){
    const p=pends[i], ax=marginX+i*spacing;
    const ang=theta0*Math.cos(2*Math.PI*t/p.T);
    const bx=ax+p.L*Math.sin(ang), by=anchorY+p.L*Math.cos(ang);
    ctx.strokeStyle='rgba(255,255,255,0.5)'; ctx.lineWidth=2;
    ctx.beginPath(); ctx.moveTo(ax,anchorY); ctx.lineTo(bx,by); ctx.stroke();
    ctx.beginPath(); ctx.arc(ax,anchorY,3,0,Math.PI*2); ctx.fillStyle='#888'; ctx.fill();
    ctx.beginPath(); ctx.arc(bx,by,14,0,Math.PI*2); ctx.fillStyle=`hsl(${p.hue},80%,60%)`; ctx.fill();
  }
  requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
</script>
</body></html>
Claude OpusOK★ 8.5/10
Show code
<!doctype html><html><head><meta charset="utf-8"><title>Pendulum Wave</title>
<style>body{margin:0;background:#0d0d1a;display:flex;justify-content:center;align-items:center;height:100vh}canvas{background:#0d0d1a}</style>
</head><body>
<canvas id="c" width="700" height="560"></canvas>
<script>
const cv=document.getElementById('c'),x=cv.getContext('2d');
const N=15,cycle=30,base=20,amp=0.55,py0=50,k=178;
let pend=[];
for(let i=0;i<N;i++){let f=(base+i)/cycle;pend.push({f:f,L:k/(f*f),px:80+i*38,hue:i/N*300});}
let t0=performance.now();
function loop(now){
 let t=(now-t0)/1000;
 x.clearRect(0,0,700,560);
 x.fillStyle='#444';x.fillRect(60,py0-4,600,4);
 for(let p of pend){
  let th=amp*Math.cos(2*Math.PI*p.f*t);
  let bx=p.px+p.L*Math.sin(th),by=py0+p.L*Math.cos(th);
  x.strokeStyle='rgba(255,255,255,0.25)';x.lineWidth=1;
  x.beginPath();x.moveTo(p.px,py0);x.lineTo(bx,by);x.stroke();
  x.beginPath();x.arc(bx,by,9,0,7);x.fillStyle='hsl('+p.hue+',80%,60%)';x.fill();
 }
 requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
</script></body></html>
Claude FableOK★ 8.5/10
Claude Fable – rendered output R23
Show code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Pendulum Wave</title>
<style>body{margin:0;background:#0b0e14;display:flex;justify-content:center;align-items:center;height:100vh}</style>
</head>
<body>
<canvas id="c" width="900" height="520"></canvas>
<script>
const ctx=document.getElementById("c").getContext("2d");
const N=15,CYC=40,BASE=25,PY=40,AMP=0.3;
const ps=[];
for(let i=0;i<N;i++){
const f=(BASE+i)/CYC;
ps.push({px:170+i*40,f:f,L:170/(f*f),c:"hsl("+i*24+",80%,60%)"});
}
const t0=performance.now();
function loop(now){
const t=(now-t0)/1000;
ctx.fillStyle="#0b0e14";ctx.fillRect(0,0,900,520);
ctx.strokeStyle="#778";ctx.lineWidth=6;
ctx.beginPath();ctx.moveTo(150,PY);ctx.lineTo(750,PY);ctx.stroke();
for(const p of ps){
const th=AMP*Math.cos(2*Math.PI*p.f*t);
const bx=p.px+p.L*Math.sin(th),by=PY+p.L*Math.cos(th);
ctx.strokeStyle="#99a";ctx.lineWidth=1.5;
ctx.beginPath();ctx.moveTo(p.px,PY);ctx.lineTo(bx,by);ctx.stroke();
ctx.fillStyle=p.c;ctx.beginPath();ctx.arc(bx,by,11,0,7);ctx.fill();
}
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
</script>
</body>
</html>