asigalov61's picture
Update stars.js
589c696 verified
// Original stars.js code modified with AI in the following order:
// 1) Microsoft Copilot
// 2) Deepseek AI
// 3) Qwen3 Coder
(() => {
const canvas = document.getElementById("starfield");
const ctx = canvas.getContext("2d");
let width, height;
let bgCanvas, bgCtx;
let starSprites = [];
let layers = [];
let comets = [];
let pulses = [];
let particles = [];
let mouse = { x: 0, y: 0, active: false };
// Layer configurations: count, base speed, draw size
const layerConfigs = [
{ count: 500, speed: 1.5, size: 2.5 },
{ count: 400, speed: 3.0, size: 4.0 },
{ count: 300, speed: 6.0, size: 5.5 },
{ count: 200, speed: 10.0, size: 8.0 },
];
const rand = (min, max) => min + Math.random() * (max - min);
// Handle resize
function resize() {
width = window.innerWidth;
height = window.innerHeight;
canvas.width = width;
canvas.height = height;
// Create background with enhanced nebula effect
bgCanvas = document.createElement("canvas");
bgCanvas.width = width;
bgCanvas.height = height;
bgCtx = bgCanvas.getContext("2d");
// Base gradient - pure black background
const bgGrad = bgCtx.createRadialGradient(
width / 2, height / 2, 0,
width / 2, height / 2, width * 0.8
);
bgGrad.addColorStop(0, "#000000");
bgGrad.addColorStop(0.5, "#000000");
bgGrad.addColorStop(1, "#000000");
bgCtx.fillStyle = bgGrad;
bgCtx.fillRect(0, 0, width, height);
// Enhanced nebula effect with multiple layers - more vibrant
const nebulaCount = Math.floor(width * height / 30000);
bgCtx.globalCompositeOperation = "screen";
for (let i = 0; i < nebulaCount; i++) {
const x = rand(0, width);
const y = rand(0, height);
const radius = rand(100, 400);
const hue = rand(220, 280);
const alpha = rand(0.03, 0.08);
const grd = bgCtx.createRadialGradient(
x, y, 0,
x, y, radius
);
grd.addColorStop(0, `hsla(${hue}, 100%, 100%, ${alpha})`);
grd.addColorStop(0.3, `hsla(${hue + 20}, 100%, 80%, ${alpha * 0.8})`);
grd.addColorStop(1, `hsla(${hue - 20}, 100%, 50%, 0)`);
bgCtx.beginPath();
bgCtx.fillStyle = grd;
bgCtx.arc(x, y, radius, 0, Math.PI * 2);
bgCtx.fill();
}
// Add subtle star clusters - brighter
bgCtx.globalCompositeOperation = "lighter";
for (let i = 0; i < nebulaCount / 3; i++) {
const x = rand(0, width);
const y = rand(0, height);
const clusterSize = rand(20, 60);
const clusterGrad = bgCtx.createRadialGradient(
x, y, 0,
x, y, clusterSize
);
clusterGrad.addColorStop(0, `rgba(255, 255, 255, 0.2)`);
clusterGrad.addColorStop(1, `rgba(200, 220, 255, 0)`);
bgCtx.beginPath();
bgCtx.fillStyle = clusterGrad;
bgCtx.arc(x, y, clusterSize, 0, Math.PI * 2);
bgCtx.fill();
}
bgCtx.globalCompositeOperation = "source-over";
}
// Pre-render enhanced star sprites with glow
function createStarSprites() {
starSprites = layerConfigs.map(cfg => {
const r = cfg.size;
const sz = Math.ceil(r * 8);
const off = document.createElement("canvas");
off.width = off.height = sz;
const octx = off.getContext("2d");
// Core glow with gradient - brighter for black background
const gradient = octx.createRadialGradient(
sz/2, sz/2, 0,
sz/2, sz/2, r * 3
);
gradient.addColorStop(0, "#ffffff");
gradient.addColorStop(0.3, "#a0c0ff");
gradient.addColorStop(1, "rgba(50, 100, 255, 0)");
octx.fillStyle = gradient;
octx.beginPath();
octx.arc(sz/2, sz/2, r * 3, 0, Math.PI * 2);
octx.fill();
// Bright core with corona - enhanced brightness
octx.shadowColor = "#ffffff";
octx.shadowBlur = r * 3;
octx.globalCompositeOperation = "lighter";
octx.fillStyle = "#ffffff";
octx.beginPath();
octx.arc(sz/2, sz/2, r * 0.8, 0, Math.PI * 2);
octx.fill();
// Secondary corona - enhanced brightness
octx.shadowColor = "#a0c0ff";
octx.shadowBlur = r * 5;
octx.fillStyle = "rgba(180, 220, 255, 0.9)";
octx.beginPath();
octx.arc(sz/2, sz/2, r * 0.6, 0, Math.PI * 2);
octx.fill();
return off;
});
}
// Initialize star layers with enhanced twinkle parameters
function initStars() {
layers = layerConfigs.map((cfg, idx) => {
const stars = [];
for (let i = 0; i < cfg.count; i++) {
stars.push({
x: rand(-width/2, width/2),
y: rand(-height/2, height/2),
z: rand(1, width),
twPhase: rand(0, Math.PI * 2),
twFreq: rand(0.01, 0.05),
twRange: rand(0.3, 0.9),
sprIndex: idx,
hue: rand(180, 220), // Blue-ish stars
saturation: rand(80, 100),
brightness: rand(90, 100),
pulsePhase: rand(0, Math.PI * 2),
pulseSpeed: rand(0.02, 0.08),
originalSize: cfg.size
});
}
return { ...cfg, stars };
});
}
// Spawn comets with enhanced effects
function maybeComet() {
if (Math.random() < 0.003) {
const angle = Math.PI * 0.25 + rand(-0.5, 0.5);
comets.push({
x: rand(-100, width + 100),
y: rand(-100, height * 0.4),
len: 0,
maxLen: rand(100, 250),
angle: angle,
speed: rand(12, 20),
segments: [],
alpha: 1.0,
hue: rand(180, 220),
size: rand(2, 5)
});
}
}
// Create particle explosion
function createParticles(x, y, count, color) {
for (let i = 0; i < count; i++) {
particles.push({
x: x,
y: y,
vx: rand(-3, 3),
vy: rand(-3, 3),
life: 1.0,
decay: rand(0.01, 0.03),
size: rand(1, 3),
color: color || `hsl(${rand(180, 220)}, 100%, ${rand(80, 100)}%)`
});
}
}
// Click creates enhanced warp pulse with particles
canvas.addEventListener("click", e => {
// Create main pulses
for (let i = 0; i < 5; i++) {
pulses.push({
x: e.clientX,
y: e.clientY,
r: i * 15,
maxR: 200 + i * 60,
thickness: 20 - i * 2,
alpha: 0.9 - i * 0.15,
speed: 10 - i * 1.5,
hue: rand(180, 220)
});
}
// Create particle explosion
createParticles(e.clientX, e.clientY, 50, `hsl(${rand(180, 220)}, 100%, 90%)`);
});
// Mouse move for star attraction
canvas.addEventListener("mousemove", e => {
mouse.x = e.clientX;
mouse.y = e.clientY;
mouse.active = true;
});
canvas.addEventListener("mouseleave", () => {
mouse.active = false;
});
// Update positions and effects
function update() {
const now = Date.now();
// Update stars with mouse attraction
layers.forEach(layer => {
layer.stars.forEach(s => {
s.z -= layer.speed;
// Mouse attraction effect
if (mouse.active) {
const dx = (mouse.x - width/2) - s.x;
const dy = (mouse.y - height/2) - s.y;
const dist = Math.sqrt(dx*dx + dy*dy);
if (dist < 300) {
const force = (300 - dist) / 300 * 0.5;
s.x += dx * force * (s.z / width);
s.y += dy * force * (s.z / width);
}
}
if (s.z <= 0) {
s.z = width;
s.x = rand(-width/2, width/2);
s.y = rand(-height/2, height/2);
}
// Update twinkle and pulsing
s.twPhase += s.twFreq;
s.pulsePhase += s.pulseSpeed;
});
});
// Update comets
comets = comets.filter(c => c.alpha > 0.05);
comets.forEach(c => {
c.len += c.speed;
const headX = c.x + Math.cos(c.angle) * c.len;
const headY = c.y + Math.sin(c.angle) * c.len;
// Add new segment
c.segments.push({
x: headX,
y: headY,
alpha: 1.0,
size: c.size * (0.5 + 0.5 * Math.random())
});
// Fade old segments
c.segments.forEach(seg => seg.alpha -= 0.015);
// Remove old segments
if (c.segments.length > 30) c.segments.shift();
// Fade entire comet
c.alpha -= 0.002;
// Occasionally create particles
if (Math.random() < 0.3) {
createParticles(headX, headY, 1, `hsl(${c.hue}, 100%, 80%)`);
}
});
// Update pulses
pulses = pulses.filter(p => p.r < p.maxR);
pulses.forEach(p => {
p.r += p.speed;
p.alpha -= 0.006;
});
// Update particles
particles = particles.filter(p => p.life > 0);
particles.forEach(p => {
p.x += p.vx;
p.y += p.vy;
p.vy += 0.05; // Gravity
p.life -= p.decay;
p.vx *= 0.98; // Friction
p.vy *= 0.98;
});
maybeComet();
}
// Draw the enhanced scene
function draw() {
// Background with subtle movement
ctx.clearRect(0, 0, width, height);
ctx.drawImage(bgCanvas, 0, 0);
// Subtle motion blur effect
ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
ctx.fillRect(0, 0, width, height);
// Draw particles
particles.forEach(p => {
ctx.globalAlpha = p.life;
ctx.fillStyle = p.color;
ctx.beginPath();
ctx.arc(p.x, p.y, Math.max(0.1, p.size * p.life), 0, Math.PI * 2);
ctx.fill();
});
// Stars with enhanced effects
layers.forEach((layer, li) => {
const sprite = starSprites[li];
ctx.globalCompositeOperation = "lighter";
layer.stars.forEach(s => {
const k = (width/2) / s.z;
const x = s.x * k + width/2;
const y = s.y * k + height/2;
if (x < -100 || x > width+100 || y < -100 || y > height+100) return;
// Calculate twinkle with pulsing
const twinkle = 0.5 + 0.5 * Math.sin(s.twPhase);
const pulse = 0.8 + 0.2 * Math.sin(s.pulsePhase);
const alpha = (s.twRange + (1 - s.twRange) * twinkle) * pulse;
const ds = Math.max(0.1, (1 - s.z/width) * s.originalSize * 2 * pulse);
ctx.globalAlpha = alpha;
const drawSize = Math.max(0.1, ds * 2);
ctx.drawImage(sprite, x - ds, y - ds, drawSize, drawSize);
});
});
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 1;
// Comets with enhanced particle trails
comets.forEach(c => {
ctx.lineCap = "round";
for (let i = 1; i < c.segments.length; i++) {
const seg1 = c.segments[i-1];
const seg2 = c.segments[i];
const gradient = ctx.createLinearGradient(
seg1.x, seg1.y, seg2.x, seg2.y
);
const segAlpha = Math.min(seg1.alpha, seg2.alpha) * c.alpha;
gradient.addColorStop(0, `hsla(${c.hue}, 100%, 100%, ${segAlpha})`);
gradient.addColorStop(0.5, `hsla(${c.hue - 20}, 100%, 80%, ${segAlpha * 0.8})`);
gradient.addColorStop(1, `hsla(${c.hue - 40}, 100%, 60%, ${segAlpha * 0.3})`);
ctx.strokeStyle = gradient;
ctx.lineWidth = Math.max(0.1, seg2.size * (i/c.segments.length) * c.alpha);
ctx.beginPath();
ctx.moveTo(seg1.x, seg1.y);
ctx.lineTo(seg2.x, seg2.y);
ctx.stroke();
}
});
// Warp pulses with enhanced rings
pulses.forEach(p => {
ctx.beginPath();
ctx.arc(p.x, p.y, Math.max(0.1, p.r), 0, Math.PI * 2);
const gradient = ctx.createRadialGradient(
p.x, p.y, Math.max(0.1, p.r - p.thickness/2),
p.x, p.y, Math.max(0.1, p.r + p.thickness/2)
);
gradient.addColorStop(0, `hsla(${p.hue}, 100%, 100%, ${p.alpha})`);
gradient.addColorStop(0.3, `hsla(${p.hue - 10}, 100%, 90%, ${p.alpha * 0.9})`);
gradient.addColorStop(0.7, `hsla(${p.hue - 20}, 100%, 70%, ${p.alpha * 0.5})`);
gradient.addColorStop(1, `hsla(${p.hue - 30}, 100%, 50%, 0)`);
ctx.strokeStyle = gradient;
ctx.lineWidth = Math.max(0.1, p.thickness);
ctx.stroke();
// Add inner glow
if (p.alpha > 0.3) {
const innerRadius = Math.max(0.1, p.r * 0.3);
ctx.beginPath();
ctx.arc(p.x, p.y, innerRadius, 0, Math.PI * 2);
const innerGradient = ctx.createRadialGradient(
p.x, p.y, 0,
p.x, p.y, innerRadius
);
innerGradient.addColorStop(0, `hsla(${p.hue + 20}, 100%, 100%, ${p.alpha * 0.7})`);
innerGradient.addColorStop(1, `hsla(${p.hue}, 100%, 80%, 0)`);
ctx.fillStyle = innerGradient;
ctx.fill();
}
});
}
// Animation loop
function loop() {
update();
draw();
requestAnimationFrame(loop);
}
// Initialize
function init() {
resize();
createStarSprites();
initStars();
window.addEventListener("resize", () => {
resize();
initStars();
});
// Add some initial particles for visual interest
for (let i = 0; i < 100; i++) {
setTimeout(() => {
createParticles(rand(0, width), rand(0, height), 3, `hsl(${rand(180, 220)}, 100%, ${rand(70, 90)}%)`);
}, i * 100);
}
loop();
}
init();
})();