Double pendulum · kimi-k2.7-code
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.
transcript · 12 messages
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.
thinking
We need build single-page web app index.html in current directory /workspace. Need simulate chaotic double pendulum on canvas, correct equations motion, draw arms and colorful fading trail of tip. Must be self-contained, no external resources, CSS/JS inline. Let's create an HTML with style and script. Implement double pendulum ODE via RK4, use correct equations of motion. Draw arms from pivot, draw bobs, trail of tip with fading colors. Maybe use HSL based on time/angle. Provide controls: mass, length, gravity, damping maybe, trail toggle, reset. Keep responsive canvas. Use requestAnimationFrame. Need no network. Write index.html. We'll produce robust code. Need ensure equations correct. Standard double pendulum:
For angles theta1, theta2 from vertical downward.
m1, m2, L1, L2, g plus optional damping. Equations:
Denominator d = (m1 + m2)*L1*L2 - m2*L1*L2*cos^2(theta1 - theta2) = L1*L2*(m1 + m2*sin^2(delta)).
Angular accelerations:
theta1_ddot = (-g*(2*m1 + m2)*sin(theta1) - m2*g*sin(theta1 - 2*theta2) - 2*sin(delta)*m2*(omega2^2*L2 + omega1^2*L1*cos(delta))) / (L1*(2*m1 + m2 - m2*cos(2*delta)))
theta2_ddot = (2*sin(delta)*(omega1^2*L1*(m1+m2) + g*(m1+m2)*cos(theta1) + omega2^2*L2*m2*cos(delta))) / (L2*(2*m1 + m2 - m2*cos(2*delta)))
Alternatively derive via Lagrangian. Include optional frictions: subtract damping terms proportional to omega. We can simply include friction coefficient to make trail not infinite but still chaotic. But user wants chaotic, damping can be small. We can add 'damping' slider.
We'll implement RK4 with state vector [t1,t2,w1,w2]. Need ensure delta theta used sin/cos.
Coordinates: x1 = L1 sin t1, y1 = L1 cos t1 (downward positive y). Origin at center. Scale to fit. Use trail array of positions tip, max length, draw with line or fading circles. Colorful fading trail: use gradient/line with computed HSL per segment then alpha fade at ends. Perhaps draw trail as connected line segments with strokeStyle hsla(hue, 100%, 50%, alpha). Hue changes over time/position for colorful effect. Use composite operation? Trail slight fade each frame via drawRect with low opacity? But explicit fading trail may change shape. Better use an array storing points with age and remove when age>max. Draw each segment color by age/t position. For fading alpha = 1 - age/maxAge. Colorful = hue = (point index * 2 + time*50) % 360.
Also need clear background each frame (not blank), maybe dark background.
Arms drawn as lines, bobs as circles with gradient.
Controls UI overlay with sliders and buttons. Let user drag to adjust initial angle maybe? Not necessary but nice. Use pointer events to push/kick? Could add click sets small perturbation. Maybe simple: click/drag on canvas nudges second pendulum. But focus on simulation.
Need current date maybe not relevant.
We'll write file to /workspace/index.html. Use write tool. Then verify by reading top/bottom? We'll just provide final. Maybe test open? No, but we can inspect with read after write.
Let's think about exact implementation details, performance.
HTML structure:
<!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>
body { margin:0; background:#05070a; color:#e0e6ed; font-family: system-ui, sans-serif; overflow:hidden; }
canvas { display:block; }
#ui { position:absolute; top:12px; left:12px; background:rgba(0,0,0,0.6); padding:14px; border-radius:12px; ...
.row { display:flex; align-items:center; justify-content:space-between; gap:10px; margin:8px 0; }
label { font-size:13px; }
input[type=range] { width:150px; }
button { ... }
.value { width:45px; text-align:right; font-variant-numeric:tabular-nums; }
</style>
</head>
<body>
<canvas id="c"></canvas>
<div id="ui">...
Sliders: m1,m2,L1,L2,g,damping,time scale,trail length. Buttons: Reset, Randomize, Pause.
</div>
<script>...</script>
</body>
</html>
Canvas sizing: resize to window; scale factor based on min dimension and total length. Use ctx.save/scale to physical coordinates maybe. Simpler: compute scale = min(w,h)/(2*(L1+L2+0.2)), origin center. Draw using canvas world coords. We store L1,L2 in meters-ish.
Equations with damping: Add -c1*omega1 etc to angular acceleration. Derivation for damping not exact but okay. Also maybe add very small force to test chaos.
Use standard formula. For RK4 derivative function f(state) returns [w1,w2,a1,a2].
Compute delta = t1 - t2, sinDelta = sin(delta), cosDelta = cos(delta).
den1 = L1*(2*m1 + m2 - m2*cos(2*delta)); Actually formula denominator uses cos(2*delta). Let's implement:
num1 = -g*(2*m1+m2)*sin(t1) - m2*g*sin(t1-2*t2) - 2*sinDelta*m2*(w2*w2*L2 + w1*w1*L1*cosDelta);
a1 = num1/den1;
num2 = 2*sinDelta*(w1*w1*L1*(m1+m2) + g*(m1+m2)*cos(t1) + w2*w2*L2*m2*cosDelta);
den2 = L2*(2*m1 + m2 - m2*cos(2*delta));
a2 = num2/den2;
If damping:
a1 -= c1*w1; a2 -= c2*w2; with c = damping maybe. c typically per-unit. Good.
But exact formula assumes downward angles. We'll use that. Initial angles random around downward. Use t1=Math.PI*0.75 etc.
Trail: store tip x3,y3 each frame. Limit = trailLength * 60 maybe (frames). If timeScale accelerate, store every frame compensated. Use dt fixed e.g. 0.01666 / substeps. Use substeps=10. Use timeScale factor with actual dt. State integration: each frame integrate with dt=1/60 * timeScale / subSteps, do substeps.
Draw trail: iterate trail from newest to oldest, calculate alpha based on index; maybe set lineCap round. Alternatively draw with quadratic to smooth? Use line segments. We can draw path per segment with continuous hsl.
Colorful: hue = (i * 2 + performance.now()*0.05) % 360. L=55%. Alpha = (i / len)^2? Fading toward tail. Want old transparent. Use alpha = (1 - age)^1.5 maybe.
Tip glow: draw circle with radial gradient.
Arms with gradients.
Potential issue if user sets L large, scale auto.
Interactivity: mouse drag on canvas: when pointer down/move, compute closest bob? Keep simple: dragging near tip applies force by changing second pendulum velocity or adding angular velocity. Could implement push: on pointer move while down, calculate force vector on tip; adjust omega2 by projection. But not required. We can add click to perturb: set w2 += random*0.5. Also mouse down sets w2 plus noise.
Provide reset to random initial conditions.
Need to ensure no external resources.
Let's write code carefully. Use const/let. Avoid frameworks.
Potential ODE explosions due to high dt/timeScale. Keep substeps. Maybe adapt dt by scale.
Use window.devicePixelRatio for crisp canvas: set canvas.width=w*dpr, height=h*dpr, style width=w px, ctx.scale(dpr,dpr). But world scale computed on CSS pixels. Use ctx.scale(dpr,dpr) only once in resize, then all drawing in CSS pixels. Actually if set canvas dim dpr, then ctx.setTransform(dpr,0,0,dpr,0,0) to draw in CSS pixels. Then our origin and scale are CSS pixels. Good.
Implementation details for controls: for each slider, on input update variable and span. Use object params with getters? Simpler: parseFloat on input each use.
State variables: t1,t2,w1,w2. Use let.
Reset function: set initial random/standard. Update displayed values not needed.
Pause: boolean paused; if paused, still draw but not integrate? Maybe skip integration and continue draw trail? We'll still draw arms at current state. When paused, trail remains.
If params changed mid-sim, fine. But if L changes trace positions may be inconsistent; fine.
Trail length slider changes maxTrail. If reduced, splice.
Randomize: random masses/lengths/gravity? Maybe only random initial angles? Sliders already. Button 'Randomize' randomizes angles. Reset to nice defaults.
The user didn't request controls; but helpful. Keep compact overlay.
We'll write index.html. Check the use of sliders and ensure labels.
Let's produce final with write tool.
/workspace/index.html (14430 bytes)Successfully wrote 14430 bytes to /workspace/index.html
thinking
Need verify file exists and check for syntax issues. Let's read maybe use bash node parse? Or use browser test? We can use node to parse script via new Function? Let's run quick validation and maybe ls.
{"command":"ls -l /workspace/index.html && python3 -c \"import html.parser; html.parser.HTMLParser().feed(open('/workspace/index.html').read{"command":"node --check <(sed -n '/<script>/,/<\\/script>/p' /workspace/index.html | sed 's/<script>//' | sed 's/<\\/script>//')"}-rw-r--r-- 1 node node 14430 Jul 8 00:46 /workspace/index.html /bin/bash: line 1: python3: command not found Command exited with code 127
node:fs:441 return binding.readFileUtf8(path, stringToFlags(options.flag)); ^ Error: ENOENT: no such file or directory, open '/proc/18/fd/pipe:[148009]' at Object.readFileSync (node:fs:441:20) at node:internal/main/check_syntax:36:21 { errno: -2, code: 'ENOENT', syscall: 'open', path: '/proc/18/fd/pipe:[148009]' } Node.js v24.18.0 Command exited with code 1
thinking
Python not available; node --check cannot read pipe? Let's extract script to temp file and run node --check.
{"command":"grep -n '<script>' /workspace/index.html"}{"command":"grep -n '</script>' /workspace/index.html"}139:<script>
472:</script>
thinking
Use sed extract lines 140-471 to temp file and node --check.
{"command":"sed -n '140,471p' /workspace/index.html > /tmp/dp.js && node --check /tmp/dp.js"}(no output)
thinking
JS syntax OK. We can also validate HTML manually. Good. Potential concern: initial angles are measured from downward vertical. In reset I used t1=0.75PI, t2=0.5PI. That is left side maybe. Fine. Energy readout coordinate pe reference arbitrary height; okay. Potential issue: pointer drag impulse: uses dx from previous frame which can accumulate; fine. Potential issue: trail has age 0 new, oldest age 1, alpha = 1 - age^2. Good. Now ensure no external resources. All inline. We should response concisely explain what file created. mention equations and features.
Created **/workspace/index.html** — a self-contained, offline double-pendulum simulation. What it does: - Solves the correct double-pendulum equations of motion with **RK4 integration**. - Measures angles from the downward vertical using the standard closed-form angular-acceleration formulas. - Draws both pivot arms with gradient bobs. - Leaves a **colorful, fading trail** at the second tip, colored by HSL and fading with age. - Adds a small UI overlay for live tuning: - masses, lengths, gravity - damping - time scale - trail length - reset / randomize / pause - Lets you drag/nudge the canvas to perturb the system. No CDNs or external files are used — everything is inline.
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
EVALUATION
Chaotic double pendulum with colorful fading trails animates continuously and reacts to drag/click nudges as expected.
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.