Jump to content
Search Community

Leaderboard

  1. GreenSock

    GreenSock

    Administrators


    • Points

      24

    • Posts

      23,805


  2. Rodrigo

    Rodrigo

    Administrators


    • Points

      12

    • Posts

      10,161


  3. mvaneijgen

    mvaneijgen

    Moderators


    • Points

      4

    • Posts

      4,284


  4. Jonathan

    Jonathan

    Moderators


    • Points

      3

    • Posts

      3,548


Popular Content

Showing content with the highest reputation since 04/13/2026 in all areas

  1. The main down side of this approach: images.forEach((img) => { img.onload = () => ScrollTrigger.refresh(); }); Is that it literally calls refresh() after every single image loads which is probably overkill. I assume you really just want to wait until they're all done(?). If so, I wrote a helper function that'll do just that for you in this thread:
    2 points
  2. That is not privative of CMS images. Any <image> tag that doesn't have a set height will use it's natural height and width. Of course in a CMS if the client/uploader can set the dimensions ahead and keep using those dimensions, it will mean that the images' height is predictable but still on first render and if the image is lazy loaded, it's height will be 0 pixels non matter what. That's why some developers assign a height in the CSS to either the image directly or a parent container. Same as before the browser doesn't have a clue of their size until they are loaded and rendered, but that could be set and the browser will know the size of the image regardless of the loading state. Yeah the refresh method is helpful in this cases or in any other situation that creates a layout shift, because some content has been added or removed, so ScrollTrigger can run it's calculations and correctly set the start/end points. Glad that this helped! Happy Tweening!
    2 points
  3. Sorry about any confusion there. First of all, you're not crazy - that behavior did change in 3.14 because MorphSVG got some big improvements to the way it plots where it adds points (when necessary) if the start/end shapes have a different number of anchors. Your artwork does indeed have mismatched numbers of points. I know it seems odd to say this was an "improvement" when it clearly made your particular case look worse. When subdividing path segments to plot new anchors, it's typically best to subdivide the longest ones - think about a long line with anchors like this: X----X--------------------------X It's almost always better to add the new anchor in the long segment like this: X----X-----------X-------------X Instead of the shorter one like this: X--X--X------------------------X The newer MorphSVG does a better job of that, but in your particular case you had some artwork with oddly-placed anchors (two almost on top of each other in each of the lower corners). So it was placing some extra anchors along the top of the final shape. In cases like this, it's almost always best to just prepare your artwork in a way that gives YOU control of where those anchors go. You could literally just drag the anchors to where you want them in your authoring software. For example, that curve at the bottom just introduces one extra anchor that has long control points...so you could copy that curved (end) path, then drag that anchor down so that it's inline with the very bottom and remove the control points so that it looks like one big rectangle but it has an extra anchor in the center of the bottom. Then you've got your start/end shapes to feed into MorphSVG. Here's a fork that uses cleaner artwork: https://codepen.io/GreenSock/pen/myOyxEw?editors=0010 That's what I'd strongly recommend, but I guess an alternative is for you to just load version 3.13 of MorphSVG (that works fine with later version of the GSAP core, 3.15.0 currently).
    2 points
  4. Hi @uzeyir and welcome to the GSAP Forums! As an FYI for other users coming to this thread, I believe this was solved in our discord server with the help of @Cassie and @Dipscom as they suggested to break your SVG into transparent PNG files and animate transform properties on those instead of top/left values: https://discord.com/channels/1164468371664949249/1164482297446289449/1498596344636637285 For anyone interested here you can join our discord: https://discord.gg/KBnyXg2t2 Happy Tweening!
    2 points
  5. Just circling back here because now this is entirely possible (and simple) in GSAP 3.15.0 with easeReverse! See https://gsap.com/blog/3-15
    2 points
  6. Just circling back here because now this is entirely possible (and simple) in GSAP 3.15.0 with easeReverse! See https://gsap.com/blog/3-15
    2 points
  7. Just circling back here because now this is entirely possible (and simple) in GSAP 3.15.0 with easeReverse! See https://gsap.com/blog/3-15
    2 points
  8. 1 point
  9. You can call the refresh method in the onload callback of every image. For that you can give each image a unique id or a common class selector, then do something like this: const images = gsap.utils.toArray(".lazy-image"); images.forEach((img) => { img.onload = () => ScrollTrigger.refresh(); }); You can also call the refresh method after all the images are loaded as well instead of one by one using a counter and well all the images are loaded call the refresh method. Finally here is a simple demo, check the console to see how it works: https://ix3-test-cfe332.webflow.io/ Hopefully this helps Happy Tweening!
    1 point
  10. Thanks so much! Both for the explanation and providing the cleaned up artwork! That's a huge help.
    1 point
  11. That was it! Lazy loaded CMS images collapsing to zero height on first load. I couldn't control the height of them as client uploads. Changed them to eager and it worked! Thanks so much for your help. Could not have fixed this issue without you!!
    1 point
  12. This is very helpful @Rodrigo. I did not know you can put stagger in the .set function! Thanks a lot!
    1 point
  13. Thank you, that really helped
    1 point
  14. 1 point
  15. Hi @magnetic and welcome to the GSAP Forums! Yeah because of the way SplitText works in order to correctly split nested elements this is the expected outcome. What you could do is wrap the text before the <p> tag in an extra <div> element and just split all the children of the text container: <div id="text"> <h1><u>Neapolitan ragù</u></h1> <div class="text-content"> Neapolitan ragù (rraù in the Neapolitan language) is a ragù associated with the city of Naples, Italy, made by browning then braising meat over several hours in tomato purée and sauce. When the meat is ready, it is set aside and the sauce is left to continue cooking and thickening. In an Italian meal structure, Neapolitan ragù is served in two stages: first the majority of the sauce is served over pasta, then the meat is served alone or with vegetables, lightly dressed with the remaining sauce. </div> <p> Ragùs in general are rich, often meaty sauces that are eaten across Italy. The people of Naples hold their version in high regard, and several writers from the area describe it as the "queen of sauces". In other parts of Italy, the dish is known under names including ragù alla napoletana and ragù napoletano. Although it contains both tomato and meat, it is perceived as fundamentally a meat sauce, with the tomato as a conduit for meat flavors. </p> </div> Then just create a global array for all the lines inside of it and add them as you split each children: const textParent = document.getElementById("text"); function getLines() { const lines = []; gsap.utils.toArray(textParent.children).forEach((c) => { const s = SplitText.create(c, { type: "lines", mask: "lines", linesClass: "line++", }); lines.push(...s.lines); }); } Here is a fork of your demo: https://codepen.io/GreenSock/pen/gbLYRRQ Finally I'm afraid that we can't embed the 2.0 version of codepen in the forums, so is better to stick to the classic codepen demos for now. Hopefully this helps Happy Tweening!
    1 point
  16. Without a minimal demo, it's SUPER difficult to know what's going on, but here's a quick fork of one of our demos showing the exact path data you're trying to pass in (according to your Github issue), and it works: https://codepen.io/GreenSock/pen/ogzROrB For reference, you said the error was: That kinda makes it sound like you're trying to pass that in as the target of the tween instead of the "shape" of the morphSVG. You can't pass in a string of path data as the tween target.
    1 point
  17. Just circling back here because now this is entirely possible (and simple) in GSAP 3.15.0 with easeReverse! See https://gsap.com/blog/3-15
    1 point
  18. Just circling back here because now this is entirely possible (and simple) in GSAP 3.15.0 with easeReverse! See https://gsap.com/blog/3-15
    1 point
  19. I forgot, you can use your own notation there without the need to repeat the property like this: { x: { x: 200, ease: "power2.in" }, } It would be like this: function addTweens(timeline, target, duration, properties) { for (const p in properties) { const props = properties[p]; props[p] = props.value; delete props.value; timeline.to( target, { duration, ...props }, "<" ); } } I updated the demo in the previous post. Finally you can simplify it even further and just use an array: function addTweens(timeline, target, duration, properties) { for(let i = 0; i < properties.length; i++) { timeline.to( target, { duration, ...properties[i] }, "<" ); } } addTweens(tl, ".box", 0.75, [ { x: 100, ease: "power2.in" }, { y: 200, ease: "power2.out" }, { rotation: 360, ease: "back.out" } ]); Lots of options! Happy Tweening!
    1 point
  20. If you keep animating margin-top you're going to keep having the same problem, the solution, as I mentioned in my previous post, is not animate margin top so you don't affect document flow: Here is a fork of your demo without animating margin top: https://codepen.io/GreenSock/pen/raMRbxB If you want the blue and green sections to be visible all the time you need to wrap all three sections in a common parent and pin that parent element, something I also mentioned in a previous post: https://codepen.io/GreenSock/pen/JoRzVGX Hopefully this helps Happy Tweening!
    1 point
  21. The root cause is Metal PSO (Pipeline State Object) shader compilation, not asset loading. I hit the exact same symptom and traced it through hours of measurement. Sharing the findings in case it helps others. On macOS, Chrome's filter rendering goes through Apple's Metal API. The first time a specific combination of CSS properties (including filter: blur(...)) is rendered on a page, Metal needs to compile a Pipeline State Object (PSO) for that shader. Once compiled, it gets cached to disk, which is why the glitch disappears on reload — the PSO is already on disk. How to verify this yourself: Fully quit Chrome. Delete the Metal shader cache: rm -rf "$(getconf DARWIN_USER_CACHE_DIR)com.google.Chrome.helper/com.apple.metal"/* rm -rf "$(getconf DARWIN_USER_CACHE_DIR)com.google.Chrome/com.apple.metal"/* Relaunch Chrome and load your page — the GSAP blur glitch comes back. Reload without clearing — glitch is gone. You can also watch the cache fill up live by checking the byte counts of functions.list and libraries.list inside those directories. Each entry is 56 bytes after a 36-byte header, so (size - 36) / 56 gives the PSO count. This lets you measure exactly which CSS operations trigger new shader compilations. A non-obvious catch I also found: CSS @keyframes animations of filter and GSAP-driven filter animations compile different PSOs in Metal. So you cannot "pre-warm" a GSAP blur animation by playing a CSS @keyframes blur animation earlier — the cache isn't shared between those two render paths. This is because CSS @keyframes on filter/opacity/transform can be offloaded to the compositor thread, while GSAP writes inline style.filter on the main thread every frame, which goes through a different pipeline. Practical workaround for the first-load glitch: Play the exact GSAP filter: blur(...) tween once at load time (off-screen or at opacity: 0.01) to warm the cache before the user sees the real animation. The duration matters — blur needs about 2 seconds of real animation time for Metal to finish compiling every intermediate value; shorter durations require multiple replays. Hope this saves someone else the same debugging marathon. Happy to share more measurement details if anyone's interested.
    1 point
  22. Here you go! https://codepen.io/GreenSock/pen/YzJQGbz?editors=0010 // create let mm = gsap.matchMedia(); // add a media query. When it matches, the associated function will run mm.add("(min-width: 800px)", () => { // put all your animations in here gsap.to(...); gsap.from(...); ScrollTrigger.create({...}); return () => { // optional // custom cleanup code here (runs when it STOPS matching) }; });
    1 point
  23. Does anybody have any idea on how i can make the transition between these 2 elements as smooth as possible on both desktop and mobile, I seem to get an instant white overlay rather than a smooth change between them, Happy to play around with any suggestions that can make this work as smooth as possible
    1 point
  24. Hi Thomas, Your setup is a bit convoluted IMHO. Why two different document ready events? Then inside one of those you have a load event (most likely to check for all the images to be loaded). If your images are creating some sort of layout shift, it'd be better to just create all your GSAP and ScrollTrigger instances after that and not spread everything into three different events handlers for two events. If you want to keep a more functional approach and you want to create more than one function to create your GSAP/ScrollTrigger instances then by all means do that, no problem there. The whole point is to simplify the ready/load events handling part part. On top of that you have a ScrollTrigger instance that has once set to true, the zoom instance, but it seems that this one is being created before the previous section's ScrollTrigger. That definitely could be a source of issues. Always do your best to create your ScrollTrigger instances in the order they appear on the screen. So my advice would be to create the slider ScrollTrigger first and then the Zoom ScrollTrigger instance and a single event handler for the load event or track all your images load state in order to know when to create the ScrollTrigger instances. That will give you far better control and could solve the issue you're seeing right now. I forked your codepen and inverted the order to the document ready events and it seems to work like you expect: https://codepen.io/GreenSock/pen/qBMzaRr Although it seems to work, I wouldn't trust this approach and try to follow the advice on simplifying your current approach. Hopefully this helps. Happy Tweening!
    1 point
  25. Welcome to the forums, @sarahholden! Congrats on stepping out and posting your first question (after lurking for a while). ? From what I can tell, the browser doesn't really honor the request to event.preventDefault() on wheel events when scrolling is in-progress, at least on some devices like my Mac. Very annoying, and I'd argue wildly incorrect behavior, but don't worry - we can work around it: let preventScroll = ScrollTrigger.observe({ preventDefault: true, type: "wheel,scroll", allowClicks: true, onEnable: self => self.savedScroll = self.scrollY(), // save the scroll position onChangeY: self => self.scrollY(self.savedScroll) // refuse to scroll }); preventScroll.disable(); Basically, we have to save the scroll position and revert it every time it tries to change. Here's the revised demo: https://codepen.io/GreenSock/pen/MWGVJYL?editors=0010 Does that help?
    1 point
×
×
  • Create New...