svg
(function() {
// Prevent multiple initializations
if (window.animationInitialized) {
console.log('Animation already initialized, skipping...');
return;
}
window.animationInitialized = true;
console.log('Script loaded at:', new Date().toISOString());
let initAttempts = 0;
const maxAttempts = 20;
let animationStarted = false; // Additional flag to prevent multiple starts
function initAnimation() {
// Check if animation already started
if (animationStarted) {
console.log('Animation already started, skipping initialization');
return;
}
initAttempts++;
console.log(`Initialization attempt ${initAttempts}/${maxAttempts}`);
try {
// Check if elements exist
const svg = document.querySelector('.my-animated-svg');
const container = document.querySelector('.svg-container');
const targetImage = document.querySelector('.target-image');
console.log('Element check:', {
svg: svg ? 'Found' : 'Not found',
container: container ? 'Found' : 'Not found',
targetImage: targetImage ? 'Found' : 'Not found'
});
if (!svg || !container || !targetImage) {
if (initAttempts < maxAttempts) {
console.log('Elements not ready, retrying in 500ms...');
setTimeout(initAnimation, 500);
} else {
console.error('Max attempts reached. Elements not found.');
}
return;
}
// Check if elements are visible
const containerRect = container.getBoundingClientRect();
if (containerRect.width === 0 || containerRect.height === 0) {
console.log('Container has no dimensions, waiting...');
if (initAttempts < maxAttempts) {
setTimeout(initAnimation, 500);
return;
}
}
// Mark animation as started to prevent multiple runs
animationStarted = true;
console.log('All elements found and ready! Starting animation...');
// ===== CONFIGURATION =====
const config = {
svgSelector: '.my-animated-svg',
containerSelector: '.svg-container',
targetImageSelector: '.target-image',
taglineSelector: '.tagline',
relativePosition: {
fromTop: 70,
fromLeft: 100
},
numberOfPasses: 3,
initialSpeed: 3000,
speedReduction: 0.5,
fadeInDuration: 0,
finalScale: 0.35,
explosionScale: 3,
explosionDuration: 2500,
fadeInTargetImage: true,
gradientSlowPulse: 10000,
gradientPauseBeforeRestart: 1000,
containerResizeDelay: 0,
containerResizeDuration: 2000,
containerFinalHeight: '100vh',
showCountdown: true,
countdownStart: 5,
countdownOpacity: 0.3
};
// Get additional elements
const taglines = document.querySelectorAll(config.taglineSelector);
const countdown = document.querySelector('.countdown-number');
console.log('Additional elements:', {
taglines: taglines.length + ' found',
countdown: countdown ? 'Found' : 'Not found'
});
// Store original dimensions
const originalWidth = svg.offsetWidth || svg.getBoundingClientRect().width;
const originalHeight = svg.offsetHeight || svg.getBoundingClientRect().height;
console.log('SVG dimensions:', { width: originalWidth, height: originalHeight });
if (originalWidth === 0 || originalHeight === 0) {
console.error('SVG has no dimensions! Retrying...');
animationStarted = false; // Reset flag to allow retry
if (initAttempts < maxAttempts) {
setTimeout(initAnimation, 500);
return;
}
}
let isAnimating = false;
// Hide target image initially if fade-in is enabled
if (config.fadeInTargetImage) {
targetImage.style.opacity = '0';
targetImage.style.transition = `opacity ${config.explosionDuration}ms ease-in`;
}
// Calculate final position relative to target image
function calculateFinalPosition() {
const targetRect = targetImage.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
const targetRelativeTop = targetRect.top - containerRect.top;
const targetRelativeLeft = targetRect.left - containerRect.left;
const finalLeft = targetRelativeLeft + config.relativePosition.fromLeft;
const finalTop = targetRelativeTop + config.relativePosition.fromTop;
return { top: finalTop, left: finalLeft };
}
// Main animation sequence
async function animateSequence() {
if (isAnimating) return;
isAnimating = true;
console.log('Starting progressive speed animation...');
const containerWidth = container.offsetWidth;
const svgWidth = originalWidth;
// Calculate total animation duration for countdown
let countdownTotalDuration = config.fadeInDuration;
let tempSpeed = config.initialSpeed;
for (let i = 0; i {
currentNumber--;
if (currentNumber > 0) {
countdown.textContent = currentNumber;
countdown.style.transform = 'scale(1.3)';
countdown.style.transition = 'transform 0.5s ease-out';
setTimeout(() => {
countdown.style.transform = 'scale(1)';
}, 50);
} else {
countdown.style.opacity = '0';
countdown.style.visibility = 'hidden';
countdown.textContent = '';
clearInterval(countdownTimer);
}
}, countdownInterval);
}
// Start with slow gradient pulse
container.style.animation = `gradientShift ${config.gradientSlowPulse}ms ease-in-out infinite`;
// Calculate scale reduction per pass
const totalPasses = config.numberOfPasses + 1;
const scaleReductionPerPass = (1 - config.finalScale) / totalPasses;
// Setup initial position
svg.style.left = `-${svgWidth}px`;
svg.style.top = '50%';
svg.style.transition = 'none';
// Phase 1: Fade in
console.log('Phase 1: Fading in...');
svg.style.opacity = '1';
await delay(config.fadeInDuration);
// Phase 2: Multiple passes
let currentSpeed = config.initialSpeed;
let currentScale = 1;
for (let pass = 1; pass 0) {
const taglineDuration = config.explosionDuration + config.gradientPauseBeforeRestart;
taglines.forEach(tagline => {
tagline.style.transition = `opacity ${taglineDuration}ms ease-out, filter ${taglineDuration}ms ease-out`;
tagline.style.opacity = '1';
tagline.style.filter = 'blur(0px)';
});
}
if (config.fadeInTargetImage) {
targetImage.style.opacity = '1';
}
svg.style.transition = `transform ${config.explosionDuration}ms cubic-bezier(0, 0, 0.2, 1), opacity ${config.explosionDuration}ms ease-out`;
svg.style.transform = `translate(-50%, -50%) scale(${config.finalScale * config.explosionScale})`;
svg.style.opacity = '0';
await delay(config.explosionDuration);
await delay(config.gradientPauseBeforeRestart);
container.style.animation = `gradientShiftSlow ${config.gradientSlowPulse}ms ease-in-out infinite`;
await delay(config.containerResizeDelay);
console.log('Resizing container...');
container.style.transition = `min-height ${config.containerResizeDuration}ms ease-in-out`;
container.style.minHeight = config.containerFinalHeight;
await delay(config.containerResizeDuration);
console.log('Animation complete!');
isAnimating = false;
}
// Helper function for delays
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Start animation ONLY ONCE
animateSequence();
// Click to restart
container.addEventListener('click', function() {
if (isAnimating) return;
console.log('Restarting animation...');
svg.style.transition = 'none';
svg.style.opacity = '0';
svg.style.left = `-${originalWidth}px`;
svg.style.top = '50%';
svg.style.transform = 'translateY(-50%)';
svg.style.width = `${originalWidth}px`;
svg.style.height = `${originalHeight}px`;
svg.style.animation = 'none';
svg.classList.remove('blur-light', 'blur-medium', 'blur-heavy', 'blur-extreme', 'blur-super');
if (config.fadeInTargetImage) {
targetImage.style.transition = 'none';
targetImage.style.opacity = '0';
targetImage.offsetHeight;
targetImage.style.transition = `opacity ${config.explosionDuration}ms ease-in`;
}
if (taglines && taglines.length > 0) {
taglines.forEach(tagline => {
tagline.style.transition = 'none';
tagline.style.opacity = '0';
tagline.style.filter = 'blur(10px)';
tagline.offsetHeight;
});
}
if (countdown) {
countdown.style.opacity = '0';
countdown.style.visibility = 'hidden';
countdown.textContent = '';
}
container.style.animation = `gradientShift ${config.gradientSlowPulse}ms ease-in-out infinite`;
container.style.transition = 'none';
container.style.minHeight = '100vh';
container.offsetHeight;
container.style.transition = `min-height ${config.containerResizeDuration}ms ease-in-out`;
svg.offsetHeight;
setTimeout(animateSequence, 100);
});
// Resize handler
window.addEventListener('resize', function() {
if (!isAnimating && svg.style.transform.includes('translate(-50%, -50%)')) {
const finalPosition = calculateFinalPosition();
svg.style.left = `${finalPosition.left}px`;
svg.style.top = `${finalPosition.top}px`;
}
});
} catch (error) {
console.error('Animation error:', error);
console.error('Error stack:', error.stack);
}
}
// Only ONE initialization method - wait for page to be ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
console.log('DOMContentLoaded - waiting 2s before init');
setTimeout(initAnimation, 2000);
});
} else {
// Document already loaded
console.log('Document already loaded - waiting 2s before init');
setTimeout(initAnimation, 2000);
}
})();