script.js

11.36 KB
28/01/2026 03:32
JS
script.js
// ========================================
// Floating Hearts Animation
// ========================================
function createFloatingHearts() {
    const heartsContainer = document.getElementById('heartsContainer');
    const heartSymbols = ['❤️', '💕', '💖', '💗', '💓', '💝'];

    function addHeart() {
        const heart = document.createElement('div');
        heart.className = 'floating-heart';
        heart.textContent = heartSymbols[Math.floor(Math.random() * heartSymbols.length)];
        heart.style.left = Math.random() * 100 + '%';
        heart.style.animationDuration = (Math.random() * 5 + 8) + 's';
        heart.style.fontSize = (Math.random() * 1.5 + 1) + 'rem';

        heartsContainer.appendChild(heart);

        setTimeout(() => {
            heart.remove();
        }, 12000);
    }

    // Create initial hearts
    for (let i = 0; i < 15; i++) {
        setTimeout(addHeart, i * 500);
    }

    // Continue creating hearts
    setInterval(addHeart, 1000);
}

// ========================================
// Particle System
// ========================================
function initParticleSystem() {
    const canvas = document.getElementById('particleCanvas');
    const ctx = canvas.getContext('2d');

    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    const particles = [];
    const particleCount = 50;

    class Particle {
        constructor() {
            this.x = Math.random() * canvas.width;
            this.y = Math.random() * canvas.height;
            this.size = Math.random() * 3 + 1;
            this.speedX = Math.random() * 2 - 1;
            this.speedY = Math.random() * 2 - 1;
            this.opacity = Math.random() * 0.5 + 0.2;
        }

        update() {
            this.x += this.speedX;
            this.y += this.speedY;

            if (this.x > canvas.width) this.x = 0;
            if (this.x < 0) this.x = canvas.width;
            if (this.y > canvas.height) this.y = 0;
            if (this.y < 0) this.y = canvas.height;
        }

        draw() {
            ctx.fillStyle = `rgba(255, 255, 255, ${this.opacity})`;
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
            ctx.fill();
        }
    }

    function init() {
        for (let i = 0; i < particleCount; i++) {
            particles.push(new Particle());
        }
    }

    function animate() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        particles.forEach(particle => {
            particle.update();
            particle.draw();
        });

        requestAnimationFrame(animate);
    }

    init();
    animate();

    window.addEventListener('resize', () => {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
    });
}

// ========================================
// Countdown Timer
// ========================================
function initCountdown() {
    const daysEl = document.getElementById('days');
    const hoursEl = document.getElementById('hours');
    const minutesEl = document.getElementById('minutes');
    const secondsEl = document.getElementById('seconds');

    function updateCountdown() {
        const now = new Date();
        const currentYear = now.getFullYear();
        let valentinesDay = new Date(currentYear, 1, 14); // February 14

        // If Valentine's Day has passed this year, count to next year
        if (now > valentinesDay) {
            valentinesDay = new Date(currentYear + 1, 1, 14);
        }

        const diff = valentinesDay - now;

        const days = Math.floor(diff / (1000 * 60 * 60 * 24));
        const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
        const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
        const seconds = Math.floor((diff % (1000 * 60)) / 1000);

        daysEl.textContent = String(days).padStart(2, '0');
        hoursEl.textContent = String(hours).padStart(2, '0');
        minutesEl.textContent = String(minutes).padStart(2, '0');
        secondsEl.textContent = String(seconds).padStart(2, '0');
    }

    updateCountdown();
    setInterval(updateCountdown, 1000);
}

// ========================================
// Scroll Reveal Animation
// ========================================
function initScrollReveal() {
    const revealElements = document.querySelectorAll('.reveal-on-scroll');

    const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                entry.target.classList.add('revealed');
            }
        });
    }, {
        threshold: 0.1,
        rootMargin: '0px 0px -50px 0px'
    });

    revealElements.forEach(el => observer.observe(el));
}

// ========================================
// Typewriter Effect
// ========================================
function initTypewriter() {
    const messageEl = document.getElementById('loveMessage');
    const message = `My Dearest Valentine,

Every moment with you feels like a beautiful dream come true. Your smile lights up my world, and your laughter is the sweetest melody I've ever heard.

From the first time we met, I knew you were special. You've brought so much joy, love, and meaning into my life. Every day with you is an adventure, and I cherish every single moment we share together.

Thank you for being my partner, my best friend, and my greatest love. You make every day feel like Valentine's Day.

I love you more than words can express, today and always. 💖`;

    let index = 0;

    function type() {
        if (index < message.length) {
            messageEl.textContent += message.charAt(index);
            index++;
            setTimeout(type, 30);
        } else {
            messageEl.classList.remove('typewriter');
        }
    }

    // Start typing when element is in view
    const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            if (entry.isIntersecting && index === 0) {
                type();
                observer.unobserve(entry.target);
            }
        });
    }, { threshold: 0.5 });

    observer.observe(messageEl);
}

