Search the Community
Showing results for tags 'gsap'.
-
Hi everyone! I need some help. I want to recreate the words-carousel section like on the site: https://c2montreal.com/ It's a section with three titles Learn, Experience, Connect. Section is full screen and on scroll have SplitText in some like roller/carousel effect. Here is my CodPen (scroll): https://codepen.io/NGrdanjski/pen/XJXwyOq Thank you very much everyone.
- 2 replies
-
- gsap
- scrolltrigger
-
(and 1 more)
Tagged with:
-
Hey, I'm trying to apply a zoom masking effect where, as I scroll down, the text scales up. But when I scroll back up quickly, the masking doesn't align properly with the scroll speed.
- 3 replies
-
- scrolltriger
- scrolltrigger
-
(and 3 more)
Tagged with:
-
Animating UI components (e.g. React): Best practices, patterns, tips and tricks
Kanji Nakamoto posted a topic in GSAP
Hi, I used to be a proficient GSAP user until 2016, as a Creative Technologist in the Creative industry, Agencies, etc. Since 2015, I've been mainly working as a full-stack developer, interface or Frontend develop; and my focus and priorities have changed completely. Much has changed since, from Popmotion to Motion, GSAP becoming free? Etc. Although I worked with GSAP and similar libraries occasionally; I'm planning to pick GSAP again, as I'd like to focus more on design + engineering for some time. GSAP seem to have a good starting point at https://gsap.com/ui, which I'll use as a reference. If any of you have any good practices and conventions when working with React + Components + Vanilla CSS or Tailwindcss, is appreciated. Thank you! -
Hi GSAP team, I’m running into an issue with ScrollTrigger pinning. I have a section with a .menu__image__wrapper that I want to pin while scrolling. On first page load, the pin doesn’t work (the image disappears). If I switch categories in my app (which destroys and re-inits the triggers), the pin suddenly works correctly. I also noticed earlier that I had a y transform (GSAP.set(..., { y: ... })) on the pinned element itself. Removing that transform fixed some glitching, but I still sometimes see the pin fail on first load. Video Of Issue:https://www.loom.com/share/f02251051e0d40a5b0595020b76bd8b7?sid=2a13507c-e9aa-4d87-9644-47d2f085eb01 Here’s a simplified version of my setup: Here is the animation class code for the menuPIN only: import GSAP from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; GSAP.registerPlugin(ScrollTrigger); export default class MenuPin { constructor() { this.mm = null; // matchMedia instance this.triggers = []; // ScrollTrigger instances this.clickHandlers = []; // mobile click handlers this.currentSection = null; } setupSection(section) { if (!section) return; const runSetup = () => { // destroy previous triggers/spacers this.destroy(); this.currentSection = section; this.mm = GSAP.matchMedia(); const initDesktop = () => { this.setupDesktop(section); }; // Desktop this.mm.add("(min-width:1024px)", () => { const firstImg = section.querySelector(".menu__image"); if (firstImg && !firstImg.complete) { firstImg.addEventListener("load", initDesktop, { once: true }); setTimeout(initDesktop, 300); } else { initDesktop(); } return () => { }; }); // Mobile this.mm.add("(max-width:1023px)", () => { requestAnimationFrame(() => this.setupMobile(section)); return () => { }; }); }; // Run immediately if DOM is ready, otherwise wait for DOMContentLoaded if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", runSetup); } else { runSetup(); } } setupDesktop(section) { const imageWrapper = section.querySelector(".menu__image__wrapper"); if (!imageWrapper) return; const images = Array.from(section.querySelectorAll(".menu__image")); const imageHeight = section.querySelector(".menu__image").getBoundingClientRect().height const items = Array.from(section.querySelectorAll(".menu__item")); const itemHeight = section.querySelector(".menu__item").getBoundingClientRect().height if (!items.length) return; // spacer at the end let spacer = section.querySelector(".menu__spacer"); if (!spacer) { spacer = document.createElement("div"); spacer.classList.add("menu__spacer"); section.appendChild(spacer); } spacer.style.height = `${imageHeight - itemHeight - 41}px`; const pinDuration = section.scrollHeight; // Pin image wrapper const pinTrigger = ScrollTrigger.create({ trigger: section, start: "top top", end: () => `+=${pinDuration}`, pin: imageWrapper, pinSpacing: false, markers: false, }); this.triggers.push(pinTrigger); // Set first image visible right away // GSAP.set(images[0], { autoAlpha: 1 }); // Then set up triggers items.forEach((item, i) => { const t = ScrollTrigger.create({ trigger: item, start: `top-=25 top`, end: `bottom-=25 top`, // onEnter: () => this.showImage(images, i), // onEnterBack: () => this.showImage(images, i), markers: true, }); this.triggers.push(t); }); } setupMobile(section) { const images = Array.from(section.querySelectorAll(".menu__image")); const items = Array.from(section.querySelectorAll(".menu__item")); // remove previous handlers items.forEach(item => { if (item._menuPinHandler) { item.removeEventListener("click", item._menuPinHandler); delete item._menuPinHandler; } }); // add click handlers items.forEach((item, i) => { const handler = () => this.showImage(images, i); item.addEventListener("click", handler); item._menuPinHandler = handler; this.clickHandlers.push({ el: item, handler }); }); // show first image // this.showImage(images, 0); } showImage(images, index) { images.forEach((img, i) => { GSAP.set(img, { autoAlpha: i === index ? 1 : 0, border: i === index ? "3px solid red" : "none" }); }); GSAP.to(images[index], { autoAlpha: 1, duration: 0.25, ease: "expo.out" }); } destroy() { // kill triggers this.triggers.forEach(t => t && t.kill()); this.triggers = []; // remove click handlers this.clickHandlers.forEach(({ el, handler }) => { el.removeEventListener("click", handler); if (el._menuPinHandler) delete el._menuPinHandler; }); this.clickHandlers = []; // remove spacer if (this.currentSection) { const sp = this.currentSection.querySelector(".menu__spacer"); if (sp) sp.remove(); } this.currentSection = null; } } import Page from '@classes/Page'; import MenuPin from '@animations/MenuPin'; import MobileCategorySwipe from '@animations/MobileCategorySwipe'; import GSAP from 'gsap'; import { ScrollTrigger } from "gsap/ScrollTrigger"; GSAP.registerPlugin(ScrollTrigger); export default class Menu extends Page { constructor() { super({ element: '.menu', elements: { wrapper: '.menu__wrapper', section: '.menu__section', button: '.menu__category__label', }, }); } create() { super.create(); this.menuPin = new MenuPin(); const categoryEl = document.querySelector(".menu__category"); if (categoryEl) { new MobileCategorySwipe({ element: categoryEl }); } const firstSection = document.querySelector(".menu__section.--active"); if (firstSection) { this.menuPin.setupSection(firstSection); } // bind buttons this.elements.button.forEach(btn => { btn.addEventListener("click", () => { const category = btn.dataset.category; this.showCategory(category); }); }); } showCategory(category) { // Hide all sections first this.elements.section.forEach(section => { const isActive = section.dataset.category === category; if (isActive) { section.classList.add('--active'); console.log(section); // Make section visible so ScrollTrigger can measure GSAP.set(section, { autoAlpha: 1 }); // Destroy old triggers before setting up the new one if (this.menuPin) this.menuPin.destroy(); // Setup the pin/animations for the new section this.menuPin.setupSection(section); // Refresh ScrollTrigger after layout changes requestAnimationFrame(() => ScrollTrigger.refresh()); } else { section.classList.remove('--active'); GSAP.set(section, { autoAlpha: 0 }); } }); // Update buttons this.elements.button.forEach(btn => { const isActive = btn.dataset.category === category; btn.classList.toggle('--active', isActive); GSAP.to(btn, { color: isActive ? "#000" : "#CBC4B1", duration: 0.5, ease: "expo.out" }); }); } }
- 3 replies
-
- scrolltrigger
- gsap
-
(and 1 more)
Tagged with:
-
Hey guys, I finished my portfolio website, and going through it, I notice one error. As you can see, there is a strange movement on the left card. On the first visit to the website, everything is normal, but once you click the FAQ item, it moves to the left and shrinks, and if you continuously click the FAQ item, it flickers. I am 100% sure this is GSAP code. I use Smooth Scroller, and I pin the left card. When I remove the GSAP code and go with sticky on the left card, everything works normally. What could be the problem? Here is the read-only link https://preview.webflow.com/preview/veljko-portfolio-bb1f89?utm_medium=preview_link&utm_source=designer&utm_content=veljko-portfolio-bb1f89&preview=2e29e1d3721c84bd8fed760aba33f39c&workflow=preview and website https://veljkov.me/
-
Hello I have a fixed container in a fixed-width screen website. From this container, I want to add multiple images, each representing a project, along with text information about the project. The animation I want to achieve is that when you scroll the page, the images and the corresponding project information will be displayed one by one. The faster you scroll, the faster the images and text will change or switch. All of this animation should be in a loop, and each image and text should be connected to the CMS webflow. Some reference here: https://brunoarizio.com/ http://iamrossmason.com/ http://lagutalaguta.com/
- 3 replies
-
- webflow
- webflow cms
-
(and 1 more)
Tagged with:
-
Hello there, I’m encountering an issue with the GSAP animation I’ve implemented, which you can review in the CodePen link. Overall, the animation works fine, but there is one problem: The logo follows us as we scroll downward (it's sticky) and shrinks to a certain point. During the shrinking (or enlarging when scrolling back up), the motion isn’t smooth. It produces small “jumps,” making the scaling appear uneven instead of fluid. This issue becomes even more noticeable when reducing the viewport width. Essentially, it looks as if the logo’s width decreases in steps (e.g., 200px → 198px → 196px → 194px, etc.) rather than in smaller increments that would make the scaling truly smooth. I’d greatly appreciate any suggestions on how to resolve this so that the resizing feels smooth and continuous. Additionally, any recommendations for improving or optimizing the JavaScript code used here would also be very welcome, so we can achieve the best possible overall result. Thanks
- 2 replies
-
- gsap
- scroll trigger
-
(and 3 more)
Tagged with:
-
I'm requested to create something like this but I find really complex to create it, the easy way is to just listen to mouse hover event over a element but as u can see and test in the website : https://epica.ru/ the hover effect is way complex then regular add addEventListener("mouseover" do u have any idea from to start ?
-
Hello, I added lightGallery framework to my gsap project, it works fine, but there is a scroll problem. When I turn off the lightbox, it shifts up and down. How can I prevent this? Can you help me? I guess scroll is not locking
-
Click-to-rotate tween conflicts with Draggable rotation and create glitches when drag immediately after click.
Sagarsantra posted a topic in GSAP
Implementing a circular time picker where a line rotates toward the pointer on click with a short tween, and should immediately hand off to drag if the pointer moves. However, when clicking and then quickly dragging, the rotation glitches or remains bound to the tween briefly rather than following the drag instantly. onDragStart appears to fire on simple clicks (tiny pointer movement). -
Hello everyone, I'm running into some issues with ScrollTrigger and could use some guidance. I'm trying to create multiple scroll animations where images slide in from the side. I managed to get this working by pinning the container itself (https://codepen.io/zumpel96/pen/OPyBboy). However, this isn't the behavior I want, because I'd like all other content to remain pinned or "frozen". As you can see in my working pen, the other content continues to scroll. I've also tried using a single common pinned container, but that approach doesn't work either: https://codepen.io/zumpel96/pen/empPJzY Wrapping only the "visible" part in a container isn't an option either. In my pen, there's content between the animated scroll containers that's visible for both. This means that content would need to belong to both the first and second scroll containers, which isn't possible. Any advice or suggestions on how to achieve this effect would be greatly appreciated. Thank you so much!
-
I’m building a loader based on the Hermann grid: a field of ghost nodes (intersections). Choreography: nodes are always visible; for each phase the nodes that form L then A are emphasized and edges are drawn between successive nodes. Next phase repeats at a different orientation/position (90° rotations + offsets). Questions Is my approach to connect nodes with DOM edges sound, or should I switch to SVG paths for precision/perf? Any cleaner pattern to define letter sequences? I’m using small helpers (row/col/diagDR/diagDL, offset, rotate90) and explicit arrays for L/A. Best practice to clear edges between phases without flashing? (I’m fading & removing.) For the intro ripple, is using from:[(N-1)/2,(N-1)/2] the right way to stagger from the true center on even grids?
-
Hi, Not sure if this is the right forum to ask this question but hoping that one of the many geniuses on here is able to provide assistance so here it goes. I am having an issue when trying to deploy my Next.js project to Vercel and it seems to be occurring in the build process and more specifically to due with gsap.context() This is my code inside my index.tsx page: import { useRef } from 'react'; import dynamic from "next/dynamic" import { montserrat } from '../utils/fonts' import { gsap } from "gsap" import { ScrollTrigger } from "gsap/dist/ScrollTrigger" import { ScrollSmoother } from "gsap/dist/ScrollSmoother" import useIsomorphicLayoutEffect from '../utils/isomorphicEffect'; import Head from 'next/head' import Image from 'next/image' import styles from '@/styles/home.module.scss' import profilePic from '@/images/dayne-profile-circle-new.png' import gradientPic from '@/images/gradient-bg.jpg' gsap.registerPlugin(ScrollTrigger, ScrollSmoother); export default function Home() { const smoother = useRef(); const ctx = useRef(); useIsomorphicLayoutEffect(() => { ctx.current = gsap.context(() => { smoother.current = ScrollSmoother.create({ smooth: 2, effects: true, }); ScrollTrigger.create({ trigger: '#pinned-element', pin: true, start: 'top top', end: '+=5000', pinSpacing: false }); }); return () => ctx.current.revert(); }); return ( <> <Head> <title>Online portfolio of web developer, Dayne Coulson-Hoffacker</title> <meta name="description" content="Online portfolio of web developer Dayne Coulson-Hoffacker" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="/favicon.png" type="image/png" sizes="any" /> </Head> <div id="smooth-wrapper" className={styles.scrollWrapper}> <div id='smooth-content'> </div> </div> </> ) } This code works perfectly on my local server (https://localhost:3000) The issue is when I push changes to my repo and Vercel runs a build from those changes. I have attached the error message that I am being given from Vercel to this post. Please, any React geniuses who can shed some light it would be greatly appreciated. Thanks, Dayne
-
Horizontal scrolling to vertical scrolling issue ( GSAP + ScrollTrigger)
Nathan LOHEAC posted a topic in GSAP
Hi community, Im' a beginner with GSAP and ScrollTrigger and I'm running into an issue. My goal is for the user to scroll horizontally through 6 sections, and after the 6th section, the scrolling should switch back to vertical to display the final section (simply as that, ahah). Right now, instead of that, a large (undesired) section appears after the 6th sectoin (maybe a problem with the "pin"?). I've tried many things to debug it, but I just can't figure it out. Code here : https://codepen.io/Nathan-Loheac/pen/gbaPeXW Thank you so much for any help or advices- 1 reply
-
- scrolltriggers
- gsap
-
(and 1 more)
Tagged with:
-
Scroll trigger pinned section with dynamic height based on inner content
Nick Lewis posted a topic in GSAP
Hi Everyone, Long time GSAP dabbler, but first time posting in the forum. Looking for some help and advice. I'm trying to create a scroll triggered and pinned section of a site that scrolls through content within a 'frame' inside the section. This is on desktop only. on mobile the animations are killed. What I'm struggling with managing is the height of the container and how long it is pinned for before the content below naturally appears and the scroll continues as normal. I have created an example of what I'm trying to achieve here. https://codepen.io/nickylew/pen/RNWWMop I feel as thought I may be over complicating things, trying to set the height of the section dynamically based on the number of 'boxes' there are to scroll through. These 'boxes' will be dynamic, pulled from a CMS, so there could be 5 of them, could be 10+. Which is why I was trying to get the height and uses that to dynamically set things up. Any help greatly appreciated! As I'm getting a little spun round in circles. Additionally, improving performance would be amazing to know as well. As this is janky! But, that might be because it is trying to work out heights.- 2 replies
-
- gsap
- scrolltrigger
-
(and 1 more)
Tagged with:
-
Hi, Im new here! I just started to use GSAP in order to animate things in my website, but the thing is that I'm not sure what's the best way to make a complex button like for example this one, I know I have to use useGSAP, useRef and Timeline in order to make complex animations, But I'm not sure how to trigger mouseenter or mouseleave and how would look a button component with the best use guides for performance.
-
Hey my amazing community and GSAP Geniuses!! When I activate ScrollSmoother, all my pinned elements and animations become noticeably jaggy during slow scrolling. The smoothness is lost, and animations appear jumpy. I’m not sure what I’m doing wrong, but it seems like ScrollTrigger animations aren’t playing well with ScrollSmoother.
- 3 replies
-
- scrollsmoother
- scrolltrigger
-
(and 2 more)
Tagged with:
-
Brand new to this, but I'm not seeing the answer out there (maybe I'm looking up the wrong terms). Anyway, I'm doing a few tests, and I'm seeing a flash of the unanimated objects before they come on. For instance, if they animate from 0% scale to 100, they appear for an instant at full size before they disappear and the animation begins. It's only local at the moment, but I see it in both chrome and firefox. I'm using jquery for selectors, and both jquery, TweenMax, and the function to animate are all being loaded in the head before any of the elements are defined in the body html. Is there a typical way to resolve this or most likely cause to look at?
-
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)
-
Hi, I am using a gsap animation. The problem is I want to hide the bottom left navigation when the inner side is opened. But there is not way, I can do it. I only want to show the navigation when the main slide is opened. Here is my website:https://www.judexaya.com/anomalies
-
I've found a reference site for scroll animation, but I'm unsure how to create this effect. You can check it out here: https://webisoft.com/advisory#:~:text=APPLICATION. In the services section, you'll notice that the animations change depending on whether you scroll up or down. Here is the CodePen example. I'm experiencing an issue with the scrolling effect. Can anyone help me with this?
- 4 replies
-
- scrolltriggers
- canvas gsap
-
(and 1 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 GSAP Community, I'm currently working on a page transition using GSAP's flip plugin, and I'm encountering an issue where the element seems to "jump" from a lower position during the transition, which affects the UX. I'm using Barba.js for page transitions, and GSAP/Flip are used to animate the transition. The element in question is cloned and moved to a new container during the transition. I've attached a video that better explains my problem, and here's my JavaScript code that handles the transition. If you need more elements (HTML content, styles), don't hesitate to let me know! gsap.registerPlugin(ScrollTrigger, CustomEase, Flip); const $ = (el) => document.querySelector(el) let scroll; const BASIC_DURATION = 1.2; let transitionOffset = 1100; let staggerDefault = 0.07; CustomEase.create("primary-ease", "0.42, 0.1, 0.05, 0.89"); CustomEase.create("primary-ease-out", ".34, 1.56, 0.64, 1"); function leaveWorkSingle(container) { const tl = gsap.timeline({ default: { duration: BASIC_DURATION, ease: "primary-ease" } }) let transitionElements = document.querySelector('.transition-work-single'); let transitionElementsFooterImage = transitionElements.querySelector('.img-next'); let cloneTransitionElements = transitionElements.cloneNode(true); let transitionElementsNewContainer = document.querySelector('.transition-work-single-container'); let transitionElementsOldContainer = document.querySelector('.transition-work-single-old-container'); let transitionElementsState = Flip.getState(".transition-work-single"); transitionElementsNewContainer.classList.add('transitioning'); transitionElementsNewContainer.appendChild(transitionElements); transitionElementsOldContainer.appendChild(cloneTransitionElements); tl.set('main.main', { autoAlpha: 0 }) tl.add(Flip.from(transitionElementsState, { ease: "primary-ease", duration: 1.2, absolute: true, }), 0.5); tl.set(cloneTransitionElements, { autoAlpha: 0 }); } function enterWorkSingle(container) { // todo const tl = gsap.timeline({ default: { duration: BASIC_DURATION, ease: "primary-ease" } }) tl.set('main.main', { autoAlpha: 1, onComplete: () => { console.log('done') let r = $('.transition-work-single-container.transitioning .transition-work-single') console.log(r) r.remove() } }) } function delay(n) { n = n || 2000; return new Promise((done) => { setTimeout(() => { done(); }, n); }); } function initLenis() { scroll = new Lenis({ duration: 1 }) scroll.on('scroll', ScrollTrigger.update) gsap.ticker.add((time) => { scroll.raf(time * 1000); }) gsap.ticker.lagSmoothing(0) } function initTransitions() { history.scrollRestoration = "manual"; barba.hooks.afterEnter(() => { window.scrollTo(0, 0); ScrollTrigger.refresh(); }); barba.init({ sync: true, debug: false, timeout: 7000, transitions: [ { name: 'from-to-work-single', from: { namespace: ['work-single'] }, to: { namespace: ['work-single'] }, async leave(data) { leaveWorkSingle(data.current.container); await delay(1700); }, async enter(data) { enterWorkSingle(data.next.container); }, async beforeEnter(data) { // ScrollTrigger.getAll().forEach(t => t.kill()); initSmoothScroll(data.next.container); // initScript(); }, } ] }); function initSmoothScroll(container) { initLenis(); ScrollTrigger.refresh(); } } initTransitions(); Thank you in advance for your help. w_ybkKeqbJ.mp4
-
Hello, First off, I just want to say how excited I am about GSAP going completely free for everyone—thanks to Webflow’s support. The community is buzzing, and I honestly can’t wait to see what’s coming next! I’m reaching out for some guidance and clarification as I prepare to dive into a new personal project that will heavily rely on GSAP animations, along with WordPress and Elementor Pro. 🔧 Project Setup – My Current Plan The project will involve a variety of animations and page-level interactions. Here's a brief outline of how I plan to manage everything: ----------- Layer Purpose Key Tools / Locations Local Dev Safe playground for building & testing. Local by Flywheel → (my local Browser URL) running Hello Elementor + Hello Child Theme. Source Code Modular animation code & global styles. hello-theme-child-master/src/… • js/animations/*/index.js • css/animations/*.css • js/app.js (aggregator) Bundling Turn scattered modules into a single, optimized payload. Webpack (installed via npm) + custom webpack.config.js; output enqueued by PHP. Version Control Single source of truth & change history. Git (repo lives in child‑theme folder) → push to GitHub main via VS Code’s Git Bash. Deployment Ship the latest build to production with one click. WP Pusher (monitors main branch). After each push, click Update in WP Pusher. Runtime (Browser) Execute GSAP timelines inside Elementor’s markup. GSAP CDN + your compiled app.js & animation CSS, loaded in the order you defined. ----------- ❓My Main Question Is this the right approach for a GSAP-heavy WordPress project using Elementor, or would it be more practical to simply use a Code Snippet Manager plugin and embed everything there? I’m aiming to be as structured and intentional as possible from the start, but if this direction is overcomplicating things, I’d rather adjust now than burn time later. Your insight would be invaluable and honestly a huge time-saver. I deeply appreciate your time, and apologies for the long message — I just wanted to provide full context. Looking forward to your response. Warm regards, George