Spaces:
Running
Running
File size: 3,630 Bytes
4d83ec2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | // ===== 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();
});
});
|