/** * 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; }