Jump to content
Search Community

All Activity

This stream auto-updates

  1. Past hour
  2. Today
  3. Got a demo illustrating that? I wonder if you're not setting refreshPriority properly. Perhaps you've got it inverted or you've got overlapping values. 🤷‍♂️ 🥳
  4. That's so much better – I completely forgot about ScrollTrigger! You've been insanely helpful!
  5. Yesterday
  6. Wow, this works out of the box for me🫠. For some reason refreshPriority is not working for me even while increasing the values dynamically. Thanks Jack & Rodrigo
  7. The useGSAP hook has a dependency for at least React 16, but it doesn't use/install React 16: "dependencies": { "gsap": "^3.12.5", "react": ">=16" }, If you already have React 18 installing the @gsap/react package won't change a thing and won't install another version of React. I just tested this on a demo here on my local machine using the latest version of Next without any issues. We only encountered some issues while importing the @gsap/react package from esm.sh, which solves by doing this: import React from "https://esm.sh/react@18.3.1"; import ReactDOM from "https://esm.sh/react-dom@18.3.1"; import gsap from "https://esm.sh/gsap"; import { useGSAP } from "https://esm.sh/@gsap/react?deps=react@18.3.1"; We'll update the dependencies on the hook to be at least version 17 of React. Finally it would be super helpful if you could create a minimal demo that reproduces this error. Happy Tweening!
  8. Mhh... Why are you using intersection observer for something that can be done with ScrollTrigger? I think you are overcomplicating this quite a bit. If I was you I'd create an extra prop for ScrollTrigger and if that prop has a ScrollTrigger configuration, you just need to check if is not falsy, instead of using just SplitText use ScrollTrigger to handle when the animation plays, something like this: https://codepen.io/GreenSock/pen/abxMRgp I updated the demo I posted before so it uses ScrollTrigger https://stackblitz.com/edit/nuxt-starter-vzsxyp?file=app.vue The only detail is that this check is not needed with ScrollTrigger: completed && tween.progress(1); Hopefully this helps. Happy Tweening!
  9. Hi @Anas Ali Khan, Lenis is free but is a product of Studio Freight: https://lenis.darkroom.engineering/ Just be aware that we can't offer support for Lenis here, since we need to keep our focus on GSAP related questions. Finally we do have a smooth scrolling solution called ScrollSmoother, that is fully integrated with ScrollTrigger: https://gsap.com/docs/v3/Plugins/ScrollSmoother/ Happy Tweening!
  10. Hi @explorerzip, In Blake's demo all you have to do is add a repeatDelay value: https://gsap.com/docs/v3/GSAP/Timeline/repeatDelay() Something like this: var tl = gsap.timeline({ paused: true, repeat: -1, repeatDelay: 2, // Two seconds between animations onRepeat: updateImages, onUpdate: updatePath }) .to(arc, { duration: 3, end: 360, ease: "none" }) Hopefully this helps. Happy Tweening!
  11. Thanks for clarifying, I'll definitely be using this syntax in the future! If this isn't too far out of the scope of my initial issue, I managed to reproduce something I'm running into with these tweens. I have two instances of the same component (it's all in the demo) – one on the page and one inside a modal. For their timelines to run independently I need to declare them as Vue refs. Which is fine, except for some reason when the timeline is reset on reside, the timeline for the other instance of the component gets messed up. For example in this demo, scroll down to activate the on-page animation, resize it, scroll again to re-activate it, then toggle the modal. The modal splitText animation doesn't run correctly, probably because the split isn't properly recalculated. I suspect it's a vue-specific issue but if there's any way to negate it I'm all ears! Here's the demo: https://stackblitz.com/edit/nuxt-starter-zdudyt?file=app.vue,components%2FTextComponent.vue
  12. Thanks @OSUblake for the amazing example. I need to create a similar animation, but need to have it stop to show each image for a few seconds. Can you clue me in on how to do that? Also, when I try replacing one of the images, it does not radial wipe. Here's my example: https://codepen.io/glenn-ko/pen/YzMgJrV
  13. Thank you @Rodrigo. The hook itself looks good. I think the issue could be a mismatch of React versions. Looking at the package.json. I'm using version ^18. and the hook is using ^16. I do think there are some breaking changes between these versions. I've ran into issues like this before. The error message: `Uncaught TypeError: Cannot read properties of null (reading 'useRef')` I've read can be associated with version mismatches.
  14. Yep, same issue - you're creating things out of order, thus they refresh in the wrong order. For example, let's say elementA is 100px from the top of the screen, and there's a ScrollTrigger that triggers when that hits the top of the screen ("top top"). So normally, the start would be 100. But what if there's another ScrollTrigger that pins an element above that one for 1000px - that'd push everything down, thus that element should trigger at 1100px instead of 100px. If ScrollTrigger calculates them in the wrong order, it'd set the first one to a start of 100px (because the pinning one hasn't been factored in yet). Here's a helper function that you can call after all of your elements are in place, and it'll order things based on their proximity to the top of the viewport: function verticalSort() { let scroll = window.pageYOffset; ScrollTrigger.getAll().forEach(t => t._sortY = t.trigger ? scroll + t.trigger.getBoundingClientRect().top : t.start + window.innerHeight); ScrollTrigger.sort((a, b) => a._sortY - b._sortY); } https://codepen.io/GreenSock/pen/ZEZPqyd?editors=0010 Better? Of course you could solve everything by explicitly stating the unique refreshPriority for each, but the above function seemed easier and it should work in most cases.
  15. Yes, like @Rodrigo said, you're creating your ScrollTriggers out-of-order. You're supposed to create them in the order they would be encountered (top to bottom). You're creating the top and bottom first, then the middle, so the refreshing order goes: 1, 3, 2 instead of 1, 2, 3. For relatively simple setups, it could be adequate to just call ScrollTrigger.sort() which will order them by whatever their "start" is calculated to be. But you can explicitly control the order of things by setting a refreshPriority on each one so you have total control of the order. https://codepen.io/GreenSock/pen/PogLyGO?editors=1010 And here's a verticalSort() helper function that'll sort them by their proximity to the very top of the viewport: https://codepen.io/GreenSock/pen/ExJMdXj?editors=0010
  16. Hi, You also posted in this other thread: Where Jack suggested using ScrollTrigger's sort() method for solving this: https://gsap.com/docs/v3/Plugins/ScrollTrigger/static.sort()/ This works as expected: sectionB.forEach((section) => { const textElement = section.querySelector("span"); // Load some data, then initialize animation later(3000).then(() => { console.log("Loaded!!"); const tl = gsap.timeline({ scrollTrigger: { trigger: section, start: "top top", end: `+=2000`, markers: true, scrub: true, pin: true } }); tl.to(textElement, { scale: 1.2, ease: "power1.inOut" }); // Sort the ScrollTrigger instances ScrollTrigger.sort(); }); }); This happens because the ScrollTrigger are not created in the order they appear on the screen, if that is not possible we recommend using the refreshPriority configuration in combination with the sort() method, from the ScrollTrigger docs: refreshPriority number - it's VERY unlikely that you'd need to define a refreshPriority as long as you create your ScrollTriggers in the order they'd happen on the page (top-to-bottom or left-to-right)...which we strongly recommend doing. Otherwise, use refreshPriority to influence the order in which ScrollTriggers get refreshed to ensure that the pinning distance gets added to the start/end values of subsequent ScrollTriggers further down the page (that's why order matters). See the sort() method for details. A ScrollTrigger with refreshPriority: 1 will get refreshed earlier than one with refreshPriority: 0 (the default). You're welcome to use negative numbers too, and you can assign the same number to multiple ScrollTriggers. Hopefully this helps. Happy Tweening!
  17. Hi, I can't see anything wrong in the code you posted, plus the latest version of the hook is importing useRef as you can see here: https://github.com/greensock/react/blob/main/src/index.js Can you provide a minimal demo on Stackblitz that illustrates this? https://stackblitz.com/ Happy Tweening!
  18. That demo is using Tailwind CSS https://tailwindcss.com/
  19. I'm just starting out with React and `useGSAP` and I'm running into an issue with out what appears to be the hook registering: react.development.js:1630 Uncaught TypeError: Cannot read properties of null (reading 'useRef') at useRef (react.development.js:1630:1) at useGSAP (index.js:32:1) However, despite this error - I can console.log the `useGSAP` hook, and also the `gsap` package and both are successfully loaded. This error message happens when I try to use useGSAP. This is the error message i'm getting: Segment.tsx:39 Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: 1. You might have mismatching versions of React and the renderer (such as React DOM) 2. You might be breaking the Rules of Hooks 3. You might have more than one copy of React in the same app See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem. printWarning @ react.development.js:209 error @ react.development.js:183 resolveDispatcher @ react.development.js:1592 useRef @ react.development.js:1629 useGSAP @ index.js:32 (anonymous) @ Segment.tsx:39 react.development.js:1630 Uncaught TypeError: Cannot read properties of null (reading 'useRef') at useRef (react.development.js:1630:1) at useGSAP (index.js:32:1) at Segment.tsx:39:1 at renderWithHooks (react-dom.development.js:16305:1) at updateForwardRef (react-dom.development.js:19226:1) at beginWork (react-dom.development.js:21636:1) at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1) at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1) at invokeGuardedCallback (react-dom.development.js:4277:1) at beginWork$1 (react-dom.development.js:27451:1) here's what i have so far: import React, { forwardRef, useEffect, useCallback, useRef } from "react"; import { useActiveSegment, BkExpeditionContextValues, } from "src/BkExpedition/index"; import { mergeRefs } from "src/util/mergRefs"; import clsx from "clsx"; import gsap from "gsap/dist/gsap"; import { useGSAP } from "@gsap/react"; gsap.registerPlugin(useGSAP); export type SegmentProps = Omit< React.ComponentPropsWithoutRef<"section">, "onAnimationStart" | "onDragStart" | "onDragEnd" | "onDrag" | "onDragOver" > & { segmentKey: BkExpeditionContextValues["activeSegment"]; }; export const Segment = forwardRef<HTMLDivElement, SegmentProps>( (props, ref) => { const { segmentKey, className, children, ...restOfHtmlAttrs } = props; const { activeSegment, previousSegment } = useActiveSegment(); const isActive = activeSegment === segmentKey; const sectionRef = useRef<HTMLDivElement>(null); const animateInTL = useRef<gsap.core.Timeline>(); const animateOutTL = useRef<gsap.core.Timeline>(); useGSAP(() => { // console.log("sectionRef", sectionRef.current); // if (sectionRef.current === null) return; // // animateInTL.current = gsap // .timeline({ paused: true }) // .fromTo(sectionRef?.current, { x: "100%" }, { x: "0%" }); // animateOutTL.current = gsap // .timeline({ paused: true }) // .fromTo(sectionRef?.current, { x: "0%" }, { x: "-100%" }); }); useEffect(() => { if (previousSegment === null) { return; } if (activeSegment === segmentKey) { animateInTL?.current?.play(); return; } if (previousSegment === segmentKey) { animateOutTL?.current?.play(); return; } }, [activeSegment, previousSegment, segmentKey]); return ( <section ref={mergeRefs(ref, sectionRef)} {...restOfHtmlAttrs} aria-hidden={!isActive} className={clsx(className, styles.segment, isActive && styles.isActive)} style={{ transform: isActive ? "translateX(0%)" : "translateX(100%)", }} > {children} </section> ); }, ); Segment.displayName = "Segment"; Am i not registering the book in the right place? Should it be registered inside the function component? FWIW - I plan to use this component in Next.js. Any help would be really appreciated -Gabriel
  20. yes thank you very much that's exactly what I need. I tried to reproduce what you did but I don't have access to the entire css
  21. @Rodrigo Thank you for clarifying. I'll take a look into this further. Thanks again!
  22. I think I have the exact issue as you. Is it the same as here? Basically a section that loads a bit slow, will mess up the triggers in the sections after it
  23. It takes only one wheel/touch event, but the previous animation has to be completed first and we want to wait for some specific situations: let allowScroll = true; // sometimes we want to ignore scroll-related stuff, like when an Observer-based section is transitioning. let scrollTimeout = gsap.delayedCall(1, () => allowScroll = true).pause(); // controls how long we should wait after an Observer-based animation is initiated before we allow another scroll-related action Sure thing, just tinker with the logic in the gotoPanel method, that's where everything happens in terms of animations: function gotoPanel(index, isScrollingDown) { // return to normal scroll if we're at the end or back up to the start if ((index === swipePanels.length && isScrollingDown) || (index === -1 && !isScrollingDown)) { intentObserver.disable(); // resume native scroll return; } allowScroll = false; scrollTimeout.restart(true); let target = isScrollingDown ? swipePanels[currentIndex] : swipePanels[index]; gsap.to(target, { yPercent: isScrollingDown ? -100 : 0, duration: 0.75 }); currentIndex = index; } You can switch yPercent for opacity/autoAlpha without any issues. Hopefully this clear things up. Happy Tweening!
  24. No problemo! Also in these forums there are no stupid questions 👍 That's just the Logical AND operator: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND Basically it checks if timer is truthy, if it is it'll clear the timeout. By default the timer variable is undefined which will return falsy and the clearTimeout won't be executed, same with the completed boolean. I want to set the progress of the tween to 1 only if the tween has run completely. Hopefully this clear things up. Happy Tweening!
  25. @Rodrigo also, if we could add fade in/out effect for the swiper section instead of scroll that would be excellent? Thank you!
  26. Thanks for the reply Jack, as always In the above case when there are only 3-4 components its fine, but when I placed more components under it like 7-9 its breaking. Ideally I understand we wont use that many video components on the same page, but still thinking this is an issue and may break or not compatible with other pinned scrolltrigger components(non-video but with other animations). Here in below code pen, I repeated the same component few more times & you can see from 4th component UI is breaking/overlapping & playing too soon. GSAP Video Onscroll issue updated (codepen.io)
  1. Load more activity
×
×
  • Create New...