asigalov61 commited on
Commit
b780be5
·
verified ·
1 Parent(s): b2b0658

Update stars.js

Browse files
Files changed (1) hide show
  1. stars.js +158 -71
stars.js CHANGED
@@ -1,5 +1,3 @@
1
- // High-Contrast, High-Density Starfield – Script Only
2
-
3
  (() => {
4
  const canvas = document.getElementById("starfield");
5
  const ctx = canvas.getContext("2d");
@@ -10,7 +8,7 @@
10
  let comets = [];
11
  let pulses = [];
12
 
13
- // Four parallax star layers: count, base speed, draw size
14
  const layerConfigs = [
15
  { count: 400, speed: 1.5, size: 2.5 },
16
  { count: 300, speed: 3.0, size: 4.0 },
@@ -20,56 +18,95 @@
20
 
21
  const rand = (min, max) => min + Math.random() * (max - min);
22
 
23
- // Handle resize: update sizes, cache background
24
  function resize() {
25
  width = window.innerWidth;
26
  height = window.innerHeight;
27
  canvas.width = width;
28
  canvas.height = height;
29
 
30
- // Cache a deep-space gradient background
31
  bgCanvas = document.createElement("canvas");
32
  bgCanvas.width = width;
33
  bgCanvas.height = height;
34
  bgCtx = bgCanvas.getContext("2d");
 
 
35
  const bgGrad = bgCtx.createRadialGradient(
36
  width / 2, height / 2, 0,
37
- width / 2, height / 2, width
38
  );
39
  bgGrad.addColorStop(0, "#111122");
40
- bgGrad.addColorStop(1, "#000000");
41
  bgCtx.fillStyle = bgGrad;
42
  bgCtx.fillRect(0, 0, width, height);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  }
44
 
45
- // Pre-render star sprites with strong glow
46
  function createStarSprites() {
47
  starSprites = layerConfigs.map(cfg => {
48
  const r = cfg.size;
49
- const sz = r * 6;
50
  const off = document.createElement("canvas");
51
  off.width = off.height = sz;
52
  const octx = off.getContext("2d");
 
 
53
  octx.fillStyle = "#fff";
54
  octx.shadowColor = "#fff";
55
- octx.shadowBlur = r * 3;
 
 
 
 
 
 
 
 
56
  octx.beginPath();
57
- octx.arc(sz / 2, sz / 2, r, 0, Math.PI * 2);
58
  octx.fill();
 
59
  return off;
60
  });
61
  }
62
 
63
- // Initialize each star layer
64
  function initStars() {
65
  layers = layerConfigs.map((cfg, idx) => {
66
  const stars = [];
67
  for (let i = 0; i < cfg.count; i++) {
68
  stars.push({
69
- x: rand(-width / 2, width / 2),
70
- y: rand(-height / 2, height / 2),
71
  z: rand(1, width),
72
- twAngle: rand(0, Math.PI * 2),
 
 
73
  sprIndex: idx,
74
  });
75
  }
@@ -77,108 +114,158 @@
77
  });
78
  }
79
 
80
- // Spawn comets occasionally
81
  function maybeComet() {
82
  if (Math.random() < 0.002) {
 
83
  comets.push({
84
- x: rand(0, width),
85
- y: rand(0, height * 0.2),
86
  len: 0,
87
  maxLen: rand(80, 200),
88
- angle: Math.PI * 0.25 + rand(-0.3, 0.3),
89
  speed: rand(10, 16),
 
 
90
  });
91
  }
92
  }
93
 
94
- // Click for warp pulse
95
  canvas.addEventListener("click", e => {
96
- pulses.push({ x: e.clientX, y: e.clientY, r: 0, alpha: 0.6 });
 
 
 
 
 
 
 
 
 
 
97
  });
98
 
99
- // Update star positions, twinkles, comets, pulses
100
  function update() {
101
  const now = Date.now();
 
 
102
  layers.forEach(layer => {
103
  layer.stars.forEach(s => {
104
- s.z -= layer.speed; // faster movement
105
  if (s.z <= 0) {
106
  s.z = width;
107
- s.x = rand(-width / 2, width / 2);
108
- s.y = rand(-height / 2, height / 2);
109
- s.twAngle = rand(0, Math.PI * 2);
110
  }
111
- // sinusoidal twinkle based on depth + time
112
- s.twAngle += 0.02;
113
  });
114
  });
115
-
116
- comets = comets.filter(c => c.len < c.maxLen);
 
117
  comets.forEach(c => {
118
  c.len += c.speed;
119
- c.x += Math.cos(c.angle) * c.speed;
120
- c.y += Math.sin(c.angle) * c.speed;
 
 
 
 
 
 
 
 
 
 
 
 
121
  });
122
-
123
- pulses = pulses.filter(p => p.alpha > 0);
 
124
  pulses.forEach(p => {
125
- p.r += 30;
126
- p.alpha -= 0.012;
127
  });
128
-
129
  maybeComet();
130
  }
131
 
132
- // Draw the full scene
133
  function draw() {
134
- // 1) Background
135
  ctx.clearRect(0, 0, width, height);
136
  ctx.drawImage(bgCanvas, 0, 0);
137
-
138
- // 2) Motion trails
139
- ctx.fillStyle = "rgba(0,0,0,0.15)";
140
  ctx.fillRect(0, 0, width, height);
141
-
142
- // 3) Stars
143
  layers.forEach((layer, li) => {
144
  const sprite = starSprites[li];
145
  ctx.globalCompositeOperation = "lighter";
146
  layer.stars.forEach(s => {
147
- const k = (width / 2) / s.z;
148
- const x = s.x * k + width / 2;
149
- const y = s.y * k + height / 2;
150
- if (x < 0 || x > width || y < 0 || y > height) return;
151
- const ds = (1 - s.z / width) * layer.size * 1.5;
152
- // compute twinkle alpha
153
- const alpha = 0.5 + 0.5 * Math.sin(s.twAngle + s.z / 30);
 
 
 
 
154
  ctx.globalAlpha = alpha;
155
  ctx.drawImage(sprite, x - ds, y - ds, ds * 2, ds * 2);
156
  });
157
- ctx.globalCompositeOperation = "source-over";
158
  });
 
159
  ctx.globalAlpha = 1;
160
-
161
- // 4) Comets
162
  comets.forEach(c => {
163
- ctx.strokeStyle = "rgba(255,255,255,0.8)";
164
- ctx.lineWidth = 1.2;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  ctx.beginPath();
166
- ctx.moveTo(c.x, c.y);
167
- ctx.lineTo(
168
- c.x - Math.cos(c.angle) * c.len,
169
- c.y - Math.sin(c.angle) * c.len
170
  );
 
 
 
 
 
 
171
  ctx.stroke();
172
  });
173
-
174
- // 5) Warp pulses
175
- pulses.forEach(p => {
176
- const grd = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, p.r);
177
- grd.addColorStop(0, `rgba(255,255,255,${p.alpha})`);
178
- grd.addColorStop(1, "rgba(0,0,0,0)");
179
- ctx.fillStyle = grd;
180
- ctx.fillRect(0, 0, width, height);
181
- });
182
  }
183
 
184
  // Animation loop
@@ -188,7 +275,7 @@
188
  requestAnimationFrame(loop);
189
  }
190
 
191
- // Initialize everything
192
  function init() {
193
  resize();
194
  createStarSprites();
@@ -201,4 +288,4 @@
201
  }
202
 
203
  init();
204
- })();
 
 
 
