animation2code benchmark
For best compatibility, please view this dashboard in a Chrome browser.
← back to Only CSS: Peacock

model output

Claude Sonnet 4.6

Only CSS: Peacock

A 0.48T 0.15
compare with ground truth →
1<!DOCTYPE html>
2<html>
3<head>
4<style>
5* { margin: 0; padding: 0; box-sizing: border-box; }
6body { background: #000; overflow: hidden; width: 100vw; height: 100vh; }
7canvas { 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 = 390;
19const startTime = performance.now();
20const duration = 3000;
21
22function hslToRgb(h, s, l) {
23  h = h % 360; if (h < 0) h += 360;
24  s /= 100; l /= 100;
25  const c = (1 - Math.abs(2*l-1)) * s;
26  const x = c * (1 - Math.abs((h/60)%2 - 1));
27  const m = l - c/2;
28  let r=0,g=0,b=0;
29  if(h<60){r=c;g=x;}else if(h<120){r=x;g=c;}else if(h<180){g=c;b=x;}
30  else if(h<240){g=x;b=c;}else if(h<300){r=x;b=c;}else{r=c;b=x;}
31  return `rgb(${Math.round((r+m)*255)},${Math.round((g+m)*255)},${Math.round((b+m)*255)})`;
32}
33
34function drawBlade(ctx, angle, size, color) {
35  ctx.save();
36  ctx.rotate(angle);
37  ctx.fillStyle = color;
38  ctx.beginPath();
39  // Jagged blade shape
40  const r = size;
41  ctx.moveTo(0, 0);
42  const steps = 12;
43  for (let i = 0; i <= steps; i++) {
44    const a = (i / steps) * Math.PI * 0.7 - Math.PI * 0.1;
45    const jag = (i % 2 === 0) ? r : r * 0.75;
46    ctx.lineTo(Math.cos(a) * jag, Math.sin(a) * jag);
47  }
48  ctx.closePath();
49  ctx.fill();
50  ctx.restore();
51}
52
53function drawFrame(t) {
54  ctx.clearRect(0, 0, canvas.width, canvas.height);
55  ctx.fillStyle = '#000';
56  ctx.fillRect(0, 0, canvas.width, canvas.height);
57
58  const progress = Math.min(t / duration, 1);
59  
60  // Number of trail copies
61  const maxTrail = 60;
62  const trailCount = Math.floor(progress * maxTrail) + 4;
63  
64  // Base rotation speed
65  const totalRotation = progress * Math.PI * 6;
66  
67  // Spiral expansion
68  const maxRadius = 350;
69  
70  for (let i = 0; i < trailCount; i++) {
71    const frac = i / Math.max(trailCount - 1, 1);
72    const age = 1 - frac; // older = smaller frac index
73    
74    // Each copy is offset in rotation and position along spiral
75    const trailFrac = i / maxTrail;
76    const angle = totalRotation - frac * Math.PI * 5;
77    
78    // Spiral position
79    const spiralR = trailFrac * maxRadius * progress;
80    const spiralAngle = -frac * Math.PI * 4 + totalRotation * 0.3;
81    
82    const px = cx + Math.cos(spiralAngle) * spiralR * progress;
83    const py = cy + Math.sin(spiralAngle) * spiralR * progress;
84    
85    // Size: core is bigger, trail gets smaller
86    const size = (1 - frac * 0.6) * (20 + progress * 30);
87    
88    // Color: red(0) -> pink -> magenta -> purple -> blue(240)
89    const hue = frac * 240;
90    const sat = 100;
91    const light = 45 + frac * 10;
92    const color = hslToRgb(hue, sat, light);
93    
94    const alpha = 0.7 + frac * 0.3;
95    
96    ctx.save();
97    ctx.globalAlpha = alpha;
98    ctx.translate(px, py);
99    
100    // Draw 4-blade pinwheel
101    for (let b = 0; b < 4; b++) {
102      drawBlade(ctx, angle + b * Math.PI / 2, size, color);
103    }
104    
105    // Center circle
106    ctx.beginPath();
107    ctx.arc(0, 0, size * 0.18, 0, Math.PI * 2);
108    ctx.fillStyle = '#000';
109    ctx.fill();
110    
111    ctx.restore();
112  }
113}
114
115function animate(now) {
116  const t = now - startTime;
117  drawFrame(t);
118  if (t < duration + 500) {
119    requestAnimationFrame(animate);
120  }
121}
122
123requestAnimationFrame(animate);
124</script>
125</body>
126</html>