Jump to content

akapowl last won the day on March 21

akapowl had the most liked content!


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by akapowl

  1. Hello Carl, welcome to the GSAP forum. The main problem is that your CSS is not set up to align the sections beside one another. So you'll want to have another look at the many many examples for fake-horizontal scenarios like that to see how you can get that done - e.g. using flex on your main-container and adjusting everything according to that properly, or alternatively using a display: inline/inline-block setup for your sections. Here is your demo with the main container scaled down to showcase the issue causing your troubles (scroll down a bit to see the problem). https://codepen.io/akapowl/pen/mdzQmeg You can find some examples fake-horizontal setups here... https://greensock.com/st-demos/ ... and this here is one of my demos. https://codepen.io/akapowl/pen/dyvygmj Edit: Here is a rather basic Flex-Layout for your convenience - this one might be a bit easier to wrap your head around. https://codepen.io/akapowl/pen/RweqVKm
  2. ... and even kept the original Codepen Demo as it was, so others can reenact the process of this thread and learn from your Oopsie - just wonderful! Good job!
  3. Hello there Sean. I think you just need to put the position property and z-index on the SVG itself instead of your group #seven. Does this work more like you intended? (I changed the radius of your svg circle from 80 to 75 - and added some infinite yoyo repeat to the tween; latter just for better showcasing) https://codepen.io/akapowl/pen/wvYQJXb
  4. Been there, done that ... but in hindsight it's always funny to see what naming ideas you can come up with, when you need it the least 😅 Happy to help. That'd be great for others to see. Good luck with the project 👍
  5. Hey there @grizhlie It sounds like you are actually looking for svgOrigin - there is no such thing as svgCenter, afaik. https://greensock.com/docs/v3/GSAP/CorePlugins/CSSPlugin#h3-svgorigin I'm not entirely sure why, but even if I set that to "200 200" which is supposed to be the center of your SVG, it doesn't align properly - very likely because of the transforms you have on your moon - so you might want to rework that in your SVG Editor. I do recall, that Affinity Designer v1 had an option to flatten transforms on export; so you might want to look for that option in v2, too - maybe it solves that problem for you. Apart from that, setting the svgOrigin to "180 180", appears to be working fine in your case, though. I hope this will help a bit at least. Happy rotating! https://codepen.io/akapowl/pen/mdzQWyp P.S.: You might also want to consider updating your syntax to the newer v3 syntax (e.g. with regard to durations and eases); although it is still supported, support for the old v2 syntax might get erased in a major future version of GSAP at some point.
  6. Use the position parameter as you did before, but now with the stagger parameter before the position parameter removed. https://codepen.io/akapowl/pen/xxyYQjm
  7. Hello @ninmorfeo What you are referring to as the starting parameter actually is the amount of stagger for in between starts of each element. In your converted version it should go where you now have the 1.5 - which is the actual duration of the tween, so that should go in the duration property. If the code below doesn't work for you, please provide a minimal demo that makes it clearer, what you are expecting to happen. gsap.to(chi, { duration: 1.5, x: "-=70", rotationY: 180, rotationX: -10, boxShadow: "20px 20px 15px 0px rgba(0,0,0,0.1)", ease: "power4.out", stagger: { each: 0.05 } }); Old https://codepen.io/akapowl/pen/WNaMYGG New https://codepen.io/akapowl/pen/XWxZypE
  8. Hello @maths This thread should help with achieving that effect. Please keep in mind though, that this forum is not actually intended for requests à la “How do I do this cool effect I saw on a trendy website?”. Someone here may point you in the right direction but please don't expect tutorials on how to create any effect you saw on a web site, as stated in the Forum Guidlines. Good luck and happy tweening!
  9. Hello @dagda1 horizontal: true is for settings, where you are actually using the browser's native horizontal scrolling, which is not the case here. You are only making the site appear to be scrolling horizontally by tweening the content to the side, while actually scrolling vertically. What you'll want to have a look at is the containerAnimation property, that was build for usecases exactly like yours. This is from the ScrollTrigger docs: containerAnimation Tween | Timeline - A popular effect is to create horizontally-moving sections that are tied to vertical scrolling but since that horizontal movement isn't a native scroll, a regular ScrollTrigger can't know when, for example, an element comes into view horizontally, so you must tell ScrollTrigger to monitor the container's [horizontal] animation to know when to trigger, like containerAnimation: yourTween. See a demo here and more information here. Caveats: the container's animation must use a linear ease ( ease: "none"). Also, pinning and snapping aren't available on containerAnimation-based ScrollTriggers. You should avoid animating the trigger element horizontally or if you do, just offset the start/end values according to how far you're animating the trigger.
  10. Hello Maya. If you have access to a custom CSS file it might be enough to just set the transition on elements you don't want to have transitions applied to back to their default value, via using initial. https://www.w3schools.com/cssref/css3_pr_transition.php If that doesn't work for you, try specifically setting the transition-property to none and transition-duration and transition-delay to 0 or 0s. If that still won't work, as a last resort (although not really recommended) you can do all of the above with !important added at the end. And if you don't want to target every element individually, you can use the wildcard selector * instead. If you don't have access to any custom CSS file, or none of the above works for you, you're likely better of asking the people who built Elementor about this. This should at least give you some basic ideas, though. https://codepen.io/akapowl/pen/JjmrMNy
  11. I'm glad, it helps Not silly at all - the concept is a bit rough to wrap your head around, if you don't think about it too much. If I am not totally mistaken, the calculation leading to the 6.5 seconds would be as follows. The only part we'll have a look at for now is the tween(s) for the tick-mark, because the tween(s) for the headlines don't have an effect on the timeline's total duration the way they are timed and positioned on the timeline. So; the duration for a line to scale from the initial 0.2 to 1 is 1 second. Each onel starts 0.25 seconds after the one before has started, so we need to take into account 18 lines that start later and multiply that number by the time each one starts later than the one before it does. Then we also have 1 more second to take into account for them to go back to their initial state again. 2 × 1s = 2s 18 × 0.25s = 4.5s ------------------ 2s + 4.5s = 6.5s Try picturing it something like this (although it might not be 100% accurate as I think I slightly messed up the spacing) - for me that makes it easier: ------------ 1st tick-mark in ------------ 2nd tick-mark in ------------ 3rd tick-mark in ------------ 4th tick-mark in ------------ 5th tick-mark in ------------ 6th tick-mark in ------------ 7th tick-mark in ------------ 8th tick-mark in ------------ 9th tick-mark in ------------ 10th tick-mark in ------------ 11th tick-mark in ------------ 12th tick-mark in ------------ 13th tick-mark in ------------ 14th tick-mark in ------------ 15th tick-mark in ------------ 16th tick-mark in ------------ 17th tick-mark in ------------ 18th tick-mark in ------------ 19th tick-mark in ------------ 1st tick-mark out ------------ 2nd tick-mark out ------------ 3rd tick-mark out ------------ 4th tick-mark out ------------ 5th tick-mark out ------------ 6th tick-mark out ------------ 7th tick-mark out ------------ 8th tick-mark out ------------ 9th tick-mark out ------------ 10th tick-mark out ------------ 11th tick-mark out ------------ 12th tick-mark out ------------ 13th tick-mark out ------------ 14th tick-mark out ------------ 15th tick-mark out ------------ 16th tick-mark out ------------ 17th tick-mark out ------------ 18th tick-mark out ------------ 19th tick-mark out | | v |-----------|-----------|-----------|-----------|-----------|-----------|-----------|------ 0 1 2 3 4 5 6 7 With 'keep in sync' I meant to keep the value in all lines that have that value equal across those lines. You can change that value, but if you do, change it everywhere that value is used - to properly keep both parts of the timeline in sync so to say. If any of those deviated from the others having that value, the highlighted headline wouldn't match the longest line anymore, so to say. Also worth mentioning, that the value should probably not be bigger than the duration value of the tick-mark tween(s) as that would cause the position of the headline tween() on the timeline to become negative, and that might technically lead to problems - and of course it looks a bit odd. Does that make sense to you? This way you can change the 'spread' width of the curve (if that makes sense). A rather low value in those places (and thus a rather high position parameter) would result in a visually wider spread of 'active' lines... https://codepen.io/akapowl/pen/rNqmqba ...while a rather high value in those places (and thus a rather low position parameter) would result in a 'narrower curve'. https://codepen.io/akapowl/pen/abRWRRv And since I mentioned it in the comments, too, changing the ease of the tick-mark tween(s) would result in different 'shapes of the curve formed' by the lines. The examples above all use .in eases, so their curvature is bound inwards - changing that to .out or .inOut would result in an outward bound curvature (of different degrees between .in and .inOut). [ease: 'none' would probably just form the outline of a straight triangle 🤔] https://codepen.io/akapowl/pen/mdzmaVZ https://codepen.io/akapowl/pen/ExdmGaQ By changing the base-type of the ease you can change the appearance of the distribution curve even further to achieve some really 'special' effects. Not that it will be helpful or you might want it for this specific scenario - but for different setups it might be somewhat useful maybe. https://codepen.io/akapowl/pen/ExdmGKE
  12. Hello there @cobragtk - welcome to the GSAP forum. You likely could use the distribute utility, but I think you can also get the effect you are after with staggers just fine - in the end it'll probably boil down to what you are more comfortable with. Especially when it comes to adding in ScrollTrigger, I guess you will have even more options for how to approach this. Depending on where exactly you want to go with this in the end, some might be easier to implement/understand and/or make more sense to use, than others. The general idea of what you tried in your pen with regard to GSAP alone, looks great already, but with the initial setup you have it does logically not work, because GSAP will tween the lines from where they started to the full scale and then back to where they started, which is exactly what is happening. Since some of them started with a bigger initial scale than others, that's where your problem originates. One of the many great things about GSAP is, that it can practically tween on any object with properties that have numeric values. [See: "Any numeric value, color, or complex string containing numbers" in the Getting Started article] Since GSAP tweens and timelines are objects too, and they have properties with numeric values, to a certain degree that also includes them. [See: "Tween the progress() and timeScale() of an animation" in this Learning Center article] Now because calculating the progress of the timeline (as is a mentionin that second article linked) from and to when/where you'd want to have things animate could become a bit tricky, instead you could e.g. tween on the time of the timeline directly. With this approach that I'm going to use in the example below, I would suggest not setting the initial scales for each of your starting elements manually, but instead let GSAP handle that for you which will get rid of that logic problem you ran into. Since I'm going to use a fromTo tween, the initial setting will probably not be neccessary, but I still wanted to mention it as it can be handy on its own. Because you have your timeline set to paused anyway, you can now set the initial time of the timeline after its creation - you know how long it takes for 1 line to completely fill up, and that is exactly the time you want to set it to, because you want the first line to appear filled initially. Careful; in my demos below I set the duration to 1 - in your example the duration is the default of 0.5 as you did not specify it. const tl = gsap.timeline({ paused: true }) tl.to('.tick-mark', {...}) tl.time(1); Now that was easy enough, but you probably also want to end the animation in a state where the last line will stay at full width, right? For that, as mentioned above, you can create a new independent tween, that tweens the time of the timeline from that initial set time to the whole timeline's duration minus that amount it takes for one line to fill up - with an ease of 'none' as we're going to add the ScrollTrigger to this tween instead of the timeline itself now, and we want the tween to be scrubbed visually in sync with the scroll-position. gsap.fromTo(tl, { time: 1 }, { time: tl.duration() - 1, // tl.duration() - duration tick-mark ease: 'none', scrollTrigger: { trigger: "#wrapper", start: `top 50%`, end: `+=70%`, scrub: true, markers: true, }, } ) This should get you where you wanted with the part of the lines scaling up and down on scroll. https://codepen.io/akapowl/pen/JjmNMyw For the headlines to become animated/highlighted too, just add another tween to the timeline, making use of the position parameter to start it at the same time as the other tween and allow them to be synced. This example uses the same values for the tween on the headlines, as are used for the tween on the lines. https://codepen.io/akapowl/pen/vYVmJjE The tricky bit here is to get the timing right. I found that this final solution works well with a decent tween on the headline opacity... https://codepen.io/akapowl/pen/XWxRVOy ... but especially with an ease of steps(1) for if you just want to toggle between different opacity-values of the headlines. https://codepen.io/akapowl/pen/LYgyzzN I'd suggest, after digesting all this, start playing around with the values and see what they do when changing them. I added a few comments in the the last two examples posted, to try and pinpoint what's important there. I hope this will help. Happy tweening!
  13. As I said; left and right work with horizontal: true OR ... Now if it is speicfically an issue with the gsap-bonus.tgz file you are having; maybe you could just upload a very minimal and as much as possible stripped down .zip-file of your project in a post of yours. Edit: Coming to think of it again, that probably isn't a good idea, since users of the free tier would be able to download it. Anyways, I think that would be something, one of the Admins would have to have a look at then.
  14. Sorry, but I don't have the time to create a Nuxt project right now for testing this; if you need any assistance, please provide a minimal demo. If you're using something like Nuxt, you could use StackBlitz for example. There is a series of collections with different templates for you to get started on these different frameworks: React/Next/Vue/Nuxt. Which version are you speaking of; my code using the containerAnimation feature or your code from the initial example? Because if it is your initial code example you are referring to, that won't work by simply just setting the start to using 'left somewhere' as its value. Using singular parameters like that is invalid, btw - ScrollTrigger's start and end always need two parameters in their string-syntax; one for the trigger-element and one for the viewport. Also,left and right will only fulfill their purpose in either native-horizontal scrolling with horizontal: true set on the ScrollTrigger or in ScrollTriggers with the containerAnimation property set. So I'm rather confused - and I can't be much more helpful than that without a minimal demo of some sorts.
  15. That is exactly what containerAnimation is built for. If after seeing the example I added below, you're still interested in getting this done without containerAnimation at any cost, here's an older post of mine, explaining the issue you are facing, and how to handle it. Yeah, I think you might be overcomplicating things a bit - it's actually quite a bit easier than you might think. Here's how I would set it up with containerAnimation - that looks a decent bit less complex than what you had before; and it works. You'd just need to adjust the start and end of the individual ScrollTriggers to your liking. And one more change I would suggest making, is not animating the element that you are using as the trigger-element; that is bound to cause issues. Instead you could/should probably wrap that element and use that wrapping element as the trigger. I hope this will help, though. https://codepen.io/akapowl/pen/WNaGzZE
  16. Hello there, Simon. containerAnimation is very likely the feature you are looking for. It is built to make what (from my understanding) you are trying to achieve a whole lot easier. Give it a shot and let us know if you run into any issues along the way. This right here is from the ScrollTrigger docs: containerAnimation Tween | Timeline - A popular effect is to create horizontally-moving sections that are tied to vertical scrolling but since that horizontal movement isn't a native scroll, a regular ScrollTrigger can't know when, for example, an element comes into view horizontally, so you must tell ScrollTrigger to monitor the container's [horizontal] animation to know when to trigger, like containerAnimation: yourTween. See a demo here and more information here. Caveats: the container's animation must use a linear ease ( ease: "none"). Also, pinning and snapping aren't available on containerAnimation-based ScrollTriggers. You should avoid animating the trigger element horizontally or if you do, just offset the start/end values according to how far you're animating the trigger.
  17. Hello there, Nora. containerAnimation is very likely the feature you are looking for. Give it a shot and let us know if you run into any issues along the way. This right here is from the ScrollTrigger docs: containerAnimation Tween | Timeline - A popular effect is to create horizontally-moving sections that are tied to vertical scrolling but since that horizontal movement isn't a native scroll, a regular ScrollTrigger can't know when, for example, an element comes into view horizontally, so you must tell ScrollTrigger to monitor the container's [horizontal] animation to know when to trigger, like containerAnimation: yourTween. See a demo here and more information here. Caveats: the container's animation must use a linear ease ( ease: "none"). Also, pinning and snapping aren't available on containerAnimation-based ScrollTriggers. You should avoid animating the trigger element horizontally or if you do, just offset the start/end values according to how far you're animating the trigger.
  18. Hello @moonunit7 When you are using a number value for the scrub, like you are doing in your codesandbox, it will take that amount of time for the animation to catch up to the scroll-bar/-position. So there is a time window, where the next animation might logically very well be triggered in that amount of time; before the last animation has caught up to the scroll-position - see the problem? When you set scrub to true (or apparently to 0 as you tried) instead, scroll and tween will be pretty much synced, so there won't be the chance of the above happening. You should be able to fix that behaviour you are experiencing by either changing your setup to use one large timeline handling all the tweens instead of using multiple individual timelines like you do now - or alternatively keep your setup as it is, use scrub: true on your ScrollTriggers and switch to a smooth-scrolling implementation like ScrollSmoother to smoothen out the scroll. This thread should have all the information you need. I hope it will help.
  19. Welcome to the forum @Danoz2411 If you want to make the indicators clickable, you'll first need to make them accessible for mouse events, because now, albeit not visually, they are burried below other elements - in the example below I put a high z-index on their parent element, to change that. Since you are super new to this, for adding functionality on click via JS, you'll want to read up on the click event... https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event ...and getting familiar with loops will probably come in handy for this, too; e.g. the forEach loop. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach ScrollTrigger does have a .labelToScroll() method (since version 3.9.0 - so you'll need to update the GSAP and ST versions, as I did in my demo below) that makes it easy to get the scroll-position of a label placed on a timeline that is hooked up to a ScrollTrigger. For the actual auto-scrolling part you could combine all of the mentioned above with GreenSock's ScrollToPlugin, meaning; when looping over all the points and adding the tweens to the timeline, at an appropriate point, add a unique label to the timeline(e.g. by using the index as an identifier) loop over all the indicators and forEach of the indicators add a click event in the function that is triggered by that event add a tween that leverages the ScrollToPlugin to scrollTo the respective labelToScroll (e.g. by using the index as an identifier) That could look something like this, then: https://codepen.io/akapowl/pen/OJBMrYP Now, with a bit of experience this was easy enough to do and short enough to explain - but for future questions, it would be great, if you could show us something you have tried yourself on that you are struggling and need help/clarification with, because this forum is not actually intended to provide full on solutions/explanations for any given effect/functionality from scratch. Nonetheless, I hope this will help you get a clearer picture. Happy tweening!
  20. Hello @eli-ott, I think that is more of a three.js question than it is a GSAP one. I'm far from being an expert with three.js, but from what I understand, any of the values related to the geometry of an object (width, height, depth, and their respective segment-counts) can not simply be updated on the fly and those updated values expected to be visually reflected by three.js. That's why for changing dimensions, you'd typically go with changing the scale (.x .y or .z) instead of the geometry itself (width, height, depth, ...). For changing the geometry itself, you'd need to set up a new geometry for your object, (dispose the old geometry) and then set the object's geometry to the new geometry, instead. Here's a StackOverflow Post I found on that topic: https://stackoverflow.com/questions/8392754/how-to-change-width-of-cubegeometry-with-three-js And here's a codepen changing the geometry on scroll with ScrollTrigger in an onUpdate callback of the timeline - I hope that will help. Sidenote: I added a second geometry (mesh) just for visualization reasons - of course if you don't need that, you won't have to add extra geometry. https://codepen.io/akapowl/pen/WNavmpB
  21. Judging from the explanation in the quickTo() docs, I personally would think so. Think of a quickTo() like an optimized function tied to one particular numeric property ... If you wanted to make use of percentage-values like in your code-snippet example though, you would have to make sure you'd convert the absolute coordinates you'd get from any of the mousemove event properties to percentage values first, anyway. You could e.g. make use of gsap.utils.mapRange() for that part. Then for quickTo-ing the clipPath, you could make use of CSS-Variables instead of trying to quickTo the full clip-path value. While the latter does not appear to work (although I for sure might be missing something) ... https://codepen.io/akapowl/pen/rNqVjqw https://codepen.io/akapowl/pen/zYmGNad ... using CSS-Variables works like a charm. I hope that will be helpful. Happy tweening! Edit: Here's an extra codepen making use of absolute values instead of percentages - which is just a bit shorter and simpler. https://codepen.io/akapowl/pen/bGmdgrP
  22. Hello @sawacrow You have a bunch of .fromTo() tweens on that timeline, targetting the same properties of the same element, so you might want to have a look at immediateRender. I set it to false as a default for every tween of your timeline, and it looks way better that way. Alternatively, what you could also do, is to set the timeline to paused initially, and then after you have created it set its progress to 1, then back to 0 and then play it, but that is more of a warkaround, and I would suggest getting familiar with the immediateRender property instead, as it wil come in very handy in lots of scenarios like this. Hope that will clear things up a bit. Happy tweening. https://codepen.io/akapowl/pen/gOdJJGb Edit: I only just now saw, you edited your post with another question. With regard to that second question, @Carl's tutorial on staggered staggers and especially the 'follow up' on seemles looping might be of interest for you. For a more in depth dive into GSAP basics, tips and tricks, consider checking out his full courses - he's a great teacher and those are invaluable ressources. https://www.creativecodingclub.com/bundles/creative-coding-club https://www.snorkl.tv/staggered-staggers-for-enter-and-leave-animation-sequences-gsap-3/ https://www.snorkl.tv/greensock-staggers-with-seamless-loops/
  23. Sure you can. But getting that setup right has nothing to do with GSAP - it's just CSS styling. This right here is the second result of a google search for '3d perspective div with text'. https://3dtransforms.desandro.com/perspective https://codepen.io/akapowl/pen/PodvVGo Edit: When you're going to animate it with GSAP, it will be best to set the perspective on the parent element. Click anywhere in the pen to run the animation. https://codepen.io/akapowl/pen/GRXazdJ And if you want to animate the box and text individually, you will probably be best to not have them nested, e.g. like so. Still, those are mostly CSS related things to consider. I hope that will help. https://codepen.io/akapowl/pen/dyqEaWr
  24. Hello Pedro, your thought process with regard to that has a couple of issues. But before I start explaining, let me first mention, that your html element for some reason has a height difference of about 16px in comparison to the body element - I'm not quite sure why exactly that is the case, but it leaves a blank space at the bottom of that amount when the pinning is done, and seems to be to be a CSS styling issue related to your .sidebars__list element. To ommit that, I set the font-size of that element to 0px in CSS in my fork of your example, and instead set a fixed font-size of 16px to the .vertical-bar element. This feels more like a workaround for me though, so that is something you might want to look into. The first issue I see with regard to your animations, is that you are trying to use xPercent as the property to be tweened on for your scrollTween - that won't work because your individual panels all have different widths. That fake-horizontal-scrolling technique using xPercent will only work when each of your panels has the same exact width of 100vw. If you want to have different widths for your panels, you would have to tween on the x instead, and calculate things depending on your needs. This in your case can become tricky because of how that example of yours is set up - depending where exactly you want things to end e.g. you will have to incorporate a multiple of the width of your .vertical-bar elements into your calculations (and on top of that the padding-left on your .container - unless you set your elements' box-sizing to border-box). Additionaly for the calculations (mostly for those coming up) to be precise, you would have to incorporate the width of the browser's scrollbar because of how things are set up (and probably also need to be set up for this to work). This is the case, because while your vertical bars are positioned fixed so they align with their right side flush against the browser's scrollbar, everything else is dependent on 100vw or window.innerWidth, which both also include the space below the scrollbar in their value. That's why you will see a lot of 15 added or substracted throughout my example, because that's a value that worked fine for my browser with that regard - with different browser's that value might change though, and getting it right throughout all of them can become quite a pain. Same goes for the ScrollTrigger for your vertical bars - you will need to calculate where exactly to tween them to, when the start of that tween should happen and where it should end; including all things already mentioned in those calculations. The biggest issue I see in your thought process with ragard to that ScrollTrigger for the vertical bars, is that you want to use the vertical bar as the element to be animated and the trigger element for that animation - that won't work like you might expect because those vertical bars will not move at all, as your scrollTween is not referencing them in any way - it is the horizontal panels that are moving. If you want the bars to move in sync with their respective panel, you should use the respective panel as the trigger element for each bar. As you can see in the example below, everywhere dynamic values are needed, I make use of function-based values, so ScrollTrigger can get the correct value again when the window gets resized. For start and end of a ScrollTrigger that will work out of the box - for values used for properties of the tween to be invalidated on refresh, too, you will also need to add invalidateOnRefresh: true to the ScrollTrigger. If I got the description of what you wanted to achieve right, this fork of your example should resemble a setup that would work in a scenario as such. Although it is quite a bit more complex than you initially thought it might be, I hope this will help clear some things up. You can read all about the properties mentioned above in the Scrolltrigger docs and general docs for GSAP. I hope this will help. Happy tweening and scroll responsibly! https://codepen.io/akapowl/pen/xxaNyoe
  25. Hello @agsymonds I set to my example above to public, so you should be able to fork it now and tinker with it. In general, I really think that is more of a CSS styling question, than it has to do with GSAP. As you can see in this example below, GSAP does its job of splitting into chars just fine, when you remove the -webkit-text-fill-color: transparent; on the .span-gradient. https://codepen.io/akapowl/pen/XWPwaXK Albeit doing some quick searches, I'm not sure, if there is an easy way to apply a continuous gradient to multiple individual elements, which you would need in a scenario where you were to split by chars. So I went ahead and fiddled together a quick and dirty forEach loop that sets the backgroundSize of each character in the .span-gradient to the width of the whole span element, and offsets each character's backgroundPosition depending on the width of the characters that come before it. For that, in CSS, the gradient is now applied to each element inside the span, instead of the span itself. This should give you an idea for how to possibly approach it, if nobody else knows of an easier way to get that result - I'd be curious myself if there is. I hope that will be somewhat helpful though. Happy tweening! https://codepen.io/akapowl/pen/jOvombV