← back to Loaders (WIP)compare with ground truth →
model output
Gemini 3 Flash Preview
Loaders (WIP)
A 0.84T 0.43
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>Square Loader Animation</title>
7 <style>
8 /* Define a custom property for the angle so we can animate it precisely */
9 @property --angle {
10 syntax: '<angle>';
11 initial-value: 0deg;
12 inherits: true;
13 }
14
15 :root {
16 --bg-color: #e74c3c;
17 --square-color: #ffffff;
18 --square-size: 44px;
19 --dot-size: 7px;
20 --orbit-radius: 34px;
21 --cycle-duration: 2s; /* Time for one full rotation */
22 }
23
24 * {
25 box-sizing: border-box;
26 }
27
28 body {
29 margin: 0;
30 padding: 0;
31 height: 100vh;
32 display: flex;
33 align-items: center;
34 justify-content: center;
35 background-color: var(--bg-color);
36 overflow: hidden;
37 }
38
39 /* Container for the loader elements */
40 .loader {
41 position: relative;
42 width: var(--square-size);
43 height: var(--square-size);
44 /* This animation updates the --angle variable used by children */
45 animation: angle-anim var(--cycle-duration) linear infinite;
46 }
47
48 /* The faint background square */
49 .square-faint {
50 position: absolute;
51 inset: 0;
52 background-color: var(--square-color);
53 opacity: 0.2;
54 }
55
56 /* The solid white square that gets revealed/hidden */
57 .square-solid {
58 position: absolute;
59 inset: 0;
60 background-color: var(--square-color);
61 /* Use conic-gradient with the animated --angle variable */
62 -webkit-mask-image: conic-gradient(white var(--angle), transparent 0deg);
63 mask-image: conic-gradient(white var(--angle), transparent 0deg);
64 /*
65 Logic Flip:
66 Every 2 seconds (one rotation), we toggle between "fill" and "erase" modes.
67 Total duration is 4 seconds (double the rotation duration).
68 */
69 animation: mask-logic calc(var(--cycle-duration) * 2) step-end infinite;
70 }
71
72 /* The rotating dot circle */
73 .dot {
74 position: absolute;
75 width: var(--dot-size);
76 height: var(--dot-size);
77 background-color: var(--square-color);
78 border-radius: 50%;
79 top: 50%;
80 left: 50%;
81 /*
82 Order of transform:
83 1. Center dot relative to container
84 2. Rotate the coordinate system by --angle
85 3. Move "up" by orbit-radius to place it on the circle edge
86 */
87 transform: translate(-50%, -50%) rotate(var(--angle)) translateY(calc(-1 * var(--orbit-radius)));
88 z-index: 10;
89 }
90
91 /* Animate the variable from 0 to 360 degrees */
92 @keyframes angle-anim {
93 from { --angle: 0deg; }
94 to { --angle: 360deg; }
95 }
96
97 /* Toggle the mask direction every full rotation */
98 @keyframes mask-logic {
99 0% {
100 -webkit-mask-image: conic-gradient(white var(--angle), transparent 0deg);
101 mask-image: conic-gradient(white var(--angle), transparent 0deg);
102 }
103 50% {
104 /* Erase mode: Show everything except the segment between 0 and current angle */
105 -webkit-mask-image: conic-gradient(transparent var(--angle), white 0deg);
106 mask-image: conic-gradient(transparent var(--angle), white 0deg);
107 }
108 }
109 </style>
110</head>
111<body>
112
113 <div class="loader">
114 <div class="square-faint"></div>
115 <div class="square-solid"></div>
116 <div class="dot"></div>
117 </div>
118
119 <script>
120 /**
121 * Fallback for browsers that do not support CSS @property (e.g. Firefox).
122 * This JS updates the --angle variable manually to ensure cross-browser compatibility.
123 */
124 if (!window.CSS || !CSS.registerProperty) {
125 const loader = document.querySelector('.loader');
126 let start = null;
127
128 function step(timestamp) {
129 if (!start) start = timestamp;
130 const progress = timestamp - start;
131
132 // Calculate angle (360 degrees every 2 seconds)
133 const angle = ((progress % 2000) / 2000) * 360;
134 loader.style.setProperty('--angle', `${angle}deg`);
135
136 requestAnimationFrame(step);
137 }
138 requestAnimationFrame(step);
139 }
140 </script>
141</body>
142</html>