← back to Only CSS: Pulse Boxcompare with ground truth →
model output
GPT-5.4
Only CSS: Pulse Box
A 0.65T 0.29
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" />
6<title>Neon Wireframe Drift</title>
7<style>
8 html, body {
9 margin: 0;
10 width: 100%;
11 height: 100%;
12 overflow: hidden;
13 background: #000;
14 }
15 canvas {
16 display: block;
17 width: 100%;
18 height: 100%;
19 background: #000;
20 }
21</style>
22</head>
23<body>
24<canvas id="c"></canvas>
25<script>
26(() => {
27 const canvas = document.getElementById('c');
28 const ctx = canvas.getContext('2d');
29
30 let w = 0, h = 0, dpr = Math.min(devicePixelRatio || 1, 2);
31
32 function resize() {
33 w = innerWidth;
34 h = innerHeight;
35 canvas.width = Math.round(w * dpr);
36 canvas.height = Math.round(h * dpr);
37 canvas.style.width = w + 'px';
38 canvas.style.height = h + 'px';
39 ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
40 }
41 addEventListener('resize', resize);
42 resize();
43
44 const FOV = 700;
45 const SPEED = 260; // forward camera speed
46 const SPAWN_AHEAD = 4200;
47 const DESPAWN_BEHIND = -300;
48 const COUNT = 54;
49 const COLORS = [
50 [0, 255, 120], // green
51 [0, 235, 255], // cyan
52 [0, 40, 255] // blue
53 ];
54
55 function rand(a, b) { return a + Math.random() * (b - a); }
56 function randi(a, b) { return (a + Math.floor(Math.random() * (b - a + 1))); }
57
58 const shapes = [];
59
60 function makeShape(zBase = rand(300, SPAWN_AHEAD)) {
61 const size = rand(70, 420);
62 const aspect = rand(0.55, 1.8);
63 const ww = size * aspect;
64 const hh = size;
65 const x = rand(-w * 0.9, w * 0.9);
66 const y = rand(-h * 0.9, h * 0.9);
67 const rot = rand(-Math.PI, Math.PI);
68 const tilt = rand(-0.9, 0.9);
69 const spin = rand(-0.18, 0.18);
70 const driftX = rand(-18, 18);
71 const driftY = rand(-18, 18);
72 const stroke = rand(1.2, 3.8);
73 const colorA = COLORS[randi(0, COLORS.length - 1)];
74 const colorB = COLORS[randi(0, COLORS.length - 1)];
75 const alpha = rand(0.65, 1);
76
77 // Mostly open rectangles / bent quads like the reference
78 const mode = Math.random();
79 let pts;
80 if (mode < 0.18) {
81 pts = [
82 [-ww/2, -hh/2], [ww/2, -hh/2], [ww/2, hh/2], [-ww/2, hh/2]
83 ];
84 } else if (mode < 0.55) {
85 pts = [
86 [-ww/2, -hh/2], [ww/2, -hh/2], [-ww/2, hh/2]
87 ];
88 } else {
89 const skew = rand(-ww * 0.35, ww * 0.35);
90 pts = [
91 [-ww/2, -hh/2], [ww/2, -hh/2], [ww/2 + skew * 0.35, hh/2], [-ww/2 + skew, hh/2]
92 ];
93 }
94
95 return {
96 x, y, z: zBase,
97 w: ww, h: hh,
98 rot, tilt, spin,
99 driftX, driftY,
100 stroke, colorA, colorB, alpha,
101 pts,
102 pulse: rand(0, Math.PI * 2),
103 pulseSpeed: rand(0.4, 1.2)
104 };
105 }
106
107 for (let i = 0; i < COUNT; i++) shapes.push(makeShape(rand(200, SPAWN_AHEAD)));
108
109 function project(px, py, pz) {
110 const s = FOV / Math.max(40, pz);
111 return [w * 0.5 + px * s, h * 0.5 + py * s, s];
112 }
113
114 let last = performance.now();
115 let t = 0;
116
117 function drawShape(s, dt) {
118 s.z -= SPEED * dt;
119 s.rot += s.spin * dt;
120 s.x += s.driftX * dt;
121 s.y += s.driftY * dt;
122
123 if (s.z < DESPAWN_BEHIND || Math.abs(s.x) > w * 1.8 || Math.abs(s.y) > h * 1.8) {
124 Object.assign(s, makeShape(SPAWN_AHEAD + rand(0, 1200)));
125 return;
126 }
127
128 const cos = Math.cos(s.rot), sin = Math.sin(s.rot);
129 const pulse = 1 + 0.06 * Math.sin(t * s.pulseSpeed + s.pulse);
130
131 const pts2d = [];
132 for (let i = 0; i < s.pts.length; i++) {
133 let [lx, ly] = s.pts[i];
134 lx *= pulse;
135 ly *= pulse;
136
137 const rx = lx * cos - ly * sin;
138 const ry = lx * sin + ly * cos;
139
140 // fake 3D plane tilt by offsetting z with local y
141 const pz = s.z + ry * s.tilt * 0.9;
142 const [sx, sy, sc] = project(s.x + rx, s.y + ry, pz);
143 pts2d.push([sx, sy, sc]);
144 }
145
146 // subtle trailing ghost
147 ctx.beginPath();
148 for (let i = 0; i < pts2d.length; i++) {
149 const p = pts2d[i];
150 const gx = p[0] - s.driftX * 0.08 - Math.cos(s.rot) * 8;
151 const gy = p[1] - s.driftY * 0.08 + Math.sin(s.rot) * 8;
152 if (i === 0) ctx.moveTo(gx, gy);
153 else ctx.lineTo(gx, gy);
154 }
155 if (s.pts.length === 4 && Math.random() < 0.45) ctx.closePath();
156 ctx.strokeStyle = `rgba(${s.colorA[0]},${s.colorA[1]},${s.colorA[2]},${0.08 * s.alpha})`;
157 ctx.lineWidth = Math.max(0.6, s.stroke * (FOV / Math.max(200, s.z)) * 0.7);
158 ctx.stroke();
159
160 // main stroke with gradient along shape bounds
161 let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
162 for (const p of pts2d) {
163 if (p[0] < minX) minX = p[0];
164 if (p[1] < minY) minY = p[1];
165 if (p[0] > maxX) maxX = p[0];
166 if (p[1] > maxY) maxY = p[1];
167 }
168
169 const grad = ctx.createLinearGradient(minX, minY, maxX, maxY);
170 grad.addColorStop(0, `rgba(${s.colorA[0]},${s.colorA[1]},${s.colorA[2]},${0.95 * s.alpha})`);
171 grad.addColorStop(1, `rgba(${s.colorB[0]},${s.colorB[1]},${s.colorB[2]},${0.95 * s.alpha})`);
172
173 ctx.beginPath();
174 for (let i = 0; i < pts2d.length; i++) {
175 const p = pts2d[i];
176 if (i === 0) ctx.moveTo(p[0], p[1]);
177 else ctx.lineTo(p[0], p[1]);
178 }
179 if (s.pts.length === 4 && Math.random() < 0.35) ctx.closePath();
180
181 const lw = Math.max(0.8, s.stroke * (FOV / Math.max(180, s.z)));
182 ctx.strokeStyle = grad;
183 ctx.lineWidth = lw;
184 ctx.stroke();
185
186 // occasional inner segment like the source frames
187 if (Math.random() < 0.18 && pts2d.length >= 3) {
188 const a = pts2d[0], b = pts2d[2];
189 ctx.beginPath();
190 ctx.moveTo(a[0] * 0.65 + b[0] * 0.35, a[1] * 0.65 + b[1] * 0.35);
191 ctx.lineTo(a[0] * 0.35 + b[0] * 0.65, a[1] * 0.35 + b[1] * 0.65);
192 ctx.strokeStyle = `rgba(${s.colorB[0]},${s.colorB[1]},${s.colorB[2]},${0.35 * s.alpha})`;
193 ctx.lineWidth = lw * 0.55;
194 ctx.stroke();
195 }
196 }
197
198 function frame(now) {
199 const dt = Math.min(0.033, (now - last) / 1000);
200 last = now;
201 t += dt;
202
203 ctx.clearRect(0, 0, w, h);
204 ctx.fillStyle = '#000';
205 ctx.fillRect(0, 0, w, h);
206
207 // slight persistence / glow feel
208 ctx.globalCompositeOperation = 'lighter';
209
210 shapes.sort((a, b) => b.z - a.z);
211 for (const s of shapes) drawShape(s, dt);
212
213 ctx.globalCompositeOperation = 'source-over';
214 requestAnimationFrame(frame);
215 }
216
217 requestAnimationFrame(frame);
218})();
219</script>
220</body>
221</html>