|
14 | 14 | const MOUSE_INFLUENCE = 0.12; |
15 | 15 |
|
16 | 16 | /* ── Dark-mode starfield constants ─────────────────────── */ |
17 | | - const STAR_COUNT = 800; |
| 17 | + const STAR_COUNT = 1000; |
18 | 18 | const SPEED = 0.40; |
19 | 19 | const DEPTH = 950; |
20 | 20 | const TWINKLE_SPEED = 0.035; // sine-wave twinkle rate |
21 | | - const QUASAR_CHANCE = 0.07; // fraction of stars that glow |
| 21 | + const QUASAR_CHANCE = 0.10; // fraction of stars that glow |
22 | 22 |
|
23 | 23 | /* Nebula cloud count */ |
24 | | - const NEBULA_COUNT = 12; |
| 24 | + const NEBULA_COUNT = 18; |
25 | 25 |
|
26 | 26 | /* Star colour palette (dark mode) — cool whites, blues, warm hints */ |
27 | 27 | const STAR_COLORS = [ |
|
101 | 101 | z: zOverride !== undefined ? zOverride : Math.random() * DEPTH, |
102 | 102 | phase: Math.random() * Math.PI * 2, // twinkle phase offset |
103 | 103 | quasar: Math.random() < QUASAR_CHANCE, // whether this star glows |
| 104 | + flareAngle: Math.random() * Math.PI, // unique spike rotation |
104 | 105 | r: color[0], g: color[1], b: color[2], |
105 | 106 | }; |
106 | 107 | } |
|
201 | 202 | var t3 = t * t * t; |
202 | 203 | var radius = 0.3 + t * 1.6 + t3 * 8.0; |
203 | 204 |
|
204 | | - // Core dot |
205 | | - ctx.fillStyle = "rgba(" + s.r + "," + s.g + "," + s.b + "," + alpha + ")"; |
| 205 | + // ── Starburst flare for near stars ────────────────── |
| 206 | + // Stars beyond t > 0.45 get 4-point diffraction spikes |
| 207 | + // that grow with proximity, giving a shining "flare" look |
| 208 | + // instead of flat discs. |
| 209 | + var flareIntensity = t > 0.45 ? (t - 0.45) / 0.55 : 0; // 0..1 ramp |
| 210 | + |
| 211 | + if (flareIntensity > 0) { |
| 212 | + var fi2 = flareIntensity * flareIntensity; |
| 213 | + var spikeLen = radius * (3 + fi2 * 14); // spike length grows fast |
| 214 | + var spikeW = radius * (0.15 + fi2 * 0.3); // spike half-width (thin) |
| 215 | + var spikeA = alpha * (0.35 + fi2 * 0.5); // spike opacity |
| 216 | + |
| 217 | + ctx.save(); |
| 218 | + ctx.translate(sx, sy); |
| 219 | + |
| 220 | + // Draw 4 spikes (2 pairs at 90°) |
| 221 | + for (var sp = 0; sp < 4; sp++) { |
| 222 | + ctx.save(); |
| 223 | + ctx.rotate(sp * Math.PI / 2); |
| 224 | + |
| 225 | + // Each spike is a narrow gradient that tapers to transparent |
| 226 | + var sGrad = ctx.createLinearGradient(0, 0, spikeLen, 0); |
| 227 | + sGrad.addColorStop(0, "rgba(255,255,255," + (spikeA * 0.9) + ")"); |
| 228 | + sGrad.addColorStop(0.15, "rgba(" + s.r + "," + s.g + "," + s.b + "," + (spikeA * 0.6) + ")"); |
| 229 | + sGrad.addColorStop(0.5, "rgba(" + s.r + "," + s.g + "," + s.b + "," + (spikeA * 0.2) + ")"); |
| 230 | + sGrad.addColorStop(1, "rgba(" + s.r + "," + s.g + "," + s.b + ",0)"); |
| 231 | + ctx.fillStyle = sGrad; |
| 232 | + |
| 233 | + // Tapered diamond shape for each spike |
| 234 | + ctx.beginPath(); |
| 235 | + ctx.moveTo(0, 0); |
| 236 | + ctx.lineTo(spikeLen * 0.25, -spikeW); |
| 237 | + ctx.lineTo(spikeLen, 0); |
| 238 | + ctx.lineTo(spikeLen * 0.25, spikeW); |
| 239 | + ctx.closePath(); |
| 240 | + ctx.fill(); |
| 241 | + |
| 242 | + ctx.restore(); |
| 243 | + } |
| 244 | + |
| 245 | + // Soft bloom halo behind the core |
| 246 | + var bloomR = radius * (2 + fi2 * 4); |
| 247 | + var bloomA = alpha * 0.3 * fi2; |
| 248 | + var bGrad = ctx.createRadialGradient(0, 0, radius * 0.3, 0, 0, bloomR); |
| 249 | + bGrad.addColorStop(0, "rgba(255,255,255," + (bloomA * 0.8) + ")"); |
| 250 | + bGrad.addColorStop(0.3, "rgba(" + s.r + "," + s.g + "," + s.b + "," + (bloomA * 0.4) + ")"); |
| 251 | + bGrad.addColorStop(1, "rgba(" + s.r + "," + s.g + "," + s.b + ",0)"); |
| 252 | + ctx.fillStyle = bGrad; |
| 253 | + ctx.beginPath(); |
| 254 | + ctx.arc(0, 0, bloomR, 0, Math.PI * 2); |
| 255 | + ctx.fill(); |
| 256 | + |
| 257 | + ctx.restore(); |
| 258 | + } |
| 259 | + |
| 260 | + // White-hot core with colour fringe (replaces flat disc) |
| 261 | + if (flareIntensity > 0) { |
| 262 | + // Bright core: white center fading to star colour |
| 263 | + var coreGrad = ctx.createRadialGradient(sx, sy, 0, sx, sy, radius * 1.2); |
| 264 | + coreGrad.addColorStop(0, "rgba(255,255,255," + Math.min(alpha * 1.3, 1) + ")"); |
| 265 | + coreGrad.addColorStop(0.5, "rgba(" + s.r + "," + s.g + "," + s.b + "," + alpha + ")"); |
| 266 | + coreGrad.addColorStop(1, "rgba(" + s.r + "," + s.g + "," + s.b + ",0)"); |
| 267 | + ctx.fillStyle = coreGrad; |
| 268 | + } else { |
| 269 | + ctx.fillStyle = "rgba(" + s.r + "," + s.g + "," + s.b + "," + alpha + ")"; |
| 270 | + } |
206 | 271 | ctx.beginPath(); |
207 | 272 | ctx.arc(sx, sy, radius, 0, Math.PI * 2); |
208 | 273 | ctx.fill(); |
|
0 commit comments