← back to Thinking about SVG-preloaderscompare with ground truth →
model output
Claude Sonnet 4.6
Thinking about SVG-preloaders
A 0.77T 0.21
1<!DOCTYPE html>
2<html>
3<head>
4<style>
5 * { margin: 0; padding: 0; box-sizing: border-box; }
6 body {
7 background: #0a0a0a;
8 display: flex;
9 justify-content: center;
10 align-items: center;
11 width: 100vw;
12 height: 100vh;
13 overflow: hidden;
14 }
15 canvas {
16 display: block;
17 }
18</style>
19</head>
20<body>
21<canvas id="c"></canvas>
22<script>
23const canvas = document.getElementById('c');
24const ctx = canvas.getContext('2d');
25canvas.width = window.innerWidth;
26canvas.height = window.innerHeight;
27
28const cx = canvas.width / 2;
29const cy = canvas.height / 2;
30
31const NUM_DOTS = 12;
32const RADIUS = 38; // orbit radius
33const DOT_SIZE_MAX = 10;
34const DOT_SIZE_MIN = 5;
35const SPEED = 0.8; // rotations per second (radians per ms)
36
37// The "snake" spans about 200 degrees
38// Head is bright yellow, tail fades to dark red
39// Head dots are hollow (ring), tail dots are filled
40
41function getColor(t) {
42 // t=0 is head (yellow), t=1 is tail (dark red)
43 const r = Math.round(255 * (1 - t * 0.3));
44 const g = Math.round(200 * (1 - t));
45 const b = 0;
46 return `rgb(${r},${g},${b})`;
47}
48
49function getAlpha(t) {
50 return 1.0 - t * 0.5;
51}
52
53function getDotSize(t) {
54 // head is smaller (ring), tail is larger (filled)
55 return DOT_SIZE_MIN + (DOT_SIZE_MAX - DOT_SIZE_MIN) * t;
56}
57
58let startTime = null;
59const ANGULAR_SPAN = (200 * Math.PI) / 180; // span of the snake in radians
60const ANGULAR_SPEED = (2 * Math.PI) / 2000; // full rotation in 2 seconds
61
62function draw(timestamp) {
63 if (!startTime) startTime = timestamp;
64 const elapsed = timestamp - startTime;
65
66 ctx.clearRect(0, 0, canvas.width, canvas.height);
67
68 // Head angle advances over time
69 const headAngle = (elapsed * ANGULAR_SPEED) % (2 * Math.PI);
70
71 for (let i = 0; i < NUM_DOTS; i++) {
72 const t = i / (NUM_DOTS - 1); // 0=head, 1=tail
73 // tail is behind head
74 const angle = headAngle - t * ANGULAR_SPAN;
75
76 const x = cx + Math.cos(angle) * RADIUS;
77 const y = cy + Math.sin(angle) * RADIUS;
78
79 const size = getDotSize(t);
80 const color = getColor(t);
81 const alpha = getAlpha(t);
82
83 ctx.save();
84 ctx.globalAlpha = alpha;
85
86 if (t < 0.25) {
87 // Head dots: hollow rings
88 ctx.beginPath();
89 ctx.arc(x, y, size, 0, Math.PI * 2);
90 ctx.strokeStyle = color;
91 ctx.lineWidth = 2;
92 ctx.stroke();
93 } else {
94 // Tail dots: filled circles
95 ctx.beginPath();
96 ctx.arc(x, y, size, 0, Math.PI * 2);
97 ctx.fillStyle = color;
98 ctx.fill();
99 }
100
101 ctx.restore();
102 }
103
104 requestAnimationFrame(draw);
105}
106
107requestAnimationFrame(draw);
108</script>
109</body>
110</html>