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.74T 0.26
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>Ink Spinner</title>
7<style>
8  * { margin: 0; padding: 0; box-sizing: border-box; }
9  body {
10    background: #ebebeb;
11    display: flex;
12    justify-content: center;
13    align-items: flex-start;
14    padding-top: 80px;
15    height: 100vh;
16  }
17  .spinner-container {
18    position: relative;
19    width: 40px;
20    height: 40px;
21  }
22  canvas {
23    position: absolute;
24    top: 0;
25    left: 0;
26  }
27</style>
28</head>
29<body>
30<div class="spinner-container">
31  <canvas id="spinner" width="40" height="40"></canvas>
32</div>
33
34<script>
35const canvas = document.getElementById('spinner');
36const ctx = canvas.getContext('2d');
37const W = canvas.width;
38const H = canvas.height;
39const cx = W / 2;
40const cy = H / 2;
41const R = 14;
42
43let startTime = null;
44const cycleDuration = 1200; // ms per full cycle
45
46function easeInOut(t) {
47  return t < 0.5 ? 2*t*t : -1+(4-2*t)*t;
48}
49
50function drawInkArc(progress) {
51  ctx.clearRect(0, 0, W, H);
52  
53  // progress goes 0 -> 1 over one cycle
54  // The arc sweeps from a wedge to a full circle
55  // Leading angle rotates continuously
56  
57  const rotAngle = progress * Math.PI * 2;
58  
59  // Draw multiple segments with varying opacity to create ink brush effect
60  const segments = 60;
61  const arcLength = Math.PI * 1.7; // ~300 degrees of arc visible
62  
63  for (let i = 0; i < segments; i++) {
64    const t = i / segments;
65    const angle = rotAngle - t * arcLength;
66    const nextAngle = rotAngle - (t + 1/segments) * arcLength;
67    
68    // Opacity: full at leading edge (t=0), fading at tail (t=1)
69    const opacity = Math.pow(1 - t, 0.5);
70    
71    // Line width: thicker at leading edge
72    const lineWidth = 3.5 * (1 - t * 0.6) + 0.5;
73    
74    // Color: dark at leading edge, lighter at tail
75    const darkness = Math.floor(20 + t * 180);
76    
77    ctx.beginPath();
78    ctx.arc(cx, cy, R, angle, nextAngle, true);
79    ctx.strokeStyle = `rgba(${darkness}, ${darkness}, ${darkness}, ${opacity})`;
80    ctx.lineWidth = lineWidth;
81    ctx.lineCap = 'round';
82    ctx.stroke();
83  }
84  
85  // Draw a solid dark blob at the leading edge
86  const leadX = cx + R * Math.cos(rotAngle);
87  const leadY = cy + R * Math.sin(rotAngle);
88  
89  ctx.beginPath();
90  ctx.arc(leadX, leadY, 3, 0, Math.PI * 2);
91  ctx.fillStyle = 'rgba(10, 10, 10, 0.9)';
92  ctx.fill();
93}
94
95function drawInitialWedge(progress) {
96  // progress 0->1: draw expanding wedge
97  ctx.clearRect(0, 0, W, H);
98  
99  const angle = progress * Math.PI * 0.8; // wedge opens up
100  
101  ctx.beginPath();
102  ctx.moveTo(cx, cy);
103  ctx.arc(cx, cy, R * progress * 0.8 + R * 0.2, -Math.PI/2, -Math.PI/2 + angle);
104  ctx.closePath();
105  ctx.fillStyle = '#111';
106  ctx.fill();
107}
108
109function animate(timestamp) {
110  if (!startTime) startTime = timestamp;
111  const elapsed = timestamp - startTime;
112  
113  // Phase 1: 0-400ms - wedge forms and transitions to arc
114  // Phase 2: 400ms+ - continuous spinning arc
115  
116  if (elapsed < 400) {
117    const p = elapsed / 400;
118    drawInitialWedge(p);
119  } else {
120    const cycleElapsed = (elapsed - 400) % cycleDuration;
121    const progress = cycleElapsed / cycleDuration;
122    drawInkArc(progress);
123  }
124  
125  requestAnimationFrame(animate);
126}
127
128requestAnimationFrame(animate);
129</script>
130</body>
131</html>