5

ACCELERATING

MEDTECH

Discover The Evolution of MedTech Partnership.

Intech, Tyber Medical, and Resolve Surgical Technologies have united. We are now one global platform, moving beyond the traditional CDMO model to become your essential Tier-1 strategic partner for end-to-end OEM solutions.

Discover The Evolution of MedTech Partnership.

Intech, Tyber Medical, and Resolve Surgical Technologies have united. We are now one global platform, moving beyond the traditional CDMO model to become your essential Tier-1 strategic partner for end-to-end OEM solutions.

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() { setTimeout(function() { // { if (!document.querySelector(selector)) { console.error('Missing element:', selector); allElementsFound = false; } }); if (!allElementsFound) { console.error('Required elements not found, retrying in 2 seconds...'); setTimeout(arguments.callee, 2000); return; } // ===== CONFIGURATION ===== const config = { svgSelector: '.my-animated-svg', containerSelector: '.svg-container', targetImageSelector: '.target-image', taglineSelector: '.tagline', // Selector for tagline element relativePosition: { fromTop: 70, // Final position from top of target image fromLeft: 100 // Final position from left of target image }, numberOfPasses: 3, // Number of passes before final positioning initialSpeed: 3000, // Initial duration for first pass (ms) speedReduction: 0.5, // Each pass gets faster (multiply duration by this) fadeInDuration: 0, finalScale: 0.35, // Final explosion effect settings explosionScale: 3, // Scale multiplier for explosion (3 = 300%) explosionDuration: 2500, // Duration of explosion and fade out (ms) fadeInTargetImage: true, // Whether to fade in the target image during explosion // Gradient pulse settings gradientSlowPulse: 10000, // Slow pulse duration in ms (10 seconds) gradientPauseBeforeRestart: 1000, // Pause before restarting slow pulse (1 second) // Container resize settings containerResizeDelay: 0, // Delay before container resize (1 second) containerResizeDuration: 2000, // Duration of container resize animation (2 seconds) containerFinalHeight: '100vh', // Final height of container after animation // Countdown settings showCountdown: true, // Enable/disable countdown countdownStart: 5, // Starting number countdownOpacity: 0.3 // Semi-transparency (0.3 = 30% opacity) };// Get elements const svg = document.querySelector(config.svgSelector); const container = document.querySelector(config.containerSelector); const targetImage = document.querySelector(config.targetImageSelector); const taglines = document.querySelectorAll(config.taglineSelector); const countdown = document.querySelector('.countdown-number'); if (!svg || !container || !targetImage) { console.error('Required elements not found'); return; }// Store original dimensions const originalWidth = svg.offsetWidth; const originalHeight = svg.offsetHeight; 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; // Apply scaling directly countdown.style.transform = 'scale(1.3)'; countdown.style.transition = 'transform 0.5s ease-out'; setTimeout(() => { countdown.style.transform = 'scale(1)'; }, 50); } else { // Make sure it fully disappears countdown.style.opacity = '0'; countdown.style.visibility = 'hidden'; countdown.textContent = ''; // Clear the text 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; // +1 for final positioning pass const scaleReductionPerPass = (1 - config.finalScale) / totalPasses; // Setup initial position (left side, centered vertically) svg.style.left = `-${svgWidth}px`; svg.style.top = '50%'; svg.style.transition = 'none'; // Phase 1: Fade in console.log('Fading in...'); svg.style.opacity = '1'; await delay(config.fadeInDuration); // Phase 2: Multiple passes with increasing speed and progressive scaling 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)'; }); } // Fade in target image at the same time as explosion 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); // Wait 1 second then restart slow gradient pulse await delay(config.gradientPauseBeforeRestart); container.style.animation = `gradientShiftSlow ${config.gradientSlowPulse}ms ease-in-out infinite`; // Wait then resize container 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 on page load animateSequence();// Restart animation on container 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.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'); // Reset target image opacity if fade-in is enabled if (config.fadeInTargetImage) { targetImage.style.transition = 'none'; targetImage.style.opacity = '0'; targetImage.offsetHeight; // Force reflow targetImage.style.transition = `opacity ${config.explosionDuration}ms ease-in`; } // Reset tagline if (taglines && taglines.length > 0) { taglines.forEach(tagline => { tagline.style.transition = 'none'; tagline.style.opacity = '0'; tagline.style.filter = 'blur(10px)'; tagline.offsetHeight; // Force reflow }); } // Reset countdown if (countdown) { countdown.style.opacity = '0'; countdown.style.visibility = 'hidden'; countdown.textContent = ''; } // Reset gradient container.style.animation = `gradientShift ${config.gradientSlowPulse}ms ease-in-out infinite`; // Reset container height container.style.transition = 'none'; container.style.minHeight = '100vh'; container.offsetHeight; // Force reflow container.style.transition = `min-height ${config.containerResizeDuration}ms ease-in-out`; svg.offsetHeight; // Force reflow setTimeout(animateSequence, 100); }); // Update position on resize 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 script error:', error); } }, 1500); // Add delay here });