← back to Wavy Loading Animationscompare with ground truth →
model output
GPT-5.4
Wavy Loading Animations
A 0.92T 0.30
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>Concentric Pulse</title>
7<style>
8 :root{
9 --bg:#f5f5f5;
10 --stroke:rgba(120,120,120,.34);
11 --stroke-soft:rgba(120,120,120,.18);
12 --dot:rgba(120,120,120,.42);
13 --dur:2.4s;
14 }
15
16 html,body{
17 margin:0;
18 width:100%;
19 height:100%;
20 overflow:hidden;
21 background:var(--bg);
22 font-family:sans-serif;
23 }
24
25 .stage{
26 position:relative;
27 width:100vw;
28 height:100vh;
29 background:var(--bg);
30 }
31
32 /* Slightly above center, matching the frames */
33 .cluster{
34 position:absolute;
35 left:50%;
36 top:22%;
37 width:120px;
38 height:120px;
39 transform:translate(-50%,-50%);
40 }
41
42 .ring{
43 position:absolute;
44 left:50%;
45 top:50%;
46 border:1px solid var(--stroke);
47 border-radius:50%;
48 transform:translate(-50%,-50%) scale(0.12);
49 opacity:0;
50 animation:pulse var(--dur) linear infinite;
51 box-sizing:border-box;
52 }
53
54 .ring.r1{ width:18px; height:18px; animation-delay:0s; }
55 .ring.r2{ width:28px; height:28px; animation-delay:.12s; }
56 .ring.r3{ width:40px; height:40px; animation-delay:.24s; }
57 .ring.r4{ width:54px; height:54px; animation-delay:.36s; }
58 .ring.r5{ width:70px; height:70px; animation-delay:.48s; }
59
60 .core{
61 position:absolute;
62 left:50%;
63 top:50%;
64 width:4px;
65 height:4px;
66 transform:translate(-50%,-50%);
67 border-radius:50%;
68 background:transparent;
69 border:1px solid var(--dot);
70 box-sizing:border-box;
71 animation:corePulse var(--dur) linear infinite;
72 }
73
74 .core::after{
75 content:"";
76 position:absolute;
77 inset:1px;
78 border-radius:50%;
79 background:rgba(120,120,120,.18);
80 }
81
82 @keyframes pulse{
83 0%{
84 transform:translate(-50%,-50%) scale(0.12);
85 opacity:0;
86 border-color:var(--stroke-soft);
87 }
88 10%{
89 opacity:.9;
90 }
91 35%{
92 opacity:.75;
93 }
94 65%{
95 opacity:.45;
96 }
97 100%{
98 transform:translate(-50%,-50%) scale(1);
99 opacity:0;
100 border-color:var(--stroke-soft);
101 }
102 }
103
104 @keyframes corePulse{
105 0%,100%{
106 transform:translate(-50%,-50%) scale(.9);
107 opacity:.7;
108 }
109 50%{
110 transform:translate(-50%,-50%) scale(1.08);
111 opacity:.95;
112 }
113 }
114</style>
115</head>
116<body>
117 <div class="stage">
118 <div class="cluster" aria-hidden="true">
119 <div class="ring r5"></div>
120 <div class="ring r4"></div>
121 <div class="ring r3"></div>
122 <div class="ring r2"></div>
123 <div class="ring r1"></div>
124 <div class="core"></div>
125 </div>
126 </div>
127
128<script>
129 // Keep the animation phase aligned on load for a clean looping pulse.
130 const rings = [...document.querySelectorAll('.ring')];
131 const dur = 2400;
132 const start = performance.now();
133
134 function sync(now){
135 const t = (now - start) % dur;
136 rings.forEach((ring, i) => {
137 const delay = i * 120;
138 ring.style.animationDelay = `${-(t + delay)}ms`;
139 });
140 requestAnimationFrame(sync);
141 }
142 requestAnimationFrame(sync);
143</script>
144</body>
145</html>