QuarksLab / quantum-field.js
TwoQuarks's picture
Update quantum-field.js
ec09bf0 verified
Raw
History Blame Contribute Delete
6 kB
/**
* TwoQuarks Quantum Field - Ultra Blue Particle System
* High-performance canvas animation with WebGL-style particles
*/
class QuantumField {
constructor(canvasId) {
this.canvas = document.getElementById(canvasId);
if (!this.canvas) {
console.warn(`Canvas ${canvasId} not found`);
return;
}
this.ctx = this.canvas.getContext('2d', { alpha: false });
this.particles = [];
this.connections = [];
this.mouse = { x: null, y: null, radius: 150 };
// Ultra Blue color palette
this.colors = {
primary: 'rgba(39, 80, 146, 0.8)', // #3B82F6
bright: 'rgba(96, 165, 250, 0.6)', // #60A5FA
deep: 'rgba(30, 64, 175, 0.9)', // #1E40AF
glow: 'rgba(59, 130, 246, 0.15)',
connection: 'rgba(59, 130, 246, 0.12)'
};
// Configuration
this.config = {
particleCount: 120,
particleSpeed: 0.3,
connectionDistance: 140,
mouseInteraction: true,
mouseRepelForce: 0.8,
particleSize: { min: 1, max: 3 },
glowEnabled: true
};
this.init();
}
init() {
this.resize();
this.createParticles();
this.setupEventListeners();
this.animate();
}
resize() {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
}
createParticles() {
this.particles = [];
const { particleCount, particleSpeed, particleSize } = this.config;
for (let i = 0; i < particleCount; i++) {
this.particles.push({
x: Math.random() * this.canvas.width,
y: Math.random() * this.canvas.height,
vx: (Math.random() - 0.5) * particleSpeed,
vy: (Math.random() - 0.5) * particleSpeed,
size: Math.random() * (particleSize.max - particleSize.min) + particleSize.min,
color: this.getRandomColor(),
brightness: Math.random() * 0.5 + 0.5
});
}
}
getRandomColor() {
const colorOptions = [
this.colors.primary,
this.colors.bright,
this.colors.deep
];
return colorOptions[Math.floor(Math.random() * colorOptions.length)];
}
setupEventListeners() {
window.addEventListener('resize', () => this.resize());
if (this.config.mouseInteraction) {
window.addEventListener('mousemove', (e) => {
this.mouse.x = e.clientX;
this.mouse.y = e.clientY;
});
window.addEventListener('mouseleave', () => {
this.mouse.x = null;
this.mouse.y = null;
});
}
}
updateParticles() {
const { width, height } = this.canvas;
const { mouseRepelForce } = this.config;
this.particles.forEach(p => {
// Mouse interaction - repel effect
if (this.mouse.x !== null && this.mouse.y !== null) {
const dx = p.x - this.mouse.x;
const dy = p.y - this.mouse.y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < this.mouse.radius) {
const force = (this.mouse.radius - dist) / this.mouse.radius;
const angle = Math.atan2(dy, dx);
p.vx += Math.cos(angle) * force * mouseRepelForce;
p.vy += Math.sin(angle) * force * mouseRepelForce;
}
}
// Update position
p.x += p.vx;
p.y += p.vy;
// Damping
p.vx *= 0.99;
p.vy *= 0.99;
// Boundary wrapping
if (p.x < 0) p.x = width;
if (p.x > width) p.x = 0;
if (p.y < 0) p.y = height;
if (p.y > height) p.y = 0;
// Subtle brightness pulsing
p.brightness += (Math.random() - 0.5) * 0.02;
p.brightness = Math.max(0.3, Math.min(1, p.brightness));
});
}
drawConnections() {
const { connectionDistance } = this.config;
this.ctx.strokeStyle = this.colors.connection;
this.ctx.lineWidth = 0.5;
for (let i = 0; i < this.particles.length; i++) {
for (let j = i + 1; j < this.particles.length; j++) {
const dx = this.particles[i].x - this.particles[j].x;
const dy = this.particles[i].y - this.particles[j].y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < connectionDistance) {
const opacity = (1 - dist / connectionDistance) * 0.3;
this.ctx.strokeStyle = `rgba(29, 80, 126, ${opacity})`;
this.ctx.beginPath();
this.ctx.moveTo(this.particles[i].x, this.particles[i].y);
this.ctx.lineTo(this.particles[j].x, this.particles[j].y);
this.ctx.stroke();
}
}
}
}
drawParticles() {
this.particles.forEach(p => {
// Glow effect
if (this.config.glowEnabled) {
const gradient = this.ctx.createRadialGradient(
p.x, p.y, 0,
p.x, p.y, p.size * 4
);
gradient.addColorStop(0, p.color.replace(/[\d.]+\)$/g, `${p.brightness})`));
gradient.addColorStop(1, p.color.replace(/[\d.]+\)$/g, '0)'));
this.ctx.fillStyle = gradient;
this.ctx.beginPath();
this.ctx.arc(p.x, p.y, p.size * 4, 0, Math.PI * 2);
this.ctx.fill();
}
// Core particle
this.ctx.fillStyle = p.color.replace(/[\d.]+\)$/g, `${p.brightness})`);
this.ctx.beginPath();
this.ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
this.ctx.fill();
});
}
animate() {
// Clear with black background
this.ctx.fillStyle = '#000000';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.updateParticles();
this.drawConnections();
this.drawParticles();
requestAnimationFrame(() => this.animate());
}
}
// Auto-initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
new QuantumField('quantumField');
});
} else {
new QuantumField('quantumField');
}
// Export for potential external use
if (typeof module !== 'undefined' && module.exports) {
module.exports = QuantumField;
}