/* ═══════════════════════════════════════════════════════════════ VAL'S DREAMSCAPE — 星空粒子 + 滚动动画 ═══════════════════════════════════════════════════════════════ */ (function() { 'use strict'; // ═══ 星空粒子系统 ═══ const canvas = document.getElementById('starfield'); const ctx = canvas.getContext('2d'); let width, height, stars, nebulas; let animationId; function init() { resize(); createStars(); createNebulas(); animate(); } function resize() { width = canvas.width = window.innerWidth; height = canvas.height = window.innerHeight; } function createStars() { const count = Math.floor((width * height) / 8000); stars = []; for (let i = 0; i < count; i++) { stars.push({ x: Math.random() * width, y: Math.random() * height, size: Math.random() * 1.5 + 0.5, speed: Math.random() * 0.3 + 0.1, opacity: Math.random() * 0.8 + 0.2, twinkle: Math.random() * Math.PI * 2, color: Math.random() > 0.7 ? `hsl(${220 + Math.random() * 60}, 70%, 80%)` : '#ffffff' }); } } function createNebulas() { nebulas = [ { x: width * 0.2, y: height * 0.3, r: 200, color: 'rgba(123,104,238,0.03)' }, { x: width * 0.8, y: height * 0.7, r: 250, color: 'rgba(34,211,238,0.02)' }, { x: width * 0.5, y: height * 0.5, r: 300, color: 'rgba(74,144,217,0.02)' } ]; } function animate() { ctx.fillStyle = 'rgba(3,3,8,0.1)'; ctx.fillRect(0, 0, width, height); // 绘制星云 nebulas.forEach(n => { const gradient = ctx.createRadialGradient(n.x, n.y, 0, n.x, n.y, n.r); gradient.addColorStop(0, n.color); gradient.addColorStop(1, 'transparent'); ctx.fillStyle = gradient; ctx.beginPath(); ctx.arc(n.x, n.y, n.r, 0, Math.PI * 2); ctx.fill(); }); // 绘制星星 stars.forEach(star => { star.twinkle += 0.02; const twinkleFactor = 0.5 + Math.sin(star.twinkle) * 0.5; const currentOpacity = star.opacity * twinkleFactor; ctx.beginPath(); ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2); ctx.fillStyle = star.color; ctx.globalAlpha = currentOpacity; ctx.fill(); ctx.globalAlpha = 1; // 缓慢漂移 star.y += star.speed; if (star.y > height + 10) { star.y = -10; star.x = Math.random() * width; } }); animationId = requestAnimationFrame(animate); } // ═══ 滚动显示动画 ═══ function setupReveal() { const reveals = document.querySelectorAll('.reveal'); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('visible'); } }); }, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }); reveals.forEach(el => observer.observe(el)); } // ═══ 视差效果 ═══ function setupParallax() { const hero = document.querySelector('.hero'); if (!hero) return; window.addEventListener('scroll', () => { const scrollY = window.scrollY; const opacity = Math.max(0, 1 - scrollY / 600); hero.style.opacity = opacity; hero.style.transform = `translateY(${scrollY * 0.3}px)`; }, { passive: true }); } // ═══ 鼠标光效 ═══ function setupGlow() { const cards = document.querySelectorAll('.dream-card'); cards.forEach(card => { card.addEventListener('mousemove', (e) => { const rect = card.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; card.style.setProperty('--mouse-x', `${x}px`); card.style.setProperty('--mouse-y', `${y}px`); }); }); } // ═══ 初始化 ═══ window.addEventListener('resize', () => { resize(); createStars(); createNebulas(); }); document.addEventListener('DOMContentLoaded', () => { init(); setupReveal(); setupParallax(); setupGlow(); }); })();