Search the Community
Showing results for tags 'scrolltrigger'.
-
Hi Folks, In the given demo, a kind of navigation bar appears at the top after scrolling the header. When I click any title from that e.g. Bathroom, Kitchen, Outdoor it should be highlighted and go to the respective section. However, it's not working many times especially not highlighting the title area as expected. Is there something that I'm doing wrong or is that a bug in either of the used plugins? It would be great if someone could help with the same since this is a very common use case. Thank you.
- 3 replies
-
- scrolltrigger
- scrollsmoother
-
(and 1 more)
Tagged with:
-
scrollsmoother Jittering issue with ScrollSmoother and ScrollTrigger: Pinned Elements Jittery, or the rest of my page(s) laggy
TheBrand.Estate posted a topic in GSAP
Hi everyone, I’m running into a mobile-specific issue with ScrollTrigger pinning and scroll behavior, and I’ve reached a bit of a Catch-22. I’m building my site in Webflow, but I am using Slater for custom code. My setup includes ScrollSmoother for the full page and ScrollTrigger for a number of pin-based interactions. I know that a demo would help but it would not recreate my issue. I do have a screen recording from my phone. The issue I’m facing is the following: When I use ScrollTrigger with pin: true on mobile (iOS Safari especially), I get jittery behavior — the pinned elements (like my hero section and some scrubbing animations below it) visually shake or lag as you scroll. This is the same issue described in this thread: https://gsap.com/community/forums/topic/35157-scrolltrigger-pinning-causes-jitter-when-using-touch-on-safari/ If I follow the advice from that post and enable ScrollTrigger.normalizeScroll(), it fixes the jitter for the pinned elements. Great — but then the rest of my page becomes sluggish and jittery instead. Scroll feels low-FPS and not smooth. So I’m stuck: either the pinned elements jitter, or the entire scroll experience is degraded. Here’s what I’ve tried already: I’ve used smoothTouch: 0 to reduce momentum I’ve used pinType: transform for all pinned elements I’ve tried disabling ScrollSmoother, which kind of helps, but breaks the layout too much I’ve tested combinations of turning normalizeScroll on and off I’ve tried will-change: transform on multiple container elements I’ve also tried turning off all pinning when on mobile, while keeping normalizeScroll, but the scroll still feels degraded Here’s my current ScrollSmoother setup: slater_import('/project/13553/page/34199.js') // Import gsap-globals.js gsap.registerPlugin(ScrollTrigger, ScrollSmoother); let smoother; // Initialize SmoothScroller smoother = ScrollSmoother.create({ wrapper: "#ScrollWrapper", content: "#ScrollSmoother", smooth: 1, smoothTouch: 0, effects: true, }); ScrollTrigger.normalizeScroll({ target: "#ScrollWrapper", allowNestedScroll: true, type: "touch,scroll" }); // ScrollTrigger.addEventListener("scrollStart", () => gsap.ticker.add(ScrollTrigger.update)); // ScrollTrigger.addEventListener("scrollEnd", () => gsap.ticker.remove(ScrollTrigger.update)); // function rafFix() { // requestAnimationFrame(rafFix); // } // rafFix(); window.disableScroll = function () { if (smoother) { smoother.paused(true); console.log("Pausing with smoother") } else { $("body").css("overflow", "hidden") console.log("Setting Overflow to hidden") } }; window.enableScroll = function () { if (smoother) { smoother.paused(false); console.log("Resuming with smoother") } else { $("body").css("overflow", "auto") console.log("Setting Overflow to auto") } }; window.preventDefault = function (e) { e.preventDefault(); }; Any help or insight is hugely appreciated. The video showcases my original issue with the jittery pinned elements. (without ScrollTrigger.normalizeScroll()) Thanks in advance. ScreenRecording_06-23-2025%2011-15-49_1.mp4 -
Sneaker Brand Timeline using ScrollTrigger and ScrollToPlugin from GSAP
leejaew posted a topic in GSAP
Just finished building an interactive sneaker timeline featuring sequential animations, parallax effects, and smooth scroll navigation! Here's how I implemented key GSAP features: ScrollTrigger for Timeline Progression ScrollTrigger.create({ trigger: '.timeline-container', start: "top center", end: "bottom bottom", onUpdate: (self) => { const progress = self.progress; timelineLine.style.height = `${progress * 100}%`; } }); Sequential Content Reveals gsap.to(shoeDate, { opacity: 1, y: 0, duration: 0.6, ease: "power2.out", onComplete: () => { // Chain next animation gsap.to(shoeName, { x: 0, opacity: 1, duration: 1, ease: "power2.out" }); } }); ScrollToPlugin Navigation document.addEventListener('keydown', (e) => { if (e.code === 'Space') { gsap.to(window, { duration: 1.2, scrollTo: { y: targetShoe, offsetY: 100 }, ease: "power2.inOut" }); } }); Smooth Parallax Effects gsap.to(".parallax-bg", { scrollTrigger: { scrub: true }, y: 100, scale: 1.1, ease: "none" }); Interactive Letter Animations letters.forEach((letter, index) => { tl.to(letter, { color: '#e10600', duration: 0.3, ease: "power2.inOut" }, index * 0.15); }); Other Features: Spacebar navigation between shoes SoundCloud audio integration Fully responsive design Dynamic image loading with loading state-
- 1
-
-
- scrolltrigger
- scrolltoplugin
- (and 6 more)
-
I already posted a similar problem, but I later realised that the solution I received was not wo sufficient: I have two scroll animations after each other. The Pin-Spacer of the first animation overlays the a tags at a certain scroll position and so there unclickable because they're overlayed by the pin-spacer. Is there any way I can make the a tags clickable? Mabe make the pin-spacer layer not blocking or something else. (if I enable pin Spacing the a tag gets clickable but then there's a huge white space between the two animations.) Thank you for your answers!
-
ScrollTrigger timeline break on mid-scrolling when window resize or refreshing page.
raaan127 posted a topic in GSAP
Hello, I am learning to use gsap and struggle to resolve this issue. I create these for testing: - a wrapper with original height on load is 1440px, that will change height to 0 when scrolling from .cover to .about - a scale-box which will scale from 100vh to 0 base on wrapper height / 1440 - an item of 100px * 100px on bottom of scale-box If I refresh the page on mid-scrolling between .cover and .about, or resize the browser window, the height which is controlled by gsap timeline is bugged and change and when I scroll up to top it won't return to original size (1440px) Somehow [Sign Up and Log In to CodePen is unavailable] so I post the code in here. <header> <nav class="navbar"> <div class="hero-name-wrapper"> <div class="hero-name-scale-box"> <div class="hero-name"></div> </div> </div> </nav> </header> <main id="smooth-content"> <div class="header-background"></div> <!-- Cover Section --> <section class="section cover"> <div class="cover-content"> </div> </section> <!-- About Section --> <section class="section about"> <div class="about-content"> </div> </section> </main> /* ================= INITIALIZE ================= */ :root { /* ----- COLORS -----*/ --debug-red: #f005; --debug-yellow: #ff05; --debug-green: #0f05; --debug-cyan: #0ff5; --debug-blue: #00f5; --debug-magenta: #f0f5; } *, *:before, *:after { padding: 0; margin: 0; box-sizing: border-box; list-style: none none; text-decoration: none; } html { box-sizing: inherit; scroll-behavior: smooth; height: -webkit-fill-available; } body { font-family: "Roboto", sans-serif; font-size: 26px; font-weight: 300; height: -webkit-fill-available; background-color: var(--background); color: var(--primary); } h1{ font-weight: 800; text-transform: uppercase; font-size: clamp(92px, 10vw, 300px); font-weight: bold; margin: 0; } /* =================== HEADER =================== */ header { position: fixed; top: 0; left: 0; z-index: 10; width: 100%; height: auto; margin: 0 auto; transition: all 0.35s ease; /*background-color: var(--debug-blue);*/ } .navbar { width: 100%; transition: all 0.4s ease-in-out; position: relative; } /* ==================== NAME ==================== */ .hero-name-wrapper{ position: fixed; background-color: var(--debug-green); width: 2560px; height: 1440px; border-radius: 100px; z-index: 100; pointer-events: none; } .hero-name-scale-box{ background-color: var(--debug-red); min-height: 100px; width: 100vw; display: flex; justify-content: center; align-items: flex-end; border-radius: 200px; } .hero-name{ background-color: yellow; width: 200px; height: calc(285 * (100vh/1440) ); min-height: 64px; margin: 0 auto; filter: drop-shadow(0px 0px 12px rgba(0, 0, 0, 0.15)); transform: rotate(0deg); } /* ==================== COVER =================== */ .cover{ position: relative; display: flex; justify-content: center; /* Horizontally */ align-items: flex-start; /* Vertically */ overflow: hidden; z-index: 1; } .cover-content{ position: relative; width: 100vw; height: 100vh; } /* ==================== ABOUT =================== */ .about { position: relative; } .expander{ height: 100vh; background-color: #1b6d85; } let vh = window.innerHeight; window.addEventListener("resize", () => { vh = window.innerHeight; }); window.addEventListener('DOMContentLoaded', () => { // ======================================== // // ============== INITIALIZE ============== // // Register ScrollTrigger plugin from GSAP gsap.registerPlugin(ScrollTrigger); const header = document.querySelector("header"); const heroWrapper = document.querySelector(".hero-name-wrapper"); const heroBox = document.querySelector(".hero-name-scale-box"); const heroName = document.querySelector(".hero-name"); let resizeObserverInitialized = false; function resizeHeroBox() { if (!heroBox || !heroBox.parentElement) return; const parent = heroBox.parentElement; const parentHeight = parent.offsetHeight; const vh = window.innerHeight; const boxHeight = parentHeight * (vh / 1440); heroBox.style.height = `${boxHeight}px`; // Initialize observer only once if (!resizeObserverInitialized) { // Observe parent height changes const observer = new ResizeObserver(() => resizeHeroBox()); observer.observe(parent); // Update on viewport resize window.addEventListener('resize', resizeHeroBox); resizeObserverInitialized = true; } } function setupHeroNameAnimations() { if (!heroWrapper) return; let tl = gsap.timeline({ scrollTrigger: { trigger: ".cover", start: `top top`, endTrigger: ".about", end: `top top`, pin: "none", pinSpacing: false, markers: false, scrub: true, invalidateOnRefresh: true, } }) tl .to(heroWrapper, {height: 0, ease: "none"}, 0) .to(heroName, {height: 84, ease: "none"}, 0); } // function calling resizeHeroBox(); setupHeroNameAnimations(); ScrollTrigger.refresh(); window.addEventListener("resize", () => { // resizeTestBox(); ScrollTrigger.refresh(); }); })- 3 replies
-
- scrolltrigger
- timeline
-
(and 1 more)
Tagged with:
-
Dubai Scrapbook, a GSAP powered interactive story. This demo turns a long list of tourist highlights into a playful “scrapbook” you can scroll through. What GSAP does here: 1. Hero ScrambleText – TextPlugin fakes a hacker-style scramble before landing on each lyric line. 2. Intro pop – the main title animates in with a simple fromTo on scale/rotation using back.out ease. 3. Scroll-driven page reveals – Every .photo-page card slides, rotates and scales into place via ScrollTrigger. 3. Stickers, washi-tape strips and photo frames each get their own staggered timelines inside the same trigger. 4. Per-word fade for descriptions – A helper splits the paragraph into <span> words and lets a small timeline (stagger: 0.08) fade them in as you reach the card. 5. Confetti explosion on button click – GSAP throws emoji with random x, y, rotation and opacity fades. 6. Micro-interactions – mouseenter / mouseleave handlers give buttons and photo frames a quick scale-tilt effect (power2.out). 7. Parallax extras – Floating emojis in the background scrub vertically with the page (scrub: 1) for extra depth. It’s basically a cookbook of little GSAP tricks. Feel free to copy-and-paste the parts you need. Enjoy!
- 1 reply
-
- 1
-
-
- scrambletext
- textplugin
- (and 7 more)
-
I'm having an issue with my SplitText and ScrollTrigger setup. The effect is to paint each line blue as the user scrolls. It renders perfectly on Chrome but on Safari (desktop and IOS), the line breaks happen in weird places. I recreated the animation in CodePen but couldn't replicate the issue in Safari, so not sure what's happening. For further context, I am building in WordPress using Bricks Builder, so there maybe a script conflict? Not sure, but any help is greatly appreciated! CODE: export function highlightTextOnScroll() { gsap.registerPlugin(ScrollTrigger, SplitText); document.fonts.ready.then(() => { SplitText.create(".scroll-highlight", { type: "lines", linesClass: "line", autoSplit: true, onSplit: (instance) => { const animations = instance.lines.map((line) => { return gsap.to(line, { backgroundPositionX: 0, ease: "none", scrollTrigger: { trigger: line, scrub: true, start: "top center", end: "bottom center", }, }); }); return animations; }, }); }); } CHROME: SAFARI:
- 3 replies
-
- splittext
- scrolltrigger
-
(and 1 more)
Tagged with:
-
I tried to create an on-scroll horizontal carousel by nesting it inside a GSAP timeline (tl), but it’s not working. I’ve been attempting this for a while without success. Please help me fix it. and after whole carousel get completed uncomment these codes in js : // .to(".black-screen", { visibility: 'visible' }) // .to(".ourProjects-wrapper", { bottom: '0%', duration: .5 }) These commented codes are incomming animtions.
- 1 reply
-
- scrolltrigger
- carousel
-
(and 1 more)
Tagged with:
-
Ho installato gsap sul mio sito wordpress con elementor. Solo da iphone, al caricamento della prima sessione mi disabilita tutti i link della pagina, con un refresh il problema si risolve. Da pc e android non ho nessun problema. I plugin che utilizzo sono ScrollTrigger e ScrollTo. Ho installato la verisone 3.12.5. Quale puo essere la risoluzione? -- TRANSLATION -- I installed gsap on my wordpress site with Elementor. Only from iPhone, when loading the first session it disables all the links on the page, with a refresh the problem is solved. From PC and Android I have no problem. The plugins I use are ScrollTrigger and ScrollTo. I installed version 3.12.5. What can be the resolution?
- 1 reply
-
- scrolltrigger
- scrollto
- (and 4 more)
-
horizontal scroll Implementing Horizontal Scroll with more control
adityanithariya posted a topic in GSAP
I'm trying to achieve an effect, which is a recreation of aimane.dev, it's developed in threejs, but should definitely be achievable using GSAP. Horizontal scroll is in place using ScrollTrigger and translate animation, checkout the current version here. But lacks many key things to make it smooth and presentable, not able to understand how to configure things for those animations. Includes: Card should expand bidirectionally, staying static at it's place, or we can say as smooth as possible First card and last card expands with keeping it's center as starting and ending point for scroll animation, similar for other cards too I'm not trying to give a requirement list to discuss things to fulfill it, but to know the possibilities around GSAP to tackle horizontal scroll with more control and flexibility achieving such things. I tried using translateX as key property to animate horizontal scroll, but it doesn't work as static value for x doesn't work when we have cards expanded, along with it not able to expand first card with keeping the scroll start as it's center as translateX uses top left corner as the reference point. Checked out docs for dynamic value of x, but by populating state into the gsap call for dynamic value of x doesn't work either. useEffect(() => { const horizontalSections = gsap.utils.toArray(".horizontal") const cardWidth = 200 const offset = window.innerWidth / 2 - cardWidth / 2 gsap.set(horizontalSections, { x: offset, }) gsap.to(horizontalSections, { x: offset - (cardWidth + 40) * 5 + 40, ease: "none", scrollTrigger: { trigger: ".horizontal", end: "+=1200", markers: true, start: `top ${window.innerHeight * 0.2}px`, pin: true, scrub: 1, anticipatePin: 1, }, }) }, []) I hope the problem is clear, to have more control over elements when using horizontal scroll with ScrollTrigger, using translateX or any other better alternative, please let me know if more context needed. Thanks in Advance! -
scrolltrigger animation works only when markers is true otherwise not
Niraj Trapasiya posted a topic in GSAP
window.addEventListener('load', function () { var chooseTl = gsap.timeline({ scrollTrigger: { trigger: '.choose-1', start: '0% 100%', end: '100% 100%', scrub: 1, invalidateOnRefresh: true, markers: false, id: 'money', // onEnter: () => enterSaving() } }) .to('.help-fixed-wrap', { right: '100vw', autoAlpha: 0 }, 0) .to('.choose-fixed-wrap', { autoAlpha: 1 }, 0) ScrollTrigger.refresh(); setTimeout(() => ScrollTrigger.refresh(), 1000); }); my snippet woks only when I keep markers true otherwise not -
Hey GSAP fam, I’m trying to recreate a smooth scroll-based transition like the one on Hana Road Studios — you know that slick “split-screen” animation that reveals the next section? I’ve got most of the pieces in place, but my custom animation is either not working or is breaking the rest of my GSAP setup. I tried vibe coding and it failed miserably. So here I'm.... What I'm trying to do: - When the user scrolls down: The .services-container (which has an image and animated text) scales up to fill the screen. The content then splits into top and bottom halves from the center. It reveals .services-content underneath after the split. My current setup: I'm using GSAP + ScrollTrigger (also SplitText, but just for a looping text animation). I already have 2 working animations that I don’t want to break: A SplitText loop for .services-name. A ScrollTrigger timeline for switching .desktopPhotos on scroll (with pin and scrub) My JS attempt (in its own function; not in codepen) function initServicesIntroSplit() { gsap.registerPlugin(ScrollTrigger); const overlay = document.querySelector(".split-overlay"); const imgURL = document.querySelector(".split").getAttribute("src"); overlay.innerHTML = ` <div class="half top-half" style="background-image: url('${imgURL}')"></div> <div class="half bottom-half" style="background-image: url('${imgURL}')"></div> `; const tl = gsap.timeline({ scrollTrigger: { trigger: ".services-image-split", start: "top top", end: "+=100%", scrub: true, pin: true } }); tl.to(".services-container", { scale: 1.05, duration: 1, ease: "power2.inOut" }) .to(".top-half", { yPercent: -100, duration: 1, ease: "power2.inOut" }, "-=0.8") .to(".bottom-half", { yPercent: 100, duration: 1, ease: "power2.inOut" }, "-=1") .fromTo(".services-content", { autoAlpha: 0, y: 100 }, { autoAlpha: 1, y: 0, duration: 1, ease: "power2.out" }, "-=0.5"); } The Problem The animation doesn’t run at all. Worse, it sometimes breaks the existing scroll-based animations (initServicesSplitAnimations and initServicesContentAnimations). It’s likely related to overlapping pinning or DOM layout issues. What I Need Help With How can I cleanly build this intro animation (split-from-center scroll transition)? How do I avoid conflicts with existing GSAP ScrollTrigger and SplitText animations? Is there a better approach — such as using clip-path, mask-image, or other GSAP techniques? Notes I'm open to a completely different approach if needed. I need it to be responsive and performant — works from desktop to mobile. I’m using matchMedia() for media queries in other parts of the code, if that’s relevant. The issue: This new scroll animation doesn’t run. Sometimes it breaks my other ScrollTrigger timelines. I think it’s a pinning/layout issue but not 100% sure. What I need help with: How can I properly build this “split from center and reveal” scroll animation? How do I avoid stepping on the toes of my existing GSAP timelines? Should I be using clip-path, masks, or something else to do this cleanly? FYI: Everything else works great. I’m using matchMedia() elsewhere (for responsive scroll triggers). I’m down to try a totally different approach if needed — just need it to be smooth and clean! Massive thanks in advance. Would love to hear what y’all would do in this case. CODEPEN BELOW (best views in desktop version)
-
I've managed to get video scrubbing working in a react project using the scroll trigger however once I pass the end the video snaps to first frame, and jumps back to the end if i scroll back up into the timeline is there a way to retain the value after the end position here is a video of what is currently happening https://streamable.com/sm47e4 here is a stripped down part of the code to only include relevant parts import gsap from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; import { useGSAP } from '@gsap/react' gsap.registerPlugin(ScrollTrigger, useGSAP); const ScrollTimeline: React.FC<ScrollTimelineProps> = ({ }) => { const testRef = useRef(null); const elRef = useRef(null); const videoRef = useRef<VideoRef>(null); useGSAP(() => { const trigger = testRef.current; const tl = gsap.timeline({ defaults: { duration: 1 }, scrollTrigger: { trigger: trigger, start: "top top", pin: true, end: "+=600%", scrub: true } }); const el = elRef.current; tl .fromTo( el, { rotation: 0 }, { rotation: 180 } , 0 ) // FIX THIS, GET REF PROPERLY // This is to just get the video element after its properly rendered var interval if (!initialised) { setInitialised(true) interval = setInterval(() => { const videoEl = document.querySelector('video') if (videoEl) { clearInterval(interval); tl.fromTo( videoEl, { currentTime: 0 }, { currentTime: videoEl.duration, }, 0 ) } }, 2000) } }, []); return ( <div className={clsx(styles.page)}> <div className={clsx(styles.scrollTimeline)} ref={testRef}> {/* This element contains the video element */} <BackgroundMedia {...mediaArgs} /> <div className={clsx(styles.test)} ref={elRef}> TEST </div> </div> </div> ); }
-
Plugin registration issue in module when a global GSAP instance is already loaded
Choub posted a topic in GSAP
Hello, Some context about this issue We have a customer website that uses gsap globally and loads it in its vendors.js. It's in version 3.11. On this website, we inject a Vue app that bundles gsap. We use vite to bundle the app, and use latest gsap, aswell as ScrollTrigger plugin as module imports. Problem is: ScrollTrigger plugins registers itself to the global instance when importing the plugin, and does not register on our bundled instance when we trigger registerPlugin. Issue reproduction (from the vue + scrolltrigger example): https://stackblitz.com/edit/vitejs-vite-cywcj9dz?file=index.html Only addition here is a <script> tag loading another instance of gsap globally. Looking at the source code, the last line of ScrollTrigger plugin does the auto-registration and seems to be the issue. There is no way to disable it (as I'm aware of) We cannot use the customer version as it creates a dependency between our code and his, the website and the app do not have the same lifecycle. Is there a way to handle this ? Could it be possible to add a flag to disable auto-registration of the plugin ? Is it really possible to have multiple instances of gsap on a single webpage ? Thanks in advance- 3 replies
-
- multiple versions
- plugins
-
(and 1 more)
Tagged with:
-
Hi everyone, I’m encountering an issue with GSAP’s ScrollTrigger where a section jumps when unpinning, and I’m looking for some guidance or a solution. Problem: I have a section that is pinned using ScrollTrigger while scrolling, but when the pinning ends (unpins), the section seems to "jump" or shift unexpectedly. The behavior happens when the scroll reaches the end point defined in the ScrollTrigger. I am also using scrub for smooth scrolling, and pinSpacing: false to prevent extra space for the pinned element. May refer to the section via https://cantal.bluecube.com.sg/sectors/ Here attached the CSS that I used: .scrolling-cards { overflow: hidden !important; position: relative !important; } .scrolling-cards-header-wrapper { height: 100vh !important; left: 0; position: relative !important; top: 0; width: 100% !important; } .scrolling-cards-header { height: 100vh; left: 0; position: absolute; top: 0; width: 100%; } .scrolling-cards-image { height: 100vh !important; left: 0; position: absolute !important; top: 0; width: 100% !important; } .scrolling-cards-image:after { background: #000; content: ""; height: 100%; left: 0; opacity: .3; position: absolute; top: 0; width: 100%; } .scrolling-cards-image img { height: 100vh !important; object-fit: cover !important; } .scrolling-cards-title { position: fixed !important; top: 0; left: 0; width: 50% !important; height: 100vh !important; display: flex !important; align-items: center !important; justify-content: center !important; padding: 50px !important; z-index: 10 !important; } .scrolling-cards-item { height: 100vh !important; position: relative !important; width: 100% !important; } .scrolling-cards-card { background-color: #FFF; padding: 50px !important; position: absolute !important; right: 50% !important;; top: 50% !important; transform: translateX(50%); width: 580px !important; z-index: 2 !important; } .scrolling-cards-card p:last-child { margin-bottom: 0; } @media screen and (min-width: 1024px) { .scrolling-cards-title { justify-content: center !important; padding: 0 0 0 calc((100vw - 1180px) / 2 + 20px) !important; width: 48vw !important; } .scrolling-cards-card { max-width: calc(50% - 20px); right: calc((100vw - 1180px) / 2 - 20px) !important; /* top: 250px !important; */ transform: translateY(-50%); } } @media screen and (max-width: 1024px) { .scrolling-cards-title { width: 100% !important; justify-content: unset !important; padding-left: 23px !important; padding-right: 23px !important; } .scrolling-cards-card { left: 50% !important; right: auto !important; transform: translate(-50%, -50%) !important; width: calc(100vw - 46px) !important; padding: 30px 25px !important; } } And here is the gsap script that I used: document.addEventListener("DOMContentLoaded", function () { gsap.registerPlugin(ScrollTrigger); const cards = gsap.utils.toArray(".scrolling-cards-item"); const images = gsap.utils.toArray(".scrolling-cards-image"); if (cards.length > 1 && !document.body.classList.contains("wp-admin")) { const tl = gsap.timeline({ scrollTrigger: { trigger: ".scrolling-cards", pin: ".scrolling-cards-header", start: "top top", end: "bottom bottom", scrub: 1, anticipatePin: 1, pinSpacing: false, markers: true } }); cards.forEach((cardWrapper, i) => { const card = cardWrapper.querySelector(".scrolling-cards-card"); const image = images[i]; const prevCard = i > 0 ? cards[i - 1].querySelector(".scrolling-cards-card") : null; const baseTime = i * 1.5 ; // Fade in background image (if not the first) if (i!==0) { tl.from(image, { autoAlpha: 0, duration: 1 }, baseTime); } // Fade in card // if (i !== 0) { tl.from(card, { autoAlpha: 0, y: 60, duration: 0.5 }, baseTime + 0.5); // } // Fade out previous card (if not the first) if (i > 0 && prevCard) { tl.to(prevCard, { autoAlpha: 0, y: -60, duration: 0.5 }, baseTime); } }); } }); The Issue: When the scroll reaches the end of the ScrollTrigger, the section "jumps" or shifts suddenly as the pin is released. I suspect this might be related to the CSS positioning (position: fixed on .scrolling-cards-title) and overflow: hidden on the parent .scrolling-cards. What I’ve Tried: I’ve tried adjusting the pinSpacing setting (true and false), but the jump still happens. Removing the overflow: hidden style from .scrolling-cards does not resolve the issue either. The jump seems to occur at the end of the ScrollTrigger, right before the element unpins.
-
Hey Everyone! Just trying to revert my splitText animations and triggers after resize. What am I missing here? Thanks, as always!
-
I copied some example code from the GSAP documentation to see if it had the same performance issue I’m experiencing in my own project, and it does. The CPU usage stays at around 43% or higher, even when I’m not interacting with the page at all. After looking into it, it seems like some repainting or reflows are being constantly triggered, possibly by ScrollTrigger’s requestAnimationFrame loop. Has anyone else encountered this issue? Is there a way to prevent unnecessary updates or reduce the CPU usage when the page is idle? I'm using Safari Version 18.4 (20621.1.15.11.10), and the GSAP version 3.13.0 Thanks in advance for any help or insights! Code example: https://stackblitz.com/edit/gsap-bug-test1?file=index.html Profiler:
- 3 replies
-
- safari
- scrolltrigger
-
(and 1 more)
Tagged with:
-
Hi there ! I am trying to achieve this mobile section from yard.me website . this is on the homepage of yard.me if you see the mobile view. I have achieved all the animation but heigh isn't being animated. it jumps to the top of page on trigger when i animate the height. please guide me how to achieve this animation. so far, i am stuck at my code. import {useRef} from 'react'; import {gsap} from 'gsap'; import {useGSAP} from '@gsap/react'; import {ScrollTrigger} from 'gsap/all'; import image1 from '../../../assets/test_image.jpg'; gsap.registerPlugin(ScrollTrigger); const WorksMobile = () => { const containerRef = useRef<HTMLDivElement>(null); const innerRef = useRef<HTMLDivElement>(null); const imageWrapperRef = useRef<HTMLDivElement>(null); const blackOverlayRef = useRef<HTMLDivElement>(null); const imageRef = useRef<HTMLImageElement>(null); useGSAP(() => { if ( !containerRef.current || !innerRef.current || !imageWrapperRef.current || !blackOverlayRef.current || !imageRef.current ) return; const fullHeight = innerRef.current.scrollHeight; gsap.set(innerRef.current, { height: 0, overflow: 'hidden', }); const enterTl = gsap.timeline({paused: true}); enterTl .fromTo( innerRef.current, {height: 0}, { height: fullHeight, duration: 0.6, ease: 'power2.out', }, ) .to( imageWrapperRef.current, { scaleY: 1, transformOrigin: 'bottom', duration: 0.5, ease: 'power2.out', }, '<', ) .to( blackOverlayRef.current, { translateY: '100%', duration: 0.4, ease: 'power2.out', }, '<+0.2', ) .to( imageRef.current, { translateY: '0%', duration: 0.4, ease: 'power2.out', }, '<', ); ScrollTrigger.create({ trigger: containerRef.current, scroller: '#smooth-wrapper', // make sure it's correctly configured start: 'top 85%', end: 'bottom 85%', onEnter: () => enterTl.play(0), onEnterBack: () => enterTl.play(0), }); }); return ( <div ref={containerRef}> <p className="text-white text-sm mb-2">Items 1</p> <div ref={innerRef} className="w-full overflow-hidden"> <div ref={imageWrapperRef} className="transform scale-y-0 origin-bottom overflow-hidden" > <div ref={blackOverlayRef} className="absolute top-0 left-0 w-full h-full bg-black z-10" /> <img ref={imageRef} src={image1} alt="" className="relative w-full h-auto object-cover z-0 translate-y-[100%]" /> </div> </div> </div> ); }; export default WorksMobile;
-
GSAP ScrollTrigger switches scroll-behavior property from "smooth" to "auto" and back on toggle?
wandervogel posted a topic in GSAP
I have noticed that ScrollTrigger briefly switches the scroll-behavior property of my scroller (the html element) from smooth to auto and back as it toggles between isActive states. Is this known/intentional behavior? In my case, it breaks the functionality of a native "back to top" button on the same page because the automated scroll is halted shortly after crossing the isActive threshold. I assumed using GSAPs own ScrollToPlugin would do the trick here but that didn’t help either. Neither did using zenscroll with window.noZensmooth set to true. Any help would be much appreciated. Here is my code. I commented out the code I execute on toggle as it makes no difference to the behavior described above. gsap.to(overlay[0], { scrollTrigger: { trigger: footer[0], start: "top bottom", end: "bottom top", scrub: 1, onToggle: (self) => { if (self.isActive) { // main.addClass("fixed bottom left right"); // spacer.removeClass("hidden"); // overlay.removeClass("hidden"); } else { // main.removeClass("fixed bottom left right"); // spacer.addClass("hidden"); // overlay.addClass("hidden"); } }, }, opacity: 1, });- 5 replies
-
- scrolltrigger
- scroll-behavior
-
(and 2 more)
Tagged with:
-
Hi! When an accordion item is expanded or when text is displayed (the Read More button), the yellow section of the wrap moves down, but the triggers do not. That's why the animation does not work as expected. I understand that it is necessary to use ScrollTrigger.refresh(). But what is the most correct way to do this? It's just that so far I can only think of ideas where one is worse than the other... For example, tracking clicks on the accordion and on a button like "Read More". Maybe there is a special method for this in GSAP?
- 4 replies
-
- gsap
- scrolltrigger
-
(and 1 more)
Tagged with:
-
Hey all! I'm a bit new to GSAP in general, but I've managed to use it in several projects before with minimal issues. Today I've been trying to get it setup with Vite + Vue, and i'm running into some problems. After setting up a ScrollTrigger with snap on my web app, the animation works fine, but the console shows several "Invalid Scope" errors. More will pop up after scrolling down on the page, and even after leaving the tab. I would really like some help in understanding what's causing the problem, and how I can fix it. https://stackblitz.com/edit/vitejs-vite-dlzcv767?file=src%2Fstyle.css
-
ScrollTrigger issue - page refresh issue at halway of scrubbed ScrollTrigger element
MarkoM posted a topic in GSAP
Hi everyone, First of, I wanted to say that I recently became a premium member of GSAP Club, which is pretty exciting and nice Now to the issue. I am using GSAP in NextJS project. The video at the bottom of the post pretty much sums it up, if I scroll to the ScrollTrigger trigger element that has a scrub true and stop halway or more (as long as screen is still "inside" the element) and then hit refresh in the browser, the animated element jumps into abyss (I think it jumps back to the top of the trigger element / it's parent element). And then if I scroll in ANY direction, the element comes into the view and gets pinned correctly.. until I refresh the page again. Now, I know for sure that I am doing something wrong and it is most likely extremely obvious or just some react thing that I completely missed, but I did try a few things that just didn't work for me I hope someone knows exactly what this is but if not, I will probably have to make some minimal demo.. As I said, I did try couple of things and I searched the forums, but no success. Component code: import { useRef } from "react"; import gsap from "gsap"; import { useGSAP } from "@gsap/react"; const PromoVideoElement = () => { const videoContainerRef = useRef<HTMLDivElement>(null); useGSAP( () => { const videoContainer = videoContainerRef.current; if (!videoContainer) return; const video = videoContainer.querySelector("video"); if (!video) return; gsap.to(video, { scale: 1, scrollTrigger: { trigger: videoContainer, start: "-=100 top", end: "200% top", pin: true, scrub: true, }, }); }, { scope: videoContainerRef }, ); return ( <div ref={videoContainerRef} className="aspect-3/2 mx-auto mb-56 mt-56 block w-[81%]" > <video data-cursor-size="100px" data-cursor-icon="play" data-cursor-icon-color="#352f36" data-cursor-color="white" controls={false} autoPlay muted preload="metadata" loop className="w-full scale-[1.4] rounded-3xl" > <source src={"/promo-video-homepage.mp4"} type="video/mp4" /> </video> </div> ); }; export default PromoVideoElement; IMPORTANT NOTE: I tried adding invalidateOnRefresh: true inside ScrollTrigger, but that didn't help. Thank you very much for your help! EDIT: Guys, I am very very sorry, while waiting for an answer I came to realization that I was using a custom gsap provider that I made, where I wrapped all elements and animated them on load, I also wrapped this component in page.tsx, which caused this problem. I have been brainstorming about this for so long only for me to ralize how stupid of mistake I made. Please close this thread as solved. Sorry once again.- 1 reply
-
- scrolltrigger
- refresh page
-
(and 3 more)
Tagged with:
-
"use client"; import { useRef } from "react"; import gsap from "gsap"; import { useGSAP } from "@gsap/react"; import { ScrollTrigger } from "gsap/all"; // Register plugins gsap.registerPlugin(ScrollTrigger, useGSAP); const AnniverseryAnimationLargeScreen = () => { const container = useRef(); useGSAP( () => { const tl = gsap.timeline({ scrollTrigger: { trigger: ".number-container", markers: false, pin: true, start: "top 10%", end: "+=400%", scrub: 1, }, }); tl.to(".inside-number", { y: "-250%", }); tl.to(".inside-number", { opacity: 0, duration: 0.3, }); tl.to(".number-container", { scale: 16, duration: 4, }); }, { scope: container } ); return ( <section className="mt-4 hidden md:block"> <div className="w-full mx-auto flex flex-col bg-black text-white" ref={container} > <div className="w-full "> <ul className="number-container w-1/2 font-normal mx-auto bg-transparent text-[30vw] flex justify-evenly items-center font-fragmentSans "> <h2>9</h2> <h2 className="relative "> 0 <p className="inside-number absolute text-sm lg:text-base right-1/2 translate-x-1/2 top-1/2 -translate-y-1/2 underline font-bold text-nowrap"> Of Returning <br /> Customer </p> </h2> <h2 className="relative text-transparent"> %{" "} <span className="absolute left-0 bottom-[35%] translate-y-1/2 font-serif text-9xl text-white"> % </span> </h2> </ul> <div className=" w-full "> <div className="textContainer flex flex-col justify-center items-center pt-[900px] lg:pt-[800px] pb-[100px] mx-auto w-full p-4 gap-y-6 md:gap-y-12"> <p className="text-base lg:text-xl font-light"> Over 1500 Projects completed </p> <p className="flex flex-col items-start text-9xl"> <span>FEATURED</span> <span>PROJECTS</span> </p> </div> </div> </div> </div> </section> ); }; export default AnniverseryAnimationLargeScreen; Hey ! I'm creating an animation using React, Tailwind CSS, and GSAP. I'm facing an issue where the textContainer div appears too late while scrolling vertically. I want it to animate when the edge of the "0" digit (or element) almost touches the edge of the inner window (viewport). Can anyone help me fix this? Also, is there any specific logic behind using the duration in ScrollTrigger? Sometimes it affects the animation, and other times it doesn’t seem to do anything. Thanks! I have also attached the animation I want to acheive. Now.mp4 target.mp4
-
Multiple .to() Animations on The Same Element reset the starting value (ScrollTrigger)
onedesign posted a topic in GSAP
Hey y'all! I'm trying to pull off this effect where the background color of the page changes when you scroll in and out of new sections. I saw this demo that used `onToggle` to pull of a similar effect, but I'd really like to still leverage the `scrub` feature of ScrollTrigger, and it's my understanding that it doesn't work with toggle actions: https://codepen.io/GreenSock/pen/OJoROgY In my simplified demo below I'm attempting to just do it by looping over each section and applying a `.to()` animation on the common background element, but it seems like every time a new section/trigger is activated the `.to()` animation resets the background color of the element to its initial value, rather than just starting from the current background-color value of the element—which is why in my demo you see it flash back to red after each new section is entered. I feel like I'm close, and probably just missing something obvious. Any ideas out there in GSAP land? Thanks for your help! -
Hello Guys, I purchased the GSAP business for my organization to use the amazing motionpath plugin but it is giving me somewhat hard time to achieve my desired effect. What I am trying to achieve here is to distribute all the cards evenly on the curve path and then animate it from right to left. The cards will appear from left and end in when the last card is at the middle. please see the attached image of what I am trying to achieve. Any help will be much appreciated. Thank You
- 5 replies
-
- motionpath
- scrolltrigger
-
(and 1 more)
Tagged with: