animation2code benchmark
For best compatibility, please view this dashboard in a Chrome browser.
← back to Retro Sine Wave 〰

model output

Claude Sonnet 4.6

Retro Sine Wave 〰

A 0.90T 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>Glitch Lines Animation</title>
7<style>
8  * { margin: 0; padding: 0; box-sizing: border-box; }
9  
10  body {
11    width: 100vw;
12    height: 100vh;
13    background: radial-gradient(ellipse at 40% 40%, #2a2640 0%, #1e1b2e 50%, #181525 100%);
14    overflow: hidden;
15    display: flex;
16    align-items: center;
17    justify-content: center;
18  }
19
20  canvas {
21    display: block;
22  }
23</style>
24</head>
25<body>
26<canvas id="c"></canvas>
27<script>
28const canvas = document.getElementById('c');
29const ctx = canvas.getContext('2d');
30
31canvas.width = window.innerWidth;
32canvas.height = window.innerHeight;
33
34const W = canvas.width;
35const H = canvas.height;
36
37// Center of the shape
38const cx = W * 0.44;
39const cy = H * 0.46;
40
41// Shape radius (roughly circular/oval)
42const rx = 110;
43const ry = 130;
44
45const NUM_ROWS = 22;
46const ROW_SPACING = 13;
47
48// Each line has: baseX (left anchor), baseWidth, row index
49// The shape is roughly circular, lines span the circle width at each row
50// There are two "groups" - main body and a secondary offset group (the glitch effect)
51
52function getCircleWidth(row, totalRows) {
53  const t = (row / (totalRows - 1)) * 2 - 1; // -1 to 1
54  const w = Math.sqrt(Math.max(0, 1 - t * t));
55  return w;
56}
57
58// Lines data: each line has a "home" position and animates with offset
59class Line {
60  constructor(row, xOffset, width, opacity, delay, speed) {
61    this.row = row;
62    this.baseX = xOffset;
63    this.baseWidth = width;
64    this.opacity = opacity;
65    this.delay = delay;
66    this.speed = speed;
67    this.offset = 0;
68    this.phase = Math.random() * Math.PI * 2;
69  }
70}
71
72const lines = [];
73
74// Build lines based on the circular shape
75for (let i = 0; i < NUM_ROWS; i++) {
76  const t = (i / (NUM_ROWS - 1)) * 2 - 1;
77  const circW = Math.sqrt(Math.max(0, 1 - t * t));
78  const rowY = cy - ry + (i / (NUM_ROWS - 1)) * ry * 2;
79  
80  // Main line
81  const mainW = circW * rx * 2 * (0.7 + Math.random() * 0.5);
82  const mainX = cx - circW * rx + (Math.random() - 0.5) * 20;
83  const op = 0.5 + circW * 0.5;
84  
85  lines.push({
86    row: i,
87    y: rowY,
88    x: mainX,
89    width: mainW,
90    opacity: op,
91    animOffset: 0,
92    phase: Math.random() * Math.PI * 2,
93    speed: 0.3 + Math.random() * 0.4,
94    isSecondary: false
95  });
96  
97  // Secondary "ghost" line (the glitch offset group)
98  if (i > 3 && i < NUM_ROWS - 2) {
99    const secW = circW * rx * (0.4 + Math.random() * 0.6);
100    const secX = cx + circW * rx * 0.1 + Math.random() * 20;
101    lines.push({
102      row: i,
103      y: rowY,
104      x: secX,
105      width: secW,
106      opacity: op * 0.8,
107      animOffset: 0,
108      phase: Math.random() * Math.PI * 2 + 1,
109      speed: 0.4 + Math.random() * 0.5,
110      isSecondary: true
111    });
112  }
113}
114
115let time = 0;
116
117function drawBackground() {
118  const grad = ctx.createRadialGradient(W*0.4, H*0.4, 0, W*0.5, H*0.5, W*0.7);
119  grad.addColorStop(0, '#2d2845');
120  grad.addColorStop(0.5, '#1e1b30');
121  grad.addColorStop(1, '#161320');
122  ctx.fillStyle = grad;
123  ctx.fillRect(0, 0, W, H);
124}
125
126function drawLine(x, y, width, opacity, glowColor) {
127  if (width <= 0) return;
128  
129  // Glow effect
130  ctx.save();
131  ctx.globalAlpha = opacity * 0.3;
132  ctx.shadowColor = glowColor;
133  ctx.shadowBlur = 8;
134  ctx.strokeStyle = glowColor;
135  ctx.lineWidth = 3;
136  ctx.beginPath();
137  ctx.moveTo(x, y);
138  ctx.lineTo(x + width, y);
139  ctx.stroke();
140  
141  // Core bright line
142  ctx.globalAlpha = opacity;
143  ctx.shadowBlur = 4;
144  ctx.lineWidth = 1.5;
145  ctx.strokeStyle = '#ff6040';
146  ctx.beginPath();
147  ctx.moveTo(x, y);
148  ctx.lineTo(x + width, y);
149  ctx.stroke();
150  ctx.restore();
151}
152
153function animate() {
154  time += 0.016;
155  
156  drawBackground();
157  
158  // Ambient glow behind lines
159  const glowGrad = ctx.createRadialGradient(cx, cy, 0, cx, cy, 160);
160  glowGrad.addColorStop(0, 'rgba(180, 60, 30, 0.12)');
161  glowGrad.addColorStop(1, 'rgba(180, 60, 30, 0)');
162  ctx.fillStyle = glowGrad;
163  ctx.fillRect(0, 0, W, H);
164  
165  // The secondary group offset - oscillates back and forth
166  // Looking at frames: secondary group moves right then comes back, cycling
167  const secGroupOffset = Math.sin(time * 0.8) * 40 + Math.cos(time * 0.5) * 20;
168  
169  for (const line of lines) {
170    // Individual line animation - slight horizontal drift
171    const indivOffset = Math.sin(time * line.speed + line.phase) * 8;
172    
173    let x = line.x + indivOffset;
174    let w = line.width;
175    let op = line.opacity;
176    
177    if (line.isSecondary) {
178      x += secGroupOffset;
179      // Secondary lines fade in/out
180      op *= (0.5 + 0.5 * Math.sin(time * 0.6 + line.phase));
181    }
182    
183    // Color varies slightly - brighter in center rows
184    const t = (line.row / (NUM_ROWS - 1)) * 2 - 1;
185    const brightness = 1 - Math.abs(t) * 0.4;
186    const r = Math.floor(220 * brightness + 35);
187    const g = Math.floor(60 * brightness);
188    const b = Math.floor(20 * brightness);
189    const color = `rgb(${r},${g},${b})`;
190    
191    drawLine(x, line.y, w, op * 0.9, color);
192  }
193  
194  requestAnimationFrame(animate);
195}
196
197animate();
198
199window.addEventListener('resize', () => {
200  canvas.width = window.innerWidth;
201  canvas.height = window.innerHeight;
202});
203</script>
204</body>
205</html>