Frame

PLEASE JOIN US

TO CELEBRATE THE WEDDING OF

Bride
Naphatson Tangprasertphol (C-Ta)
Heart
Groom
Kulit Na Nakorn (Id)
23 July 2025
--
DAYS
--
HOURS
--
MIN
--
SEC

Schedule

Reception Icon
11:00
Ring Ceremony
Reception Icon
13:30
Wedding Ceremony

The Venue

The Botanical House Bangkok

Rama IX Rd, Suanluang, Prawet, Bangkok

Map of venue location
Home Program Register Gallery Location
`; document.body.appendChild(defsElement); // Define the edge margin for fade out effect const edgeMargin = 150; // pixels from the edge to start fading // Create butterflies const butterflyCount = 6; const butterflies = []; for (let i = 0; i < butterflyCount; i++) { // Create butterflies with random positions away from edges createButterfly( edgeMargin + Math.random() * (sectionWidth - 2 * edgeMargin), edgeMargin + Math.random() * (sectionHeight - 2 * edgeMargin), butterflyStyles[Math.floor(Math.random() * butterflyStyles.length)] ); } function createButterfly(x, y, style) { const butterfly = document.createElement('div'); butterfly.className = 'butterfly'; butterfly.style.left = `${x}px`; butterfly.style.top = `${y}px`; // Modified butterfly SVG with sharper wings and 30% smaller lower wings butterfly.innerHTML = ` `; homeSection.appendChild(butterfly); // Add to butterflies array for tracking butterflies.push({ element: butterfly, animation: null, isFlying: false, fadeTimeout: null }); // Start flying with a slight delay setTimeout(() => { butterfly.classList.add('visible'); startFlyingPath(butterfly); }, 1000 + Math.random() * 4000); } function startFlyingPath(butterfly) { const butterflyObj = butterflies.find(b => b.element === butterfly); if (!butterflyObj) return; butterflyObj.isFlying = true; // Generate a random path with multiple control points // to create a more natural, floating movement const points = []; const numPoints = 5 + Math.floor(Math.random() * 3); // 5-7 points // Start position points.push({ x: parseFloat(butterfly.style.left), y: parseFloat(butterfly.style.top) }); // Generate intermediate points for (let i = 1; i < numPoints - 1; i++) { points.push({ x: Math.random() * sectionWidth, y: Math.random() * sectionHeight }); } // End position points.push({ x: Math.random() * sectionWidth, y: Math.random() * sectionHeight }); // --- Configuration --- // Flutter configuration removed const baseScale = 0.8; // The base size of the butterfly. const randomScaleFactor = Math.random() * 0.4; // Add random size variation (0.0 to 0.4). const initialScale = baseScale + randomScaleFactor; // Final scale for this butterfly instance. // --- Create Keyframes --- const keyframes = []; let lastRotation = 0; // Store the last calculated rotation angle. for (let i = 0; i < points.length; i++) { const point = points[i]; // Calculate progress along the path (0.0 to 1.0) const progress = (points.length === 1) ? 1 : i / (points.length - 1); // --- Rotation Calculation --- let rotation = lastRotation; // Use the previous rotation by default. if (i < points.length - 1) { // Calculate the angle needed to face the *next* point. const nextPoint = points[i + 1]; rotation = Math.atan2(nextPoint.y - point.y, nextPoint.x - point.x) * (180 / Math.PI); lastRotation = rotation; // Remember this rotation for the next iteration or the end. } // For the very last point, 'rotation' correctly holds the value from the segment leading *to* it. // --- Flutter Calculation REMOVED --- // No more flutterOffset calculation or translateY needed. // --- Transform --- // Combine rotation and consistent scaling ONLY. // If your butterfly image doesn't face right by default, you might need to add an offset to 'rotation'. const transform = `scale(${initialScale}) rotate(${rotation}deg)`; // Removed translateY(...) keyframes.push({ left: `${point.x}px`, top: `${point.y}px`, transform: transform, offset: progress // offset dictates the timing within the animation duration. }); } // --- Apply Animation --- // Randomize duration for variety among multiple butterflies. const duration = 20000 + Math.random() * 15000; // 20-35 seconds // Ensure any previous animation on this element is cancelled before starting a new one. if (butterflyObj && butterflyObj.animation) { butterflyObj.animation.cancel(); } // Create the animation using the Web Animations API. butterflyObj.animation = butterfly.animate(keyframes, { duration: duration, // easing: 'ease-in-out', // Standard smooth start/end easing: 'cubic-bezier(0.4, 0, 0.6, 1)', // A slightly different smooth curve, can feel more natural // easing: 'linear', // Use if the spacing of your 'points' array already dictates speed changes. fill: 'forwards' // Ensures the butterfly stays at the final state (position, rotation, scale). }); // Optional: Add an event listener for when the animation finishes. // butterflyObj.animation.onfinish = () => { // console.log("Butterfly animation finished."); // // You might want to remove the butterfly or start a new animation here. // }; // Monitor position during flight to handle edge fading let positionChecker = setInterval(() => { if (!butterflyObj.isFlying) { clearInterval(positionChecker); return; } // Get current position const rect = butterfly.getBoundingClientRect(); const sectionRect = homeSection.getBoundingClientRect(); const left = rect.left - sectionRect.left; const top = rect.top - sectionRect.top; const right = left + rect.width; const bottom = top + rect.height; // Check if approaching an edge if (left < edgeMargin || top < edgeMargin || right > (sectionWidth - edgeMargin) || bottom > (sectionHeight - edgeMargin)) { // Start fade out butterfly.style.opacity = '0'; // Clear existing timeout if any if (butterflyObj.fadeTimeout) { clearTimeout(butterflyObj.fadeTimeout); } // After fade out, reset butterfly butterflyObj.fadeTimeout = setTimeout(() => { resetButterfly(butterfly); }, 2500); // Fade out duration matches CSS transition clearInterval(positionChecker); } }, 100); // When animation ends, reset the butterfly butterflyObj.animation.onfinish = () => { resetButterfly(butterfly); }; } function resetButterfly(butterfly) { const butterflyObj = butterflies.find(b => b.element === butterfly); if (!butterflyObj) return; butterflyObj.isFlying = false; if (butterflyObj.animation) { butterflyObj.animation.cancel(); } // Position butterfly at a new random position away from edges const newX = edgeMargin + Math.random() * (sectionWidth - 2 * edgeMargin); const newY = edgeMargin + Math.random() * (sectionHeight - 2 * edgeMargin); butterfly.style.opacity = '0'; butterfly.style.left = `${newX}px`; butterfly.style.top = `${newY}px`; // After a short delay, make visible and start new path setTimeout(() => { butterfly.style.opacity = '1'; startFlyingPath(butterfly); }, 2000 + Math.random() * 4000); } // Handle window resize window.addEventListener('resize', function() { // Update section dimensions const newWidth = homeSection.offsetWidth; const newHeight = homeSection.offsetHeight; // Reset all butterflies butterflies.forEach(butterflyObj => { const butterfly = butterflyObj.element; // Cancel ongoing animations if (butterflyObj.animation) { butterflyObj.animation.cancel(); } // Clear timeouts if (butterflyObj.fadeTimeout) { clearTimeout(butterflyObj.fadeTimeout); } // Remove from DOM butterfly.remove(); }); // Clear the array butterflies.length = 0; // Create new butterflies for the new dimensions for (let i = 0; i < butterflyCount; i++) { createButterfly( edgeMargin + Math.random() * (newWidth - 2 * edgeMargin), edgeMargin + Math.random() * (newHeight - 2 * edgeMargin), butterflyStyles[Math.floor(Math.random() * butterflyStyles.length)] ); } }); }); -->