animation2code benchmark
For best compatibility, please view this dashboard in a Chrome browser.
← back to Motion Table - Solid Rotation

model output

Claude Sonnet 4.6

Motion Table - Solid Rotation

A 0.45T 0.14
compare with ground truth →
1<!DOCTYPE html>
2<html>
3<head>
4<style>
5  * { margin: 0; padding: 0; box-sizing: border-box; }
6  body { background: #4a4a4a; display: flex; justify-content: center; align-items: center; width: 100vw; height: 100vh; overflow: hidden; }
7  canvas { display: block; }
8</style>
9</head>
10<body>
11<canvas id="c"></canvas>
12<script>
13const canvas = document.getElementById('c');
14const ctx = canvas.getContext('2d');
15canvas.width = 1024;
16canvas.height = 768;
17
18const cx = 512, cy = 384;
19const R = 130;
20
21// Spirograph: epitrochoid/hypotrochoid
22// Looking at the frames: starts as a single circle, then inner circle rolls inside
23// creating a hypotrochoid pattern that cycles through various petal/loop configurations
24
25// The animation shows a spirograph being drawn progressively
26// It looks like a hypotrochoid with slowly changing parameters
27
28let t = 0;
29const totalDuration = 20000; // 20 seconds for full cycle
30let startTime = null;
31
32// Store drawn path points
33let points = [];
34let phase = 0;
35
36// Parameters that slowly change to create the morphing effect
37// Hypotrochoid: x = (R-r)*cos(t) + d*cos((R-r)/r * t)
38//               y = (R-r)*sin(t) - d*sin((R-r)/r * t)
39
40// From the frames, it looks like multiple overlapping ellipses/circles
41// that create spirograph patterns. The ratio changes over time.
42
43const outerR = R;
44
45function draw(timestamp) {
46  if (!startTime) startTime = timestamp;
47  const elapsed = (timestamp - startTime) % totalDuration;
48  const progress = elapsed / totalDuration; // 0 to 1
49
50  ctx.clearRect(0, 0, canvas.width, canvas.height);
51  ctx.fillStyle = '#4a4a4a';
52  ctx.fillRect(0, 0, canvas.width, canvas.height);
53
54  // Draw the spirograph path up to current progress
55  // The pattern: ratio r/R slowly changes from ~1 (circle) through various fractions
56  // creating different petal counts
57
58  ctx.strokeStyle = 'rgba(255,255,255,0.85)';
59  ctx.lineWidth = 1;
60  ctx.lineCap = 'round';
61  ctx.lineJoin = 'round';
62
63  // Draw multiple overlapping hypotrochoids with slightly different phases
64  // to create the "hand-drawn" sketchy look
65
66  const numTrails = 8;
67  
68  for (let trail = 0; trail < numTrails; trail++) {
69    const trailOffset = (trail / numTrails) * 0.15;
70    const trailProgress = Math.max(0, progress - trailOffset * 0.3);
71    
72    if (trailProgress <= 0) continue;
73    
74    const alpha = trail === 0 ? 0.9 : 0.3 - trail * 0.02;
75    ctx.strokeStyle = `rgba(255,255,255,${Math.max(0.05, alpha)})`;
76    
77    drawSpirograph(trailProgress, trail * 0.08);
78  }
79
80  requestAnimationFrame(draw);
81}
82
83function drawSpirograph(progress, phaseOffset) {
84  // The ratio changes over time to create morphing patterns
85  // r/R ratio: starts near 1 (circle), morphs through various values
86  
87  const totalAngle = progress * Math.PI * 20; // total angle swept
88  
89  // Slowly varying inner radius ratio
90  const rRatio = 0.5 + 0.45 * Math.sin(progress * Math.PI * 2 + phaseOffset);
91  const r = outerR * Math.abs(rRatio);
92  const d = outerR * 0.85;
93  
94  const steps = Math.floor(totalAngle / (Math.PI * 2) * 360);
95  if (steps < 2) return;
96  
97  ctx.beginPath();
98  
99  for (let i = 0; i <= steps; i++) {
100    const angle = (i / steps) * totalAngle + phaseOffset;
101    
102    // Hypotrochoid
103    const Rr = outerR - r;
104    const x = cx + Rr * Math.cos(angle) + d * Math.cos((Rr / Math.max(r, 1)) * angle);
105    const y = cy + Rr * Math.sin(angle) - d * Math.sin((Rr / Math.max(r, 1)) * angle);
106    
107    if (i === 0) ctx.moveTo(x, y);
108    else ctx.lineTo(x, y);
109  }
110  
111  ctx.stroke();
112}
113
114// Better approach: draw a spirograph that looks like the frames
115// The frames show: single circle -> overlapping ellipses -> star/petal patterns -> back to circle
116// This is a Lissajous/spirograph with slowly changing frequency ratio
117
118function drawBetter(timestamp) {
119  if (!startTime) startTime = timestamp;
120  const elapsed = (timestamp - startTime) % totalDuration;
121  const progress = elapsed / totalDuration;
122
123  ctx.clearRect(0, 0, canvas.width, canvas.height);
124  ctx.fillStyle = '#4a4a4a';
125  ctx.fillRect(0, 0, canvas.width, canvas.height);
126
127  // Draw multiple slightly offset spirographs for sketchy look
128  const layers = [
129    { alpha: 0.85, offset: 0, rOffset: 0 },
130    { alpha: 0.35, offset: 0.03, rOffset: 2 },
131    { alpha: 0.25, offset: -0.02, rOffset: -1.5 },
132    { alpha: 0.2, offset: 0.05, rOffset: 3 },
133    { alpha: 0.15, offset: -0.04, rOffset: -2.5 },
134  ];
135
136  for (const layer of layers) {
137    ctx.strokeStyle = `rgba(255,255,255,${layer.alpha})`;
138    ctx.lineWidth = 1;
139    ctx.beginPath();
140    
141    const totalAngle = progress * Math.PI * 24;
142    const steps = Math.max(2, Math.floor(totalAngle * 60));
143    
144    // Slowly changing ratio creates the morphing spirograph
145    // ratio oscillates to create different petal counts
146    const baseRatio = 1 - progress * 0.15; // slowly decreasing
147    
148    for (let i = 0; i <= steps; i++) {
149      const t = (i / steps) * totalAngle;
150      
151      // Use a ratio that creates interesting patterns
152      // The ratio between outer and inner determines petal count
153      const ratio = 7/8 + layer.rOffset * 0.005;
154      const r = outerR * ratio;
155      const Rr = outerR - r;
156      const d = outerR * 0.92;
157      
158      const x = cx + Rr * Math.cos(t + layer.offset) + d * Math.cos((Rr/r) * t + layer.offset);
159      const y = cy + Rr * Math.sin(t + layer.offset) - d * Math.sin((Rr/r) * t + layer.offset);
160      
161      if (i === 0) ctx.moveTo(x, y);
162      else ctx.lineTo(x, y);
163    }
164    ctx.stroke();
165  }
166
167  requestAnimationFrame(drawBetter);
168}
169
170requestAnimationFrame(drawBetter);
171</script>
172</body>
173</html>