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

model output

GPT-5.4

Only CSS: 3D Scan 2

A 0.83T 0.43
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>Wireframe Cube Dice Animation</title>
7<style>
8  :root{
9    --bg1:#0a0d16;
10    --bg2:#132235;
11    --wire:rgba(210,230,255,.18);
12    --wire2:rgba(210,230,255,.10);
13    --green:#59f07d;
14    --purple:#a86bff;
15    --blue:#5f6dff;
16  }
17
18  html,body{
19    margin:0;
20    height:100%;
21    overflow:hidden;
22    background:
23      radial-gradient(circle at 50% 58%, #17304a 0%, #0d1624 34%, #090c15 72%, #070910 100%);
24    font-family:system-ui,sans-serif;
25  }
26
27  .scene{
28    width:100vw;
29    height:100vh;
30    display:grid;
31    place-items:center;
32  }
33
34  svg{
35    width:min(78vmin,760px);
36    height:min(78vmin,760px);
37    overflow:visible;
38    filter: drop-shadow(0 0 10px rgba(120,180,255,.05));
39  }
40
41  .cube line,.cube polyline,.cube rect{
42    stroke:var(--wire);
43    stroke-width:1.1;
44    fill:none;
45    vector-effect:non-scaling-stroke;
46  }
47
48  .cube .inner{
49    stroke:var(--wire2);
50  }
51
52  .pip{
53    fill:none;
54    stroke-width:2.2;
55    vector-effect:non-scaling-stroke;
56    opacity:.95;
57    mix-blend-mode:screen;
58  }
59
60  .pip.green{ stroke:var(--green); filter:drop-shadow(0 0 3px rgba(89,240,125,.18)); }
61  .pip.purple{ stroke:var(--purple); filter:drop-shadow(0 0 3px rgba(168,107,255,.18)); }
62  .pip.blue{ stroke:var(--blue); opacity:.8; }
63
64  .ghost{
65    fill:none;
66    stroke-width:1.1;
67    opacity:.55;
68    vector-effect:non-scaling-stroke;
69  }
70
71  .ghost.green{ stroke:rgba(89,240,125,.45); }
72  .ghost.purple{ stroke:rgba(168,107,255,.42); }
73  .ghost.blue{ stroke:rgba(95,109,255,.35); }
74
75  .tiny{
76    fill:none;
77    stroke:rgba(190,220,255,.35);
78    stroke-width:.9;
79    vector-effect:non-scaling-stroke;
80  }
81</style>
82</head>
83<body>
84<div class="scene">
85  <svg viewBox="0 0 800 800" aria-label="Animated wireframe cube with moving neon rings">
86    <g id="cube" class="cube"></g>
87    <g id="rings"></g>
88    <g id="tiny"></g>
89  </svg>
90</div>
91
92<script>
93(() => {
94  const svgNS = "http://www.w3.org/2000/svg";
95  const cube = document.getElementById("cube");
96  const ringsLayer = document.getElementById("rings");
97  const tinyLayer = document.getElementById("tiny");
98
99  const W = 800, H = 800;
100  const cx = 400, cy = 400;
101
102  // Cube geometry tuned to match the reference perspective.
103  const front = { x: 275, y: 205, w: 250, h: 390 };
104  const dx = 120, dy = 48;
105  const depthSteps = 18;
106
107  function el(name, attrs={}, parent){
108    const n = document.createElementNS(svgNS, name);
109    for(const k in attrs) n.setAttribute(k, attrs[k]);
110    if(parent) parent.appendChild(n);
111    return n;
112  }
113
114  function lerp(a,b,t){ return a + (b-a)*t; }
115  function easeInOut(t){ return 0.5 - 0.5*Math.cos(Math.PI*t); }
116
117  function project(u,v,z){
118    // u,v in [0,1], z in [0,1] from front to back
119    return {
120      x: front.x + u*front.w + z*dx,
121      y: front.y + v*front.h - z*dy
122    };
123  }
124
125  // Draw stacked wireframe cube slices.
126  for(let i=0;i<depthSteps;i++){
127    const z = i/(depthSteps-1);
128    const p = project(0,0,z);
129    el("rect", {
130      x:p.x, y:p.y, width:front.w, height:front.h, rx:10, ry:10,
131      class:i < depthSteps-1 ? "inner" : ""
132    }, cube);
133  }
134
135  // Connect corners.
136  const corners = [
137    [[0,0,0],[0,0,1]], [[1,0,0],[1,0,1]],
138    [[0,1,0],[0,1,1]], [[1,1,0],[1,1,1]]
139  ];
140  corners.forEach(c=>{
141    const a = project(...c[0]), b = project(...c[1]);
142    el("line",{x1:a.x,y1:a.y,x2:b.x,y2:b.y},cube);
143  });
144
145  // Dice-like positions on front face.
146  const slots = {
147    tl:[0.22,0.22],
148    tc:[0.50,0.22],
149    tr:[0.78,0.22],
150    ml:[0.34,0.50],
151    mc:[0.50,0.50],
152    mr:[0.66,0.50],
153    bl:[0.22,0.78],
154    bc:[0.50,0.78],
155    br:[0.78,0.78]
156  };
157
158  // Ring groups approximate the frame sequence:
159  // green clusters drift into a 5-like arrangement while purple recedes.
160  const rings = [
161    {from:"tl", to:"tl", z0:.10, z1:.34, color:"green", r:42, copies:4, phase:0.00},
162    {from:"tc", to:"tr", z0:.28, z1:.18, color:"green", r:48, copies:4, phase:0.08},
163    {from:"mc", to:"mc", z0:.22, z1:.22, color:"green", r:36, copies:4, phase:0.16},
164    {from:"bc", to:"br", z0:.26, z1:.18, color:"green", r:46, copies:4, phase:0.24},
165    {from:"bl", to:"bl", z0:.12, z1:.30, color:"green", r:42, copies:4, phase:0.32},
166
167    {from:"tr", to:"ml", z0:.18, z1:.08, color:"purple", r:40, copies:4, phase:0.50},
168    {from:"mr", to:"ml", z0:.18, z1:.10, color:"purple", r:40, copies:4, phase:0.62},
169    {from:"tc", to:"ml", z0:.12, z1:.12, color:"purple", r:34, copies:3, phase:0.74},
170    {from:"bc", to:"ml", z0:.12, z1:.12, color:"purple", r:34, copies:3, phase:0.86},
171
172    {from:"mr", to:"mr", z0:.42, z1:.42, color:"blue", r:28, copies:1, phase:0.18},
173    {from:"tc", to:"tc", z0:.46, z1:.46, color:"blue", r:26, copies:1, phase:0.58}
174  ];
175
176  const ringNodes = rings.map(r=>{
177    const g = el("g",{},ringsLayer);
178    const circles = [];
179    for(let i=0;i<r.copies;i++){
180      circles.push(el("circle",{class:`pip ${r.color}`, r:r.r},g));
181    }
182    return {cfg:r, circles};
183  });
184
185  // Tiny faint circles seen inside some positions.
186  const tinySpecs = [
187    {slot:"tl", z:.18}, {slot:"tr", z:.42}, {slot:"tc", z:.34},
188    {slot:"ml", z:.10}, {slot:"mc", z:.22}, {slot:"mr", z:.46},
189    {slot:"bl", z:.14}, {slot:"bc", z:.28}, {slot:"br", z:.18}
190  ];
191  const tinyNodes = tinySpecs.map(s => el("circle",{class:"tiny", r:8}, tinyLayer));
192
193  const duration = 3200; // smooth loop close to the sampled sequence
194
195  function slotPos(name){ return slots[name]; }
196
197  function update(now){
198    const t = (now % duration) / duration;
199    const e = easeInOut(t);
200
201    ringNodes.forEach(({cfg,circles})=>{
202      const [u0,v0] = slotPos(cfg.from);
203      const [u1,v1] = slotPos(cfg.to);
204
205      const u = lerp(u0,u1,e);
206      const v = lerp(v0,v1,e);
207      const z = lerp(cfg.z0,cfg.z1,e);
208
209      const base = project(u,v,z);
210
211      circles.forEach((c,i)=>{
212        const spread = (i - (circles.length-1)/2);
213        const localZ = Math.max(0, Math.min(1, z + spread*0.035));
214        const p = project(u,v,localZ);
215
216        // Slight horizontal ellipse feel from perspective by scaling x via rx illusion:
217        c.setAttribute("cx", p.x + spread*2.5);
218        c.setAttribute("cy", p.y);
219        c.setAttribute("r", cfg.r + Math.sin((t + cfg.phase + i*0.03)*Math.PI*2)*1.2);
220        c.setAttribute("opacity", cfg.color === "blue" ? 0.72 : 0.92 - Math.abs(spread)*0.08);
221      });
222    });
223
224    tinyNodes.forEach((n,i)=>{
225      const s = tinySpecs[i];
226      const [u,v] = slotPos(s.slot);
227      const p = project(u,v,s.z);
228      const drift = Math.sin(t*Math.PI*2 + i*0.8)*2;
229      n.setAttribute("cx", p.x + drift);
230      n.setAttribute("cy", p.y + Math.cos(t*Math.PI*2 + i)*1.5);
231      n.setAttribute("opacity", 0.18 + 0.18*Math.sin(t*Math.PI*2 + i*0.7 + 1));
232    });
233
234    requestAnimationFrame(update);
235  }
236
237  requestAnimationFrame(update);
238})();
239</script>
240</body>
241</html>