From idea…

… to Concept

From Design

… to Production & Compliance

TO

script for magic scroll
document.addEventListener('DOMContentLoaded', function() { const items = 4; // Total number of items const scrollHeight = document.querySelector('.scroll-spacer').offsetHeight; window.addEventListener('scroll', function() { const scrolled = window.pageYOffset; const maxScroll = scrollHeight - window.innerHeight; const scrollProgress = scrolled / maxScroll; // Calculate which item should show (1 to items) let currentIndex = Math.ceil(scrollProgress * items); if (currentIndex items) currentIndex = items; // Update all items at once document.querySelectorAll('.fade-item').forEach(item => { if (item.dataset.index == currentIndex) { item.classList.add('active'); } else { item.classList.remove('active'); } }); }); });
scramble
class TextScramble { constructor(el) { this.el = el; this.chars = '!-_\\/[]{}—=+*^?#________'; this.update = this.update.bind(this); } setText(newText) { const oldText = this.el.innerText; const length = Math.max(oldText.length, newText.length); const promise = new Promise((resolve) => this.resolve = resolve); this.queue = []; for (let i = 0; i < length; i++) { const from = oldText[i] || ''; const to = newText[i] || ''; const start = Math.floor(Math.random() * 40); const end = start + Math.floor(Math.random() * 40); this.queue.push({ from, to, start, end }); } cancelAnimationFrame(this.frameRequest); this.frame = 0; this.update(); return promise; } update() { let output = ''; let complete = 0; for (let i = 0, n = this.queue.length; i = end) { complete++; output += to; } else if (this.frame >= start) { if (!char || Math.random() { // Skip if already initialized if (element.hasAttribute('data-scramble-init')) return; // Get the original text - prioritize data-text attribute if it exists // Otherwise use the actual text content let originalText = element.getAttribute('data-text') || element.textContent || element.innerText; // Clean up the text (remove extra whitespace) originalText = originalText.trim(); // Mark as initialized element.setAttribute('data-scramble-init', 'true'); // Store original text element.setAttribute('data-text', originalText); // Clear text initially element.textContent = ''; // Find the parent fade-item element const fadeItem = element.closest('.fade-item'); if (fadeItem) { // Track if currently animating to prevent overlapping animations let isAnimating = false; // Create MutationObserver to watch for class changes const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.type === 'attributes' && mutation.attributeName === 'class') { // Check if 'active' class was added if (fadeItem.classList.contains('active') && !isAnimating) { // Set animating flag isAnimating = true; // Create scramble effect instance const fx = new TextScramble(element); // Small delay to sync with fade-in setTimeout(() => { element.classList.add('visible'); fx.setText(originalText).then(() => { // Optional: Add glow effect after animation completes element.classList.add('glowing'); setTimeout(() => { element.classList.remove('glowing'); }, 500); }); }, 100); // Adjust delay as needed } // Reset when active class is removed else if (!fadeItem.classList.contains('active') && isAnimating) { // Reset for re-animation isAnimating = false; element.textContent = ''; element.classList.remove('visible'); element.classList.remove('glowing'); } } }); }); // Start observing the fade-item for class changes observer.observe(fadeItem, { attributes: true, attributeFilter: ['class'] }); // Check if already active on page load if (fadeItem.classList.contains('active')) { setTimeout(() => { isAnimating = true; const fx = new TextScramble(element); element.classList.add('visible'); fx.setText(originalText); }, 100); } } else { // If not inside a fade-item, use Intersection Observer as fallback const observerOptions = { threshold: 0.2, rootMargin: '0px' }; const scrambleObserver = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting && !element.hasAttribute('data-scramble-animated')) { element.setAttribute('data-scramble-animated', 'true'); const fx = new TextScramble(element); element.classList.add('visible'); fx.setText(originalText).then(() => { element.classList.add('glowing'); setTimeout(() => { element.classList.remove('glowing'); }, 500); }); scrambleObserver.unobserve(element); } }); }, observerOptions); scrambleObserver.observe(element); } }); } // Initialize on DOMContentLoaded document.addEventListener('DOMContentLoaded', function() { // Small delay to ensure your scroll script runs first setTimeout(initScrambleEffect, 100); }); // Also initialize when Elementor loads new content (for popup, tabs, etc.) if (typeof jQuery !== 'undefined' && window.elementorFrontend) { jQuery(window).on('elementor/frontend/init', function() { elementorFrontend.hooks.addAction('frontend/element_ready/widget', initScrambleEffect); }); }// For Elementor: Re-run on Elementor preview refresh if (window.elementor) { window.elementor.on('preview:loaded', function() { // Re-initialize for preview mode const elements = document.querySelectorAll('.scramble-text'); elements.forEach((element) => { const fx = new TextScramble(element); const originalText = element.getAttribute('data-text'); if (originalText) { element.innerText = ''; element.classList.remove('visible'); setTimeout(() => { element.classList.add('visible'); fx.setText(originalText); }, 500); } }); }); }
svg anim
document.addEventListener('DOMContentLoaded', function() { // ===== CONFIGURATION - Customize these values ===== const config = { svgSelector: '.my-animated-svg', containerSelector: '.svg-container', targetImageSelector: '.target-image', // Selector for the target image relativePosition: { // Position in pixels from top-left corner of target image fromTop: 70, // Pixels from top edge of target image fromLeft: 100// Pixels from left edge of target image }, fadeInDuration: 1000, speedEffectDuration: 2000, scaleAndMoveDuration: 2000, finalScale: 0.35 };// Get elements const svg = document.querySelector(config.svgSelector); const container = document.querySelector(config.containerSelector); const targetImage = document.querySelector(config.targetImageSelector); if (!svg) { console.error('SVG element not found. Check your svgSelector:', config.svgSelector); return; } if (!container) { console.error('Container element not found. Check your containerSelector:', config.containerSelector); return; } if (!targetImage) { console.error('Target image not found. Check your targetImageSelector:', config.targetImageSelector); return; }// Store original dimensions const originalWidth = svg.offsetWidth; const originalHeight = svg.offsetHeight; // Flag to prevent animation overlap let isAnimating = false;// Function to calculate final position relative to target image function calculateFinalPosition() { const targetRect = targetImage.getBoundingClientRect(); const containerRect = container.getBoundingClientRect(); // Calculate target image position relative to container const targetRelativeTop = targetRect.top - containerRect.top; const targetRelativeLeft = targetRect.left - containerRect.left; // Calculate final position from top-left corner of target image // The SVG center will be positioned at these coordinates 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 animation sequence...'); // Phase 1: Fade in console.log('Phase 1: Fading in...'); svg.style.transition = `opacity ${config.fadeInDuration}ms ease-in`; svg.style.opacity = '1'; await delay(config.fadeInDuration);// Phase 2: Speed effect (standing still) console.log('Phase 2: Speed effect while standing still...'); svg.style.animation = 'vibrate 0.1s infinite, speedEffect 0.2s infinite'; await delay(config.speedEffectDuration);// Phase 3: Progressive scale down and move to position console.log('Phase 3: Scaling down and moving...'); // Clear the vibrate animation svg.style.animation = 'speedEffect 0.2s infinite'; // Calculate positions const finalPosition = calculateFinalPosition(); const finalWidth = originalWidth * config.finalScale; const finalHeight = originalHeight * config.finalScale; // Starting position (center of container) const containerRect = container.getBoundingClientRect(); const startTop = containerRect.height / 2; const startLeft = containerRect.width / 2; // Ending position const endTop = finalPosition.top; const endLeft = finalPosition.left; console.log('Moving to position relative to target image:', { endTop, endLeft }); const startTime = Date.now(); const duration = config.scaleAndMoveDuration; // Animate position and scale progressively const animateFrame = () => { const elapsed = Date.now() - startTime; const progress = Math.min(elapsed / duration, 1); // Easing function (ease-in-out) const easeProgress = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2; // Calculate current values const currentScale = 1 + (config.finalScale - 1) * easeProgress; const currentTop = startTop + (endTop - startTop) * easeProgress; const currentLeft = startLeft + (endLeft - startLeft) * easeProgress; // Apply transformation svg.style.width = (originalWidth * currentScale) + 'px'; svg.style.height = (originalHeight * currentScale) + 'px'; svg.style.top = currentTop + 'px'; svg.style.left = currentLeft + 'px'; // Add slight vibration during movement const vibrationOffset = Math.sin(elapsed * 0.05) * 2; svg.style.transform = `translate(calc(-50% + ${vibrationOffset}px), -50%)`; if (progress setTimeout(resolve, ms)); }// Start animation on page load animateSequence();// Restart animation on click container.addEventListener('click', function() { if (isAnimating) return; console.log('Restarting animation...'); // Reset all styles svg.style.transition = 'none'; svg.style.opacity = '0'; svg.style.top = '50%'; svg.style.left = '50%'; svg.style.width = originalWidth + 'px'; svg.style.height = originalHeight + 'px'; svg.style.transform = 'translate(-50%, -50%)'; svg.style.animation = 'none'; // Force browser to recalculate styles svg.offsetHeight; // Restart animation after brief delay setTimeout(animateSequence, 100); }); // Recalculate position on window resize window.addEventListener('resize', function() { if (!isAnimating) { // Update final position if animation is complete const finalPosition = calculateFinalPosition(); if (parseFloat(svg.style.opacity) === 1 && !svg.style.animation) { svg.style.top = finalPosition.top + 'px'; svg.style.left = finalPosition.left + 'px'; } } }); });

TIME TO

MARKET