← back to flat loading animatecompare with ground truth →
model output
GPT-5.4
flat loading animate
A 0.76T 0.25
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>Minimal Morphing Loader</title>
7<style>
8 :root{
9 --bg:#ffffff;
10 --orange:#ffb35c;
11 --teal:#16b3a8;
12 --slate:#3b5564;
13 --coral:#ff5757;
14 --size:100px;
15 --dur:2.4s;
16 }
17
18 html,body{
19 margin:0;
20 width:100%;
21 height:100%;
22 background:var(--bg);
23 overflow:hidden;
24 }
25
26 body{
27 display:grid;
28 place-items:center;
29 }
30
31 .loader{
32 position:relative;
33 width:var(--size);
34 height:var(--size);
35 }
36
37 .shape{
38 position:absolute;
39 inset:0;
40 transform-origin:50% 50%;
41 animation: morph var(--dur) linear infinite;
42 }
43
44 .shape::before,
45 .shape::after{
46 content:"";
47 position:absolute;
48 inset:0;
49 border-radius:50%;
50 }
51
52 /* base orange circle */
53 .shape::before{
54 background:var(--orange);
55 animation: baseMask var(--dur) linear infinite;
56 }
57
58 /* overlay color that changes and clips */
59 .shape::after{
60 background:var(--teal);
61 animation:
62 overlayMask var(--dur) linear infinite,
63 overlayColor var(--dur) linear infinite;
64 }
65
66 @keyframes morph{
67 /* circle */
68 0%, 8%{
69 transform:rotate(0deg) scale(1);
70 }
71
72 /* right-facing semicircle */
73 16%, 28%{
74 transform:rotate(0deg) scale(1);
75 }
76
77 /* rotate to bottom-facing semicircle */
78 40%, 52%{
79 transform:rotate(90deg) scale(1);
80 }
81
82 /* squash back into circle */
83 60%{
84 transform:rotate(90deg) scaleX(.92) scaleY(.92);
85 }
86
87 68%, 100%{
88 transform:rotate(0deg) scale(1);
89 }
90 }
91
92 @keyframes baseMask{
93 /* full orange circle */
94 0%, 10%{
95 clip-path:inset(0 round 50%);
96 opacity:1;
97 }
98
99 /* orange left crescent while teal covers right half */
100 16%, 22%{
101 clip-path:inset(0 38% 0 0 round 50%);
102 opacity:1;
103 }
104
105 /* orange disappears */
106 28%, 56%{
107 clip-path:inset(0 100% 0 0 round 50%);
108 opacity:0;
109 }
110
111 /* coral bottom semicircle phase handled by overlay only */
112 60%, 64%{
113 clip-path:inset(0 100% 0 0 round 50%);
114 opacity:0;
115 }
116
117 /* orange blob reforms */
118 72%{
119 clip-path:inset(8% 10% 6% 10% round 46% 54% 52% 48%);
120 opacity:1;
121 }
122
123 82%, 100%{
124 clip-path:inset(0 round 50%);
125 opacity:1;
126 }
127 }
128
129 @keyframes overlayMask{
130 /* hidden at start */
131 0%, 10%{
132 clip-path:inset(0 100% 0 0 round 50%);
133 opacity:1;
134 }
135
136 /* teal right semicircle */
137 16%, 32%{
138 clip-path:inset(0 0 0 50% round 50%);
139 opacity:1;
140 }
141
142 /* dark slate top semicircle after rotation */
143 40%, 52%{
144 clip-path:inset(0 0 50% 0 round 50%);
145 opacity:1;
146 }
147
148 /* coral bottom semicircle */
149 60%, 68%{
150 clip-path:inset(50% 0 0 0 round 50%);
151 opacity:1;
152 }
153
154 /* fade out as orange circle returns */
155 74%, 100%{
156 clip-path:inset(0 100% 0 0 round 50%);
157 opacity:0;
158 }
159 }
160
161 @keyframes overlayColor{
162 0%, 32%{ background:var(--teal); }
163 40%, 56%{ background:var(--slate); }
164 60%, 72%{ background:var(--coral); }
165 74%, 100%{ background:var(--teal); }
166 }
167</style>
168</head>
169<body>
170 <div class="loader" aria-label="loading animation">
171 <div class="shape"></div>
172 </div>
173</body>
174</html>