← back to Only CSS: Sunset Beachcompare with ground truth →
model output
Claude Sonnet 4.6
Only CSS: Sunset Beach
A 0.92T 0.20
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>Red Helmet Animation</title>
7<style>
8 * { margin: 0; padding: 0; box-sizing: border-box; }
9
10 body {
11 background: #000;
12 width: 100vw;
13 height: 100vh;
14 display: flex;
15 align-items: center;
16 justify-content: center;
17 overflow: hidden;
18 }
19
20 .scene {
21 position: relative;
22 width: 1024px;
23 height: 768px;
24 }
25
26 canvas {
27 position: absolute;
28 top: 0;
29 left: 0;
30 }
31</style>
32</head>
33<body>
34<div class="scene">
35 <canvas id="c" width="1024" height="768"></canvas>
36</div>
37
38<script>
39const canvas = document.getElementById('c');
40const ctx = canvas.getContext('2d');
41
42function drawHelmet(t) {
43 ctx.clearRect(0, 0, 1024, 768);
44 ctx.fillStyle = '#000';
45 ctx.fillRect(0, 0, 1024, 768);
46
47 // Subtle breathing/pulsing animation
48 const pulse = Math.sin(t * 0.5) * 2;
49
50 const cx = 512;
51 const cy = 370;
52
53 ctx.fillStyle = '#ff0000';
54 ctx.beginPath();
55
56 // Main helmet dome - semicircle top
57 // Center around (512, 370)
58 // Dome radius ~110px
59 const r = 110 + pulse * 0.3;
60 const domeY = cy - 20;
61
62 // Draw the helmet shape using path
63 ctx.beginPath();
64
65 // Top dome arc
66 ctx.arc(cx, domeY, r, Math.PI, 0, false);
67
68 // Right side going down to brim
69 ctx.lineTo(cx + r + 30, domeY + 30);
70 // Right brim bump
71 ctx.quadraticCurveTo(cx + r + 45, domeY + 45, cx + r + 20, domeY + 55);
72 ctx.quadraticCurveTo(cx + r + 5, domeY + 60, cx + r - 10, domeY + 50);
73
74 // Bottom of brim going left
75 ctx.lineTo(cx - r + 10, domeY + 50);
76
77 // Left brim
78 ctx.quadraticCurveTo(cx - r - 10, domeY + 55, cx - r - 20, domeY + 45);
79 ctx.quadraticCurveTo(cx - r - 35, domeY + 30, cx - r - 10, domeY + 20);
80 ctx.lineTo(cx - r, domeY);
81
82 ctx.closePath();
83 ctx.fill();
84
85 // Chin strap / neck area - connecting piece
86 ctx.beginPath();
87 ctx.moveTo(cx - 10, domeY + 55);
88 ctx.lineTo(cx + 30, domeY + 55);
89 ctx.quadraticCurveTo(cx + 40, domeY + 65, cx + 35, domeY + 75);
90 ctx.lineTo(cx + 20, domeY + 80);
91 ctx.quadraticCurveTo(cx + 10, domeY + 85, cx, domeY + 82);
92 ctx.quadraticCurveTo(cx - 15, domeY + 80, cx - 20, domeY + 70);
93 ctx.quadraticCurveTo(cx - 15, domeY + 60, cx - 10, domeY + 55);
94 ctx.closePath();
95 ctx.fill();
96
97 // Small drip/puddle below
98 ctx.beginPath();
99 ctx.ellipse(cx + 10, domeY + 105, 35, 18, 0.1, 0, Math.PI * 2);
100 ctx.fill();
101}
102
103let startTime = null;
104
105function animate(timestamp) {
106 if (!startTime) startTime = timestamp;
107 const t = (timestamp - startTime) / 1000;
108
109 drawHelmet(t);
110 requestAnimationFrame(animate);
111}
112
113requestAnimationFrame(animate);
114</script>
115</body>
116</html>