← back to Only CSS: 3D Scancompare with ground truth →
model output
GPT-5.4
Only CSS: 3D Scan
A 0.79T 0.18
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 + Orbiting Rings</title>
7<style>
8 :root{
9 --bg1:#0a0d17;
10 --bg2:#102131;
11 --cube:#d7e6ff;
12 --cyan:#7fe7df;
13 --blue:#6f7cff;
14 --violet:#8a5cff;
15 --panel:#17365a;
16 --dur:6.4s;
17 --ease:cubic-bezier(.42,0,.58,1);
18 }
19
20 html,body{
21 margin:0;
22 height:100%;
23 overflow:hidden;
24 background:
25 radial-gradient(ellipse at center, #17304a 0%, #0d1624 42%, #090c15 100%);
26 font-family:system-ui,sans-serif;
27 }
28
29 .scene{
30 position:relative;
31 width:100vw;
32 height:100vh;
33 display:grid;
34 place-items:center;
35 }
36
37 .wrap{
38 position:relative;
39 width:min(54vmin,560px);
40 aspect-ratio:1;
41 transform:translateY(-1vmin);
42 }
43
44 svg{
45 width:100%;
46 height:100%;
47 overflow:visible;
48 filter: drop-shadow(0 0 .35vmin rgba(120,180,255,.08));
49 }
50
51 .cube line,
52 .cube rect{
53 stroke:rgba(220,235,255,.18);
54 stroke-width:1.1;
55 fill:none;
56 vector-effect:non-scaling-stroke;
57 }
58
59 .panel{
60 fill:rgba(40,95,155,.18);
61 stroke:none;
62 }
63
64 .rings ellipse{
65 fill:none;
66 stroke-width:2.2;
67 vector-effect:non-scaling-stroke;
68 mix-blend-mode:screen;
69 filter: drop-shadow(0 0 4px rgba(120,160,255,.12));
70 }
71
72 .rings .c1{ stroke:rgba(127,231,223,.72); }
73 .rings .c2{ stroke:rgba(111,124,255,.72); }
74 .rings .c3{ stroke:rgba(138,92,255,.68); }
75
76 .dot{
77 fill:none;
78 stroke-width:1.4;
79 vector-effect:non-scaling-stroke;
80 opacity:.9;
81 }
82
83 .dot.cyan{ stroke:rgba(127,231,223,.7); }
84 .dot.violet{ stroke:rgba(111,124,255,.7); }
85
86 .ringsGroup{
87 transform-origin:50% 50%;
88 animation: drift var(--dur) var(--ease) infinite;
89 }
90
91 .splitL,.splitR{
92 animation: split var(--dur) linear infinite;
93 }
94
95 .pulse{
96 animation: pulse var(--dur) linear infinite;
97 }
98
99 @keyframes drift{
100 0% { transform:translateX(-7.5%) translateY(0); }
101 55% { transform:translateX(8.5%) translateY(0); }
102 72% { transform:translateX(10%) translateY(0); }
103 84% { transform:translateX(2%) translateY(0); }
104 100% { transform:translateX(-7.5%) translateY(0); }
105 }
106
107 @keyframes split{
108 0%,72% { opacity:0; }
109 73% { opacity:0; }
110 80% { opacity:1; }
111 92% { opacity:1; }
112 100% { opacity:0; }
113 }
114
115 @keyframes pulse{
116 0%,68% { opacity:1; }
117 74% { opacity:.95; }
118 80% { opacity:.85; }
119 88% { opacity:.55; }
120 100% { opacity:1; }
121 }
122</style>
123</head>
124<body>
125<div class="scene">
126 <div class="wrap">
127 <svg viewBox="0 0 600 600" aria-label="abstract geometric animation">
128 <!-- cube -->
129 <g class="cube" id="cube"></g>
130
131 <!-- center panel -->
132 <rect class="panel" x="205" y="145" width="190" height="310" rx="10"></rect>
133
134 <!-- main moving ring cluster -->
135 <g class="ringsGroup pulse">
136 <g class="rings" id="rings"></g>
137 </g>
138
139 <!-- split phase overlays -->
140 <g class="splitL rings" id="splitLeft"></g>
141 <g class="splitR rings" id="splitRight"></g>
142 </svg>
143 </div>
144</div>
145
146<script>
147(() => {
148 const svgNS = "http://www.w3.org/2000/svg";
149
150 // --- Wireframe cube made from repeated rounded rectangles + connecting edges
151 const cube = document.getElementById("cube");
152 const front = { x: 205, y: 145, w: 190, h: 310, rx: 10 };
153 const dx = 10.5, dy = -5.2, layers = 18;
154
155 for(let i = layers - 1; i >= 0; i--){
156 const r = document.createElementNS(svgNS, "rect");
157 r.setAttribute("x", front.x - dx * i);
158 r.setAttribute("y", front.y - dy * i);
159 r.setAttribute("width", front.w);
160 r.setAttribute("height", front.h);
161 r.setAttribute("rx", front.rx);
162 cube.appendChild(r);
163 }
164
165 const corners = [
166 [front.x, front.y],
167 [front.x + front.w, front.y],
168 [front.x + front.w, front.y + front.h],
169 [front.x, front.y + front.h]
170 ];
171
172 corners.forEach(([x,y]) => {
173 const line = document.createElementNS(svgNS, "line");
174 line.setAttribute("x1", x);
175 line.setAttribute("y1", y);
176 line.setAttribute("x2", x - dx * (layers - 1));
177 line.setAttribute("y2", y - dy * (layers - 1));
178 cube.appendChild(line);
179 });
180
181 // --- Main ring cluster
182 const rings = document.getElementById("rings");
183 const cx = 300, cy = 300;
184 const colors = ["c1","c2","c3"];
185
186 // overlapping vertical ellipses to mimic the spherical stack
187 const offsets = [-72,-58,-44,-30,-16,0,16,30,44,58,72];
188 offsets.forEach((ox, i) => {
189 const e = document.createElementNS(svgNS, "ellipse");
190 e.setAttribute("cx", cx + ox);
191 e.setAttribute("cy", cy);
192 e.setAttribute("rx", 78);
193 e.setAttribute("ry", 118);
194 e.setAttribute("class", colors[i % colors.length]);
195 rings.appendChild(e);
196 });
197
198 // a few inner rings visible during the sweep
199 [
200 {x:cx-58, rx:42, ry:74, c:"c1"},
201 {x:cx-8, rx:52, ry:92, c:"c3"},
202 {x:cx+42, rx:38, ry:62, c:"c1"}
203 ].forEach(o=>{
204 const e = document.createElementNS(svgNS, "ellipse");
205 e.setAttribute("cx", o.x);
206 e.setAttribute("cy", cy);
207 e.setAttribute("rx", o.rx);
208 e.setAttribute("ry", o.ry);
209 e.setAttribute("class", o.c);
210 rings.appendChild(e);
211 });
212
213 // tiny center dot ring
214 const dot = document.createElementNS(svgNS, "ellipse");
215 dot.setAttribute("cx", cx - 42);
216 dot.setAttribute("cy", cy);
217 dot.setAttribute("rx", 10);
218 dot.setAttribute("ry", 14);
219 dot.setAttribute("class", "dot cyan");
220 rings.appendChild(dot);
221
222 // --- Split phase: left purple cluster
223 const splitLeft = document.getElementById("splitLeft");
224 [
225 {cx:220, cy:300, rx:58, ry:82, c:"c3"},
226 {cx:232, cy:300, rx:42, ry:64, c:"c2"},
227 {cx:244, cy:300, rx:28, ry:42, c:"c3"}
228 ].forEach(o=>{
229 const e = document.createElementNS(svgNS, "ellipse");
230 e.setAttribute("cx", o.cx);
231 e.setAttribute("cy", o.cy);
232 e.setAttribute("rx", o.rx);
233 e.setAttribute("ry", o.ry);
234 e.setAttribute("class", o.c);
235 splitLeft.appendChild(e);
236 });
237
238 // --- Split phase: right cyan cluster
239 const splitRight = document.getElementById("splitRight");
240 [
241 {cx:392, cy:300, rx:54, ry:76, c:"c1"},
242 {cx:382, cy:300, rx:38, ry:56, c:"c1"},
243 {cx:372, cy:300, rx:22, ry:34, c:"c1"}
244 ].forEach(o=>{
245 const e = document.createElementNS(svgNS, "ellipse");
246 e.setAttribute("cx", o.cx);
247 e.setAttribute("cy", o.cy);
248 e.setAttribute("rx", o.rx);
249 e.setAttribute("ry", o.ry);
250 e.setAttribute("class", o.c);
251 splitRight.appendChild(e);
252 });
253
254 // small isolated ring appearing before the split
255 const lone = document.createElementNS(svgNS, "ellipse");
256 lone.setAttribute("cx", 190);
257 lone.setAttribute("cy", 300);
258 lone.setAttribute("rx", 22);
259 lone.setAttribute("ry", 34);
260 lone.setAttribute("class", "dot violet");
261 lone.style.animation = "split var(--dur) linear infinite";
262 lone.style.animationDelay = "-0.22s";
263 splitLeft.appendChild(lone);
264})();
265</script>
266</body>
267</html>