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

model output

Claude Sonnet 4.6

Only CSS: Pulse Box

A 0.71T 0.30
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>Neon Geometry Animation</title>
7<style>
8  * { margin: 0; padding: 0; box-sizing: border-box; }
9  body { background: #000; overflow: hidden; width: 100vw; height: 100vh; }
10  canvas { display: block; }
11</style>
12</head>
13<body>
14<canvas id="c"></canvas>
15<script>
16const canvas = document.getElementById('c');
17const ctx = canvas.getContext('2d');
18canvas.width = window.innerWidth;
19canvas.height = window.innerHeight;
20
21const W = canvas.width, H = canvas.height;
22
23function rand(a, b) { return a + Math.random() * (b - a); }
24function randInt(a, b) { return Math.floor(rand(a, b)); }
25
26// Color palette: green, blue, cyan
27const colors = [
28  '#00ff44', '#00ee33', '#00cc22',
29  '#0044ff', '#0033ee', '#0022cc',
30  '#00ffff', '#00ccff', '#00aaff',
31  '#00ff88', '#00ffaa'
32];
33
34function randColor() {
35  return colors[randInt(0, colors.length)];
36}
37
38function lerpColor(c1, c2, t) {
39  // parse hex
40  const p = c => [parseInt(c.slice(1,3),16), parseInt(c.slice(3,5),16), parseInt(c.slice(5,7),16)];
41  const a = p(c1), b = p(c2);
42  const r = Math.round(a[0]+(b[0]-a[0])*t);
43  const g = Math.round(a[1]+(b[1]-a[1])*t);
44  const bl = Math.round(a[2]+(b[2]-a[2])*t);
45  return `rgb(${r},${g},${bl})`;
46}
47
48class Shape {
49  constructor() {
50    this.reset(true);
51  }
52
53  reset(initial) {
54    this.type = Math.random() < 0.6 ? 'rect' : 'line';
55    this.x = rand(-W*0.5, W*1.5);
56    this.y = rand(-H*0.5, H*1.5);
57    if (initial) {
58      this.x = rand(-W*0.2, W*1.2);
59      this.y = rand(-H*0.2, H*1.2);
60    }
61    this.vx = rand(-3, 3);
62    this.vy = rand(-3, 3);
63    this.angle = rand(0, Math.PI * 2);
64    this.va = rand(-0.02, 0.02);
65    this.color1 = randColor();
66    this.color2 = randColor();
67    this.alpha = 0;
68    this.fadeIn = rand(0.005, 0.02);
69    this.life = rand(200, 600);
70    this.age = initial ? rand(0, 300) : 0;
71    this.maxAlpha = rand(0.5, 1.0);
72
73    if (this.type === 'rect') {
74      this.w = rand(60, 200);
75      this.h = rand(60, 200);
76      this.lineWidth = rand(2, 8);
77    } else {
78      this.len = rand(40, 200);
79      this.lineWidth = rand(1, 4);
80    }
81  }
82
83  update() {
84    this.x += this.vx;
85    this.y += this.vy;
86    this.angle += this.va;
87    this.age++;
88
89    if (this.age < 60) {
90      this.alpha = Math.min(this.maxAlpha, this.alpha + this.fadeIn);
91    } else if (this.age > this.life - 60) {
92      this.alpha = Math.max(0, this.alpha - this.fadeIn);
93    }
94
95    if (this.age > this.life || 
96        (this.x < -W || this.x > W*2 || this.y < -H || this.y > H*2)) {
97      this.reset(false);
98    }
99  }
100
101  draw(ctx) {
102    ctx.save();
103    ctx.globalAlpha = this.alpha;
104    ctx.translate(this.x, this.y);
105    ctx.rotate(this.angle);
106    ctx.lineWidth = this.lineWidth;
107    ctx.strokeStyle = this.color1;
108
109    if (this.type === 'rect') {
110      // gradient stroke
111      const grad = ctx.createLinearGradient(-this.w/2, -this.h/2, this.w/2, this.h/2);
112      grad.addColorStop(0, this.color1);
113      grad.addColorStop(1, this.color2);
114      ctx.strokeStyle = grad;
115      ctx.strokeRect(-this.w/2, -this.h/2, this.w, this.h);
116    } else {
117      const grad = ctx.createLinearGradient(-this.len/2, 0, this.len/2, 0);
118      grad.addColorStop(0, this.color1);
119      grad.addColorStop(1, this.color2);
120      ctx.strokeStyle = grad;
121      ctx.beginPath();
122      ctx.moveTo(-this.len/2, 0);
123      ctx.lineTo(this.len/2, 0);
124      ctx.stroke();
125    }
126    ctx.restore();
127  }
128}
129
130// Also add some "partial rect" shapes (L-shapes, open rectangles)
131class PartialRect {
132  constructor() {
133    this.reset(true);
134  }
135
136  reset(initial) {
137    this.x = rand(-W*0.3, W*1.3);
138    this.y = rand(-H*0.3, H*1.3);
139    if (initial) {
140      this.x = rand(0, W);
141      this.y = rand(0, H);
142    }
143    this.vx = rand(-2.5, 2.5);
144    this.vy = rand(-2.5, 2.5);
145    this.angle = rand(0, Math.PI * 2);
146    this.va = rand(-0.025, 0.025);
147    this.color1 = randColor();
148    this.color2 = randColor();
149    this.alpha = 0;
150    this.fadeIn = rand(0.008, 0.025);
151    this.life = rand(150, 500);
152    this.age = initial ? rand(0, 200) : 0;
153    this.maxAlpha = rand(0.4, 1.0);
154    this.w = rand(50, 180);
155    this.h = rand(50, 180);
156    this.lineWidth = rand(2, 7);
157    // which sides to draw: top, right, bottom, left
158    this.sides = [true, Math.random()>0.3, Math.random()>0.2, Math.random()>0.3];
159  }
160
161  update() {
162    this.x += this.vx;
163    this.y += this.vy;
164    this.angle += this.va;
165    this.age++;
166
167    if (this.age < 60) {
168      this.alpha = Math.min(this.maxAlpha, this.alpha + this.fadeIn);
169    } else if (this.age > this.life - 60) {
170      this.alpha = Math.max(0, this.alpha - this.fadeIn);
171    }
172
173    if (this.age > this.life ||
174        (this.x < -W || this.x > W*2 || this.y < -H || this.y > H*2)) {
175      this.reset(false);
176    }
177  }
178
179  draw(ctx) {
180    ctx.save();
181    ctx.globalAlpha = this.alpha;
182    ctx.translate(this.x, this.y);
183    ctx.rotate(this.angle);
184    ctx.lineWidth = this.lineWidth;
185
186    const hw = this.w/2, hh = this.h/2;
187    const corners = [[-hw,-hh],[hw,-hh],[hw,hh],[-hw,hh]];
188    const sideMap = [[0,1],[1,2],[2,3],[3,0]];
189
190    for (let i = 0; i < 4; i++) {
191      if (!this.sides[i]) continue;
192      const [ai, bi] = sideMap[i];
193      const t = i / 3;
194      ctx.strokeStyle = lerpColor(this.color1, this.color2, t);
195      ctx.beginPath();
196      ctx.moveTo(...corners[ai]);
197      ctx.lineTo(...corners[bi]);
198      ctx.stroke();
199    }
200    ctx.restore();
201  }
202}
203
204const shapes = [];
205const partials = [];
206
207// Initialize shapes
208for (let i = 0; i < 25; i++) shapes.push(new Shape());
209for (let i = 0; i < 20; i++) partials.push(new PartialRect());
210
211let startTime = null;
212
213function animate(ts) {
214  if (!startTime) startTime = ts;
215  const elapsed = ts - startTime;
216
217  // Fade in from black
218  const fadeAlpha = Math.min(1, elapsed / 2000);
219
220  ctx.fillStyle = 'rgba(0,0,0,0.15)';
221  ctx.fillRect(0, 0, W, H);
222
223  // Overall scene alpha
224  ctx.save();
225  ctx.globalAlpha = fadeAlpha;
226
227  for (const s of shapes) {
228    s.update();
229    s.draw(ctx);
230  }
231  for (const p of partials) {
232    p.update();
233    p.draw(ctx);
234  }
235
236  ctx.restore();
237
238  requestAnimationFrame(animate);
239}
240
241// Start with black
242ctx.fillStyle = '#000';
243ctx.fillRect(0, 0, W, H);
244
245requestAnimationFrame(animate);
246
247window.addEventListener('resize', () => {
248  canvas.width = window.innerWidth;
249  canvas.height = window.innerHeight;
250});
251</script>
252</body>
253</html>