Jump to content
Search Community

Rodrigo last won the day on April 24

Rodrigo had the most liked content!

Rodrigo

Administrators
  • Posts

    6,598
  • Joined

  • Last visited

  • Days Won

    285

Everything posted by Rodrigo

  1. Hi, Unfortunately a code snippet and a live site doesn't tell us the issue you're having. We need to see it live on a demo that we can fork and tinker with in order to make it faster to identify. That's why we offer a set of stackblitz demos that allow you to fork and create your demo. React Next Please don't create a stackblitz demo that includes your entire project, just a few colored divs that clearly illustrates the problem. Happy Tweening!
  2. Great to hear that it actually helped! Thanks for sharing your demo with the community! The only thing I would point about it is that you don't need to store the timer in a ref if you're using it inside the useGSAP hook's scope. Also this is not going to do what you expect: timer && timer.current.pause(); Because timer never will be falsy, because since is a react ref, by default react will add the current property to it, so timer won't be undefined, will always have the current property because it will be an object. That's why I suggest to keep everything in the useGSAP scope and set the timer as a constant. Hopefully this helps. Happy Tweening!
  3. Yeah, that's basically how it works. When you call a function and a variable has been updated the function will reflect the updated value, just the way most programming languages work, as far as I know at least, I can speak for JS and PHP, but it would make sense that it works like that in every language. Happy Tweening!
  4. Hi, I think the issue is in your CSS actually but not the transition: all property that was being added, but in some of the media queries you have. I'm testing this on a screen that is 1600x900 pixels and the issue is not when you change the width of the screen but the height. In this distribution everything works great regardless of the screen width: The reported height of the result container in codepen is 516 px. But in this disposition it doesn't work and the markers are at the top of the document: The reported height in this one is 388 px, so you should look into the media queries you have in your setup and how that is affecting the document's flow. Hopefully this helps. Happy Tweening!
  5. Hi, Sorry about the issues, but as mentioned without a demo that clearly reproduces the problem there is not a lot we can do. The only advice I can give you is to keep looking into anything that could change the height of the document when resizing, maybe images with src set, maybe different screen sizes will use different images with different heights, that could load the image after the ScrollTrigger instance is created. Happy Tweening!
  6. Hi, For what I can see you're not using GSAP Context for cleaning up and reverting the ScrollTrigger instance when you close the modal: https://gsap.com/docs/v3/GSAP/gsap.context() This demo shows how to use the onMounted and onUnmounted hooks for that: https://stackblitz.com/edit/nuxt-starter-aih1uf Is not the same as your approach, but it should give you a solid start point. Hopefully this helps. Happy Tweening!
  7. Hi, This demo uses the useGSAP hook with GSAP MatchMedia: https://stackblitz.com/edit/vitejs-vite-pfhzkf?file=src%2FApp.jsx Here you can see the docs for MatchMedia: https://gsap.com/docs/v3/GSAP/gsap.matchMedia() Hopefully this helps. Happy Tweening!
  8. Hi @BennyBatta and welcome to the GSAP Forums! Unfortunately there is not a lot we can do without a minimal demo, a live site doesn't give us the opportunity to edit the code and see what could be the issue. If possible setup a minimal demo forking this: https://codepen.io/GreenSock/pen/aYYOdN Happy Tweening!
  9. Hi @Ahlecss and welcome to the GSAP Forums! Yeah without a minimal demo is not really easy for us to see what could be the problem. Keep in mind though that GSAP can tween any numeric value of any object. A GSAP instance is an object and progress is a numeric value so you can tween the progress of a GSAP Tween! const t = gsap.to("#circle", { width: 100, ease: "none", paused: true, }); // Then tween the progress const clickHandler = (value) => { gsap.to(t, { progress: value, // between 0 and 1 of course, duration: 0.5, ease: "power1.inOut", // Any easing function you want here }); }; Doing this without creating a new GSAP instance is just not possible. Maybe you could look into creating a re-usable quickTo instance: https://gsap.com/docs/v3/GSAP/gsap.quickTo() const t = gsap.to("#circle", { width: 100, ease: "none", paused: true, }); const pTo = gsap.quickTo(t, "progress", { duration: 1, ease: "power2" }); // Then tween the progress const clickHandler = (value) => { pTo(value); }; Hopefully this helps. Happy Tweening!
  10. Hi, I think this is a better approach: https://codepen.io/GreenSock/pen/JjVmWKb I wasn't able to create a react version of it for technical issues on my end (ISP is super slow and creating a codepen is not as slow as a react demo on stackblitz), but porting this to react shouldn't be a really complicated task. The heart of this is on the doSlide method that takes a specific value (+1 or -1) which updates the index value. Also the difference with your approach is that this uses a fromTo instance for the next slide, regardless of the direction so that takes the clip path of the next image from the bottom to the top which makes looping possible. Hopefully this helps. Happy Tweening!
  11. Hi, Unfortunately there is not a lot we can do without a minimal demo. If you have your ScrollTrigger instances in different components, be sure to use the right selectors and scoping. Try to create a minimal demo on Stackblitz that clearly replicates the issue, please don't use the full project or a git repo since that makes it more difficult to fork and find the issues since we have to go through a lot of files and lines of code, the simpler the better. Happy Tweening!
  12. Hi, The first issue in your code is that you're using the quick setter on the parent element, that is the element that contains the grid, and not the grid elements so staggering will have no effect whatsoever. Then I fail to see the point of a quick setter if you can achieve the same with just a GSAP Tween that gets overwritten if another is created. Something like this: useGSAP(() => { let proxy = { translate: 0 }, translateSetter = gsap.quickSetter('.video-container', 'y', 'px'), clamp = gsap.utils.clamp(-1000, 1000); ScrollTrigger.create({ onUpdate: (self) => { translateSetter(clamp(self.getVelocity() / -100)); gsap.to('.video-container', { y: 0, duration: 0.2, stagger: 0.05, overwrite: true, }); }, }); }); Here is a fork of your demo with that approach: https://stackblitz.com/edit/react-hnfbhc?file=src%2FApp.js Hopefully this helps. Happy Tweening!
  13. The React way is always something that will lead to discussions and disagreements no matter what. I've worked with react for over 8 years, ranging from small static websites to large SaaS apps with hundreds of files and convoluted state management. At the end you have to decide what's more important the so called component encapsulation and abstraction or a more flat and simpler architecture that makes other tasks easier. Unfortunately we can't have both. On that subject, what is understood with encapsulation? How is not secure if you don't abide to it? How can it lead to issues? Those are not general concepts and cannot be applied in the same way to every project in react, that is something that has to be dealt with on a project basis. Is your project handling any information that needs an extra security layer? If not then the whole argument that component encapsulation could lead to security problems is out the window. Is your project mostly static in terms of what is rendered during the app's life cycle? Then what's the point of having hundreds of refs, use forwarding refs and imperative handlers, if you know that the selectors you're pointing to are going to be there no matter what? See how deep this rabbit hole gets? I'm not a big fan of the react way TBH (is worth mentioning that I'm not entirely against it either) since I've seen it create some confusion from time to time. I'm a believer that these type of decisions need common sense as well as pre-set guidelines. For example in this forum everyone with some experience will tell you: "animate scale instead of height and width because you get better performance". But there are some projects and situations when that is not an option, so you have to use width and/or height. In those cases be sure to make the elements as small as possible and that they affect the document's flow in the most minimal way. The dogmatic approach is to always animate transforms but the realistic one is that sometimes there is no other option and when is done properly you'll get a nice smooth animation that won't hurt UX. Again is a project by project approach not something set in stone. A project in react is no different. Sure component abstraction in order to keep everything as small as possible and make it easier to maintain, is the desired outcome, but if that will imply that you'll have to code through a bunch of hoops in order to get things working the way you want, you might want to re-visit that approach and maybe in a few cases/components, just have a flatter structure with a bit more code in those components in order to make code simpler and easier to maintain. The only rule of thumb I follow no matter what is this: "Test, test, test and then test more". If you break encapsulation and you're not doing things the react-way, but the app works the way you want/need, nothing breaks and development and maintainability is easy, then what's the problem? In this case you have to decide based on what works. Keep everything the way you have it now and find a way to tell the child component that is safe to use a specific selector and only then create your GSAP instances? Somehow pass the parent ref to the child component and use that as the scope in order to create the GSAP instances when that ref is not null/undefined? Flatten your structure in order to make it simpler? I was adamant to a flatten structure because in my experience that is always the best road in the long term, nothing more, but this is your project and your time, hence your decision. I just offer my personal opinion based on my experience, but I don't intend to enforce anything on anyone here or anywhere else. If somehow it felt that way I'm sorry about it and trust me, it was never my intention. Finally if in some way I was rude, blunt, condescending or insulting to you, I apologize for that as well, it wasn't my intention neither. The GSAP forums have been for over a decade a safe place where nobody gets called names, downvoted or anything of the sort. Is a healthy community that aims to give the best possible advice with the time we have in our hands, while making everyone welcome and transmitting the vibe that you're safe here. If I failed in that way, then there is a learning experience for me, for sure. The aim is to be better than I was yesterday. Happy Tweening!
  14. Hi @OliverHH and welcome to the GSAP Forums! I'm afraid that is not possible, at least not in a simple way. Maybe there is a way to achieve that with enough custom logic but is beyond the scope of the help we provide in these free forums. ScrollTrigger does provides a duration option for the snap configuration that gives you the possibility to either set a fixed duration of the snapping or set a min and max durations: duration [Number | Object] - the duration of the snapping animation (in seconds). duration: 0.3 would always take 0.3 seconds, but you can also define a range as an object like duration: {min: 0.2, max: 3} to clamp it within the provided range, based on the velocity. That way, if the user stops scrolling close to a snapping point, it'd take less time to snap than if the natural stopping point is far from a snapping point. Something like this: snap: { duration: { min: 0.5, max: 1, } } But those values can't be altered as the ScrollTrigger instance is snapping though. Hopefully this helps. Happy Tweening!
  15. Not reallly, your method was making the calculations, but the value being used by GSAP wasn't being updated. GSAP records the initial value of the properties you want to tween and then iterates between that value and the final one you're passing in the config. In order to optimize this process GSAP doesn't do constant read/write operations, it does that once and then just iterates between the values. Invalidating a GSAP instances removes the initial values (the value the element currently has) but not necessarily the target value. If you want to update the target value that's when function based values come in handy, because that tells GSAP to update both the initial and final values in this particular case. Your method was updating the value of a variable, the approach I use is to call a function that returns a value. You could use other approaches to get the same result but using a function is always the cleanest one IMHO. Hopefully this clear things up. Happy Tweening!
  16. Hi, That's an interesting site to say the least. I inspected with devtools and saw that it actually uses two different sets of images. This is the thumbs container: And this is the feed (single column) one Now how the animation is achieved and which elements are being animated, honestly I couldn't tell you but if you set the opacity of the thumbs container to zero like this: <div class="page__modal home__index__modal" style="visibility: initial; opacity: 0;"> You'll see the scroll bar of the feed element right behind this, so basically the developer uses two different elements, hides immediately the thumbs view using visibility (hidden/initial) and then only animates the elements in the feed section, that's why the scroll position is remembered for saying it in some way, because when you're on the thumbs view only that scroll changes. Here you can see the first image behind the thumbs: The trick in this website is all about timing and which set of images are the ones being animated. As you can see your setup and approach is far different than this website so I doubt you'll get the same result, especially when it comes to the scrolling part. I'd recommend you to have a look at this demo in order to get an idea of switching between a grid and columns, of course this uses Flex and not Grid, but the approach should be similar: https://codepen.io/GreenSock/pen/zYqLjre Hopefully this helps. Happy Tweening!
  17. Hi @Jc Denton and welcome to the GSAP Forums! I'm not 100% sure how feasible this is, at least not in a simple way. It must be possible but it could require quite a bit of custom logic, but again I'm not sure. We have this demo that predicates on every section's height being 100vh with the snapping you're looking for: https://codepen.io/GreenSock/pen/NWxNEwY The issue is that IDK, at the top of my head, how to make this work with different heights TBH. Then we have this demo that layers the elements with different heights but there is no jump to section in them: https://codepen.io/GreenSock/pen/jOerKOb It's a matter of mix and matching that, again, I don't know right now how to approach in a quick and simple way. I'll see if I can think of something or if another user can chime in and shed some light on this. Sorry I can't be of more assistance. Happy Tweening!
  18. Hi, I think this is a bit of an edge case. This is the best solution I was able to come up with and I can't guarantee you that it'll work 100% of the times, so you'll have to test and see what happens: https://codepen.io/GreenSock/pen/eYojqEB Here is the debug view: https://cdpn.io/pen/debug/eYojqEB Hopefully this helps. Happy Tweening!
  19. Hi, Mainly the issue is that when using invalidateOnRefresh with ScrollTrigger your values need to be function based. This is what was happening, invalidateOnRefresh was flushing the starting values of the scale tween, but nothing more. The final value was always the same. This seems to fix the problem: let logoToScale = () => (window.innerWidth / logo.getBBox().width) * 5; const timelineHeader = gsap.timeline({ scrollTrigger: { id: "ZOOM", trigger: "div.landing", scrub: true, start: "top top", end: "+=100% 0", pin: true, markers: true, invalidateOnRefresh: true } }); timelineHeader.to(logo, { duration: 1.5, ease: "none", scale: () => logoToScale() }); Here is a fork of your demo: https://codepen.io/GreenSock/pen/WNWgaqZ Hopefully this helps. Happy Tweening!
  20. Hi, You might want to have a look at our learning resources regarding useGSAP: https://gsap.com/resources/React Most specifically at how contextSafe works, because that could be the missing piece for you here. Also check this video as well: We have a collection of React starter templates on Stackblitz that could help as well: https://stackblitz.com/@gsap-dev/collections/gsap-react-starters Happy Tweening!
  21. Hi, Yeah I think the issue was more an order of operation one rather than anything else. When to clear the styles from the gallery items was the key. Also I used scale: true because in your original demo you have that setting. I changed the image as well in order to make it more clear if it gets distorted as well. Here is the demo updated: https://codepen.io/GreenSock/pen/vYMzKZx Happy Tweening!
  22. Hi, I don't have time to go through all your HTML and CSS, but I believe that is creating a problem where not enough scrolling is generated to accommodate all the animations you want to create, that's why using clamp in the end configuration object forces the animation to be completed in that amount of scroll: let scrollHome = gsap.timeline({ scrollTrigger: { trigger: '#main', start: "top top", end: 'clamp(+=5000)', pin: true, markers: { startColor: 'green', endColor: 'red', }, scrub: 1 } }); You might want to have a look at this video @Cassie made on the subject: Hopefully this helps. Happy Tweening!
  23. Hi @aleks3650 and welcome to the GSAP Forums! There is far too much code in here and without a minimal demo there is not a lot we can do. The first error you're getting is mostly a React related one and not a GSAP related one: https://dev.to/collegewap/fix-rendered-fewer-hooks-than-expected-in-react-3757 https://medium.com/@jonchurch/how-to-fix-react-error-rendered-fewer-hooks-than-expected-e6a378985d3c The issue with the target undefined, that means that the element you're passing to GSAP is undefined most likely because of that conditional rendering block you have here: {choosed ? ( <h3> <span className="AreaInfo" ref={lowerref}> XXXXXXXXXXX km² </span> </h3> ) : ( // {NameFun(newSize) || "Area"} <div className="buttonContainer"> <button className="less" onClick={() => handleCompare("less")}> smaller </button> <button className="more" onClick={() => handleCompare("more")}> bigger </button> </div> )} When choosed is falsy lowerref is no longer a DOM element but is undefined: useGSAP( () => { gsap.to(lowerref.current, { // UNDEFINED -> WARNING! duration: 0.9, delay: 0.1, text: newSize, ease: "bounce.inOut", }); }, { dependencies: [AnotherCountryInfo] } ); I would suggest you to use revertOnUpdate in the useGSAP hook, but I'm afraid that it won't fix the logic issue of the ref not being defined. You should look into that first. We have a collection of starter templates in Stackblitz where you can fork one of those and create a minimal demo: https://stackblitz.com/@gsap-dev/collections/gsap-react-starters Happy Tweening!
  24. Yeah this is mostly a React related thing and not a GSAP related one. We need to keep our focus on GSAP related issues. You should get more knowledge on react components, components communication and state management, all react features that fall outside the scope of these free forums. If you have a specific GSAP related question we'd be happy to look into that. Good luck with your project! Happy Tweening!
  25. Hi, In React always use the useGSAP hook, is far simpler and cleaner: https://gsap.com/resources/React Here is a simple demo that uses the useGSAP hook with GSAP MatchMedia: https://stackblitz.com/edit/vitejs-vite-pfhzkf?file=src%2FApp.jsx Also in your codepen you're using the same element as the trigger: gsap.to(".work-block", { x: () => horizontalSection.scrollWidth * -1, xPercent: 100, scrollTrigger: { trigger: ".work-block", // FIRST TRIGGER start: "center center", start: "0% 50%", end: "+=2000px 30%", pin: ".work-wrapper-main", scrub: true, invalidateOnRefresh: true, markers: true } }); gsap.to(".work-block-2", { x: () => horizontalSection2.scrollWidth * -1, xPercent: 100, scrollTrigger: { trigger: ".work-block", // FIRST TRIGGER AGAIN HERE!!! start: "center center", start: "0% 50%", end: "+=2000px 30%", pin: ".work-wrapper-main-2", scrub: true, invalidateOnRefresh: true, markers: true } }); Changing that to trigger: ".work-block-2" seems to work the way you expect. Hopefully this helps. Happy Tweening!
×
×
  • Create New...