oneshotlm
Compare all models on this prompt →

Double pendulum · ring-2.6-1t

Simulate a chaotic double pendulum on a canvas using the correct equations of motion, drawing the arms and a colorful fading trail of the tip.

⛨ sandboxed Open in new tab ↗
transcript · 6 messages
user

Simulate a chaotic double pendulum on a canvas using the correct equations of motion, drawing the arms and a colorful fading trail of the tip.

assistant
thinking
The user wants a single-page web app that simulates a chaotic double pendulum with correct equations of motion, drawing the arms and a colorful fading trail of the tip. I need to create an index.html file with all CSS and JS inline, no external resources.Let me think about the physics:

A double pendulum consists of two pendulums attached end to end. The equations of motion are derived from Lagrangian mechanics.

State variables: θ1, θ2 (angles), ω1, ω2 (angular velocities)

The equations of motion for a double pendulum:

Let:
- m1, m2 = masses
- L1, L2 = rod lengths
- g = gravity
- θ1, θ2 = angles from vertical
- ω1 = dθ1/dt, ω2 = dθ2/dt

The angular accelerations are:

α1 = d²θ1/dt²
α2 = d²θ2/dt²

The standard equations:

α1 = (-g(2m1+m2)sin(θ1) - m2*g*sin(θ1-2θ2) - 2*sin(θ1-θ2)*m2*(ω2²*L2 + ω1²*L1*cos(θ1-θ2))) / (L1*(2m1+m2-m2*cos(2θ1-2θ2)))

α2 = (2*sin(θ1-θ2)*(ω1²*L1*(m1+m2) + g*(m1+m2)*cos(θ1) + ω2²*L2*m2*cos(θ1-θ2))) / (L2*(2m1+m2-m2*cos(2θ1-2θ2)))

I'll use RK4 integration for numerical stability.

For the trail, I'll store past positions and draw them with decreasing opacity and changing hue.

Let me write this all up in a single HTML file.

I'll create a self-contained double pendulum simulation with correct Lagrangian equations of motion, RK4 integration, and a colorful fading trail.

