← back to Spinners using Font Iconscompare with ground truth →
model output
Claude Sonnet 4.6
Spinners using Font Icons
A 0.85T 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.0">
6<title>Loading Animation</title>
7<style>
8 * {
9 margin: 0;
10 padding: 0;
11 box-sizing: border-box;
12 }
13
14 body {
15 background-color: #1a1a1a;
16 display: flex;
17 justify-content: center;
18 align-items: flex-start;
19 height: 100vh;
20 overflow: hidden;
21 }
22
23 .spinner {
24 position: absolute;
25 top: 45px;
26 left: 50%;
27 transform: translateX(-50%);
28 width: 50px;
29 height: 50px;
30 animation: rotate 1s linear infinite;
31 }
32
33 .dot {
34 position: absolute;
35 border-radius: 50%;
36 background: white;
37 transform-origin: center center;
38 }
39
40 @keyframes rotate {
41 from { transform: translateX(-50%) rotate(0deg); }
42 to { transform: translateX(-50%) rotate(360deg); }
43 }
44
45 @keyframes pulse {
46 0%, 100% { opacity: 0.3; width: 3px; height: 3px; }
47 0% { opacity: 1; width: 7px; height: 7px; }
48 }
49</style>
50</head>
51<body>
52<div class="spinner" id="spinner"></div>
53
54<script>
55 const spinner = document.getElementById('spinner');
56 const numDots = 10;
57 const radius = 20;
58 const centerX = 25;
59 const centerY = 25;
60
61 for (let i = 0; i < numDots; i++) {
62 const dot = document.createElement('div');
63 dot.classList.add('dot');
64
65 const angle = (i / numDots) * 2 * Math.PI - Math.PI / 2;
66 const x = centerX + radius * Math.cos(angle);
67 const y = centerY + radius * Math.sin(angle);
68
69 // Size based on position (dots at top are larger - "active" position)
70 const progress = i / numDots;
71 // The "bright" dots are at the top (i=0) and fade going clockwise
72 const size = Math.max(2, 7 * (1 - progress) + 2 * progress);
73 const opacity = Math.max(0.2, 1 - progress * 0.8);
74
75 dot.style.width = size + 'px';
76 dot.style.height = size + 'px';
77 dot.style.left = (x - size / 2) + 'px';
78 dot.style.top = (y - size / 2) + 'px';
79 dot.style.opacity = opacity;
80
81 // Add animation delay for each dot
82 dot.style.animation = `dotFade 1s linear infinite`;
83 dot.style.animationDelay = `${-(i / numDots)}s`;
84
85 spinner.appendChild(dot);
86 }
87
88 // Use canvas-based approach for more accurate rendering
89 const canvas = document.createElement('canvas');
90 canvas.width = 60;
91 canvas.height = 60;
92 canvas.style.position = 'absolute';
93 canvas.style.top = '45px';
94 canvas.style.left = '50%';
95 canvas.style.transform = 'translateX(-50%)';
96 document.body.appendChild(canvas);
97 spinner.remove();
98
99 const ctx = canvas.getContext('2d');
100 let angle = 0;
101
102 function draw() {
103 ctx.clearRect(0, 0, 60, 60);
104 const cx = 30, cy = 30, r = 20;
105 const n = 10;
106
107 for (let i = 0; i < n; i++) {
108 const a = angle + (i / n) * Math.PI * 2 - Math.PI / 2;
109 const x = cx + r * Math.cos(a);
110 const y = cy + r * Math.sin(a);
111
112 // i=0 is the "head" (brightest, largest)
113 const t = i / n;
114 const size = 4.5 * (1 - t) + 1.5 * t;
115 const alpha = 1 - t * 0.85;
116
117 ctx.beginPath();
118 ctx.arc(x, y, size, 0, Math.PI * 2);
119 ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`;
120 ctx.fill();
121 }
122
123 angle += (2 * Math.PI) / 60; // ~1 rotation per second at 60fps
124 requestAnimationFrame(draw);
125 }
126
127 draw();
128</script>
129</body>
130</html>