File size: 1,828 Bytes
71c9d6d | 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 | ```javascript
// Initialize particles
function initParticles() {
const particleHost = document.getElementById('particles');
const VW = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
const VH = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
const BASE = 12;
const density = Math.round((VW * VH) / (900 * 900));
const PARTICLE_COUNT = Math.max(8, Math.min(22, BASE + density * 4));
const make = (t, c) => {
const e = document.createElement(t);
if (c) e.className = c;
return e;
};
const rand = (a, b) => Math.random() * (b - a) + a;
for (let i = 0; i < PARTICLE_COUNT; i++) {
const p = make('div', 'particle');
const size = rand(2, 6);
p.style.width = p.style.height = size + 'px';
p.style.left = rand(0, 100) + '%';
p.style.top = rand(0, 100) + '%';
p.style.animationDelay = rand(0, 5) + 's';
const dur = (4 + Math.random() * 3).toFixed(2) + 's';
p.style.animationDuration = dur;
particleHost.appendChild(p);
}
}
// Initialize intersection observer for reveals
function initReveals() {
const io = new IntersectionObserver((entries) => {
entries.forEach(e => {
if (e.isIntersecting) {
e.target.classList.add('in-view');
io.unobserve(e.target);
}
});
}, { root: null, rootMargin: '-100px', threshold: 0 });
document.querySelectorAll('.reveal-up, .reveal-left, .reveal-scale, .feature').forEach(el => io.observe(el));
document.querySelectorAll('.feature').forEach((el, i) => {
el.style.transitionDelay = (0.6 + i * 0.1) + 's';
});
document.querySelectorAll('.reveal-up').forEach((el, i) => {
if (!el.style.transitionDelay) {
el.style.transitionDelay = (0.2 + i * 0.2) + 's';
});
}
// Initialize parallax effect
function init |