write {"content":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, ini
toolResult

Validation failed for tool "write": - path: must have required properties path Received arguments: { "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Chaotic Double Pendulum</title>\n<style>\n*{margin:0;padding:0;box-sizing:border-box}\nbody{background:#000;overflow:hidden;display:flex;justify-content:center;align-items:center;height:100vh}\ncanvas{display:block;cursor:pointer}\n.info{position:absolute;top:12px;left:12px;color:rgba(255,255,255,0.5);font:13px/1.5 monospace;pointer-events:none;user-select:none}\n.info span{color:#aaa}\n</style>\n</head>\n<body>\n<div class=\"info\">\n <span>Double Pendulum</span> — chaotic motion simulation<br>\n Lagrangian mechanics · RK4 integration · fading trail<br>\n Click to reset with new initial conditions\n</div>\n<canvas id=\"c\"></canvas>\n<script>\n// --- Canvas setup ---\nconst canvas = document.getElementById('c');\nconst ctx = canvas.getContext('2d');\nfunction resize() {\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n}\nresize();\nwindow.addEventListener('resize', resize);\n\n// --- Physics constants ---\nconst G = 9.81; // gravitational acceleration\nconst M1 = 1.0; // mass 1\nconst M2 = 1.0; // mass 2\nconst L1 = 1.0; // length 1 (metres, scaled on screen)\nconst L2 = 1.0; // length 2\nconst DT = 0.01; // base time step\nconst STEPS_PER_FRAME = 8;\nconst TRAIL_MAX = 600; // trail length\nconst DAMPING = 0.9999; // very slight damping for visual settling\n\n// --- State: [theta1, omega1, theta2, omega2] ---\nlet state = [];\nlet trail = []; // array of {x, y, hue}\nlet time = 0;\n\n// Pivot position (center-bottom area of canvas)\nfunction pivot() {\n return { x: canvas.width / 2, y: canvas.height * 0.35 };\n}\n\n// Random initial condition (small perturbation from rest)\nfunction randomInit() {\n const p = pivot();\n const scale = Math.min(p.x, p.y);\n return [\n Math.PI * (0.5 + (Math.random()-0.5)*0.8), // theta1: near upright\n 0, // omega1\n Math.PI * (0.5 + (Math.random()-0.5)*0.8), // theta2\n 0 // omega2\n ];\n}\n\nfunction init() {\n state = randomInit();\n trail = [];\n time = 0;\n}\n\n// --- Equations of motion (Lagrangian derivation) ---\n// Returns [dtheta1, domega1, dtheta2, domega2]\nfunction derivatives(s) {\n const [t1, w1, t2, w2] = s;\n const dt = t1 - t2;\n const st = Math.sin(dt);\n const ct = Math.cos(dt);\n const s1 = Math.sin(t1);\n const s2 = Math.sin(t2);\n\n const den = 2*M1 + M2 - M2*Math.cos(2*dt); // common denominator\n\n const a1 = (\n -G*(2*M1 + M2)*s1\n - M2*G*Math.sin(t1 - 2*t2)\n - 2*st*M2*(w2*w2*L2 + w1*w1*L1*ct)\n ) / (L1 * den);\n\n const a2 = (\n 2*st*(w1*w1*L1*(M1+M2)\n + G*(M1+M2)*Math.cos(t1)\n + w2*w2*L2*M2*ct)\n ) / (L2 * den);\n\n return [w1, a1, w2, a2];\n}\n\n// --- RK4 integrator ---\nfunction rk4Step(s, h) {\n const k1 = derivatives(s);\n\n const s2 = s.map((v,i) => v + 0.5*h*k1[i]);\n const k2 = derivatives(s2);\n\n const s3 = s.map((v,i) => v + 0.5*h*k2[i]);\n const k3 = derivatives(s3);\n\n const s4 = s.map((v,i) => v + h*k3[i]);\n const k4 = derivatives(s4);\n\n return s.map((v,i) =>\n v + (h/6)*(k1[i] + 2*k2[i] + 2*k3[i] + k4[i])\n );\n}\n\n// --- Compute tip position from angles ---\nfunction tipPos(s) {\n const [t1, , t2] = s;\n const p = pivot();\n const scale = Math.min(p.y * 0.45, p.x * 0.35);\n const x1 = p.x + scale * L1 * Math.sin(t1);\n const y1 = p.y + scale * L1 * Math.cos(t1);\n const x2 = x1 + scale * L2 * Math.sin(t2);\n const y2 = y1 + scale * L2 * Math.cos(t2);\n return { x1, y1, x2, y2 };\n}\n\n// --- Drawing ---\nfunction draw() {\n ctx.fillStyle = 'rgba(0,0,0,0.06)'; // fade factor for trail\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n const pos = tipPos(state);\n\n // --- Draw trail ---\n if (trail.length > 1) {\n for (let i = 1; i < trail.length; i++) {\n const prev = trail[i-1];\n const cur = trail[i];\n const t = i / trail.length; // 0 … 1\n const alpha = t * 0.9; // fade out\n\n ctx.beginPath();\n ctx.moveTo(prev.x, prev.y);\n ctx.lineTo(cur.x, cur.y);\n ctx.strokeStyle = `hsla(${cur.hue},100%,60%,${alpha})`;\n ctx.lineWidth = Math.max(1, t * 3);\n ctx.lineCap = 'round';\n ctx.stroke();\n }\n }\n\n // --- Draw arms ---\n const p = pivot();\n const armW = 3;\n\n // Arm 1\n ctx.beginPath();\n ctx.moveTo(p.x, p.y);\n ctx.lineTo(pos.x1, pos.y1);\n ctx.strokeStyle = 'rgba(220,220,220,0.85)';\n ctx.lineWidth = armW;\n ctx.lineCap = 'round';\n ctx.stroke();\n\n // Arm 2\n ctx.beginPath();\n ctx.moveTo(pos.x1, pos.y1);\n ctx.lineTo(pos.x2, pos.y2);\n ctx.strokeStyle = 'rgba(180,180,180,0.85)';\n ctx.stroke();\n\n // --- Draw masses ---\n const r1 = 10, r2 = 8;\n\n ctx.beginPath();\n ctx.arc(p.x, p.y, 4, 0, Math.PI*2);\n ctx.fillStyle = '#fff';\n ctx.fill();\n\n ctx.beginPath();\n ctx.arc(pos.x1, pos.y1, r1, 0, Math.PI*2);\n ctx.fillStyle = 'rgba(255,255,255,0.15)';\n ctx.fill();\n ctx.strokeStyle = 'rgba(255,255,255,0.5)';\n ctx.lineWidth = 1.5;\n ctx.stroke();\n\n ctx.beginPath();\n ctx.arc(pos.x2, pos.y2, r2, 0, Math.PI*2);\n ctx.fillStyle = 'rgba(255,255,255,0.2)';\n ctx.fill();\n ctx.strokeStyle = 'rgba(255,255,255,0.6)';\n ctx.lineWidth = 1.5;\n ctx.stroke();\n}\n\n// --- Main loop ---\nfunction step() {\n // Sub-step integration\n for (let i = 0; i < STEPS_PER_FRAME; i++) {\n state = rk4Step(state, DT);\n // apply light damping to angular velocities\n state[1] *= DAMPING;\n state[3] *= DAMPING;\n time += DT;\n }\n\n // Record trail point\n const pos = tipPos(state);\n const hue = (time * 40) % 360; // slowly shifting colour\n trail.push({ x: pos.x2, y: pos.y2, hue });\n\n // Keep trail bounded\n if (trail.length > TRAIL_MAX) {\n trail.shift();\n }\n\n draw();\n requestAnimationFrame(step);\n}\n\n// --- Start ---\ninit();\nstep();\n\n// Click to restart with new initial conditions\ncanvas.addEventListener('click', () => {\n // Fade trail quickly\n trail = [];\n state = randomInit();\n});\n</script>\n</body>\n</html>" }

assistant
thinking
The write tool failed because I didn't specify the path parameter. Let me fix that.
write /tmp/ws/index.html (5086 bytes)
toolResult

Successfully wrote 5086 bytes to /tmp/ws/index.html

assistant
thinking
The file has been written successfully. Let me verify it exists and looks correct.

Done. The file `/tmp/ws/index.html` is a fully self-contained double pendulum simulation. Here's what it includes: **Physics:** - Correct Lagrangian-derived equations of motion for a double pendulum - 4th-order Runge-Kutta (RK4) integration for numerical stability - Tiny velocity damping so motion eventually settles **Visuals:** - Black canvas with semi-transparent overlay each frame to create a **colorful fading trail** of the tip - Trail hue shifts over time (HSL color wheel), with opacity and width fading from old to new - Two white pendulum arms drawn as lines, with mass circles at pivot and both bobs - Responsive canvas that fills the viewport **Interaction:** - Click anywhere to reset with new randomized initial conditions, producing a completely different chaotic trajectory

TAKE IT TO CODE

A single self-contained HTML file — copy it and open in any browser, or reuse the prompt with your own pi-agent run.

RUN

modelring-2.6-1t
vendorinclusionai
harnesspi-agent
generated2026-08-01

EVALUATION

4/5 working

Chaotic double pendulum with colorful fading tip trail; click/drag/wheel/keys appear to reset/restart the simulation to a fresh swing.

Vision grade · anthropic/claude-sonnet-5

MEASUREMENTS

Raw readings from the capture, not a verdict — the grade above is the only judgement. Percentages are how much of the screen changed; the measure under-reports sparse motion on a dark background.

idle motion8.5%
on click11.0%
on drag7.1%
on wheel7.7%
on enter + space5.1%
on arrow keys4.4%
on w/a/s/d4.5%
frame spread19.9 / 255
console errors0
js errors none

METRICS

runtime35.7s
tokens in17k
tokens out5.1k
cached13k
cost / run$0.0037