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

model output

GPT-5.4

Spiral Tower

A 0.65T 0.28
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" />
6<title>Twisting Layered Prism</title>
7<style>
8  :root{
9    --bg:#f3f3fb;
10    --top:#8b9899;
11    --left:#9aa8ad;
12    --right:#8f9d9f;
13    --w:136px;
14    --h:340px;
15    --d:78px;
16    --layers:56;
17    --step:6px;
18    --dur:4.8s;
19  }
20
21  html,body{
22    height:100%;
23    margin:0;
24    overflow:hidden;
25    background:var(--bg);
26    font-family:sans-serif;
27  }
28
29  .stage{
30    width:100vw;
31    height:100vh;
32    display:grid;
33    place-items:center;
34    perspective:1100px;
35    perspective-origin:50% 42%;
36  }
37
38  .object{
39    position:relative;
40    width:var(--w);
41    height:var(--h);
42    transform-style:preserve-3d;
43    transform:
44      rotateX(-24deg)
45      rotateY(-45deg)
46      translateY(10px);
47  }
48
49  .stack{
50    position:absolute;
51    inset:0;
52    transform-style:preserve-3d;
53    animation: spin var(--dur) linear infinite;
54  }
55
56  .slice{
57    position:absolute;
58    left:0;
59    width:var(--w);
60    height:var(--step);
61    transform-style:preserve-3d;
62    transform-origin:50% 50%;
63  }
64
65  .face{
66    position:absolute;
67    inset:0;
68    backface-visibility:hidden;
69  }
70
71  .topFace{
72    background:var(--top);
73    transform:rotateX(90deg) translateZ(calc(var(--step) / 2));
74    transform-origin:50% 50%;
75  }
76
77  .leftFace{
78    width:var(--d);
79    height:var(--step);
80    background:var(--left);
81    left:0;
82    transform-origin:0 50%;
83    transform:
84      rotateY(-90deg)
85      translateZ(calc(var(--step) / 2));
86  }
87
88  .rightFace{
89    width:var(--d);
90    height:var(--step);
91    background:var(--right);
92    right:0;
93    left:auto;
94    transform-origin:100% 50%;
95    transform:
96      rotateY(90deg)
97      translateZ(calc(var(--step) / 2));
98  }
99
100  .cap{
101    position:absolute;
102    width:var(--w);
103    height:var(--d);
104    background:var(--top);
105    transform-style:preserve-3d;
106  }
107
108  .cap.top{
109    transform:
110      translateY(0)
111      rotateX(90deg)
112      translateZ(calc(var(--d) / 2));
113  }
114
115  .cap.bottom{
116    transform:
117      translateY(calc(var(--h) - 2px))
118      rotateX(90deg)
119      translateZ(calc(var(--d) / 2));
120    filter:brightness(.96);
121  }
122
123  @keyframes spin{
124    0%,18%{
125      transform:rotateY(0deg);
126    }
127    50%{
128      transform:rotateY(180deg);
129    }
130    82%,100%{
131      transform:rotateY(360deg);
132    }
133  }
134</style>
135</head>
136<body>
137<div class="stage">
138  <div class="object">
139    <div class="stack" id="stack">
140      <div class="cap top"></div>
141      <div class="cap bottom"></div>
142    </div>
143  </div>
144</div>
145
146<script>
147  const stack = document.getElementById('stack');
148
149  const layers = 56;
150  const step = 6;
151  const height = layers * step;
152  const amp = 34;          // side in/out deformation
153  const twistMax = 34;     // per-slice local twist
154  const phaseShift = Math.PI * 0.95;
155
156  for(let i=0;i<layers;i++){
157    const t = i/(layers-1);                 // 0..1 bottom->top
158    const y = i * step;
159
160    // Envelope keeps top/bottom nearly rectangular and middle most deformed
161    const env = Math.sin(Math.PI * t);
162
163    // Two opposing traveling waves around the height to mimic the frames
164    const waveA = Math.sin((t * 2 - 0.15) * Math.PI);
165    const waveB = Math.sin((t * 2 + 0.85) * Math.PI);
166
167    // Horizontal squeeze/expand and local twist
168    const x = amp * env * Math.sin(2 * Math.PI * t + phaseShift);
169    const rot = twistMax * env * Math.sin(2 * Math.PI * t - 0.35);
170
171    const slice = document.createElement('div');
172    slice.className = 'slice';
173    slice.style.top = `${y}px`;
174    slice.style.transform = `
175      translate3d(${x}px,0,0)
176      rotateZ(${rot}deg)
177      scaleX(${1 - 0.10 * env * Math.cos(2*Math.PI*t)} )
178    `;
179
180    const top = document.createElement('div');
181    top.className = 'face topFace';
182
183    const left = document.createElement('div');
184    left.className = 'face leftFace';
185
186    const right = document.createElement('div');
187    right.className = 'face rightFace';
188
189    // subtle tonal variation by height, like stacked sheets catching light
190    const l1 = 70 - env * 4 + waveA * 1.5;
191    const l2 = 74 - env * 3 + waveB * 1.2;
192    const l3 = 68 - env * 5 - waveA * 1.2;
193
194    top.style.background = `hsl(190 8% ${l1}%)`;
195    left.style.background = `hsl(195 11% ${l2}%)`;
196    right.style.background = `hsl(190 10% ${l3}%)`;
197
198    slice.append(top,left,right);
199    stack.appendChild(slice);
200  }
201</script>
202</body>
203</html>