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

model output

Claude Sonnet 4.6

Motion Table - Orbit

A 0.89T 0.32
compare with ground truth →
1<!DOCTYPE html>
2<html lang="en">
3<head>
4<meta charset="UTF-8">
5<meta name="viewport" content="width=device-width, initial-scale=1.0">
6<title>Target Animation</title>
7<style>
8  * { margin: 0; padding: 0; box-sizing: border-box; }
9  
10  body {
11    background-color: #555252;
12    display: flex;
13    justify-content: center;
14    align-items: center;
15    width: 100vw;
16    height: 100vh;
17    overflow: hidden;
18  }
19
20  .scene {
21    position: relative;
22    width: 200px;
23    height: 200px;
24  }
25
26  canvas {
27    position: absolute;
28    top: 50%;
29    left: 50%;
30    transform: translate(-50%, -50%);
31  }
32</style>
33</head>
34<body>
35<canvas id="c" width="300" height="300"></canvas>
36
37<script>
38const canvas = document.getElementById('c');
39const ctx = canvas.getContext('2d');
40const W = canvas.width;
41const H = canvas.height;
42const cx = W / 2;
43const cy = H / 2;
44
45// Orbit dots - 3 dots orbiting at different speeds/phases
46// From frames: dots orbit around center on a circle of radius ~50px
47// There appear to be 3 dots orbiting, with occasional "ghost" trail effect
48
49const DOT_RADIUS = 6;
50const ORBIT_R1 = 50; // outer orbit
51const ORBIT_R2 = 28; // inner orbit (for second set)
52
53// Crosshair/target rings
54function drawTarget() {
55  ctx.save();
56  
57  // Outer circle (large)
58  ctx.beginPath();
59  ctx.arc(cx, cy, 55, 0, Math.PI * 2);
60  ctx.strokeStyle = 'rgba(220, 220, 220, 0.6)';
61  ctx.lineWidth = 1;
62  ctx.stroke();
63  
64  // Middle circle
65  ctx.beginPath();
66  ctx.arc(cx, cy, 30, 0, Math.PI * 2);
67  ctx.strokeStyle = 'rgba(220, 220, 220, 0.7)';
68  ctx.lineWidth = 1;
69  ctx.stroke();
70  
71  // Inner circle
72  ctx.beginPath();
73  ctx.arc(cx, cy, 15, 0, Math.PI * 2);
74  ctx.strokeStyle = 'rgba(220, 220, 220, 0.8)';
75  ctx.lineWidth = 1;
76  ctx.stroke();
77  
78  // Tiny center circle
79  ctx.beginPath();
80  ctx.arc(cx, cy, 4, 0, Math.PI * 2);
81  ctx.strokeStyle = 'rgba(220, 220, 220, 0.9)';
82  ctx.lineWidth = 1;
83  ctx.stroke();
84  
85  // Center dot
86  ctx.beginPath();
87  ctx.arc(cx, cy, 2, 0, Math.PI * 2);
88  ctx.fillStyle = 'rgba(220, 220, 220, 0.9)';
89  ctx.fill();
90  
91  // Dashed crosshair lines
92  ctx.setLineDash([3, 3]);
93  ctx.strokeStyle = 'rgba(220, 220, 220, 0.6)';
94  ctx.lineWidth = 1;
95  
96  // Horizontal line
97  ctx.beginPath();
98  ctx.moveTo(cx - 70, cy);
99  ctx.lineTo(cx + 70, cy);
100  ctx.stroke();
101  
102  // Vertical line
103  ctx.beginPath();
104  ctx.moveTo(cx, cy - 70);
105  ctx.lineTo(cx, cy + 70);
106  ctx.stroke();
107  
108  ctx.setLineDash([]);
109  ctx.restore();
110}
111
112// Dots configuration
113// 3 dots orbiting, one on outer ring, two on inner-ish
114// From frames analysis: dots rotate clockwise
115// Frame 1: left, right, bottom positions (3 dots + 1 = 4 dots visible)
116// Actually 4 dots: top, bottom, left, right at start, then rotating
117
118// Let's do: 3 dots on outer orbit rotating, 1 dot on inner orbit
119// Frame analysis shows 3-4 red dots orbiting
120
121const dots = [
122  { angle: Math.PI,       speed: 0.8,  r: 50, color: '#b84040' },  // left
123  { angle: 0,             speed: 0.8,  r: 50, color: '#b84040' },  // right  
124  { angle: Math.PI/2,     speed: 0.8,  r: 50, color: '#b84040' },  // bottom
125  { angle: -Math.PI/2,    speed: 0.8,  r: 50, color: '#b84040' },  // top - sometimes hidden
126];
127
128// Trail history for ghost effect
129const trailHistory = dots.map(() => []);
130const MAX_TRAIL = 8;
131
132let lastTime = null;
133let totalTime = 0;
134
135// Ghost circles that appear periodically
136let ghostCircles = [];
137
138function spawnGhosts(dot) {
139  // spawn a fading circle at dot position
140  ghostCircles.push({
141    x: dot.x,
142    y: dot.y,
143    r: 0,
144    maxR: 30,
145    alpha: 0.4,
146    life: 0,
147    maxLife: 0.8
148  });
149}
150
151let ghostTimer = 0;
152
153function animate(timestamp) {
154  if (!lastTime) lastTime = timestamp;
155  const dt = Math.min((timestamp - lastTime) / 1000, 0.05);
156  lastTime = timestamp;
157  totalTime += dt;
158  ghostTimer += dt;
159
160  ctx.clearRect(0, 0, W, H);
161
162  // Update dots
163  dots.forEach((dot, i) => {
164    dot.angle += dot.speed * dt;
165    dot.x = cx + Math.cos(dot.angle) * dot.r;
166    dot.y = cy + Math.sin(dot.angle) * dot.r;
167    
168    // Store trail
169    trailHistory[i].push({ x: dot.x, y: dot.y, alpha: 0.3 });
170    if (trailHistory[i].length > MAX_TRAIL) {
171      trailHistory[i].shift();
172    }
173  });
174
175  // Spawn ghost circles occasionally
176  if (ghostTimer > 1.5) {
177    ghostTimer = 0;
178    dots.forEach(dot => {
179      ghostCircles.push({
180        x: dot.x,
181        y: dot.y,
182        r: 5,
183        maxR: 35,
184        alpha: 0.35,
185        life: 0,
186        maxLife: 1.0,
187        color: dot.color
188      });
189    });
190  }
191
192  // Update and draw ghost circles
193  ghostCircles = ghostCircles.filter(g => g.life < g.maxLife);
194  ghostCircles.forEach(g => {
195    g.life += dt;
196    const progress = g.life / g.maxLife;
197    const currentR = g.r + (g.maxR - g.r) * progress;
198    const currentAlpha = g.alpha * (1 - progress);
199    
200    ctx.beginPath();
201    ctx.arc(g.x, g.y, currentR, 0, Math.PI * 2);
202    ctx.strokeStyle = `rgba(180, 180, 180, ${currentAlpha})`;
203    ctx.lineWidth = 1;
204    ctx.stroke();
205    
206    // Also fill with color
207    ctx.beginPath();
208    ctx.arc(g.x, g.y, currentR * 0.7, 0, Math.PI * 2);
209    ctx.fillStyle = `rgba(80, 120, 140, ${currentAlpha * 0.5})`;
210    ctx.fill();
211  });
212
213  // Draw target
214  drawTarget();
215
216  // Draw dot trails
217  dots.forEach((dot, i) => {
218    trailHistory[i].forEach((pos, j) => {
219      const alpha = (j / trailHistory[i].length) * 0.15;
220      ctx.beginPath();
221      ctx.arc(pos.x, pos.y, DOT_RADIUS * 0.7, 0, Math.PI * 2);
222      ctx.fillStyle = `rgba(184, 64, 64, ${alpha})`;
223      ctx.fill();
224    });
225  });
226
227  // Draw dots
228  // Only show 3 dots (hide the 4th one - top dot fades in/out)
229  dots.forEach((dot, i) => {
230    // 4th dot (top) is sometimes not visible - make it always visible for simplicity
231    // but from frames it looks like 3-4 dots
232    ctx.beginPath();
233    ctx.arc(dot.x, dot.y, DOT_RADIUS, 0, Math.PI * 2);
234    ctx.fillStyle = dot.color;
235    ctx.fill();
236  });
237
238  requestAnimationFrame(animate);
239}
240
241requestAnimationFrame(animate);
242</script>
243</body>
244</html>