animation2code benchmark
For best compatibility, please view this dashboard in a Chrome browser.
← back to Spiral Tower

model output

Claude Sonnet 4.6

Spiral Tower

A 0.78T 0.27
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>Twisted Box Animation</title>
7<style>
8  * { margin: 0; padding: 0; box-sizing: border-box; }
9  body {
10    background: #eef0f5;
11    display: flex;
12    justify-content: center;
13    align-items: center;
14    width: 100vw;
15    height: 100vh;
16    overflow: hidden;
17  }
18  canvas {
19    display: block;
20  }
21</style>
22</head>
23<body>
24<canvas id="c"></canvas>
25<script>
26const canvas = document.getElementById('c');
27const ctx = canvas.getContext('2d');
28canvas.width = 1024;
29canvas.height = 768;
30
31// Colors
32const colorTop = '#8aa5a0';
33const colorLeft = '#8faaa5';
34const colorRight = '#6b8a85';
35
36// Isometric projection helpers
37function iso(x, y, z) {
38  // isometric projection
39  const ix = (x - y) * Math.cos(Math.PI / 6);
40  const iy = (x + y) * Math.sin(Math.PI / 6) - z;
41  return { x: ix, y: iy };
42}
43
44// Draw a single horizontal slice (a square at height z, rotated by angle)
45// The square has half-size s, centered at (cx, cy) in 3D, rotated by angle around Z axis
46function getSquarePoints(cx, cy, s, angle) {
47  const corners = [
48    [-s, -s],
49    [ s, -s],
50    [ s,  s],
51    [-s,  s]
52  ];
53  return corners.map(([x, y]) => {
54    const rx = x * Math.cos(angle) - y * Math.sin(angle) + cx;
55    const ry = x * Math.sin(angle) + y * Math.cos(angle) + cy;
56    return [rx, ry];
57  });
58}
59
60function isoPoint(x, y, z, ox, oy) {
61  const p = iso(x, y, z);
62  return [p.x + ox, p.y + oy];
63}
64
65function drawTwistedBox(twist, ox, oy) {
66  ctx.clearRect(0, 0, canvas.width, canvas.height);
67  ctx.fillStyle = '#eef0f5';
68  ctx.fillRect(0, 0, canvas.width, canvas.height);
69
70  const N = 60; // number of slices
71  const s = 80; // half-size of square
72  const totalHeight = 300; // total height in 3D units
73  const sliceHeight = totalHeight / N;
74
75  // We'll draw slices from bottom to top
76  // For each slice, compute the 4 corners at z and z+dz
77  // Draw the side faces between consecutive slices
78
79  const slices = [];
80  for (let i = 0; i <= N; i++) {
81    const t = i / N;
82    const z = i * sliceHeight;
83    const angle = twist * t; // rotation angle at this level
84    const pts = getSquarePoints(0, 0, s, angle);
85    // Convert to isometric
86    const isoPts = pts.map(([x, y]) => isoPoint(x, y, z, ox, oy));
87    slices.push({ pts, isoPts, z, angle });
88  }
89
90  // Draw side faces from bottom to top
91  // For each slice pair (i, i+1), draw 4 quad faces
92  // We need to determine which faces are visible
93  // In isometric view from front-left, faces on left side (negative x) and front (negative y) are visible
94
95  // Draw back faces first (right side and back), then front faces
96  // Actually let's just draw all quads from bottom to top
97  // The order matters for painter's algorithm
98
99  // For isometric view: we see top, left face (front-left), right face (front-right)
100  // Let's identify faces by their normal direction
101  // Face 0: between corner 0-1 (top edge, y=-s) -> front face (visible)
102  // Face 1: between corner 1-2 (right edge, x=s) -> right face (visible)  
103  // Face 2: between corner 2-3 (bottom edge, y=s) -> back face (hidden)
104  // Face 3: between corner 3-0 (left edge, x=-s) -> left face (visible)
105
106  // Draw back faces (face 2) first
107  for (let i = 0; i < N; i++) {
108    const bot = slices[i];
109    const top = slices[i + 1];
110    // Face 2: corners 2 and 3
111    const p = [
112      bot.isoPts[2],
113      bot.isoPts[3],
114      top.isoPts[3],
115      top.isoPts[2]
116    ];
117    ctx.beginPath();
118    ctx.moveTo(p[0][0], p[0][1]);
119    for (let k = 1; k < p.length; k++) ctx.lineTo(p[k][0], p[k][1]);
120    ctx.closePath();
121    ctx.fillStyle = colorRight;
122    ctx.fill();
123  }
124
125  // Draw right faces (face 1)
126  for (let i = 0; i < N; i++) {
127    const bot = slices[i];
128    const top = slices[i + 1];
129    const p = [
130      bot.isoPts[1],
131      bot.isoPts[2],
132      top.isoPts[2],
133      top.isoPts[1]
134    ];
135    ctx.beginPath();
136    ctx.moveTo(p[0][0], p[0][1]);
137    for (let k = 1; k < p.length; k++) ctx.lineTo(p[k][0], p[k][1]);
138    ctx.closePath();
139    ctx.fillStyle = colorRight;
140    ctx.fill();
141  }
142
143  // Draw left faces (face 3)
144  for (let i = 0; i < N; i++) {
145    const bot = slices[i];
146    const top = slices[i + 1];
147    const p = [
148      bot.isoPts[3],
149      bot.isoPts[0],
150      top.isoPts[0],
151      top.isoPts[3]
152    ];
153    ctx.beginPath();
154    ctx.moveTo(p[0][0], p[0][1]);
155    for (let k = 1; k < p.length; k++) ctx.lineTo(p[k][0], p[k][1]);
156    ctx.closePath();
157    ctx.fillStyle = colorLeft;
158    ctx.fill();
159  }
160
161  // Draw front faces (face 0)
162  for (let i = 0; i < N; i++) {
163    const bot = slices[i];
164    const top = slices[i + 1];
165    const p = [
166      bot.isoPts[0],
167      bot.isoPts[1],
168      top.isoPts[1],
169      top.isoPts[0]
170    ];
171    ctx.beginPath();
172    ctx.moveTo(p[0][0], p[0][1]);
173    for (let k = 1; k < p.length; k++) ctx.lineTo(p[k][0], p[k][1]);
174    ctx.closePath();
175    ctx.fillStyle = colorLeft;
176    ctx.fill();
177  }
178
179  // Draw top face
180  const topSlice = slices[N];
181  ctx.beginPath();
182  ctx.moveTo(topSlice.isoPts[0][0], topSlice.isoPts[0][1]);
183  for (let k = 1; k < 4; k++) ctx.lineTo(topSlice.isoPts[k][0], topSlice.isoPts[k][1]);
184  ctx.closePath();
185  ctx.fillStyle = colorTop;
186  ctx.fill();
187}
188
189// Animation
190const duration = 3000; // ms for one full cycle
191let startTime = null;
192
193function easeInOut(t) {
194  return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
195}
196
197function animate(ts) {
198  if (!startTime) startTime = ts;
199  const elapsed = (ts - startTime) % (duration * 2);
200  let t;
201  if (elapsed < duration) {
202    t = easeInOut(elapsed / duration);
203  } else {
204    t = easeInOut(1 - (elapsed - duration) / duration);
205  }
206
207  const maxTwist = Math.PI / 2; // 90 degrees total twist
208  const twist = t * maxTwist;
209
210  // Center the box
211  const ox = canvas.width * 0.55;
212  const oy = canvas.height * 0.72;
213
214  drawTwistedBox(twist, ox, oy);
215  requestAnimationFrame(animate);
216}
217
218requestAnimationFrame(animate);
219</script>
220</body>
221</html>