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>Radial Light Streaks</title>
7<style>
8 :root{
9 --bg1:#070c18;
10 --bg2:#08111f;
11 --bg3:#09182a;
12 }
13 html,body{
14 margin:0;
15 width:100%;
16 height:100%;
17 overflow:hidden;
18 background:
19 radial-gradient(120vmax 120vmax at 50% 58%, #0a1a2d 0%, #08111f 34%, #060b16 72%, #04070f 100%);
20 }
21 canvas{
22 display:block;
23 width:100vw;
24 height:100vh;
25 filter: saturate(1.08) blur(.15px);
26 }
27</style>
28</head>
29<body>
30<canvas id="c"></canvas>
31<script>
32(() => {
33 const canvas = document.getElementById('c');
34 const ctx = canvas.getContext('2d');
35 let w = 0, h = 0, dpr = Math.min(devicePixelRatio || 1, 2);
36 let cx = 0, cy = 0, minDim = 0;
37
38 const TAU = Math.PI * 2;
39 const rand = (a,b)=>a + Math.random()*(b-a);
40
41 const palette = [
42 [255,255,255],
43 [72,185,255],
44 [39,240,236]
45 ];
46
47 const core = [];
48 const outer = [];
49
50 function resize(){
51 w = innerWidth;
52 h = innerHeight;
53 dpr = Math.min(devicePixelRatio || 1, 2);
54 canvas.width = Math.round(w * dpr);
55 canvas.height = Math.round(h * dpr);
56 canvas.style.width = w + 'px';
57 canvas.style.height = h + 'px';
58 ctx.setTransform(dpr,0,0,dpr,0,0);
59 cx = w * 0.5;
60 cy = h * 0.52;
61 minDim = Math.min(w,h);
62 }
63
64 function makeParticle(group){
65 const isCore = group === 'core';
66 const color = palette[(Math.random()*palette.length)|0];
67 return {
68 group,
69 angle: rand(0, TAU),
70 rotSpeed: rand(-0.45, 0.45) * (isCore ? 1.2 : 0.35),
71 radius: isCore ? rand(8, 42) : rand(minDim*0.28, minDim*0.78),
72 speed: isCore ? rand(18, 55) : rand(55, 120),
73 len: isCore ? rand(minDim*0.06, minDim*0.16) : rand(minDim*0.08, minDim*0.18),
74 thick: isCore ? rand(8, 14) : rand(8, 12),
75 alpha: isCore ? rand(0.65, 0.95) : rand(0.55, 0.9),
76 color,
77 phase: rand(0, TAU),
78 pulse: rand(0.6, 1.4),
79 drift: rand(-18, 18),
80 blur: isCore ? rand(8, 16) : rand(6, 12)
81 };
82 }
83
84 function init(){
85 core.length = 0;
86 outer.length = 0;
87 for(let i=0;i<28;i++) core.push(makeParticle('core'));
88 for(let i=0;i<34;i++) outer.push(makeParticle('outer'));
89 }
90
91 function resetOuter(p){
92 p.angle = rand(0, TAU);
93 p.radius = rand(minDim*0.26, minDim*0.42);
94 p.speed = rand(55, 120);
95 p.len = rand(minDim*0.08, minDim*0.18);
96 p.thick = rand(8, 12);
97 p.alpha = rand(0.55, 0.9);
98 p.color = palette[(Math.random()*palette.length)|0];
99 p.phase = rand(0, TAU);
100 p.pulse = rand(0.6, 1.4);
101 p.rotSpeed = rand(-0.18, 0.18);
102 p.blur = rand(6, 12);
103 }
104
105 function resetCore(p){
106 p.angle = rand(0, TAU);
107 p.radius = rand(8, 26);
108 p.speed = rand(18, 55);
109 p.len = rand(minDim*0.06, minDim*0.16);
110 p.thick = rand(8, 14);
111 p.alpha = rand(0.65, 0.95);
112 p.color = palette[(Math.random()*palette.length)|0];
113 p.phase = rand(0, TAU);
114 p.pulse = rand(0.6, 1.4);
115 p.rotSpeed = rand(-0.45, 0.45);
116 p.blur = rand(8, 16);
117 }
118
119 function drawStreak(x, y, angle, len, thick, rgb, alpha, blur){
120 ctx.save();
121 ctx.translate(x, y);
122 ctx.rotate(angle);
123 ctx.shadowBlur = blur;
124 ctx.shadowColor = `rgba(${rgb[0]},${rgb[1]},${rgb[2]},${alpha*0.9})`;
125
126 const g = ctx.createLinearGradient(0, 0, len, 0);
127 g.addColorStop(0.00, `rgba(${rgb[0]},${rgb[1]},${rgb[2]},${alpha})`);
128 g.addColorStop(0.18, `rgba(${rgb[0]},${rgb[1]},${rgb[2]},${alpha*0.95})`);
129 g.addColorStop(0.72, `rgba(${rgb[0]},${rgb[1]},${rgb[2]},${alpha*0.18})`);
130 g.addColorStop(1.00, `rgba(${rgb[0]},${rgb[1]},${rgb[2]},0)`);
131
132 ctx.strokeStyle = g;
133 ctx.lineWidth = thick;
134 ctx.lineCap = 'round';
135 ctx.beginPath();
136 ctx.moveTo(0,0);
137 ctx.lineTo(len,0);
138 ctx.stroke();
139 ctx.restore();
140 }
141
142 let last = performance.now();
143 function frame(now){
144 const dt = Math.min(0.033, (now - last) / 1000);
145 last = now;
146
147 ctx.clearRect(0,0,w,h);
148
149 // soft vignette / depth
150 const bg = ctx.createRadialGradient(cx, cy, 0, cx, cy, Math.max(w,h)*0.8);
151 bg.addColorStop(0, 'rgba(8,20,34,0.10)');
152 bg.addColorStop(0.55, 'rgba(5,10,20,0.08)');
153 bg.addColorStop(1, 'rgba(0,0,0,0.18)');
154 ctx.fillStyle = bg;
155 ctx.fillRect(0,0,w,h);
156
157 // outer ring
158 for(const p of outer){
159 p.angle += p.rotSpeed * dt;
160 p.radius += p.speed * dt;
161 if (p.radius > minDim * 0.95) resetOuter(p);
162
163 const pulse = 0.88 + 0.22 * Math.sin(now*0.0018*p.pulse + p.phase);
164 const x = cx + Math.cos(p.angle) * p.radius;
165 const y = cy + Math.sin(p.angle) * p.radius;
166 drawStreak(
167 x, y,
168 p.angle,
169 p.len * pulse,
170 p.thick,
171 p.color,
172 p.alpha * pulse,
173 p.blur
174 );
175 }
176
177 // central burst
178 for(const p of core){
179 p.angle += p.rotSpeed * dt;
180 p.radius += p.speed * dt * 0.35;
181 if (p.radius > minDim * 0.18) resetCore(p);
182
183 const pulse = 0.82 + 0.35 * Math.sin(now*0.003*p.pulse + p.phase);
184 const x = cx + Math.cos(p.angle) * p.radius;
185 const y = cy + Math.sin(p.angle) * p.radius;
186 drawStreak(
187 x, y,
188 p.angle,
189 p.len * pulse,
190 p.thick,
191 p.color,
192 p.alpha * pulse,
193 p.blur
194 );
195 }
196
197 // glowing center
198 ctx.save();
199 ctx.globalCompositeOperation = 'screen';
200 let cg = ctx.createRadialGradient(cx, cy, 0, cx, cy, minDim*0.06);
201 cg.addColorStop(0, 'rgba(255,255,255,0.95)');
202 cg.addColorStop(0.12, 'rgba(120,220,255,0.85)');
203 cg.addColorStop(0.35, 'rgba(50,235,240,0.35)');
204 cg.addColorStop(1, 'rgba(50,235,240,0)');
205 ctx.fillStyle = cg;
206 ctx.beginPath();
207 ctx.arc(cx, cy, minDim*0.06, 0, TAU);
208 ctx.fill();
209 ctx.restore();
210
211 requestAnimationFrame(frame);
212 }
213
214 addEventListener('resize', () => {
215 resize();
216 init();
217 });
218
219 resize();
220 init();
221 requestAnimationFrame(t => { last = t; frame(t); });
222})();
223</script>
224</body>
225</html>