1
  (() => {
2
  const canvas = document.getElementById("starfield");
3
  const ctx = canvas.getContext("2d");
 
8
  let comets = [];
9
  let pulses = [];
10
 
11
+ // Layer configurations: count, base speed, draw size
12
  const layerConfigs = [
13
  { count: 400, speed: 1.5, size: 2.5 },
14
  { count: 300, speed: 3.0, size: 4.0 },
 
18
 
19
  const rand = (min, max) => min + Math.random() * (max - min);
20
 
21
+ // Handle resize
22
  function resize() {
23
  width = window.innerWidth;
24
  height = window.innerHeight;
25
  canvas.width = width;
26
  canvas.height = height;
27
 
28
+ // Create background with nebula effect
29
  bgCanvas = document.createElement("canvas");
30
  bgCanvas.width = width;
31
  bgCanvas.height = height;
32
  bgCtx = bgCanvas.getContext("2d");
33
+
34
+ // Base gradient
35
  const bgGrad = bgCtx.createRadialGradient(
36
  width / 2, height / 2, 0,
37
+ width / 2, height / 2, width * 0.8
38
  );
39
  bgGrad.addColorStop(0, "#111122");
40
+ bgGrad.addColorStop(1, "#000011");
41
  bgCtx.fillStyle = bgGrad;
42
  bgCtx.fillRect(0, 0, width, height);
43
+
44
+ // Nebula effect
45
+ const nebulaCount = Math.floor(width * height / 40000);
46
+ bgCtx.globalCompositeOperation = "lighter";
47
+ for (let i = 0; i < nebulaCount; i++) {
48
+ const x = rand(0, width);
49
+ const y = rand(0, height);
50
+ const radius = rand(50, 300);
51
+ const hue = rand(220, 280);
52
+ const alpha = rand(0.01, 0.03);
53
+
54
+ const grd = bgCtx.createRadialGradient(
55
+ x, y, 0,
56
+ x, y, radius
57
+ );
58
+ grd.addColorStop(0, `hsla(${hue}, 70%, 60%, ${alpha})`);
59
+ grd.addColorStop(1, `hsla(${hue}, 80%, 30%, 0)`);
60
+
61
+ bgCtx.beginPath();
62
+ bgCtx.fillStyle = grd;
63
+ bgCtx.arc(x, y, radius, 0, Math.PI * 2);
64
+ bgCtx.fill();
65
+ }
66
+ bgCtx.globalCompositeOperation = "source-over";
67
  }
68
 
69
+ // Pre-render star sprites with glow
70
  function createStarSprites() {
71
  starSprites = layerConfigs.map(cfg => {
72
  const r = cfg.size;
73
+ const sz = Math.ceil(r * 6);
74
  const off = document.createElement("canvas");
75
  off.width = off.height = sz;
76
  const octx = off.getContext("2d");
77
+
78
+ // Core glow
79
  octx.fillStyle = "#fff";
80
  octx.shadowColor = "#fff";
81
+ octx.shadowBlur = r * 4;
82
+ octx.beginPath();
83
+ octx.arc(sz/2, sz/2, r, 0, Math.PI * 2);
84
+ octx.fill();
85
+
86
+ // Bright core
87
+ octx.shadowBlur = 0;
88
+ octx.globalCompositeOperation = "source-over";
89
+ octx.fillStyle = "#ffffff";
90
  octx.beginPath();
91
+ octx.arc(sz/2, sz/2, r * 0.6, 0, Math.PI * 2);
92
  octx.fill();
93
+
94
  return off;
95
  });
96
  }
97
 
98
+ // Initialize star layers with twinkle parameters
99
  function initStars() {
100
  layers = layerConfigs.map((cfg, idx) => {
101
  const stars = [];
102
  for (let i = 0; i < cfg.count; i++) {
103
  stars.push({
104
+ x: rand(-width/2, width/2),
105
+ y: rand(-height/2, height/2),
106
  z: rand(1, width),
107
+ twPhase: rand(0, Math.PI * 2),
108
+ twFreq: rand(0.01, 0.03),
109
+ twRange: rand(0.3, 0.7),
110
  sprIndex: idx,
111
  });
112
  }
 
114
  });
115
  }
116
 
117
+ // Spawn comets with natural motion
118
  function maybeComet() {
119
  if (Math.random() < 0.002) {
120
+ const angle = Math.PI * 0.25 + rand(-0.3, 0.3);
121
  comets.push({
122
+ x: rand(-50, width + 50),
123
+ y: rand(-50, height * 0.3),
124
  len: 0,
125
  maxLen: rand(80, 200),
126
+ angle: angle,
127
  speed: rand(10, 16),
128
+ segments: [],
129
+ alpha: 1.0
130
  });
131
  }
132
  }
133
 
134
+ // Click creates warp pulse with multiple rings
135
  canvas.addEventListener("click", e => {
136
+ for (let i = 0; i < 3; i++) {
137
+ pulses.push({
138
+ x: e.clientX,
139
+ y: e.clientY,
140
+ r: i * 20,
141
+ maxR: 150 + i * 80,
142
+ thickness: 15 - i * 3,
143
+ alpha: 0.7 - i * 0.2,
144
+ speed: 8 - i * 2
145
+ });
146
+ }
147
  });
148
 
149
+ // Update positions and effects
150
  function update() {
151
  const now = Date.now();
152
+
153
+ // Update stars
154
  layers.forEach(layer => {
155
  layer.stars.forEach(s => {
156
+ s.z -= layer.speed;
157
  if (s.z <= 0) {
158
  s.z = width;
159
+ s.x = rand(-width/2, width/2);
160
+ s.y = rand(-height/2, height/2);
 
161
  }
162
+ // Update twinkle
163
+ s.twPhase += s.twFreq;
164
  });
165
  });
166
+
167
+ // Update comets
168
+ comets = comets.filter(c => c.alpha > 0.1);
169
  comets.forEach(c => {
170
  c.len += c.speed;
171
+ const headX = c.x + Math.cos(c.angle) * c.len;
172
+ const headY = c.y + Math.sin(c.angle) * c.len;
173
+
174
+ // Add new segment
175
+ c.segments.push({x: headX, y: headY, alpha: 1.0});
176
+
177
+ // Fade old segments
178
+ c.segments.forEach(seg => seg.alpha -= 0.02);
179
+
180
+ // Remove old segments
181
+ if (c.segments.length > 20) c.segments.shift();
182
+
183
+ // Fade entire comet
184
+ c.alpha -= 0.003;
185
  });
186
+
187
+ // Update pulses
188
+ pulses = pulses.filter(p => p.r < p.maxR);
189
  pulses.forEach(p => {
190
+ p.r += p.speed;
191
+ p.alpha -= 0.008;
192
  });
193
+
194
  maybeComet();
195
  }
196
 
197
+ // Draw the scene
198
  function draw() {
199
+ // Background
200
  ctx.clearRect(0, 0, width, height);
201
  ctx.drawImage(bgCanvas, 0, 0);
202
+
203
+ // Motion trails
204
+ ctx.fillStyle = "rgba(0,0,10,0.1)";
205
  ctx.fillRect(0, 0, width, height);
206
+
207
+ // Stars
208
  layers.forEach((layer, li) => {
209
  const sprite = starSprites[li];
210
  ctx.globalCompositeOperation = "lighter";
211
  layer.stars.forEach(s => {
212
+ const k = (width/2) / s.z;
213
+ const x = s.x * k + width/2;
214
+ const y = s.y * k + height/2;
215
+
216
+ if (x < -100 || x > width+100 || y < -100 || y > height+100) return;
217
+
218
+ // Calculate twinkle
219
+ const twinkle = 0.5 + 0.5 * Math.sin(s.twPhase);
220
+ const alpha = s.twRange + (1 - s.twRange) * twinkle;
221
+ const ds = (1 - s.z/width) * layer.size * 1.5;
222
+
223
  ctx.globalAlpha = alpha;
224
  ctx.drawImage(sprite, x - ds, y - ds, ds * 2, ds * 2);
225
  });
 
226
  });
227
+ ctx.globalCompositeOperation = "source-over";
228
  ctx.globalAlpha = 1;
229
+
230
+ // Comets with particle trails
231
  comets.forEach(c => {
232
+ ctx.lineCap = "round";
233
+ for (let i = 1; i < c.segments.length; i++) {
234
+ const seg1 = c.segments[i-1];
235
+ const seg2 = c.segments[i];
236
+
237
+ const gradient = ctx.createLinearGradient(
238
+ seg1.x, seg1.y, seg2.x, seg2.y
239
+ );
240
+ const segAlpha = Math.min(seg1.alpha, seg2.alpha) * c.alpha;
241
+ gradient.addColorStop(0, `rgba(200,220,255,${segAlpha})`);
242
+ gradient.addColorStop(1, `rgba(100,150,255,${segAlpha * 0.2})`);
243
+
244
+ ctx.strokeStyle = gradient;
245
+ ctx.lineWidth = Math.max(1, 3 * (i/c.segments.length));
246
+ ctx.beginPath();
247
+ ctx.moveTo(seg1.x, seg1.y);
248
+ ctx.lineTo(seg2.x, seg2.y);
249
+ ctx.stroke();
250
+ }
251
+ });
252
+
253
+ // Warp pulses with multiple rings
254
+ pulses.forEach(p => {
255
  ctx.beginPath();
256
+ ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
257
+ const gradient = ctx.createRadialGradient(
258
+ p.x, p.y, p.r - p.thickness/2,
259
+ p.x, p.y, p.r + p.thickness/2
260
  );
261
+ gradient.addColorStop(0, `rgba(180,220,255,${p.alpha})`);
262
+ gradient.addColorStop(0.5, `rgba(100,180,255,${p.alpha * 0.8})`);
263
+ gradient.addColorStop(1, `rgba(50,100,255,0)`);
264
+
265
+ ctx.strokeStyle = gradient;
266
+ ctx.lineWidth = p.thickness;
267
  ctx.stroke();
268
  });
 
 
 
 
 
 
 
 
 
269
  }
270
 
271
  // Animation loop
 
275
  requestAnimationFrame(loop);
276
  }
277
 
278
+ // Initialize
279
  function init() {
280
  resize();
281
  createStarSprites();
 
288
  }
289
 
290
  init();
291
+ })();