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

model output

Claude Sonnet 4.6

Only CSS: 3D Scan 2

A 0.63T 0.33
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>3D Cube Animation</title>
7<style>
8  * { margin: 0; padding: 0; box-sizing: border-box; }
9  body {
10    background: radial-gradient(ellipse at center, #0d2233 0%, #071520 60%, #050e18 100%);
11    width: 100vw; height: 100vh;
12    display: flex; align-items: center; justify-content: center;
13    overflow: hidden;
14  }
15  canvas { display: block; }
16</style>
17</head>
18<body>
19<canvas id="c"></canvas>
20<script>
21const canvas = document.getElementById('c');
22const ctx = canvas.getContext('2d');
23canvas.width = 1024;
24canvas.height = 576;
25
26const W = canvas.width, H = canvas.height;
27const cx = W * 0.5, cy = H * 0.5;
28
29// Isometric cube parameters
30const cubeSize = 160;
31// Isometric projection vectors
32// Right: (cos30, sin30), Left: (-cos30, sin30), Up: (0, -1)
33const cos30 = Math.cos(Math.PI/6);
34const sin30 = Math.sin(Math.PI/6);
35
36// Cube center offset
37const ox = cx - 20, oy = cy + 10;
38
39// Convert 3D cube coords (x,y,z) in [-1,1] to 2D isometric
40function iso(x, y, z) {
41  // x: right, y: up, z: depth (toward viewer)
42  const px = ox + (x - z) * cos30 * cubeSize;
43  const py = oy + (x + z) * sin30 * cubeSize - y * cubeSize;
44  return [px, py];
45}
46
47// Draw the wireframe cube layers
48function drawCubeWireframe(layers) {
49  ctx.strokeStyle = 'rgba(200,220,255,0.15)';
50  ctx.lineWidth = 0.5;
51  
52  for (let i = 0; i < layers; i++) {
53    const t = i / (layers - 1); // 0 to 1
54    const s = 0.3 + t * 0.7; // scale from 0.3 to 1
55    
56    // Draw cube edges at scale s
57    const corners = [
58      [-s, -s, -s], [s, -s, -s], [s, s, -s], [-s, s, -s],
59      [-s, -s, s], [s, -s, s], [s, s, s], [-s, s, s]
60    ];
61    
62    const edges = [
63      [0,1],[1,2],[2,3],[3,0], // back face
64      [4,5],[5,6],[6,7],[7,4], // front face
65      [0,4],[1,5],[2,6],[3,7]  // connecting
66    ];
67    
68    edges.forEach(([a,b]) => {
69      const [ax,ay] = iso(corners[a][0], corners[a][1], corners[a][2]);
70      const [bx,by] = iso(corners[b][0], corners[b][1], corners[b][2]);
71      ctx.beginPath();
72      ctx.moveTo(ax, ay);
73      ctx.lineTo(bx, by);
74      ctx.stroke();
75    });
76  }
77}
78
79// Draw cube faces (filled)
80function drawCubeFaces() {
81  // Bottom face
82  ctx.fillStyle = 'rgba(10,40,70,0.4)';
83  ctx.beginPath();
84  const bl = iso(-1,-1,-1), br = iso(1,-1,-1), fr = iso(1,-1,1), fl = iso(-1,-1,1);
85  ctx.moveTo(bl[0],bl[1]); ctx.lineTo(br[0],br[1]); ctx.lineTo(fr[0],fr[1]); ctx.lineTo(fl[0],fl[1]);
86  ctx.closePath(); ctx.fill();
87  
88  // Left face
89  ctx.fillStyle = 'rgba(10,50,80,0.3)';
90  ctx.beginPath();
91  const tl = iso(-1,1,-1), tlf = iso(-1,1,1);
92  ctx.moveTo(bl[0],bl[1]); ctx.lineTo(fl[0],fl[1]); ctx.lineTo(tlf[0],tlf[1]); ctx.lineTo(tl[0],tl[1]);
93  ctx.closePath(); ctx.fill();
94  
95  // Front face
96  ctx.fillStyle = 'rgba(15,60,100,0.35)';
97  ctx.beginPath();
98  const tr = iso(1,1,1), trf = iso(-1,1,1);
99  ctx.moveTo(fl[0],fl[1]); ctx.lineTo(fr[0],fr[1]); ctx.lineTo(tr[0],tr[1]); ctx.lineTo(tlf[0],tlf[1]);
100  ctx.closePath(); ctx.fill();
101}
102
103// Circle positions in 3x3 grid on front face (z=1)
104// Grid positions: col -1,0,1 and row -1,0,1 mapped to x,y
105const gridPositions = [];
106for (let row = -1; row <= 1; row++) {
107  for (let col = -1; col <= 1; col++) {
108    gridPositions.push({col, row});
109  }
110}
111
112// Colors cycling: green (#3dff8f) and purple (#9b59ff)
113const greenColor = '#3dff8f';
114const purpleColor = '#9b59ff';
115const blueColor = '#4466ff';
116
117// Each circle has its own animation phase
118// The animation shows circles pulsing/growing with color cycling
119// From frames: circles animate between green and purple, some are blue transitioning
120
121function getCircleColor(t, phase) {
122  // t is global time 0-1 cycling
123  const p = (t + phase) % 1;
124  if (p < 0.5) {
125    // green to purple
126    const f = p / 0.5;
127    const r = Math.round(61 + (155-61)*f);
128    const g = Math.round(255 + (89-255)*f);
129    const b = Math.round(143 + (255-143)*f);
130    return `rgb(${r},${g},${b})`;
131  } else {
132    // purple to green
133    const f = (p - 0.5) / 0.5;
134    const r = Math.round(155 + (61-155)*f);
135    const g = Math.round(89 + (255-89)*f);
136    const b = Math.round(255 + (143-255)*f);
137    return `rgb(${r},${g},${b})`;
138  }
139}
140
141// Draw a circle on the isometric front face
142function drawIsoCircle(col, row, radius, color, alpha, numRings) {
143  // Center of circle in 3D
144  const cx3 = col * 0.62;
145  const cy3 = -row * 0.62;
146  const cz3 = 1.0;
147  
148  const [pcx, pcy] = iso(cx3, cy3, cz3);
149  
150  // In isometric view, circles on the front face appear as ellipses
151  // The front face normal is along (1,1,0) direction in iso
152  // Scale x by cos30, y by sin30 for the face
153  const scaleX = cos30 * cubeSize * 0.62;
154  const scaleY = sin30 * cubeSize * 0.62;
155  
156  ctx.save();
157  ctx.globalAlpha = alpha;
158  ctx.strokeStyle = color;
159  ctx.lineWidth = 1.5;
160  
161  for (let r = 0; r < numRings; r++) {
162    const rScale = radius * (0.4 + r * 0.2);
163    ctx.beginPath();
164    // Draw ellipse approximating circle on isometric face
165    ctx.ellipse(pcx, pcy, rScale * 0.85, rScale * 0.85, 0, 0, Math.PI * 2);
166    ctx.stroke();
167  }
168  ctx.restore();
169}
170
171// Animation state
172let startTime = null;
173const CYCLE = 4000; // ms per full cycle
174
175function easeInOut(t) {
176  return t < 0.5 ? 2*t*t : -1+(4-2*t)*t;
177}
178
179function animate(ts) {
180  if (!startTime) startTime = ts;
181  const elapsed = (ts - startTime) % CYCLE;
182  const t = elapsed / CYCLE; // 0 to 1
183  
184  ctx.clearRect(0, 0, W, H);
185  
186  // Background
187  const grad = ctx.createRadialGradient(cx, cy, 0, cx, cy, W*0.7);
188  grad.addColorStop(0, '#0d2233');
189  grad.addColorStop(0.6, '#071520');
190  grad.addColorStop(1, '#050e18');
191  ctx.fillStyle = grad;
192  ctx.fillRect(0, 0, W, H);
193  
194  // Draw cube faces
195  drawCubeFaces();
196  
197  // Draw wireframe layers
198  drawCubeWireframe(18);
199  
200  // Draw circles on front face (3x3 grid)
201  // Each circle has phase offset
202  const phases = [
203    0.0, 0.15, 0.3,
204    0.45, 0.6, 0.75,
205    0.9, 0.05, 0.2
206  ];
207  
208  // Determine which circles are visible based on animation
209  // From frames: circles grow/shrink and color cycles
210  // Some circles disappear (scale to 0) at certain phases
211  
212  const positions = [
213    {col:-1, row:1},  {col:0, row:1},  {col:1, row:1},
214    {col:-1, row:0},  {col:0, row:0},  {col:1, row:0},
215    {col:-1, row:-1}, {col:0, row:-1}, {col:1, row:-1}
216  ];
217  
218  positions.forEach((pos, i) => {
219    const phase = phases[i];
220    const p = (t + phase) % 1;
221    
222    // Size animation: pulse
223    let size = 0.5 + 0.3 * Math.sin(p * Math.PI * 2);
224    
225    // Visibility: some circles fade in/out
226    let alpha = 0.8 + 0.2 * Math.sin(p * Math.PI * 2 + 1);
227    
228    // Color
229    const color = getCircleColor(t, phase);
230    
231    // Number of rings based on size
232    const numRings = Math.floor(3 + size * 4);
233    
234    drawIsoCircle(pos.col, pos.row, size * 55, color, alpha, numRings);
235  });
236  
237  // Also draw smaller circles on left face
238  const leftPositions = [
239    {x:-1, y:1}, {x:-1, y:-1}
240  ];
241  
242  leftPositions.forEach((pos, i) => {
243    const phase = 0.1 + i * 0.3;
244    const p = (t + phase) % 1;
245    const size = 0.3 + 0.2 * Math.sin(p * Math.PI * 2);
246    const color = getCircleColor(t, phase + 0.5);
247    
248    // Left face: x=-1, y varies, z varies
249    const [pcx, pcy] = iso(-1, pos.y * 0.5, pos.x * 0.5);
250    
251    ctx.save();
252    ctx.globalAlpha = 0.5;
253    ctx.strokeStyle = color;
254    ctx.lineWidth = 1;
255    for (let r = 0; r < 3; r++) {
256      const rr = size * 30 * (0.5 + r * 0.25);
257      ctx.beginPath();
258      ctx.ellipse(pcx, pcy, rr * 0.4, rr * 0.9, -Math.PI/6, 0, Math.PI*2);
259      ctx.stroke();
260    }
261    ctx.restore();
262  });
263  
264  requestAnimationFrame(animate);
265}
266
267requestAnimationFrame(animate);
268</script>
269</body>
270</html>