oneshotlm
Compare all models on this prompt →

Double pendulum · aion-2.0

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.

⚠ no runnable output

This one-shot run produced no runnable artifact.

agent produced no index.html

The transcript below shows what the model did — read it to see why the one shot fell short.

transcript · 2 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
My response will ALWAYS be within the  tag and I will not output any spaces/characters after that tag. The response will be in full HTML format as requested, with no markdown fences.

The user wants a single-page web app in index.html: a chaotic double pendulum simulation on a canvas. I need to implement the correct equations of motion (Lagrangian mechanics for a double pendulum), draw the arms, and a colorful fading trail of the tip. Everything inline - CSS in style, JS in script. No external resources.

Let me plan the implementation:

1. HTML structure: canvas element
2. CSS: style the canvas, body
3. JavaScript:
   - Double pendulum physics using RK4 or Verlet integration with the correct equations of motion
   - The equations of motion for a double pendulum (from Lagrangian):
     Let m1, m2 be masses, l1, l2 lengths, theta1, theta2 angles, g gravity.
     
     The accelerations:
     d2theta1/dt^2 = ( -g*(2*m1+m2)*sin(theta1) - m2*g*sin(theta1-2*theta2) - 2*sin(theta1-theta2)*m2*( (dtheta2)^2*l2 + (dtheta1)^2*l1*cos(theta1-theta2) ) ) / ( l1*(2*m1+m2 - m2*cos(2*theta1-2*theta2)) )
     
     d2theta2/dt^2 = ( 2*sin(theta1-theta2)*( (dtheta1)^2*l1*(m1+m2) + g*(m1+m2)*cos(theta1) + (dtheta2)^2*l2*m2*cos(theta1-theta2) ) ) / ( l2*(2*m1+m2 - m2*cos(2*theta1-2*theta2)) )
   
   Actually, let me use the more standard form:
   
   Let:
   delta = theta2 - theta1
   den = 2*m1 + m2 - m2*cos(2*delta)
   
   theta1_acc = ( -g*(2*m1+m2)*sin(theta1) - m2*g*sin(theta1-2*theta2) - 2*sin(delta)*m2*(theta2_vel^2*l2 + theta1_vel^2*l1*cos(delta)) ) / (l1 * den)
   
   theta2_acc = ( 2*sin(delta)*( theta1_vel^2*l1*(m1+m2) + g*(m1+m2)*cos(theta1) + theta2_vel^2*l2*m2*cos(delta) ) ) / (l2 * den)
   
   Wait, I should double-check. Let me use the formulation from well-known sources.
   
   Actually, the standard equations from the Lagrangian:
   
   d2θ1/dt^2 = [ -g*(2*m1+m2)*sin(θ1) - m2*g*sin(θ1-2*θ2) - 2*sin(θ1-θ2)*m2*(θ2'^2*l2 + θ1'^2*l1*cos(θ1-θ2)) ] / [ l1*(2*m1+m2 - m2*cos(2*θ1-2*θ2)) ]
   
   d2θ2/dt^2 = [ 2*sin(θ1-θ2)*( θ1'^2*l1*(m1+m2) + g*(m1+m2)*cos(θ1) + θ2'^2*l2*m2*cos(θ1-θ2) ) ] / [ l2*(2*m1+m2 - m2*cos(2*θ1-2*θ2)) ]
   
   I'll use RK4 integration for accuracy.

4. Drawing:
   - Draw two arms as lines from pivot to mass1 to mass2
   - Draw circles for masses
   - Trail: store positions of the tip (mass2) and draw a fading colorful trail

5. Colorful fading trail: store an array of {x, y, t} points, draw with varying hue based on position/time, and fade out alpha based on age.

Let me write this all into index.html.

I'll use a reasonable canvas size, say 800x600 or responsive. Let me make it responsive to window size.

Let me write the code now.

Actually, let me think about the trail implementation. I'll store the trail points with their color (hue) and draw them with decreasing opacity. The trail length could be limited to, say, 500 points. Each point gets a hue that cycles based on the angle or time.

For a colorful trail, I can map the hue to the angle of the second pendulum or just use a time-based hue that cycles through colors.

Let me write the complete file now.

I need to be careful with the physics:

```javascript
function derivatives(state) {
    const [theta1, theta2, omega1, omega2] = state;
    const delta = theta2 - theta1;
    const den = 2 * m1 + m2 - m2 * Math.cos(2 * delta);
    
    const theta1_acc = (-g * (2 * m1 + m2) * Math.sin(theta1) - m2 * g * Math.sin(theta1 - 2 * theta2) - 2 * Math.sin(delta) * m2 * (omega2 * omega2 * l2 + omega1 * omega1 * l1 * Math.cos(delta))) / (l1 * den);
    
    const theta2_acc = (2 * Math.sin(delta) * (omega1 * omega1 * l1 * (m1 + m2) + g * (m1 + m2) * Math.cos(theta1) + omega2 * omega2 * l2 * m2 * Math.cos(delta))) / (l2 * den);
    
    return [omega1, omega2, theta1_acc, theta2_acc];
}
```

