← back to flat loading animatecompare with ground truth →
model output
Gemini 3 Flash Preview
flat loading animate
A 0.86T 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>Semicircle Loading Spinner</title>
7 <style>
8 :root {
9 --teal: #1abc9c;
10 --orange: #ffb369;
11 --bg-color: #ffffff;
12 --size: 80px;
13 }
14
15 body {
16 margin: 0;
17 padding: 0;
18 height: 100vh;
19 display: flex;
20 justify-content: center;
21 align-items: center;
22 background-color: var(--bg-color);
23 }
24
25 .loader-container {
26 position: relative;
27 width: var(--size);
28 height: var(--size);
29 }
30
31 .spinner {
32 width: 100%;
33 height: 100%;
34 border-radius: 50%;
35 /* The gradient is updated via JavaScript to achieve precise timing of the filling effect */
36 background: conic-gradient(var(--teal) 180deg, var(--orange) 0deg);
37 /*
38 The rotation is 360deg every 2 seconds, which matches
39 the 90deg vertical shift every 0.5s seen in the frames.
40 */
41 animation: rotate-ccw 2s linear infinite;
42 }
43
44 @keyframes rotate-ccw {
45 from {
46 transform: rotate(0deg);
47 }
48 to {
49 transform: rotate(-360deg);
50 }
51 }
52 </style>
53</head>
54<body>
55
56 <div class="loader-container">
57 <div id="spinner" class="spinner"></div>
58 </div>
59
60 <script>
61 const spinner = document.getElementById('spinner');
62 const teal = getComputedStyle(document.documentElement).getPropertyValue('--teal').trim();
63 const orange = getComputedStyle(document.documentElement).getPropertyValue('--orange').trim();
64
65 /**
66 * The animation logic:
67 * Total cycle: 3 seconds
68 * 0.0s: 180deg (Half/Half)
69 * 1.0s: 360deg (Full Teal)
70 * 1.5s: 180deg (Half/Half)
71 * 2.5s: 0deg (Full Orange)
72 * 3.0s: 180deg (Back to start)
73 */
74 function updateGradient(timestamp) {
75 if (!this.startTime) this.startTime = timestamp;
76 const elapsed = (timestamp - this.startTime) % 3000;
77 let arc = 180;
78
79 if (elapsed < 1000) {
80 // 0 to 1s: 180 to 360
81 arc = 180 + (elapsed / 1000) * 180;
82 } else if (elapsed < 1500) {
83 // 1s to 1.5s: 360 to 180
84 arc = 360 - ((elapsed - 1000) / 500) * 180;
85 } else if (elapsed < 2500) {
86 // 1.5s to 2.5s: 180 to 0
87 arc = 180 - ((elapsed - 1500) / 1000) * 180;
88 } else {
89 // 2.5s to 3s: 0 to 180
90 arc = ((elapsed - 2500) / 500) * 180;
91 }
92
93 // Apply the calculated arc length to the conic-gradient
94 // 0deg ensures the orange fills the rest of the circle cleanly
95 spinner.style.background = `conic-gradient(${teal} ${arc}deg, ${orange} 0deg)`;
96
97 requestAnimationFrame(updateGradient);
98 }
99
100 requestAnimationFrame(updateGradient);
101 </script>
102</body>
103</html>