Typo Animation : GSAP Wipe Effect
Cette animation applique un effet de wipe aux textes, avec un easing personnalisé. Une fois les attributs posés, l'animation se déclenche quand l'élément entre dans le viewport. Vous contrôlez le délai, la durée et le point de déclenchement au scroll. Le résultat : une entrée nette et dynamique, bloc par bloc.
Attributs
data-anim="menu-link" : élément cible de l'effet
data-anim-delay="200" : délai avant le démarrage (en ms)
data-anim-duration="800" : durée de l'animation (en ms)
data-anim-offset="60" : décalage de déclenchement au scroll (en %)
Attributs d'exemple
data-anim = "menu-link" Target element to animate with the wipe effect data-anim-delay = "200" Delay before the animation starts (in ms) data-anim-duration = "800" Duration of the animation (in ms) data-anim-offset = "60" offset for starting animation (in %)
Librairies GSAP + CustomEase (CDN)
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.2/dist/gsap.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/gsap@3.12.2/dist/CustomEase.min.js"></script>
Script de l'animation
<script> document.addEventListener("DOMContentLoaded", function () { gsap.registerPlugin(CustomEase); CustomEase.create("main", "0.65, 0.01, 0.05, 0.99"); const containers = document.querySelectorAll('[data-anim="menu-link"]'); containers.forEach(container => { const delayAttr = parseInt(container.getAttribute('data-anim-delay')) || 0; const animDurationAttr = parseInt(container.getAttribute('data-anim-duration')) || 800; const offsetPercent = parseInt(container.getAttribute('data-anim-offset')) || 0; // ⚠️ Set initial state: hidden gsap.set(container, { opacity: 0, yPercent: 140, rotate: 10 }); // Convert offset % to px const offsetPixels = window.innerHeight * (offsetPercent / 100); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { gsap.to(container, { yPercent: 0, rotate: 0, opacity: 1, duration: animDurationAttr / 1000, delay: delayAttr / 1000, ease: "main" }); observer.unobserve(container); } }); }, { threshold: 0.01, rootMargin: `0px 0px -${offsetPixels}px 0px` }); observer.observe(container); }); }); </script>