animation2code benchmark
For best compatibility, please view this dashboard in a Chrome browser.
← back to Wavy Loading Animations

model output

Claude Sonnet 4.6

Wavy Loading Animations

A 0.66T 0.17
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>Loader Animation</title>
7<style>
8  * { margin: 0; padding: 0; box-sizing: border-box; }
9  
10  body {
11    background: #ebebeb;
12    display: flex;
13    justify-content: center;
14    align-items: flex-start;
15    padding-top: 60px;
16    height: 100vh;
17  }
18
19  .loader {
20    position: relative;
21    width: 80px;
22    height: 30px;
23    display: flex;
24    align-items: center;
25    justify-content: center;
26  }
27
28  canvas {
29    display: block;
30  }
31</style>
32</head>
33<body>
34<canvas id="c" width="1024" height="768"></canvas>
35
36<script>
37const canvas = document.getElementById('c');
38const ctx = canvas.getContext('2d');
39
40canvas.style.background = '#ebebeb';
41
42const cx = 512;
43const cy = 75;
44
45let t = 0;
46const CYCLE = 120; // frames per full cycle
47
48function easeInOut(t) {
49  return t < 0.5 ? 2*t*t : -1+(4-2*t)*t;
50}
51
52function drawDashes() {
53  // Horizontal dashes: series of small rectangles
54  ctx.fillStyle = '#888';
55  const dashW = 4;
56  const dashH = 2;
57  const gap = 2;
58  const count = 10;
59  const totalW = count * dashW + (count-1) * gap;
60  const startX = cx - totalW/2;
61  for (let i = 0; i < count; i++) {
62    ctx.fillRect(startX + i*(dashW+gap), cy - dashH/2, dashW, dashH);
63  }
64}
65
66function drawArrow(progress) {
67  // Triangle pointing right with dashes trailing left
68  ctx.fillStyle = '#666';
69  const tipX = cx + 10;
70  const midY = cy;
71  const h = 18;
72  const w = 18;
73  
74  // Triangle
75  ctx.beginPath();
76  ctx.moveTo(tipX, midY);
77  ctx.lineTo(tipX - w, midY - h/2);
78  ctx.lineTo(tipX - w, midY + h/2);
79  ctx.closePath();
80  ctx.fill();
81  
82  // Trailing dashes
83  ctx.fillStyle = '#888';
84  const dashW = 4;
85  const dashH = 2;
86  const gap = 3;
87  const count = 4;
88  for (let i = 0; i < count; i++) {
89    ctx.fillRect(tipX - w - 8 - i*(dashW+gap) - dashW, midY - dashH/2, dashW, dashH);
90  }
91}
92
93function drawBarrel(progress) {
94  // Barrel: vertical stripes forming a barrel/cylinder shape
95  const stripeCount = 9;
96  const maxH = 36;
97  const stripeW = 4;
98  const gap = 1;
99  const totalW = stripeCount * stripeW + (stripeCount-1) * gap;
100  const startX = cx - totalW/2 + 5;
101  
102  for (let i = 0; i < stripeCount; i++) {
103    // Barrel shape: middle stripes taller
104    const mid = (stripeCount-1)/2;
105    const dist = Math.abs(i - mid) / mid;
106    const h = maxH * Math.sqrt(1 - dist*dist * 0.5);
107    
108    // Color: lighter in middle, darker on edges
109    const lightness = Math.floor(160 + 30 * (1 - dist));
110    ctx.fillStyle = `rgb(${lightness},${lightness},${lightness})`;
111    
112    const x = startX + i * (stripeW + gap);
113    ctx.fillRect(x, cy - h/2, stripeW, h);
114  }
115}
116
117function drawExpandedDashes() {
118  // Dashes spread out to left, bars on right
119  ctx.fillStyle = '#888';
120  const dashW = 4;
121  const dashH = 2;
122  const gap = 3;
123  const dashCount = 3;
124  const barCount = 8;
125  const barW = 4;
126  const barGap = 1;
127  
128  // Bars on right side
129  const maxH = 36;
130  const totalBarW = barCount * barW + (barCount-1) * barGap;
131  const barStartX = cx - totalBarW/2 + 15;
132  
133  for (let i = 0; i < barCount; i++) {
134    const mid = (barCount-1)/2;
135    const dist = Math.abs(i - mid) / (mid || 1);
136    const h = maxH * Math.sqrt(Math.max(0, 1 - dist*dist * 0.4));
137    const lightness = Math.floor(155 + 25 * (1 - dist));
138    ctx.fillStyle = `rgb(${lightness},${lightness},${lightness})`;
139    ctx.fillRect(barStartX + i*(barW+barGap), cy - h/2, barW, h);
140  }
141  
142  // Dashes on left
143  ctx.fillStyle = '#888';
144  for (let i = 0; i < dashCount; i++) {
145    ctx.fillRect(barStartX - 10 - i*(dashW+gap) - dashW, cy - dashH/2, dashW, dashH);
146  }
147}
148
149function render() {
150  ctx.clearRect(0, 0, canvas.width, canvas.height);
151  
152  const phase = (t % CYCLE) / CYCLE;
153  
154  // Phase 0.0 - 0.15: dashes
155  // Phase 0.15 - 0.35: transition to arrow
156  // Phase 0.35 - 0.5: arrow
157  // Phase 0.5 - 0.65: transition to barrel  
158  // Phase 0.65 - 0.85: barrel with dashes
159  // Phase 0.85 - 1.0: back to dashes
160  
161  if (phase < 0.15) {
162    drawDashes();
163  } else if (phase < 0.35) {
164    drawArrow((phase - 0.15) / 0.2);
165  } else if (phase < 0.5) {
166    drawArrow(1);
167  } else if (phase < 0.65) {
168    drawBarrel((phase - 0.5) / 0.15);
169  } else if (phase < 0.85) {
170    drawExpandedDashes();
171  } else {
172    drawArrow(1 - (phase - 0.85) / 0.15);
173  }
174  
175  t++;
176  requestAnimationFrame(render);
177}
178
179// Better interpretation: the animation loops through 3 states
180// Let's use a simpler direct approach based on what we see
181
182let startTime = null;
183const PERIOD = 1200; // ms per cycle
184
185function renderTime(ts) {
186  if (!startTime) startTime = ts;
187  const elapsed = (ts - startTime) % PERIOD;
188  const phase = elapsed / PERIOD;
189  
190  ctx.clearRect(0, 0, canvas.width, canvas.height);
191  
192  if (phase < 0.25) {
193    // Dashes
194    drawDashes();
195  } else if (phase < 0.42) {
196    // Arrow
197    drawArrow(1);
198  } else if (phase < 0.58) {
199    // Barrel
200    drawBarrel(1);
201  } else if (phase < 0.75) {
202    // Expanded dashes (bars + dashes)
203    drawExpandedDashes();
204  } else if (phase < 0.88) {
205    // Arrow again
206    drawArrow(1);
207  } else {
208    // Back to barrel
209    drawBarrel(1);
210  }
211  
212  requestAnimationFrame(renderTime);
213}
214
215requestAnimationFrame(renderTime);
216</script>
217</body>
218</html>