// ===== CXART Gallery — Interactions & Particles ===== document.addEventListener('DOMContentLoaded', () => { // ---------- Floating Particles ---------- const canvas = document.getElementById('particles'); const ctx = canvas.getContext('2d'); let particles = []; let animFrameId; function resizeCanvas() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } function createParticles() { particles = []; const count = Math.floor((canvas.width * canvas.height) / 18000); for (let i = 0; i < count; i++) { particles.push({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, radius: Math.random() * 1.2 + 0.3, alpha: Math.random() * 0.4 + 0.05, dx: (Math.random() - 0.5) * 0.15, dy: (Math.random() - 0.5) * 0.1 - 0.05, pulse: Math.random() * Math.PI * 2, pulseSpeed: Math.random() * 0.008 + 0.003, }); } } function drawParticles() { ctx.clearRect(0, 0, canvas.width, canvas.height); particles.forEach((p) => { p.x += p.dx; p.y += p.dy; p.pulse += p.pulseSpeed; // Wrap around if (p.x < -5) p.x = canvas.width + 5; if (p.x > canvas.width + 5) p.x = -5; if (p.y < -5) p.y = canvas.height + 5; if (p.y > canvas.height + 5) p.y = -5; const currentAlpha = p.alpha * (0.6 + 0.4 * Math.sin(p.pulse)); ctx.beginPath(); ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2); ctx.fillStyle = `rgba(139, 92, 246, ${currentAlpha})`; ctx.fill(); }); animFrameId = requestAnimationFrame(drawParticles); } resizeCanvas(); createParticles(); drawParticles(); window.addEventListener('resize', () => { resizeCanvas(); createParticles(); }); // ---------- Scroll-triggered card reveal ---------- const cards = document.querySelectorAll('.card'); const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { entry.target.classList.add('visible'); observer.unobserve(entry.target); } }); }, { threshold: 0.08, rootMargin: '0px 0px -30px 0px' } ); cards.forEach((card) => observer.observe(card)); // ---------- Lightbox ---------- const lightbox = document.getElementById('lightbox'); const lightboxImg = document.getElementById('lightbox-img'); const lightboxTitle = document.getElementById('lightbox-title'); const lightboxTagline = document.getElementById('lightbox-tagline'); const lightboxClose = document.getElementById('lightbox-close'); function openLightbox(imgSrc, title, tagline) { lightboxImg.src = imgSrc; lightboxTitle.textContent = title; lightboxTagline.textContent = tagline; lightbox.classList.add('active'); document.body.style.overflow = 'hidden'; } function closeLightbox() { lightbox.classList.remove('active'); document.body.style.overflow = ''; } cards.forEach((card) => { card.addEventListener('click', () => { const img = card.querySelector('.card__image'); const title = card.querySelector('.card__title').textContent; const tagline = card.querySelector('.card__tagline').textContent; openLightbox(img.src, title, tagline); }); }); lightboxClose.addEventListener('click', (e) => { e.stopPropagation(); closeLightbox(); }); lightbox.addEventListener('click', (e) => { if (e.target === lightbox) closeLightbox(); }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeLightbox(); }); });