OverviewPhysics Lab › R29
Physics Lab

R29 · Orbital mechanics

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 120 lines total) that shows orbital mechanics on a <canvas>: a sun fixed in the center, exactly 3 planets on stable near-circular orbits of different radii, and 1 comet on a strongly elliptical orbit that swings close past the sun. All motion must come from a Newtonian gravity simulation (acceleration = G*M/r^2 toward the sun, velocity integration), NOT from parametric circle formulas. Each body leaves a fading trail showing its orbit shape. Smooth requestAnimationFrame animation. 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:30b19.1 sERRBLANK★ 1/10
Show code
```html
<!DOCTYPE html>
<html><body><canvas id="c"></canvas><script>const c=document.getElementById('c');c.width=800;c.height=600;const ctx=c.getContext('2d');let bodies=[{id:0,px:{x:-1,y,-1},py:{x:-1,y,-1},vx:{x:0,y:0},vy:{x:0,y:0},mass:597200,radius:8,color='#ffcc00',trail:{}},{id:1,px:{x:150,y:0},py:{x:150,y:0},vx:{x:-0.5,y:0.6},vy:{x:0,y:-0.04},mass:3.1e-3,radius:10,color='#00bfff',trail:{}},{id:2,px:{x:{}-250,y:0},py:{x:-250,y:0},vx:{x:0.8,y:0},vy:{x:0.04,y:0.2},mass:1e-3,radius:7,color='#ff69b4',trail:{}},{id:3,px:{x:-5,y:0},py:{x:-5,y:0},vx:{x:0,y:0},vy:{x:0,y:0},mass:1e-5,radius:2,color='#99ccff',trail:{}}];const G=1;const dt=0.1;function update(bodies) {let accs=[{x:0,y:0},{x:0,y:0},{x:0,y:0},{x:0,y:0}];for(let i=1;i<bodies.length;i++)({const p_i=bodies[i].px;const m_i=bodies[i].mass;accs[i]={x:0,y:0};}for(let i=1;i<bodies.length;i++){let totalAx={x:0,y:0};for(let j=0;j<bodies.length;j++){if(i===j)continue;const dx=bodies[j].px.x-bodies[i].px.x;const dy=bodies[j].px.y-bodies[i].px.y;const r=Math.sqrt(dx*dx+dy*dy);const f=G*(bodies[j].mass*m_i)/(r*r+(2*dt));totalAx.x+=f*dx/r;totalAx.y+=f*dy/r;}bodies[i].vx.x+=totalAx.x*dt;bodies[i].vy.y+=totalAx.y*dt;p=bodies[i];const newX=p.px.x+p.vx.x*dt;const newY=p.px.y+p.vy.y*dt;if(newX<0){p.px.x=newX}else if(newX>800){p.px.x=800}else{p.px.x=newX;}if(newY<0){p.px.y=newY}else if(newY>600){p.px.y=600}else{p.px.y=newY;}bodies[i].trail.push({...p.px});if(bodies[i].trail.length>50)bodies[i].trail.shift();}function draw() {ctx.fillStyle='rgba(0,0,0,0.1)';ctx.fillRect(0,0,800,600);for(let i=0;i<bodies.length;i++){const b=bodies[i];if(b.trail.length>1)ctx.beginPath();let x=b.trail[0].x,y=b.trail[0].y;ctx.moveTo(x,y);for(let j=1;j<b.trail.length;j++){ctx.lineTo(b.trail[j].x,b.trail[j].y);}ctx.strokeStyle=b.color+'30';ctx.stroke();const r_draw=Math.pow(bodies[i].mass/597200+0.1,0.8)*Math.random()*0.6+4;ctx.beginPath();ctx.arc(b.px.x,b.px.y,r_draw,(Date.now()/500)%Math.PI*2,0);ctx.fillStyle=b.color;ctx.fill();}}function animate() {update(bodies);draw();}requestAnimationFrame(animate);</script></body></html>
```
qwen3.5:9b28.7 sERRBLANKLIM★ 0.5/10
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Newtonian Orbits</title>
    <style>body { margin: 0; background: #111; }</style>
</head>
<body><canvas id="c"></canvas><script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const SCALE = 50; // Pixels per AU (visualization scale)

function setup() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    
    const G_PHYS = 1 * 10; // Gravitational constant for simulation units
    const SUN_MASS = 10000;
    
    let bodies = [
        // Planet 1 (Inner, stable) - Near circular orbit approximation
        { pos: { x: 25 * SCALE, y: 0 }, vel: { x: 0, y: 3.85 * Math.sqrt(G_PHYS * SUN_MASS / 25) }, mass: 1, radius: 6, trail: [] },
        // Planet 2 (Medium, stable)
        { pos: { x: -70 * SCALE, y: 0 }, vel: { x: 0, y: 1.4 * Math.sqrt(G_PHYS * SUN_MASS / 70) }, mass: 1, radius: 8, trail: [] },
        // Planet 3 (Outer, stable)
        { pos: { x: 0, y: 120 * SCALE }, vel: { x: -1.1 * Math.sqrt(G_PHYS * SUN_MASS / 120), y: 0 }, mass: 1, radius: 5, trail: [] },
        // Comet (Highly elliptical path) - Initial state set for perihelion passage near t=0
        { pos: { x: 180 * SCALE, y: -40 * SCALE }, vel: { x: -3.5 * Math.sqrt(G_PHYS * SUN_MASS / 200), y: 6 }, mass: 0.01, radius: 3, trail: [], isComet: true }
    ];

    let dt = 0.01; // Time step
    lastTime = performance.now();

    function update_gravity(body) {
        const dx = body.pos.x - bodies[0].pos.x;
        const dy = body.pos.y - bodies[0].pos.y;
        const r2 = dx * dx + dy * dy;
        const r = Math.sqrt(r2);

        let ax = G_PHYS * SUN_MASS / (r * r2);
        let ay = 0; // Sun is fixed at origin in simulation coordinates, but visually centered.
        
        // Calculate acceleration towards the sun (origin) using relative positions 
        body.ax = -dx / r + ax * dx / Math.pow(r, 3);
        body.ay = -dy / r + ay * dy / Math.pow(r, 3);

    }

    function update_pos(body) {
        const px = body.pos.x;
        const py = body.pos.y;
        const vx = body.vel.x;
        const vy = body.vel.y;
        
        // Euler integration step
        body.vel.x += body.ax * dt;
        body.vel.y += body.ay * dt;

        body.pos.x += body.vel.x * dt;
        body.pos.y += body.vel.y * dt;

        return { x: px, y: py };
    }
    
    function update_simulation() {
        // Reset accelerations for all bodies (only planets/comet need them)
        bodies.forEach(b => { b.ax = 0; b.ay = 0; });

        // Calculate forces *for* the sun's fixed position (local origin in physics units)
        bodies[1].ax = -bodies[1].pos.x / Math.max(0.1, Math.hypot(bodies[1].pos.x, bodies[1].pos.y))**3;
        bodies[1].ay = -bodies[1].pos.y / Math.max(0.1, Math.hypot(bodies[1].pos.x, bodies[1].pos.y))**3;
        
        // Simulate the main mechanics (using local origin for force calculation simplicity)
        for (let i = 0; i < bodies.length; i++) {
             const body = bodies[i];

            if (body !== bodies[0]) { // Skip sun update logic
                const dx = -body.pos.x; // Vector from body to origin (Sun)
                const dy = -body.pos.y;
                const r2 = dx * dx + dy * dy;
                const r = Math.sqrt(r2);

                if (i > 0 && i < bodies.length) {
                    // Acceleration calculation towards the origin (Sun at 0,0)
                    body.ax = G_PHYS * SUN_MASS / Math.pow(r, 3) * dx;
                    body.ay = G_PHYS * SUN_MASS / Math.pow(r, 3) * dy;
                }
            }

            // Update position and trail
            const newPos = update_pos(body);
            body.trail.push({ x: newPos.x, y: newPos.y });
            if (body.trail.length > 500) body.trail.shift(); // Keep trail length manageable

        }
    }

    function draw() {
        ctx.fillStyle = 'rgba(17, 17, 17, 0.2)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.globalAlpha = 0.8;

        bodies.forEach((b, i) => {
            const drawBody = (x, y, r, color);
            ctx.beginPath();
            ctx.arc(x, y, r, 0, Math.PI * 2);
            ctx.fillStyle = color;
            ctx.fill();

            // Draw Trail
            ctx.strokeStyle = b.isComet ? 'rgba(255, 255, 100, 0.6)' : 'rgba(150, 150, 255, 0.4)';
            ctx.lineWidth = 1;
            ctx.beginPath();
            if (b.trail.length > 0) {
                const startTrail = b.trail[0];
                ctx.moveTo(startTrail.x * SCALE, startTrail.y * SCALE);
                b.trail.forEach((p, j) => {
                    ctx.lineTo(p.x * SCALE, p.y * SCALE);
                });
            }
            ctx.stroke();

            // Draw body itself (re-draw to ensure visibility over faint trail edge)
            const drawX = b.pos.x * SCALE + canvas.width / 2;
            const drawY = b.pos.y * SCALE;
            ctx.beginPath();
            ctx.arc(drawX, drawY, b.radius, 0, Math.PI * 2);
            ctx.fillStyle = color || '#fff';
            ctx.fill();
        });

        requestAnimationFrame(() => { update_simulation(); draw(); });
    }

    // Initialize the simulation loop upon load
    window.onload = () => {
        setup();
        draw();
    };
</script></body></html>
```
qwen3:14b22.2 sERRBLANK★ 1/10
Show code
```html
<!DOCTYPE html>
<html>
<head>
    <title>N-Body Orbit Simulation</title>
    <style>body {margin:0;overflow:hidden;background-color:#000;}</style>
</head>
<body>
<canvas id="c"></canvas><script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
let width = window.innerWidth;
let height = window.innerHeight;
canvas.width = width;
canvas.height = height;

function Body(x, y, vx, vy, r, m, color) {
    this.x = x; this.y = y; 
    this.vx = vx; this.vy = vy; 
    this.r = r; this.m = m;
    this.color = color;
    this.trail = [];
}

const G = 100; // Gravitational constant scale factor, adjusted for visualization speed
let planets = [
    new Body(width/2 - 150, height/2, 0 - Math.sqrt((G * 1e10) / 150), 0, 8, 1e9, 'cyan'), // Planet 1 (Semi-circular, faster velocity)
    new Body(width/2 + 100, height/2, 0, Math.sqrt((G * 1e10) / 100), 6, 5e9, 'yellowgreen'), // Planet 2 (Near circular)
    new Body(width/2 - 280, height/2, 0, -Math.sqrt((G * 1e10) / 280), 7, 1e8, 'orange'), // Planet 3 (Slower, outer orbit)
];

// Comet: Highly elliptical starting point/velocity guess for a swing past origin
let comet = new Body(width/2 + 350, height/2, - Math.sqrt(1 * G*1e10 / 350), 0, 4, 5e6, 'white');

const dt = 0.1;
const trailLength = 800; 

function updateBodies() {
    let bodies = [...planets, comet];
    for (let body of bodies) {
        // Calculate acceleration vector A = G*M/r^2 * R_vec / r
        let dx = body.x - width/2;
        let dy = body.y - height/2;
        let r2 = dx * dx + dy * dy;

        if (r2 < 1) r2 = 1; // Avoid division by zero
        let r_inv3 = 1 / Math.pow(Math.sqrt(r2), 3);
        
        let accX = G * body.m * dx * r_inv3;
        let accY = G * body.m * dy * r_inv3;

        // Integration (Basic Euler)
        body.vx += accX * dt;
        body.vy += accY * dt;
        
        body.x += body.vx * dt;
        body.y += body.vy * dt;

        // Trail management
        body.trail.push({ x: body.x, y: body.y });
        if (body.trail.length > trailLength) {
            body.trail.shift();
        }
    }
}

function draw() {
    ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; // Fading effect background fill
    ctx.fillRect(0, 0, width, height);

    let bodies = [...planets, comet];
    for (let body of bodies) {
        // Draw Trail
        ctx.strokeStyle = body.color;
        ctx.globalAlpha = 0.5;
        ctx.lineWidth = 1;
        ctx.beginPath();
        if (body.trail.length > 0) {
            ctx.moveTo(body.trail[0].x, body.trail[0].y);
            for (let i = 1; i < body.trail.length; i++) {
                let alpha = i / body.trail.length * 0.5 + 0.2; // Fade effect calculation
                ctx.strokeStyle = `rgba(${body.color === 'cyan' ? '0, 255, 255' : (body.color === 'yellowgreen' ? '102, 204, 0' : (body.color === 'orange' ? '255, 165, 0' : '255, 255, 255')}), ${Math.round(alpha * 255)}, ${Math.round(alpha * 255)}, ${Math.round(alpha * 255)})`;
                ctx.lineTo(body.trail[i].x, body.trail[i].y);
            }
            ctx.stroke();
        }

        // Draw Body (Sun fixed at center)
        ctx.globalAlpha = 1;
        ctx.fillStyle = body.color || 'gold';
        ctx.beginPath();
        ctx.arc(body.x, body.y, body.r, 0, Math.PI * 2);
        ctx.fill();
    }

    requestAnimationFrame(draw_loop);
}

function draw_loop() {
    updateBodies();
    draw();
}

window.onresize = () => {
    width = window.innerWidth;
    height = window.innerHeight;
    canvas.width = width;
    canvas.height = height;
};

if (typeof requestAnimationFrame !== 'undefined') draw_loop();
</script>
</body>
</html>
```
qwen3:8b DNF / pending DNF (infra)
DNF — infrastructure: 10/10 requests returned status 500
llama3.115.0 sERRBLANK★ 1/10
Show code
```html
<!DOCTYPE html>
<html>
<head>
<title>Orbital Mechanics Demo</title>
<style>
canvas { border: 1px solid black; }
</style>
<script>
const GRAVITATIONAL_CONSTANT = 0.001;
let sun = { x: 200, y: 200, vx: 0, vy: 0 };
let planets = [
  { r: 10, angle: Math.PI / 2 },
  { r: 30, angle: 3 * Math.PI / 4 },
  { r: 60, angle: Math.PI }
];
let comet = {
  r: 50,
  e: 0.75,
  x: 200 + Math.random() * 100 - 50,
  y: Math.random() * 300 - 150,
  vx: (sun.x - this.x) / ((Math.pow(sun.x, 2) + Math.pow(sun.y, 2)) ** 0.5),
  vy: (sun.y - this.y) / ((Math.pow(sun.x, 2) + Math.pow(sun.y, 2)) ** 0.5)
};
let drawSun = (canvas) => {
    const ctx = canvas.getContext('2d');
    ctx.beginPath();
    ctx.arc(canvas.width/2, canvas.height/2, 10, 0, 2 * Math.PI);
    ctx.fillStyle = 'yellow';
    ctx.fill();
}
let updatePlanets = () => {
  planets.forEach(p => {
    const dx = p.x - sun.x;
    const dy = p.y - sun.y;
    p.vx += (GRAVITATIONAL_CONSTANT * 1 / (Math.pow(dx, 2) + Math.pow(dy, 2))) * (dx/sun.y);
    p.vy += (GRAVITATIONAL_CONSTANT * 1 / (Math.pow(dx, 2) + Math.pow(dy, 2))) * (dy/sun.y);
    p.x += p.vx;
    p.y += p.vy;
  });
}
let updateComet = () => {
  comet.vx += GRAVITATIONAL_CONSTANT * ((sun.x - comet.x) / (Math.pow(comet.x - sun.x, 2) + Math.pow(comet.y - sun.y, 2)));
  comet.vy += GRAVITATIONAL_CONSTANT * ((sun.y - comet.y) / (Math.pow(comet.x - sun.x, 2) + Math.pow(comet.y - sun.y, 2)));
  comet.x += comet.vx;
  comet.y += comet.vy;

  if (comet.y < sun.y && comet Vy > 0) {
    comet Vy = -comet Vy * comet.e;
  }
}
let clearCanvas = (canvas) => {
  const ctx = canvas.getContext('2d');
  ctx.clearRect(0, 0, canvas.width, canvas.height);
}
let drawTrail = (ctx, p) => {
  let l = 1
  while (l >= 5) {
      drawPlanet(ctx, Math.cos(p.angle), Math.sin(p.angle));
      if(l%10 === 0)
          break;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
      drawSun(canvas.getContext('2d'));
    };
};
let drawPlanets = (ctx, p) => {
    const c = new Array();
    for (let [x, y] of planets) {
        c.push([x,y]);
    }
};

function drawPlanet(ctx, x, y)
{
  ctx.beginPath();
  ctx.arc(200+x*30, 200+y*30, 10, 0, 2 * Math.PI);
  ctx.fillStyle = 'blue';
  ctx.fill();

}

let animate = (timestamp) => {
    updatePlanets();
    updateComet()
    const canvas = document.querySelector('canvas');
    clearCanvas(canvas);
    drawSun(canvas);
    planets.forEach(planet =>
      drawTrail(
        canvas.getContext('2d'),
        planet
      )
    );
  requestAnimationFrame(animate);
}
let initialize = () => {
  let canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  canvas.width = 400;
  canvas.height = 300;
  animate();
};
document.addEventListener("DOMContentLoaded", function() {
  document.body.appendChild(document.createElement('canvas'));
});
</script>
</head>
<body>
</body>
</html>
```
deepseek-r132.7 sERRBLANK★ 1/10
Show code
```html
<!DOCTYPE html>
<html><head><title>Orbital Mechanics</title>
 <style>canvas{border:1px solid silver;background:#000}</style></head>
<body style="overflow:hidden;margin:0;">
 <canvas id=c size=512 512></canvas>
 <script>
 var c=document.getElementById('c'), ctx=c.getContext('2d');
 const SUN_MASS=2e3, G=1.878; // gravitational constant
 var sun={x:256,y:256,radius:40,mass:SUN_MASS};
 var bodies=[sun];
 function init(){ // initialize planets and comet
  let a= [80,140,210]; // orbital radii for planets
  a.forEach((r,i) => {
   const angle = i * Math.PI/3;
   bodies.push({
    mass:i==0?250:100,
    radius:r<70?8:(6),
    x:Math.cos(angle)*r+sun.x,
    y:Math.sin(angle)*r+sun.y,
    vx:-Math.sin(angle)*Math.sqrt(G*SUN_MASS/(r)),
    vy: Math.cos(angle)*Math.sqrt(G*SUN_MASS/(r)),
    ax:0,ay:0,trail:[],
    opacity:t=>(1 - Date.now()%(50*(i+2)))/(1 + i)
   });
  });
  // comet initialization
  const c={mass:8,radius:4,x:360,y:sun.y-20,vx:-Math.sqrt(G*SUN_MASS/20),
   vy:0,ax:0,ay:0,trail:[], opacity:f=>(1-(Date.now()%80))/1};
  bodies.push(c);
 }
 
 function updateAccels(){
 for(let b of bodies){
  if(b === sun)continue;
  let dx = b.x - sun.x, dy= b.y -sun.y;
  distSq=dx*dx + dy*dy;
  const force=G*sun.mass*b.mass/(distSq);
  b.ax=force * dx/distSq**0.5 /b.mass;
  b.ay=force * dy/distSq**0.5 /b.mass;
 }
 }
 
 function updateVelocities(){
 for(let i of bodies){
  i.vx +=i.ax*dt; i.vy +=i.ay*dt;
 }
 }

 function integratePosition(){
 for(let i of bodies){
  const t = dt/2;
  i.x += i.vx*t +0.5*i.ax*(t)*t;
  i.y += i.vy*t +0.5*i.ay*(t)*t;
 }
}

function updateBodies() {
   let t1=Date.now();
   Object.assign(dt, {value:(Date.now()-gLast)/6e4});
   while(dt.value<0.003)t1=gLast+5;
   requestAnimationFrame(function(){updateBodies();});
   dt.value&&(
    (function anim(timestamp){
     gLast = timestamp,
     updateAccels(),
     integratePosition(),
     updateVelocities();
     draw();
    })(t1));
}

function trailUpdate() {
 for(let b of bodies){
  let i;
  b.trail.push({x:b.x,y:b.y,alpha:b.opacity()});
  while(b.trail[b.trail.length-1].alpha < (0.8/(b.trail.length)) && b.trail.length>40)b.trail.shift();
 }
}

function draw() {
 ctx.fillStyle='#000'; ctx.fillRect(0,0,c.width,c.height);
 ctx.beginPath(); // sun
 ctx.fillStyle='yellow';
 ctx.arc(sun.x,sun.y,sun.radius,0,2*Math.PI); 
 ctx.fill();
 for(let b of bodies){
  if(b === sun)continue;
  const saved=false,
   trail=b.trail.slice(0,60).reverse();
     ctx.beginPath();
     ctx.fillStyle=`hsl(${Math.abs(Date.now()%5)+130},${90 - Math.abs(i*40-20)}%,70}`;
     trail.forEach(p => {
      if(!saved){
       b.x=p.x;b.y=p.y; saved=true;
      }
      ctx.fillRect(p.x,p.y,b.radius/2,b.radius/2);
     });
    }
 function drawPlanet(x,y,radius,color){ // helper
  ctx.beginPath();
  ctx.fillStyle=color;
  ctx.arc(x,y,radius,0,Math.PI*2);ctx.fill();
 }
 
 for(let b of bodies){
   if(b === sun)continue;
   const ang= (Date.now()%86400)/1e3;
      drawPlanet(b.x,b.y,b.radius, `hsl(${(ang/(.4*Math.PI))*50},90%,70)`); 
 }
}

// Initialize
gLast=0, dt={value:0.03};
init();
trailUpdate(); // ensure trail is ready
updateAccels(); // precompute initial accels
setInterval(updateBodies, 1);
 </script>
</body></html>
```
mistral-small83.1 sBLANK★ 1.5/10
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Orbital Mechanics</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
</style>
</head>
<body>
<canvas id="orchestral"></canvas>
<script>
let canvas = document.getElementById('orchestral');
let ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

const G = 1e-3;
const bodies = [
    {m: 100, x: canvas.width / 2, y: canvas.height / 2, vx: 0, vy: 0, trail: []},
    {m: 1, x: 50, y: 180, vx: 3, vy: 4, trail: []},
    {m: 1, x: 300, y: canvas.height / 2, vx: -2.2, vy: 0.6, trail: []},
    {m: 5, x: 700, y: 150, vx: 0, vy: 4.8, trail: []},
    {m: 3, x: canvas.width / 2 + 350, y: canvas.height - 50, vx: -6.9, vy: -2, trail: []}
];

function drawBody(body) {
    ctx.beginPath();
    ctx.arc(body.x, body.y, Math.sqrt(body.m), 0, 2 * Math.PI);
    ctx.fillStyle = 'white';
    ctx.fill();

    if (body.trail.length > 100) body.trail.shift();
    for (let i = 0; i < body.trail.length; i++) {
        let point = body.trail[i];
        ctx.beginPath();
        ctx.arc(point.x, point.y, 2 * Math.sqrt(body.m), 0, 2 * Math.PI);
        ctx.fillStyle = `rgba(255, 255, 255, ${1 - i / 50})`;
        ctx.fill();
    }
}

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

    for (let body of bodies) {
        drawBody(body);
    }

    for (let body of bodies.slice(1)) {
        let fx = 0;
        let fy = 0;

        for (let other of bodies) {
            if (body !== other) {
                let dx = other.x - body.x;
                let dy = other.y - body.y;
                let r2 = dx * dx + dy * dy;
                let force = G * other.m * body.m / r2;

                fx += force * dx / Math.sqrt(r2);
                fy += force * dy / Math.sqrt(r2);
            }
        }

        body.vx += fx / body.m;
        body.vy += fy / body.m;
        body.x += body.vx;
        body.y += body.vy;
        body.trail.push({ x: body.x, y: body.y });
    }

    requestAnimationFrame(draw);
}

draw();
</script>
</body>
</html>
```
Cloud
GPT-5.5 (codex)21.0 sOK★ 8.5/10
Show code
```html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Orbital Mechanics</title>
<style>
html,body{margin:0;height:100%;overflow:hidden;background:#050711}
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,cx,cy,dpr;
function size(){
  dpr=devicePixelRatio||1; W=innerWidth; H=innerHeight;
  c.width=W*dpr; c.height=H*dpr; x.setTransform(dpr,0,0,dpr,0,0);
  cx=W/2; cy=H/2;
}
addEventListener("resize",size); size();

const mu=90000, dt=.018, scale=1;
function body(name,r,clr,rad,phase=0){
  let a=phase, px=Math.cos(a)*r, py=Math.sin(a)*r, v=Math.sqrt(mu/r);
  return {name,x:px,y:py,vx:-Math.sin(a)*v,vy:Math.cos(a)*v,clr,rad,tr:[]};
}
const bodies=[
  body("p1",95,"#6ec6ff",4,.4),
  body("p2",155,"#ffd166",5,2.1),
  body("p3",230,"#9cff8f",6,4.2)
];
let ra=360,rp=42,a=(ra+rp)/2,vc=Math.sqrt(mu*(2/ra-1/a));
bodies.push({name:"comet",x:ra,y:0,vx:0,vy:vc,clr:"#ffffff",rad:3,tr:[]});

function step(){
  for(const b of bodies){
    let r2=b.x*b.x+b.y*b.y, r=Math.sqrt(r2), acc=-mu/(r2*r);
    b.vx+=b.x*acc*dt; b.vy+=b.y*acc*dt;
  }
  for(const b of bodies){
    b.x+=b.vx*dt; b.y+=b.vy*dt;
    b.tr.push([b.x,b.y]);
    if(b.tr.length>520)b.tr.shift();
  }
}
function draw(){
  x.fillStyle="rgba(5,7,17,.22)";
  x.fillRect(0,0,W,H);
  let g=x.createRadialGradient(cx,cy,0,cx,cy,42);
  g.addColorStop(0,"#fff7b0"); g.addColorStop(.35,"#ffb347"); g.addColorStop(1,"rgba(255,120,20,0)");
  x.fillStyle=g; x.beginPath(); x.arc(cx,cy,42,0,7); x.fill();
  x.fillStyle="#ffd35a"; x.beginPath(); x.arc(cx,cy,13,0,7); x.fill();

  for(const b of bodies){
    for(let i=1;i<b.tr.length;i++){
      let p=b.tr[i-1], q=b.tr[i], alpha=i/b.tr.length;
      x.strokeStyle=b.clr+Math.floor(alpha*160).toString(16).padStart(2,"0");
      x.lineWidth=b.name==="comet"?1.4:1;
      x.beginPath(); x.moveTo(cx+p[0]*scale,cy+p[1]*scale);
      x.lineTo(cx+q[0]*scale,cy+q[1]*scale); x.stroke();
    }
  }
  for(const b of bodies){
    x.fillStyle=b.clr;
    x.beginPath(); x.arc(cx+b.x*scale,cy+b.y*scale,b.rad,0,7); x.fill();
  }
}
function loop(){
  for(let i=0;i<5;i++)step();
  draw();
  requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>
```
Claude HaikuOK★ 8.5/10
Show code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Orbital Mechanics</title>
<style>
body { margin: 0; overflow: hidden; background: #000; }
canvas { display: block; }
</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
canvas.width = 1200;
canvas.height = 900;

const G = 1;
const M = 10000;
const bodies = [
  {x: 600, y: 450, vx: 0, vy: 0, r: 8, col: '#ffcc00', m: M, trail: []},
  {x: 800, y: 450, vx: 0, vy: -9, r: 4, col: '#4488ff', m: 1, trail: []},
  {x: 950, y: 450, vx: 0, vy: -6, r: 3, col: '#44ff88', m: 1, trail: []},
  {x: 1100, y: 450, vx: 0, vy: -4.5, r: 2, col: '#ff8844', m: 1, trail: []},
  {x: 700, y: 450, vx: 0, vy: -12, r: 3, col: '#ff00ff', m: 1, trail: []}
];

function update() {
  bodies.forEach((b, i) => {
    if (i === 0) return;
    let ax = 0, ay = 0;
    const dx = bodies[0].x - b.x;
    const dy = bodies[0].y - b.y;
    const r2 = dx*dx + dy*dy;
    const r = Math.sqrt(r2);
    const f = G * M / r2;
    ax = f * dx / r;
    ay = f * dy / r;
    b.vx += ax * 0.01;
    b.vy += ay * 0.01;
    b.x += b.vx;
    b.y += b.vy;
    b.trail.push({x: b.x, y: b.y});
    if (b.trail.length > 300) b.trail.shift();
  });
}

function draw() {
  ctx.fillStyle = '#000';
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  
  bodies.forEach(b => {
    ctx.strokeStyle = b.col;
    ctx.globalAlpha = 0.15;
    ctx.lineWidth = 1;
    ctx.beginPath();
    b.trail.forEach((p, i) => {
      if (i === 0) ctx.moveTo(p.x, p.y);
      else ctx.lineTo(p.x, p.y);
    });
    ctx.stroke();
    ctx.globalAlpha = 1;
    
    ctx.fillStyle = b.col;
    ctx.beginPath();
    ctx.arc(b.x, b.y, b.r, 0, Math.PI * 2);
    ctx.fill();
  });
}

function loop() {
  update();
  draw();
  requestAnimationFrame(loop);
}

loop();
</script>
</body>
</html>
Claude SonnetOK★ 8.5/10
Show code
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Orbital Mechanics</title>
<style>body{margin:0;background:#000;overflow:hidden}canvas{display:block}</style></head>
<body><canvas id="c"></canvas>
<script>
const cvs=document.getElementById('c'),ctx=cvs.getContext('2d');
function resize(){cvs.width=innerWidth;cvs.height=innerHeight}
resize();addEventListener('resize',resize);
const G=800000,M=1;
function cx(){return cvs.width/2}
function cy(){return cvs.height/2}
function circular(r,dir=1){
  const v=Math.sqrt(G*M/r);
  return {x:cx()+r,y:cy(),vx:0,vy:dir*v,color:'#fff',trail:[]};
}
let bodies=[
  Object.assign(circular(90),{color:'#88ccff'}),
  Object.assign(circular(150),{color:'#ffcc66'}),
  Object.assign(circular(220),{color:'#88ff99'}),
];
const comet=(()=>{
  const r=320,vcirc=Math.sqrt(G*M/r);
  return {x:cx()+r,y:cy(),vx:0,vy:vcirc*0.45,color:'#ff6688',trail:[]};
})();
bodies.push(comet);
function frame(){
  ctx.fillStyle='rgba(0,0,0,0.15)';
  ctx.fillRect(0,0,cvs.width,cvs.height);
  const steps=6,dt=0.004;
  for(let s=0;s<steps;s++){
    bodies.forEach(b=>{
      const dx=cx()-b.x,dy=cy()-b.y;
      const dist=Math.max(Math.hypot(dx,dy),8);
      const a=G*M/(dist*dist);
      b.vx+=a*(dx/dist)*dt;b.vy+=a*(dy/dist)*dt;
      b.x+=b.vx*dt;b.y+=b.vy*dt;
    });
  }
  ctx.beginPath();ctx.arc(cx(),cy(),14,0,7);
  const grad=ctx.createRadialGradient(cx(),cy(),0,cx(),cy(),14);
  grad.addColorStop(0,'#fff8dd');grad.addColorStop(1,'#ffaa00');
  ctx.fillStyle=grad;ctx.fill();
  bodies.forEach(b=>{
    b.trail.push({x:b.x,y:b.y});
    if(b.trail.length>500)b.trail.shift();
    ctx.beginPath();
    b.trail.forEach((p,i)=>{if(i===0)ctx.moveTo(p.x,p.y);else ctx.lineTo(p.x,p.y);});
    ctx.strokeStyle=b.color;ctx.globalAlpha=0.4;ctx.lineWidth=1;ctx.stroke();
    ctx.globalAlpha=1;
    ctx.beginPath();ctx.arc(b.x,b.y,5,0,7);ctx.fillStyle=b.color;ctx.fill();
  });
  requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
</script></body></html>
Claude OpusOK★ 8.5/10
Show code
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Orbital Mechanics</title>
<style>html,body{margin:0;background:#02040a;overflow:hidden}canvas{display:block}</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
const cv=document.getElementById('c'),ctx=cv.getContext('2d');
let W,H,cx,cy;
function resize(){W=cv.width=innerWidth;H=cv.height=innerHeight;cx=W/2;cy=H/2;}
addEventListener('resize',resize);resize();
const G=2000,M=1000;
function body(r,c,ecc){const v=Math.sqrt(G*M/r)*(ecc||1);return{x:r,y:0,vx:0,vy:v,c,trail:[]};}
const bodies=[body(70,'#8ecae6'),body(120,'#90ee90'),body(180,'#ffb703'),body(90,'#ff5a5f',0.55)];
const dt=0.05;
function grav(b){for(let k=0;k<4;k++){const r2=b.x*b.x+b.y*b.y,r=Math.sqrt(r2),a=G*M/r2;b.vx-=a*b.x/r*dt;b.vy-=a*b.y/r*dt;b.x+=b.vx*dt;b.y+=b.vy*dt;}}
function step(){ctx.fillStyle='#02040a';ctx.fillRect(0,0,W,H);
 ctx.fillStyle='#ffd23f';ctx.beginPath();ctx.arc(cx,cy,12,0,7);ctx.fill();
 for(const b of bodies){grav(b);
  b.trail.push([b.x,b.y]);if(b.trail.length>400)b.trail.shift();
  ctx.strokeStyle=b.c;ctx.beginPath();
  for(let i=0;i<b.trail.length;i++){ctx.globalAlpha=i/b.trail.length*0.8;const p=b.trail[i];i?ctx.lineTo(cx+p[0],cy+p[1]):ctx.moveTo(cx+p[0],cy+p[1]);}
  ctx.stroke();ctx.globalAlpha=1;
  ctx.fillStyle=b.c;ctx.beginPath();ctx.arc(cx+b.x,cy+b.y,4,0,7);ctx.fill();
 }
 requestAnimationFrame(step);}
step();
</script>
</body>
</html>
Claude FableOK★ 8.5/10
Claude Fable – rendered output R29
Show code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Orbital Mechanics</title>
<style>html,body{margin:0;height:100%;background:#020308;overflow:hidden}canvas{display:block}</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
const cv=document.getElementById('c'),ctx=cv.getContext('2d');
let W,H,CX,CY,bodies=[];const GM=400000;
function init(){const s=Math.min(W,H)/560;bodies=[];
[[80,'#4fc3f7',4],[130,'#66bb6a',5],[190,'#ffb74d',6]].forEach(a=>{
const R=a[0]*s;bodies.push({x:CX+R,y:CY,vx:0,vy:Math.sqrt(GM/R),c:a[1],r:a[2]});});
const ra=250*s,rp=42*s,sa=(ra+rp)/2,v=Math.sqrt(GM*(2/ra-1/sa));
bodies.push({x:CX-ra,y:CY,vx:0,vy:-v,c:'#e0f7fa',r:3,comet:true});
ctx.fillStyle='#020308';ctx.fillRect(0,0,W,H);}
function resize(){W=cv.width=innerWidth;H=cv.height=innerHeight;CX=W/2;CY=H/2;init();}
resize();addEventListener('resize',resize);
let last=performance.now();
function frame(t){requestAnimationFrame(frame);
const dt=Math.min((t-last)/1000,0.033);last=t;
const steps=80,h=dt*2/steps;
for(const b of bodies)for(let i=0;i<steps;i++){
const dx=CX-b.x,dy=CY-b.y,d2=dx*dx+dy*dy,d=Math.sqrt(d2),a=GM/d2;
b.vx+=a*dx/d*h;b.vy+=a*dy/d*h;b.x+=b.vx*h;b.y+=b.vy*h;}
ctx.fillStyle='rgba(2,3,8,0.035)';ctx.fillRect(0,0,W,H);
const gr=ctx.createRadialGradient(CX,CY,2,CX,CY,26);
gr.addColorStop(0,'#fff8d0');gr.addColorStop(0.4,'#ffd54f');gr.addColorStop(1,'rgba(255,160,0,0)');
ctx.fillStyle=gr;ctx.beginPath();ctx.arc(CX,CY,26,0,7);ctx.fill();
for(const b of bodies){ctx.fillStyle=b.c;ctx.beginPath();ctx.arc(b.x,b.y,b.r,0,7);ctx.fill();
if(b.comet){const dx=b.x-CX,dy=b.y-CY,d=Math.hypot(dx,dy);
ctx.strokeStyle='rgba(224,247,250,0.5)';ctx.lineWidth=1;
ctx.beginPath();ctx.moveTo(b.x,b.y);ctx.lineTo(b.x+dx/d*18,b.y+dy/d*18);ctx.stroke();}}}
requestAnimationFrame(frame);
</script>
</body>
</html>