最終更新 1757455898

MisterFixx revised this gist 1757455898. Go to revision

1 file changed, 216 insertions

gpt-oss:120b.md(file created)

@@ -0,0 +1,216 @@
1 + Below is a **single HTML file** that creates a self‑contained triple‑pendulum animation.
2 + The physics are handled with a simple Verlet integrator plus distance‑constraints, which gives a realistic motion that obeys gravity.
3 + Each mass leaves a fading trail, so you can see the path it follows.
4 +
5 + ```html
6 + <!DOCTYPE html>
7 + <html lang="en">
8 + <head>
9 + <meta charset="UTF-8">
10 + <title>Triple Pendulum</title>
11 + <style>
12 + body {margin:0; background:#111; overflow:hidden;}
13 + canvas {display:block;}
14 + </style>
15 + </head>
16 + <body>
17 + <canvas id="c"></canvas>
18 +
19 + <script>
20 + // ------------------------------------------------------------
21 + // 1️⃣ Setup
22 + // ------------------------------------------------------------
23 + const canvas = document.getElementById('c');
24 + const ctx = canvas.getContext('2d');
25 + function resize() {
26 + canvas.width = innerWidth;
27 + canvas.height = innerHeight;
28 + }
29 + window.addEventListener('resize', resize);
30 + resize();
31 +
32 + // ------------------------------------------------------------
33 + // 2️⃣ Pendulum parameters
34 + // ------------------------------------------------------------
35 + const g = 980; // gravity (px/s²) – scaled for screen size
36 + const dt = 0.016; // time step (seconds)
37 + const substeps = 5; // for stability
38 +
39 + // rod lengths (in pixels)
40 + const L1 = 180, L2 = 130, L3 = 100;
41 +
42 + // masses (only needed for visual size)
43 + const R1 = 12, R2 = 10, R3 = 8;
44 +
45 + // pivot point (fixed)
46 + const pivot = {x: canvas.width/2, y: canvas.height/4};
47 +
48 + // -----------------------------------------------------------------
49 + // 3️⃣ Verlet state (position + previous position) for each bob
50 + // -----------------------------------------------------------------
51 + function Vec(x,y){ return {x, y}; }
52 +
53 + let bob = [
54 + { // bob 0 – attached to pivot (doesn't move, but keep for simplicity)
55 + pos: Vec(pivot.x, pivot.y),
56 + prev: Vec(pivot.x, pivot.y)
57 + },
58 + { // bob 1
59 + pos: Vec(pivot.x + L1*Math.sin(Math.PI/2), pivot.y + L1*Math.cos(Math.PI/2)),
60 + prev: Vec(pivot.x + L1*Math.sin(Math.PI/2), pivot.y + L1*Math.cos(Math.PI/2))
61 + },
62 + { // bob 2
63 + pos: Vec(pivot.x + L1*Math.sin(Math.PI/2) + L2*Math.sin(Math.PI/2),
64 + pivot.y + L1*Math.cos(Math.PI/2) + L2*Math.cos(Math.PI/2)),
65 + prev: Vec(pivot.x + L1*Math.sin(Math.PI/2) + L2*Math.sin(Math.PI/2),
66 + pivot.y + L1*Math.cos(Math.PI/2) + L2*Math.cos(Math.PI/2))
67 + },
68 + { // bob 3 – end of the chain
69 + pos: Vec(pivot.x + L1*Math.sin(Math.PI/2) + L2*Math.sin(Math.PI/2) + L3*Math.sin(Math.PI/2),
70 + pivot.y + L1*Math.cos(Math.PI/2) + L2*Math.cos(Math.PI/2) + L3*Math.cos(Math.PI/2)),
71 + prev: Vec(pivot.x + L1*Math.sin(Math.PI/2) + L2*Math.sin(Math.PI/2) + L3*Math.sin(Math.PI/2),
72 + pivot.y + L1*Math.cos(Math.PI/2) + L2*Math.cos(Math.PI/2) + L3*Math.cos(Math.PI/2))
73 + }
74 + ];
75 +
76 + // -----------------------------------------------------------------
77 + // 4️⃣ Trail storage (capped length)
78 + // -----------------------------------------------------------------
79 + const maxTrail = 300; // how many points to keep
80 + let trails = [ [], [], [] ]; // one per moving bob (1,2,3)
81 +
82 + // -----------------------------------------------------------------
83 + // 5️⃣ Physics helpers
84 + // -----------------------------------------------------------------
85 + function verletIntegrate(b, dt) {
86 + const ax = 0, ay = g; // gravity only
87 + const nx = b.pos.x + (b.pos.x - b.prev.x) + ax*dt*dt;
88 + const ny = b.pos.y + (b.pos.y - b.prev.y) + ay*dt*dt;
89 + b.prev.x = b.pos.x;
90 + b.prev.y = b.pos.y;
91 + b.pos.x = nx;
92 + b.pos.y = ny;
93 + }
94 +
95 + // enforce distance constraints (rigid rods)
96 + function satisfyConstraints() {
97 + // we iterate a few times for convergence
98 + for (let i = 0; i < 5; i++) {
99 + // 0 <-> 1 (pivot is fixed, so we only move bob1)
100 + let a = bob[0], b = bob[1];
101 + let dx = b.pos.x - a.pos.x, dy = b.pos.y - a.pos.y;
102 + let d = Math.hypot(dx, dy);
103 + let diff = (d - L1) / d;
104 + b.pos.x -= dx * diff;
105 + b.pos.y -= dy * diff;
106 +
107 + // 1 <-> 2
108 + a = bob[1]; b = bob[2];
109 + dx = b.pos.x - a.pos.x; dy = b.pos.y - a.pos.y;
110 + d = Math.hypot(dx, dy);
111 + diff = (d - L2) / d;
112 + // move both ends equally
113 + a.pos.x += dx * diff * 0.5;
114 + a.pos.y += dy * diff * 0.5;
115 + b.pos.x -= dx * diff * 0.5;
116 + b.pos.y -= dy * diff * 0.5;
117 +
118 + // 2 <-> 3
119 + a = bob[2]; b = bob[3];
120 + dx = b.pos.x - a.pos.x; dy = b.pos.y - a.pos.y;
121 + d = Math.hypot(dx, dy);
122 + diff = (d - L3) / d;
123 + a.pos.x += dx * diff * 0.5;
124 + a.pos.y += dy * diff * 0.5;
125 + b.pos.x -= dx * diff * 0.5;
126 + b.pos.y -= dy * diff * 0.5;
127 + }
128 + }
129 +
130 + // -----------------------------------------------------------------
131 + // 6️⃣ Main loop
132 + // -----------------------------------------------------------------
133 + function step() {
134 + // sub‑step integration for stability
135 + const subDt = dt / substeps;
136 + for (let s = 0; s < substeps; s++) {
137 + // integrate bobs 1‑3 (bob0 is the fixed pivot)
138 + for (let i = 1; i < bob.length; i++) verletIntegrate(bob[i], subDt);
139 + satisfyConstraints();
140 + }
141 +
142 + // store trail points
143 + for (let i = 1; i < bob.length; i++) {
144 + const tr = trails[i-1];
145 + tr.push({x: bob[i].pos.x, y: bob[i].pos.y});
146 + if (tr.length > maxTrail) tr.shift();
147 + }
148 + }
149 +
150 + // -----------------------------------------------------------------
151 + // 7️⃣ Rendering
152 + // -----------------------------------------------------------------
153 + function draw() {
154 + ctx.clearRect(0,0,canvas.width,canvas.height);
155 +
156 + // draw trails (fading)
157 + for (let i = 0; i < trails.length; i++) {
158 + const tr = trails[i];
159 + if (tr.length < 2) continue;
160 + ctx.beginPath();
161 + for (let j = 0; j < tr.length; j++) {
162 + const p = tr[j];
163 + const alpha = j / tr.length; // older points are more transparent
164 + ctx.strokeStyle = `rgba(${255-30*i},${150+30*i},${200},${alpha})`;
165 + if (j===0) ctx.moveTo(p.x,p.y);
166 + else ctx.lineTo(p.x,p.y);
167 + }
168 + ctx.lineWidth = 2;
169 + ctx.stroke();
170 + }
171 +
172 + // draw rods
173 + ctx.strokeStyle = '#fff';
174 + ctx.lineWidth = 2;
175 + ctx.beginPath();
176 + ctx.moveTo(pivot.x, pivot.y);
177 + ctx.lineTo(bob[1].pos.x, bob[1].pos.y);
178 + ctx.lineTo(bob[2].pos.x, bob[2].pos.y);
179 + ctx.lineTo(bob[3].pos.x, bob[3].pos.y);
180 + ctx.stroke();
181 +
182 + // draw bobs
183 + const radii = [0, R1, R2, R3];
184 + const colors = ['#ff6', '#6cf', '#f66'];
185 + for (let i = 1; i < bob.length; i++) {
186 + ctx.beginPath();
187 + ctx.arc(bob[i].pos.x, bob[i].pos.y, radii[i], 0, Math.PI*2);
188 + ctx.fillStyle = colors[i-1];
189 + ctx.fill();
190 + ctx.strokeStyle = '#fff';
191 + ctx.stroke();
192 + }
193 + }
194 +
195 + // -----------------------------------------------------------------
196 + // 8️⃣ Animation loop
197 + // -----------------------------------------------------------------
198 + function animate() {
199 + step();
200 + draw();
201 + requestAnimationFrame(animate);
202 + }
203 + animate();
204 +
205 + </script>
206 + </body>
207 + </html>
208 + ```
209 +
210 + ### How it works
211 + 1. **Verlet integration** – each bob’s new position is computed from its current and previous positions plus gravity.
212 + 2. **Distance constraints** – after integration the three rod lengths (`L1`, `L2`, `L3`) are enforced by repeatedly adjusting the positions, giving a realistic rigid‑rod behavior.
213 + 3. **Trails** – every frame the current positions of the three moving bobs are pushed onto three separate arrays. Old points are discarded after `maxTrail` frames, and the trail is drawn with a fading alpha so the path slowly disappears.
214 + 4. **Rendering** – the canvas is cleared each frame, trails are drawn first (so they appear beneath the pendulum), then the rods and the three bobs are drawn.
215 +
216 + Open the file in any modern browser and you’ll see a continuously moving triple pendulum, each bob leaving a colorful fading trail behind it. No controls or user interaction are required. Enjoy!
Newer Older