Jump to content
GreenSock

Rodrigo last won the day on May 2 2021

Rodrigo had the most liked content!

Rodrigo

Moderators
  • Posts

    2,114
  • Joined

  • Last visited

  • Days Won

    168

Everything posted by Rodrigo

  1. Hi, The issues you've been reporting are happening just in the test process or also in the development process? I made a simple Nuxt app in my machine and it's working fine as long as I use the minified version of the MorphSVG file, if I use the normal version I get the same error you have in development. Also you can add this in your nuxt.config.js file in order to add the plugin before the closing <body> tag: head: { script: [ { src: '/MorphSVGPlugin.min.js', body: true } ] }, The file should be in the static folder.
  2. Have you tried adding the MorphSVG plugin directly into the static folder? In your dashboard, download the zip file with the bonus content, then extract the minified version of MorphSVG and it's corresponding map (or the uncompressed if you want) in the static folder. Then in your files you import them: import { MorphSVGPlugin } from "~/static/MorphSVGPlugin.min.js"; import { DrawSVGPlugin } from "~/static/DrawSVGPlugin.min.js"; I assume that you already have this in your Nuxt config file: build: { transpile: ['gsap'], }, This actually works for me, but I haven't ran tests on a Nuxt app before. Finally if this goes into a public repo, remember to add the route to those files in your .gitignore file. Happy Tweening!!!
  3. Hi, The virtual DOM React uses it's something that a developer hardly will access at any given point in an app development. I haven't seen a single case of that. For more info read this: https://reactjs.org/docs/faq-internals.html The usage of refs is not something we came up with here in the GSAP forums, it's the way React allows developers to access the DOM elements rendered in a specific component, nothing more. The samples, again, are pretty clear in the React documentation, you can use the useRef() hook as mentioned here: https://reactjs.org/docs/refs-and-the-dom.html#refs-and-function-components. You can also use a ref callback in functional components, but always using the useRef() hook as the container of the reference: const myRef = useRef(); const createRef = (element) => { myRef.current = element; }; return ( <div ref={createRef}> </div> ); This is also handy if you're using an array.map() helper and want to store multiple refs in an array: const myArray = [/* Array Elements */]; const Component = () => { const myRefs = useRefs([]); // by default an empty array const createRef = (element, index) => { myRefs.current[index] = element; }; return ( <ul> {myArray.map((el, index) => { <li key={`myEl-${index}`} ref={() => createRef(el, index)}> </li> })} </ul> ); }; That depends on the app being build. The amount of useEffect hooks in a component should go in hand with the properties in the state and/or props being passed to the component, that are being updated. You should be able to infer that from the app's context. Not the context API, but what is actually happening in the app, what is being updated and why is important to keep track of that. Normally the best approach is to store your GSAP instances in a useRef hook in order to keep them through re-renders and make it easier to kill them when the component is unmounted. In case of a re-render the animation should continue without any issues. Keep in mind that React only replaces the part of the DOM that has to be replaced in a re-render, otherwise it would be extremely expensive and inefficient. If the DOM node being updated in a re-render is actually being animated when the component's state or props are updated, the updated element would be rendered in the position given by the original styles and the GSAP instance would not break, because GSAP will keep a reference to the DOM element's object and will keep updating it. In this cases the best approach is to use an useEffect hook to kill the animation and create a new one with the re-rendered element, but this is a rare scenario. This depends on how you plan to control the animations. If you need to control the animation of a child component in a parent one, use forwarding refs: https://reactjs.org/docs/forwarding-refs.html, otherwise keep the GSAP instances in the component where they happen, it makes more sense. Yeah, that depends on the implementation of your app. If layout effect solves the issue then is a good idea to use it. So what's the issue you mention with the layout effect hook? If you're already implementing it, I don't understand the premise of your question. Mhhh... how exactly can you use GSAP for mounting or unmounting components? GSAP works with DOM nodes by updating some properties in a specific amount of time or frames (when you use frames). It has no control on when a React component is mounted/unmounted. Why we suggest transition group? Because transition group, as well as Vue's <transition> component are based on Angular's ng-animate, which is an excellent way to control animations in components. Transition group actually handles the mount/unmount process in a way that allows to create animations for that process and, while it certainly has a few open issues in github, is currently actively maintained by the React team and many very talented developers. Finally I've used transition group in production, in many projects without any issues and I've seen in it used in plenty of projects that are highly praised and without bugs or glitches as you mention. If you're running into a particular issue, perhaps you could provide a reduced live sample in codesandbox to take a look and also report such bugs to the React team: https://github.com/reactjs/react-transition-group/issues Yep, indeed that is quite outdated and I haven't had time to update this guide. While React suggest to use the functional approach, there is no real issue in using classes, in fact React Router, not exactly a shady library, uses classes: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Router.js. Also plenty of other libraries that work without any issues on top of React, still use class based components. There is actually no hard evidence that functional components are better than class based components. You could argue that the code is better organized or something like that, but I've seen apps that are a mess in both approaches. The fact that the React team favors the use of functional programming over class programming is just a preference and nothing more. In fact GSAP uses classes and I think it works pretty good right? https://github.com/greensock/GSAP/blob/master/src/gsap-core.js#L1133 Happy Tweening!!!
  4. Hi, Unfortunately without a live, reduced and editable sample, there is not much I can do at least. Instead of using el.style.transform = 'translateY(0)'; use a set() method and see if that works: const beforeEnter = (el) => { gsap.set(el, { yPercent: -100 }); }; const beforeLeave = (el) => { gsap.set(el, { yPercent: 0 }); }; Other than that, the only solution I can provide is to match the horizontal gradient of the elements in the background, or apply that gradient in the background and make the elements transparent. The latter will not produce this line. Happy Tweening!!!
  5. I don't know if it's a trick or perhaps a subpixel rendering issue, if subpixel rendering is still something that happens. It used to cause a few headaches years ago. Can you provide a reduced sample in codesandbox that we can take a look at? Also if your elements' height is equal to the screen height you could try with yPercent, perhaps using vh could be causing an issue. Also try using the SnapPlugin to modify the values by an integer or a single decimal and avoid long decimal numbers: https://greensock.com/docs/v3/GSAP/CorePlugins/SnapPlugin Happy Tweening!!!
  6. Hi Daniel and welcome to the GreenSock forums. To move both elements at the same time you have to remove the mode attribute in the transition component: <router-view v-slot="{ Component }"> <transition @before-enter="beforeEnter" @enter="enter" @before-leave="beforeLeave" @leave="leave"> <component :is="Component" class="component-wrapper"></component> </transition> </router-view> Although you have to be aware that this will require some tinkering with the styles since both elements will be in the document flow at the same time, so you'll have to play with their positions while the animation is running. Happy Tweening!!!
  7. Hi and welcome to the GreenSock forums. Unfortunately I don't have enough time to create a fully working sample, but you can use ScrollTrigger's getVelocity() method: https://greensock.com/docs/v3/Plugins/ScrollTrigger/getVelocity() With that you can calculate the scroll velocity in pixels/seconds (lets call this A), then get the amount of pixels left to snap the element to the left of the screen (lets call this B) and then divide B/A and you'll get the amount of seconds needed to keep the current speed and use an ease out function to slow that speed towards the end of the animation. There is also a chance that this could be achieved in a simpler way, since I haven't delved too much into snap in ScrollTrigger and this solution is just me overcomplicating things Happy Tweening!!!
  8. Please provide a reduced live sample in Codepen. We can't guess what problems you're facing with the few code snippets you're providing:
  9. Hi and welcome to the GreenSock forums. By looking at the documentation of the inertia plugin, the approach is pretty much the same with some minor changes in the code. This seems to be working kind of OK: createDraggable() { var slider = this.slider, tracker = VelocityTracker.track(slider, "x")[0], pressedTop; //when the users presses down, if the mouse is in the top half of the image, pressedTop will be true. We use this to make the skewing more natural, like the mouse is "pulling" that part of the image this.draggable = Draggable.create(this.proxy, { type: "x", edgeResistance: 0.75, onPress: function(e) { var bounds = this.target.getBoundingClientRect(); pressedTop = (e.clientY < bounds.y + bounds.height / 2); //keep track of how far apart the proxy is from the slider because when the user presses down, we want to IMMEDIATELY stop any motion, thus this offset value becomes baked in until release. // this.offset = this.x - slider._gsTransform.x; this.offset = this.x - parseFloat(slider._gsap.x.replace(/px/g, "")); gsap.killTweensOf(slider); //in case it's moving gsap.to(slider, { duration: 0.2, skewX:0 }); }, onDrag: function() { gsap.to(slider, { duration: 0.8, x:this.x - this.offset, skewX:"+=1", //meaningless - we tweak the values in the modifier below. We needed to make the skewX tween to something just so that it's included in the tweening values. modifiers:{ //skew based on the current velocity, capped at 20 in either direction skewX:function(v) { var skew = tracker.get("x") / 200; if (skew > 20) { skew = 20; } else if (skew < -20) { skew = -20; } return pressedTop ? -skew : skew; } }, ease:Power2.easeOut }); }, onRelease: function() { //if the user just presses down and releases without really moving much at all, there's no need to do a throwProps tween. if (this.tween && Math.abs(tracker.get("x")) > 20) { gsap.to(slider, { duration: this.tween.duration(), inertia: { x: { end:this.endX } }, ease:Power3.easeOut }); } gsap.to(slider, { duration: 0.5, skewX:0, ease:Power1.easeOut }) }, //dragResistance: 0.5, bounds: this.container, inertia: true })[0]; } Also you need to remove the skewType config in the setBounds method, since that was removed in GSAP 3: setBounds() { this.sliderWidth = this.slides[0].offsetWidth * this.slidesNumb; gsap.set([this.slider, this.proxy], { width: this.sliderWidth, x:"+=0" }); } As I mentioned this works kind of OK because there are a few jumps in the slider when you press and drag. Unfortunately I don't have time to go through the entire sample and try to find out. Perhaps @GreenSock, @OSUblake or another user can shed some light on it and update that sample to the new syntax, but with those changes you can get the elements to skew properly. Happy Tweening!!!
  10. Hi, There area couple of approaches for this, depending on the browser support of your site. For a universal solution, you can use this: gsap.set("#chi", { position: "absolute", top: "50%", left: "50%", xPercent: -50, yPercent: -50 }); The other alternative is to use flexbox in the cards' container: HTML <div class="container"> <div class="box"></div> </div> CSS .container { height: 100vh; width: 100%; display: flex; justify-content: center; align-items: center } Also there is no need to pass this to GSAP: transform: "translate(-90px, -176px)", you can just use x and y: gsap.set(element, { x: -90, y: -176 }); If you keep getting issues with this, please try to create a reduced live sample in codepen. Happy Tweening!!!
  11. This codepen by @PointC is a great sample of using events to trigger GSAP instances: https://codepen.io/PointC/pen/YRzRyM Although PIXI uses it's own event methods it's not really that hard to port Craig's sample to PIXI: https://pixijs.io/examples/#/interaction/click.js http://pixijs.download/release/docs/PIXI.DisplayObject.html Happy Tweening!!!
  12. Have you tried using the <transition> component to create animations between routes? Since vue router is made by the vue core team it's super simple to create transitions between routes using the javascript hooks the API exposes: https://codesandbox.io/s/gsap-vue3-route-transitions-f5y4e Also what you can try this to clear the applied styles by GSAP in the beforeDestroy hook in your component: gsap.set(".start-container, .start-footer", { clearProps: "oapcity" }); Here you can read about clearProps (scroll almost to the end of the page): https://greensock.com/docs/v3/GSAP/CorePlugins/CSSPlugin Happy Tweening!!!
  13. Try removing the GSAP instance from the data object. Animations are not exactly reactive data in the realm of reactive frameworks (Vue, React, etc.) and just use this.marqueeScrollTrigger directly in the mounted hook to keep track of the instance and be able to kill it afterwards. The problem could be that the initial rendering by the browser is taking longer than the JS execution, therefore ScrollTrigger is doing all the calculations and after that the content somehow is shifting, you could check the height of the body element or the main parent element before creating the ScrolLTrigger instance and also inside a setTimeout or a delayedCall method, and see if there are differences. You could inspect in devtools and see in the performance tab if there is a long paining thread there. Honestly I don't see anything in your dependencies that seems suspicious. Happy Tweening!!!
  14. Hi, welcome to the GreenSock forums and thanks for being a club member and supporting GSAP!!! Sorry to hear that you're experiencing this issue. As you mentioned I tried a simple set up in codesandbox and in my local environment but I'm unable to reproduce the issue. Perhaps try storing the GSAP instance instead the ScrollTrigger instance in the component and use that to reference it in the beforeDestroy hook, something like this: import { gsap } from "gsap"; export default { mounted() { this.t = gsap.to(this.$refs.aboutImage, { scrollTrigger: { trigger: this.$refs.imageContainer, start: "top top", end: "+=200%", pin: true, scrub: 0.5, }, x: 200, y: 100, duration: 1, }); }, beforeDestroy() { this.t.kill(); }, }; Perhaps something else in your code or another package in your app could be causing this issue. If you can't solve it, perhaps try using a specific <div> element as the scroller. Wrap all your app in that element, give it a height of 100vh and overflow: auto. Like that you can point that as the scroll element in ScrollTrigger: gsap.to(this.$refs.element, { scrollTrigger: { scroller: "#parentElement" } }); I know that using the id selector is not the best idea but otherwise you'll have to either add it to a VueX store or pass it down as a prop to all the elements that use it or get fancy with this.$el.parent in the child components and the ones down the component tree. Also since that element is likely to be mounted just once in the app's lifecycle, it shouldn't become an issue down the line. Happy Tweening!!!
  15. Hi and welcome to the GreenSock forums. That can be achieved with the MorphSVG plugin. In fact those buttons are SVG elements and that site is actually using GSAP. The specifics of it are outside my abilities, but you could start with the samples in this thread: Perhaps @Cassie and @PointC, our resident SVG magicians could share a pointer or two on the best approach to tackle this. Happy Tweening!!!
  16. Instead of using scrub: true, try a number around 0.5 - 0.7 in order to get a more smooth animation: gsap.to(".project:not(:last-child)", { yPercent: -96 + (projects.length - 1), ease: "none", stagger: 0.5, scrollTrigger: { trigger: ".trigger-container", start: () => "top top", end: () => "+=" + ((projects.length + 1) * window.innerHeight), scrub: 0.6, pin: true, invalidateOnRefresh: true, } }); Happy Tweening!!!
  17. Indeed, just keep it there, outside the viewport and bring it in using GSAP like the sample in the other thread you mention. Happy Tweening!!!
  18. Hi, Yeah, responsive vertical accordions are not the simplest thing, but they're not the hardest neither. It's just about wrapping your head around handling the content height changes and how GSAP works. This sample is not very elegant but it's a solid approach to this. I don't know if it's the best approach, but it works: https://codepen.io/rhernando/pen/ZbGeJd The code is quite commented so all the explanation and thought process is there. Hopefully is enough to get you started. Happy Tweening!!!
  19. Hi and welcome to the GreenSock forums. Yeah both sites use PIXIJS which is great. Basically what it seems they're doing is creating one container for each scene adding the elements in those containers to create the parallax effect on mouse move. Then it seems that they scale and translate the current container, to simulate the zoom in feature and then create some sort of swap between the containers. With that being said I don't think this sites work using some sort of scroll value detection but instead they check for specific events, mouse wheel, keyboard arrows, touch, etc. in order to move to the previous/next stage. That of course doesn't mean you can't use ScrollTrigger to do it, you'll have to hide the scroll bar, which is not the same than using overflow: hidden, but is not the approach I would take to tackle something like this. I'd use events detection. Happy Tweening!!!
  20. Hi and welcome to the GreenSock forums. That's quite a project, never saw it before and to be honest not the best way to get started with GSAP. Don't get me wrong, there is nothing wrong with aiming to Mars (nobody aims to the moon anymore ), but before that you need to actually learn how to build the rocket that will take you there, it's a process. Honestly while the site certainly looks amazing, is quite messy and hard to navigate IMHO. Also keep in mind that you can't actually see any indication of a scroll bar and if you further inspect the styles you'll see that there is no changes in the scrollLeft or scrollTop properties in any of the parent elements, so most likely this site is listening to certain events like mouse wheel, keyboard, touch events, drag, etc. to advance a group of tweens and timelines. This codepen sample by @PointC illustrates how to listen and react to those events: https://codepen.io/PointC/pen/YRzRyM Perhaps what you can do is use the scrub property in Scroll trigger which advances a tween in a smooth way based on the scroll position: scrub Boolean | Number - Links the progress of the animation directly to the scrollbar so it acts like a scrubber. You can apply smoothing so that it takes a little time for the playhead to catch up with the scrollbar's position! It can be any of the following Boolean - scrub: true links the animation's progress directly to the ScrollTrigger's progress. Number - The amount of time (in seconds) that the playhead should take to "catch up", so scrub: 0.5 would cause the animation's playhead to take 0.5 seconds to catch up with the scrollbar's position. It's great for smoothing things out. https://codepen.io/GreenSock/pen/WNvVOWw Happy Tweening!!!
  21. Hi and welcome to the GreenSock forums. Indeed the fact that you're pointing to a new URL is making this break. If you remove the onclick="location.href='new-page.html'" attribute from the image it works. Unfortunately if you want to create some sort of transitions between pages, you can't use regular links, because when that happens the entire page is replaced by a new one, so you won't see a seamless transition between one page and the other. If you want to do that you'll have to use a library like Vue, React, Svelte, etc. that can handle routing for you without reloading the entire thing. On that note, since you're just starting in this area I'd strongly recommend you to get familiar with HTML, CSS and JS first, before diving head first into learning those libraries I mentioned above. There is a ton of stuff in youtube that can help you get started, here are two channels filled with great learning resources: https://www.youtube.com/c/TraversyMedia/videos https://www.youtube.com/c/Freecodecamp/videos You can search within those channels in order to look for HTML, CSS and JS starting videos. Happy Tweening!!!
  22. I need a developer with experience in THREEJS and WebGL shaders for an ongoing project in a NextJS site. React experience is not needed but it would be a plus. The job consists in two things: Create a re-usable code that generates a canvas renderer with white clouds and particle A snippet that generates a wavy background based on an hexagonal mesh. Both elements have to be fully responsive and have create and destroy methods. Interested people please contact me via PM here in the forums. Best, Rodrigo.
  23. Honestly I don't know. There are quite a few differences between the set up you posted and the one I came up with. Also I've never worked with a headless CMS in a React or Vue environments, that is using any framework based on them (Gatsby, Next, Nuxt, etc), so I have no experience with them. If I was you I would start with a barebone NextJS app with GSAP and ScrollTrigger. Then I'd start adding things up until it breaks, then you'll have the culprit. This sounds like a drag and in someway it is, but I don't see another way around it. Perhaps @elegantseagulls or @Shrug ¯\_(ツ)_/¯ have some experience with the stack you're using in your app and could chime in into this. Sorry I can't be more helpful. Happy Tweening!!!
  24. Hi, Sorry this slipped through the cracks. Honestly I don't know what to tell you. I whipped a quick sample using Next and GSAP and it seems to be working as expected: https://codesandbox.io/s/vibrant-cerf-d16uv?file=/pages/index.js Perhaps the issue resides in the usage of styled components or another package in your setup, but that's beyond what we can do around here. Try removing styled components and use either regular classes or styles declarations using objects (like I did in the sample), if CSS in JS is a must in the project. Hopefully this helps. Happy Tweening!!!
  25. Hi, That particular line is quite simple actually. When you create a GSAP instance, by default it's moving forward and of course it starts at 0 seconds. Adding a reverse() method after instantiating the timeline basically tells the timeline: "go backwards", so the timeline starts reversing until it reaches the start position. Since at that stage of the code we haven't added a single instance to the timeline and considering that at most, the time elapsed between the timeline being created and the reverse() method is 1 or 2 milliseconds (virtually nothing), the timeline is created, is at 0 seconds and going backwards. Then we add the instances to the timeline and then we control it using the reversed() method, which is basically a shorthand for using an if else block to use either play() or reverse(). Since the state property that toggles the timeline is found in the component's global scope is a very handy solution. I hope it makes sense. Happy Tweening!!!
×