I was working with Layout 484 (the big text animation). It triggers on page load, so unless it’s at the top of your page, you won’t even notice the nice animation. I wanted it to trigger (and re-trigger) when scrolled into view.
I went to Claude, and after just 50 exchanges, I settled on this updated code (to replace in the code block that comes with the component).
Refer to the top of the code for a list of features. Note in the attached gif that the debug markers are on, and I’m showing how it animates from zero, scrolling away mid-animation, and resetting when it’s out of view. Your mileage may vary. Good luck!
Features:
<!-- GSAP Word-by-Word Scroll Animation Features: - Words fade in one-by-one when scrolled into view - All words instantly fade out (reset) together when scrolled out of view - Prevents animation overlap during rapid scrolling - Configurable timing, opacity levels, and trigger points - Includes helpful debug markers (REMEMBER TO DISABLE FOR PRODUCTION!) Created by: - Claude-3.5-Sonnet (Anthropic) - Lee Fuhr (hi@leefuhr.com) (I should say: I'm no developer. I provide no support. For support, go where I went: Claude.ai.) Version 1.0 - January 2024 --> <!-- Include GSAP library first --> <script src="<a target="_blank" rel="noopener noreferrer" href="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js">https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js</a>"></script> <!-- Include ScrollTrigger plugin --> <script src="<a target="_blank" rel="noopener noreferrer" href="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js">https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js</a>"></script> <!-- Include Split-Type library --> <script src="<a target="_blank" rel="noopener noreferrer" href="https://unpkg.com/split-type">https://unpkg.com/split-type</a>"></script> <script> window.addEventListener('load', function() { // CONFIGURATION SETTINGS const config = { // CLASSES FOR TARGETING ELEMENTS triggerClass: ".section_layout484", // The section that triggers the animation textClass: ".layout484_text", // The text that will be split and animated // SCROLL TRIGGER POINTS startTrigger: "top 80%", // Animation starts when top of section reaches 80% up from bottom of viewport endTrigger: "bottom 20%", // Animation ends when bottom of section reaches 20% up from bottom of viewport showMarkers: true, // Visual indicators for trigger points (SET TO 'FALSE' FOR PRODUCTION!) // ANIMATION PARAMETERS initialOpacity: 0.3, // Starting opacity of words (0 = invisible, 1 = fully visible) finalOpacity: 1, // Ending opacity of words animationDuration: 0.8, // How long the fade takes (in seconds) staggerTime: 0.1, // Delay between each word's animation (in seconds) easeType: "power1.out" // Animation easing function (controls acceleration/deceleration) }; // REGISTER SCROLLTRIGGER PLUGIN if (typeof ScrollTrigger !== "undefined") { gsap.registerPlugin(ScrollTrigger); } // INITIALIZE TEXT SPLITTING const layoutText = new SplitType(config.textClass, { types: "words" }); // SET INITIAL STATE gsap.set(layoutText.words, { opacity: config.initialOpacity }); // ANIMATION STATE TRACKING let isAnimating = false; let currentTimeline = null; // ANIMATION FUNCTION function animate(toFinal) { // IF ANIMATION IS RUNNING, LET IT FINISH if (isAnimating) return; isAnimating = true; // CREATE NEW TIMELINE FOR THIS ANIMATION SEQUENCE currentTimeline = gsap.timeline({ onComplete: () => { isAnimating = false; currentTimeline = null; } }); if (toFinal) { // STAGGERED ANIMATION FOR APPEARING currentTimeline.to(layoutText.words, { opacity: config.finalOpacity, duration: config.animationDuration, stagger: config.staggerTime, ease: config.easeType }); } else { // INSTANT RESET FOR ALL WORDS currentTimeline.to(layoutText.words, { opacity: config.initialOpacity, duration: config.animationDuration / 2, // Faster reset stagger: 0, // No stagger - all words together ease: "power1.in" }); } } // SCROLL TRIGGER CREATION const st = ScrollTrigger.create({ trigger: config.triggerClass, start: config.startTrigger, end: config.endTrigger, markers: config.showMarkers, onEnter: () => { if (!isAnimating) animate(true); }, onLeave: () => { if (!isAnimating) animate(false); }, onEnterBack: () => { if (!isAnimating) animate(true); }, onLeaveBack: () => { if (!isAnimating) animate(false); } }); }); </script>