// ========================================
// Love Button Interaction
// ========================================
function initLoveButton() {
    const loveButton = document.getElementById('loveButton');
    const loveCount = document.getElementById('loveCount');
    let count = 0;

    loveButton.addEventListener('click', function(e) {
        count++;
        loveCount.textContent = count;

        // Create floating hearts from button
        for (let i = 0; i < 5; i++) {
            createClickHeart(e.clientX, e.clientY);
        }

        // Add animation class
        loveButton.style.transform = 'scale(0.9)';
        setTimeout(() => {
            loveButton.style.transform = '';
        }, 200);
    });

    function createClickHeart(x, y) {
        const heart = document.createElement('div');
        heart.textContent = '❤️';
        heart.style.position = 'fixed';
        heart.style.left = x + 'px';
        heart.style.top = y + 'px';
        heart.style.fontSize = '2rem';
        heart.style.pointerEvents = 'none';
        heart.style.zIndex = '9999';
        heart.style.animation = 'floatUpClick 2s ease-out forwards';

        document.body.appendChild(heart);

        setTimeout(() => {
            heart.remove();
        }, 2000);
    }

    // Add CSS animation for click hearts
    const style = document.createElement('style');
    style.textContent = `
        @keyframes floatUpClick {
            0% {
                transform: translateY(0) scale(1);
                opacity: 1;
            }
            100% {
                transform: translateY(-200px) scale(0.5);
                opacity: 0;
            }
        }
    `;
    document.head.appendChild(style);
}

// ========================================
// Smooth Scroll for Navigation
// ========================================
function initSmoothScroll() {
    document.querySelectorAll('a[href^="#"]').forEach(anchor => {
        anchor.addEventListener('click', function (e) {
            e.preventDefault();
            const target = document.querySelector(this.getAttribute('href'));
            if (target) {
                target.scrollIntoView({
                    behavior: 'smooth',
                    block: 'start'
                });
            }
        });
    });
}

// ========================================
// Gallery Hover Effects
// ========================================
function initGalleryEffects() {
    const galleryItems = document.querySelectorAll('.gallery-item');

    galleryItems.forEach(item => {
        item.addEventListener('mouseenter', function() {
            this.style.transform = 'translateY(-10px) scale(1.02)';
        });

        item.addEventListener('mouseleave', function() {
            this.style.transform = '';
        });
    });
}

// ========================================
// Mouse Trail Effect
// ========================================
function initMouseTrail() {
    let lastTime = 0;
    const throttleDelay = 100;

    document.addEventListener('mousemove', function(e) {
        const currentTime = Date.now();

        if (currentTime - lastTime < throttleDelay) {
            return;
        }

        lastTime = currentTime;

        if (Math.random() > 0.7) {
            const sparkle = document.createElement('div');
            sparkle.textContent = '✨';
            sparkle.style.position = 'fixed';
            sparkle.style.left = e.clientX + 'px';
            sparkle.style.top = e.clientY + 'px';
            sparkle.style.fontSize = '1rem';
            sparkle.style.pointerEvents = 'none';
            sparkle.style.zIndex = '9999';
            sparkle.style.animation = 'sparkle 1s ease-out forwards';

            document.body.appendChild(sparkle);

            setTimeout(() => {
                sparkle.remove();
            }, 1000);
        }
    });

    // Add sparkle animation
    const style = document.createElement('style');
    style.textContent = `
        @keyframes sparkle {
            0% {
                transform: scale(0) rotate(0deg);
                opacity: 1;
            }
            100% {
                transform: scale(1.5) rotate(180deg);
                opacity: 0;
            }
        }
    `;
    document.head.appendChild(style);
}

// ========================================
// Initialize All Features
// ========================================
document.addEventListener('DOMContentLoaded', function() {
    console.log('💖 Valentine\'s Day Website Loaded!');

    // Initialize all features
    createFloatingHearts();
    initParticleSystem();
    initCountdown();
    initScrollReveal();
    initTypewriter();
    initLoveButton();
    initSmoothScroll();
    initGalleryEffects();
    initMouseTrail();

    // Add entrance animation to body
    document.body.style.opacity = '0';
    setTimeout(() => {
        document.body.style.transition = 'opacity 1s ease';
        document.body.style.opacity = '1';
    }, 100);
});

// ========================================
// Performance Optimization
// ========================================
// Pause animations when tab is not visible
document.addEventListener('visibilitychange', function() {
    if (document.hidden) {
        // Pause heavy animations
        console.log('Tab hidden - reducing animations');
    } else {
        // Resume animations
        console.log('Tab visible - resuming animations');
    }
});