For RK4:
```javascript
function rk4Step(state, dt) {
    const k1 = derivatives(state);
    const s2 = state.map((s, i) => s + 0.5 * dt * k1[i]);
    const k2 = derivatives(s2);
    const s3 = state.map((s, i) => s + 0.5 * dt * k2[i]);
    const k3 = derivatives(s3);
    const s4 = state.map((s, i) => s + dt * k3[i]);
    const k4 = derivatives(s4);
    return state.map((s, i) => s + (dt / 6) * (k1[i] + 2 * k2[i] + 2 * k3[i] + k4[i]));
}
```

Let me write the full HTML now. I'll make it visually appealing with a dark background, colorful trail, and smooth animation.

For the trail, I'll use HSL colors cycling through hues, and fade the alpha based on how old the point is.

Let me set:
- canvas fills the viewport
- pivot at center, slightly above center
- arms drawn as thick lines with rounded ends
- masses as circles with gradient
- trail with varying hue and fading alpha

Let me write it all out now.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Chaotic Double Pendulum</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { background: #0a0a0f; display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; font-family: system-ui, sans-serif; } canvas { display: block; background: #0a0a0f; cursor: crosshair; } #info { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); color: rgba(255,255,255,0.3); font-size: 13px; letter-spacing: 0.5px; pointer-events: none; user-select: none; text-align: center; } #info span { color: rgba(255,255,255,0.5); } </style> </head> <body> <canvas id="canvas"></canvas> <div id="info">drag to reset · <span>chaotic double pendulum</span></div> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); let W, H, pivotX, pivotY, scale; function resize() { W = canvas.width = window.innerWidth; H = canvas.height = window.innerHeight; pivotX = W / 2; pivotY = H * 0.35; scale = Math.min(W, H) * 0.18; } resize(); window.addEventListener('resize', resize); // Physical parameters const m1 = 2.0, m2 = 1.5; const l1 = 1.0, l2 = 0.9; const g = 9.81; // State: [theta1, theta2, omega1, omega2] let state = [ Math.PI * 0.75 + Math.random() * 0.1, Math.PI * 0.75 + Math.random() * 0.1, 0, 0 ]; // Trail const MAX_TRAIL = 800; let trail = []; function derivatives(s) { const [t1, t2, w1, w2] = s; const delta = t2 - t1; const den = 2 * m1 + m2 - m2 * Math.cos(2 * delta); if (Math.abs(den) < 1e-12) return [w1, w2, 0, 0]; const a1 = ( -g * (2 * m1 + m2) * Math.sin(t1) - m2 * g * Math.sin(t1 - 2 * t2) - 2 * Math.sin(delta) * m2 * (w2 * w2 * l2 + w1 * w1 * l1 * Math.cos(delta)) ) / (l1 * den); const a2 = ( 2 * Math.sin(delta) * ( w1 * w1 * l1 * (m1 + m2) + g * (m1 + m2) * Math.cos(t1) + w2 * w2 * l2 * m2 * Math.cos(delta) ) ) / (l2 * den); return [w1, w2, a1, a2]; } function rk4Step(s, dt) { const k1 = derivatives(s); const s2 = s.map((v, i) => v + 0.5 * dt * k1[i]); const k2 = derivatives(s2); const s3 = s.map((v, i) => v + 0.5 * dt * k2[i]); const k3 = derivatives(s3); const s4 = s.map((v, i) => v + dt * k3[i]); const k4 = derivatives(s4); return s.map((v, i) => v + (dt / 6) * (k1[i] + 2 * k2[i] + 2 * k3[i] + k4[i])); } function getPositions() { const [t1, t2] = state; const x1 = pivotX + l1 * scale * Math.sin(t1); const y1 = pivotY + l1 * scale * Math.cos(t1); const x2 = x1 + l2 * scale * Math.sin(t2); const y2 = y1 + l2 * scale * Math.cos(t2); return { x1, y1, x2, y2 }; } let hueOffset = 0; function draw() { ctx.clearRect(0, 0, W, H); const { x1, y1, x2, y2 } = getPositions(); // Draw trail if (trail.length > 1) { for (let i = 1; i < trail.length; i++) { const p0 = trail[i - 1]; const p1 = trail[i]; const age = (i) / trail.length; const alpha = age * 0.85; const hue = (p1.h + hueOffset) % 360; ctx.beginPath(); ctx.moveTo(p0.x, p0.y); ctx.lineTo(p1.x, p1.y); ctx.strokeStyle = `hsla(${hue}, 100%, 60%, ${alpha})`; ctx.lineWidth = 2.0 + age * 1.5; ctx.lineCap = 'round'; ctx.stroke(); } } // Draw arms with glow ctx.shadowColor = 'rgba(255,200,100,0.15)'; ctx.shadowBlur = 20; // Arm 1 ctx.beginPath(); ctx.moveTo(pivotX, pivotY); ctx.lineTo(x1, y1); ctx.strokeStyle = 'rgba(255, 220, 180, 0.7)'; ctx.lineWidth = 3.5; ctx.lineCap = 'round'; ctx.stroke(); // Arm 2 ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.strokeStyle = 'rgba(255, 200, 150, 0.6)'; ctx.lineWidth = 2.8; ctx.stroke(); ctx.shadowBlur = 0; // Mass 1 const grad1 = ctx.createRadialGradient(x1 - 4, y1 - 4, 2, x1, y1, 10); grad1.addColorStop(0, '#ffddaa'); grad1.addColorStop(0.5, '#e8944a'); grad1.addColorStop(1, '#7a3d1a'); ctx.beginPath(); ctx.arc(x1, y1, 10, 0, Math.PI * 2); ctx.fillStyle = grad1; ctx.fill(); ctx.shadowColor = 'rgba(255,200,100,0.3)'; ctx.shadowBlur = 15; ctx.strokeStyle = 'rgba(255,220,180,0.4)'; ctx.lineWidth = 1.5; ctx.stroke(); // Mass 2 (tip) const grad2 = ctx.createRadialGradient(x2 - 5, y2 - 5, 2, x2, y2, 12); grad2.addColorStop(0, '#ffffcc'); grad2.addColorStop(0.4, '#ffaa44'); grad2.addColorStop(1, '#cc4400'); ctx.beginPath(); ctx.arc(x2, y2, 12, 0, Math.PI * 2); ctx.fillStyle = grad2; ctx.fill(); ctx.shadowColor = 'rgba(255,180,60,0.4)'; ctx.shadowBlur = 25; ctx.strokeStyle = 'rgba(255,240,200,0.5)'; ctx.lineWidth = 1.5; ctx.stroke(); ctx.shadowBlur = 0; // Pivot dot ctx.beginPath(); ctx.arc(pivotX, pivotY, 5, 0, Math.PI * 2); ctx.fillStyle = 'rgba(255,220,180,0.5)'; ctx.fill(); } let lastTime = 0; const DT = 0.005; const SUBSTEPS = 8; function update() { const subDt = DT / SUBSTEPS; for (let i = 0; i < SUBSTEPS; i++) { state = rk4Step(state, subDt); } // Add trail point const { x2, y2 } = getPositions(); const hue = ((state[1] * 180 / Math.PI + state[0] * 90 / Math.PI) * 0.5 + 360) % 360; trail.push({ x: x2, y: y2, h: hue }); if (trail.length > MAX_TRAIL) { trail.splice(0, trail.length - MAX_TRAIL); } hueOffset = (hueOffset + 0.15) % 360; } function loop(time) { update(); draw(); requestAnimationFrame(loop); } // Click / drag to reset let isDragging = false; canvas.addEventListener('mousedown', (e) => { isDragging = true; resetPendulum(e.clientX, e.clientY); }); canvas.addEventListener('mousemove', (e) => { if (isDragging) resetPendulum(e.clientX, e.clientY); }); canvas.addEventListener('mouseup', () => { isDragging = false; }); canvas.addEventListener('mouseleave', () => { isDragging = false; }); // Touch support canvas.addEventListener('touchstart', (e) => { e.preventDefault(); const t = e.touches[0]; resetPendulum(t.clientX, t.clientY); }); function resetPendulum(mx, my) { const dx = mx - pivotX; const dy = my - pivotY; const dist = Math.sqrt(dx * dx + dy * dy); if (dist < 5) return; // Estimate angles from mouse position const angle1 = Math.atan2(dx, dy); // Place second arm roughly in same direction, slightly perturbed const angle2 = angle1 + (Math.random() - 0.5) * 0.3; state = [ angle1 + (Math.random() - 0.5) * 0.05, angle2 + (Math.random() - 0.5) * 0.05, (Math.random() - 0.5) * 0.5, (Math.random() - 0.5) * 0.5 ]; trail = []; } // Initial random state state = [ Math.PI * 0.8 + (Math.random() - 0.5) * 0.2, Math.PI * 0.7 + (Math.random() - 0.5) * 0.2, (Math.random() - 0.5) * 0.3, (Math.random() - 0.5) * 0.3 ]; requestAnimationFrame(loop); </script> </body> </html>

TAKE IT TO CODE

This run produced no artifact — reuse the prompt with a different model or your own pi-agent run.

RUN

modelaion-2.0
vendorAion Labs
harnesspi-agent
generated2026-08-01

METRICS

runtime61.7s
tokens in0
tokens out4.3k
cached1.7k
cost / run$0.0072