Jump to content
Search Community

Chromium

Members
  • Posts

    74
  • Joined

  • Last visited

Everything posted by Chromium

  1. I'd give you the benefit of the doubt @Cassie but my complaint is a bit more broad, it isn't directed at just one instance. I elaborate more on my experience on this forum in my last response. That should give you a better picture of what I'm describing, you might have missed it because you posted your response at the same time as mine. EDIT: To be clear, I do think it's very likely that you guys don't intend to insult/shame anyone, but it comes off that way sometimes, and that just makes it all the more sad. Because I guarantee you that if I'm left feeling that way after most of our interactions, a lot of people posting on your forums probably feel the same way. Because I'm not an odd case, I don't feel this way about most other places where I seek support. EDIT2: Even in your last response, this is a bit dismissive to my concerns. Especially after this in my previous response: Again, I'm not hating on anyone on here, I love you guys. This is just a bit of tough love from me. I know you're trying your best, thanks for all your hard work! And I know that that is not how you see it from your perspective, but that is exactly why I'm sharing another perspective with you guys.
  2. I'm sorry for a 2nd response on this, but it's left a bitter taste in my mouth about this whole experience. I'mma be real with you guys for a bit. This response AFTER a solution was reached, is just unnecessary. Like what would insulting/shaming anyone/everyone who's worked on reaching a solution achieve after the fact? Is it really worth it? And I'm not blaming you Cassie, I'm pretty sure, you're instructed to do this, I mean after all, you've got a whole page dedicated to it. The only reason I'm commenting on this, is because you guys have done the exact same thing to me a year or 2 ago, which means somebody has to let you guys know about it. Even in this very thread, I've found myself having to constantly defend myself nearly every response and it's really mentally exhausting, EVEN IF you guys don't intentionally do it. Like I don't need you guys to let me know every other response that my question, topic, response, logic, etc is incoherently formatted and dumb. Like I know it is, but that's the whole point of a support forum, isn't it? To ask the dumb questions? Like you guys gotta be on the same page with me on this, because just putting yourself out there and posting something on the support forum at the risk of sounding dumb already takes a huge amount of courage without the constant shaming or somebody calling your logic flawed, incoherent, lacking, overly-complicated, and the list goes on. And please don't underestimate the weight of my complaint here. And don't reduce my examples above to just the specific synonyms I've given there, because off the top of my head at least 3 other instances in this very thread alone come to mind. And no, they don't come from Cassie. But I'm not going to name names or quote quotes. Please understand that if I didn't love your library, I simply wouldn't care to share this feedback with you guys, I'd simply just avoid using your support forum at the cost of heavily reducing my usage/reliance on your library. Unless I'm not using your support forum for what it is intended for, then in that case, ignore my entire complaint.
  3. Hahaha yes that was it! I know how to 'fork', but your CodePen had no 'fork' button to press or I would have, so I had to manually copy paste the code then copy the settings/scripts from your CodePen. This is also one of my biggest pet peeves with your guys' CodePens, they're so helpful and make it extremely easy to replicate/debug, but half of your shared CodePens have no 'fork' button for some reason which defeats the entire purpose in my opinion. I'm not familiar with keyframes in tweens, so today I definitely learned something (and I might just go on an abusive streak with this, and it's all your fault)! Thanks Your solution is exactly what I'm trying to achieve!! And in hindsight, it seems so simple now that my motionPath solution becomes overly complex/trivial for what I needed... in fact, I'm now confused as to when I'd ever use a motionPath lol I'm sorry, but if this is directed at me, then I think you're wrong. Perhaps this is intended for your team internally? Because this is just not true in this case, here's a quote of exactly what I typed in my very first post here: And here's, literally, the very first 3 lines in my next reply: Never did anyone at any point make a suggestion of "Oh hey, if you just want to add a cuve on the X-axis with a FLIP, have you tried this...?". I'm sorry if this seems harsh, but your criticism, if directed at me, seems quite harsh, so I'm forced to defend myself. Again, if your criticism is directed at me, then it sounds like to me that you're saying that I provided more information than necessary in my initial post? If so, in my entire years of debugging code/logic problems, I was taught that this is a good problem to have, you guys would be the first to say otherwise. Additionally, the very first response to that, deviated into something about FLIP.fit() which I thought was very unrelated to what I was seeking. Up until your response, at no point ever, was a question posed or a suggestion made with something along the lines of "did you just want to add a curve to a FLIP animation?". Boy oh boy tell me about it, it sent me down a rabbit hole that I didn't need to go down to. Though it's not entirely alone at fault for this, it's something I've always struggled with in GSAP and I don't know how you guys deal with it given how frequently you probably use GSAP; sometimes you get laser focused on solving something one way you simply can't find another way... even worse (and this may very well just be a me problem but it happens a LOT), sometimes when the code is not flowing synchronously, you just can't wrap your head around it, let alone come up with an asynchronous solution like the one you just came up with. Like in this instance, in my head, the FLIP animation is just DONE, after the FLIP animation is done, there's no tweaking its animation asynchronously lol Sorry Rodrigo, but I think Cassie has earned the solution badge on this one! Haha
  4. Thanks for sharing that Cassie! It's amazing to see that such flexibility is a feature! Unfortunately though, it seems that's not applicable to my case because my X is not changing by default like in your animation. I cloned your example to this CodePen: https://codepen.io/fuad-zeyad-tareq/pen/wvZEPRx In the CodePen, I simply removed the left/right properties in .box.fixed to demonstrate something very close to my current FLIP animation. However, and this is why I don't do CodePens, god forbid I clone an already working CodePen and try to make that work, it's giving me a blank screen with no console errors or anything!!! GAH, I just don't have the patience nor the time for this. In any case, like I said, if I take out the left/right properties from your .box.fixed, which makes the FLIP into a simple Y animation... but I still want to add an X-curve to that, that simply seems not possible at the moment. Does that make sense? So let's say the animation goes from (0, 0) to (0, 500) currently, I don't need the X to be different at the start or finish, but I do want it to curve during the FLIP animation. Perhaps your solution to this would be to temporarily change the X value during the FLIP animation? If so, this is where I was stumped, because it's hard to wrap my head around that. I'm comfortable with supplying a initial X, Y and final X, Y so I wouldn't know how to add an intermediary X, Y (or just X) to a FLIP animation. And the motionPath seemed to somewhat fit the bill for that, at least in my head.
  5. Yes, I kind of figured that that would be your response. And that's fine. That is why my entire post is an idea/request for consideration. So regardless of any other issues that you mention, at the end of the day, I kind of have to say, yes but please consider allowing my request to work! Haha As my last attempt to summarize my request in a clear and concise manner, I will use a real-life analogy to more correctly convey my thought process of how FLIP/MotionPath integration would work: I take a taxi to go from Point A to point B (that is the FLIP animation). I don't know how to get there myself, so I tell the driver to get me there however it takes but let's take a scenery detour, or pass by Walmart on the way there, etc (that is the motionPath). My job is to deliver my use case/idea in a cohesive and understandable manner... which I hope I have now delivered, even if it wasn't in the most efficient of ways. Your job is to make that 4% into a 140% or discard my idea altogether if it is invalid. It sounds to me like you're leaning towards the latter for now, and that's fine, sad, but fine, you're the expert! But that won't stop me from pretending that my idea is praised as revolutionary in an alternate dimension! Lol Thanks for your time! Great job on keeping the plugin smooth and performant!
  6. I'm definitely missing your point. Because it seems that, when I'm giving you a definite use case where this WORKS, you're focusing on the ones that don't... and I don't get why you are. Additionally, it seems you're asking me to debug every other use case that I'm not asking for... and since I don't work at GSAP, this seems hardly a fair request lol I'm not asking you to make every use case work, just to allow mine to work? It should be irrelevant whether 98/99 use cases won't work if we can have the flexibility to allow 1 more use case to work seamlessly without any additional overload, KB, performance, etc. And yes, I say without any additional anything because all the data needed to get my use case to work is already there! FLIP already saves the initial state (X, Y, height, width) and I'm simply saying to make that available to motionPath as well when used in a FLIP... that's literally it. That would immediately allow my use case to work. Granted, I do think that there's room to do a lot more but for the sake of simplicity, let's say that's all that is needed. What is the issue in allowing this?
  7. Man, this seemed extremely simple of a request in my head... but things like this never are simple, are they? Good question, I mean the specifics of how this will function can be planned later on when you guys decide to implement this... but if I had to chime in now on this specific scenario, I'd say there are more than one option: 1) This will do nothing. Because a motionPath in the context of a FLIP, serves only to overwrite an existing animation... so if a Y animation isn't part of the FLIP, then the motionPath will do nothing. OR 2) If it's used in the same way I used my motionPath, it adds a little detour/curve, but the starting point and ending point is still the same. And I love that about FLIP. To give a helpful analogy like @Rodrigo did earlier, I love the fact that I can just let FLIP take the wheel and take me to my destination. But that doesn't mean I don't want to, as the passenger, ask FLIP to sometimes take a different path than the one it chooses long as the path leads to the same destination. I hope this clarifies my request/idea.
  8. Not seamlessly, motionPath should simply override the FLIP animation's calculations in this case. I'm saying any time motionPath is specified on a FLIP animation, it means I'd like to override whatever that part of the FLIP animation is. So if all the FLIP animation is doing is animating the X value like you're saying, then motionPath now takes precedence, period. On the other hand, if the FLIP is animating multiple properties such as the X, scale, Y, etc among other things, motionPath simply overrides the X animation part of the FLIP. Thank you for giving a clear example in simple terms. I hope the above clarifies what I meant... sorry if I didn't make it clearer before, but I've been trying to say that motionPath simply should take priority over whatever is animating.
  9. I appreciate your detailed response and that is why I marked it as a solution. I fully appreciate the performance and KB side of the equation, and if there is no way to deliver what I am asking without sacrificing on that, then you have me there. That being said, I do think that there are ways to go about delivering what I am seeking without sacrificing any performance or KB, simply put, I am asking for an optional setting on the FLIP animation that only people like me would choose to enable... so it should have no impact on the performance or KB when that option is not enabled? Essentially, the bottomline of my disagreement is here. I don't see it how you see it, I see motionPath as more of a utility whose sole purpose is to edit the animation path of an existing animation... whether that's a tween, FLIP, or a penguin walking down the street. Now if that is not at all the intention of the motionPath plugin and I have misunderstood it, then I rest my case and I forgo my argument haha. But if that is the purpose of a motionPath, then in my opinion, it is not doing its job well when it comes to a FLIP animation, that's it. It seems like a matter of perspective to me, I understand motionPath as a utility that should work with all tweens/plugins/animations, you see it as a separate plugin that shouldn't synergize with a FLIP animation.
  10. So if I understand correctly, you're saying that there's no confusion that the user wants full/partial control over the FLIP animation, but it's just impossible to give the user any control over the FLIP animation using motionPathbecause CSS doesn't allow it? I guess why I'm still struggling to understand this is because I feel like what I'm asking for is still a JS problem. Why can't your FLIP plugin recognize that motionPath is specified and override any of its styles with the given styles from the motionPath? There should be no fight/race here for control as when motionPath is specified, it's always given priority, as to me it seems obvious that the user wants to override something in that case. And since all of these settings are specified prior to any animation occurring, then the setup above can be adjusted on the JS side prior to any CSS being injected?
  11. Hmm let me try one more crack at posing my question more clearly. 1. My FLIP animation works perfectly fine on its own... it's just animating the Y value of an element (after the element is moved from one parent to another). I wanted to add some pizzazz to this vertical FLIP animation... a curve on the X-axis came to mind. 2. I used motionPath on the FLIP animation to add an X-axis curve. Keep in mind the starting X and ending X value for the FLIP animation is 0. 3. I did get this working in the end like I said. So I don't have any CodePen to share. But it did feel like it was more effort to get it working than it should have been, so I wanted to share feedback on my experience with you guys... because I can only assume my usage to be another niche case scenario, haha. But I got it to work! Haha. The only thing I had to fight with to achieve this (which made it very un-intuitive) is that the motionPath was receiving the final state of the FLIP animation instead of the initial state/positioning of elements. Let me try to explain this with an example: If I'm moving an element in the DOM and use FLIP to animate that, I'd: 1) Get the initial state of the element. 2) Do the append. 3) Run the FLIP animation. Right? Now let me ask you a question, if I ran motionPath inside that FLIP animation, what do you think it gets as its X/Y positioning of said element? Would it be the X/Y positioning after the append or before the append? Currently, it's after. The intuitive behaviour here is that it should get the X/Y positioning of the element before it was appended; in other words, what was recorded in the initial state of the FLIP animation. If this is still unclear, what I mean by X/Y positioning before and after, is that before the element is moved, when it is under say parent 1, the X/Y positioning will be completely different than when the element is later moved to parent 2. When the element is under parent 1, I consider this the initial state (before the FLIP animation is executed) in my example. I understand that this might be the current implementation... but this is the essence of my post, is that they should be made more synergistic with each other. I like that the FLIP handles the X/Y/width/height for me to achieve the cool automatic animations it does on its own... but what if: 1) I like 75% of its animation or wanted to add an additional animation to it? 2) What if I didn't fully like the path it takes and/or wanted to add a horizontal curving to its vertical animation (my scenario)? Unless there's a better way/tool to achieve what I did here, then I see no reason why the 2 plugins shouldn't gel well with each other in the future. In fact, even if there was another way/tool to achieve what I'm after; whether it's with regular tweens or other plugins, I feel like having more than one way to achieve the same thing is a net benefit to GSAP, so I still think the synergy between the two plugins is worth improving on. I hope all of this somewhat makes sense? If not, then don't worry about it haha. I've solved my problem after all so I will be okay. I just hoped to make this process a little easier for others (including myself) in the future if motionPath was a bit more seamless/intuitively integrated with FLIP.
  12. I love the FLIP plugin and I love the fact that we can use the motionPath plugin inside of a FLIP animation inside of a timeline!!! The flexibility is awesome! Today was my first time using your motionPath plugin... and it was for doing this: t1.add(Flip.from(state, { duration: .3, ease: 'power1.inOut', absolute: true, targets: _npClone[0], // Using motion path plugin to create a subtle arc. motionPath: curveMotionPath(pos, 0) }), 0); If we comment out the motionPath: curveMotionPath(pos, 0), this FLIP animation works perfectly, believe me. I've slowed down the animation to a crawl and it gets from point A to B with 0 problems. I've even console logged the position.top() of point A and point B to ensure that was the case. Heck, I even highlighted the starting and ending points of said animation by inserting a position: absolute div on the page to ensure they were correct. So I wanted to add some pizzazz to this FLIP animation and ChatGPT suggested to use motionPath to add a nice little curve to the animation to make it a bit more realistic... I thought, this sounds fantastic! Seems simple as well, almost like adding a border to a div... boy was I wrong. I ended up spending the better part of a day to get this working! This is the content of curveMotionPath: curveMotionPath: function(startY, endY, maxDeviationX = 30) { let y1 = startY + (endY - startY) / 4, y2 = startY + 3 * (endY - startY) / 4, deviationX = -Math.min(Math.abs(endY - startY) / 2, maxDeviationX); return { path: [ {x: 0, y: startY}, {x: deviationX, y: y1}, {x: deviationX, y: y2}, {x: 0, y: endY} ], type: 'cubic', curviness: 2, //align: 'self' }; } I did not even want to modify the starting or finishing positions, surely this is easy to do, I thought it was gonna be a plug and play. Alas, imagine my surprise, when adding the motionPath into that already working animation, broke the starting position of the animating element! I gave it the correct startY, the correct endY, the FLIP animation already had the correct start and ending positions... I thought how could I have possibly screwed this up? And yes I tried the magical keyword align: 'self' or aligning to specific DOM elements. When I added align: 'self', that seemed to fix the startY but then the endY became incorrect. Fun fact: this was the main reason I was able to understand what was happening below as it posed the question in my head... if align: 'self' fixed the startY, what was it aligning to before? Well after hours of debugging, it finally occurred to me... the motionPath was NOT using the initial state of the FLIP animation like the FLIP was, it was using the final state of the DOM. Once I made that revelation, it was rather easy to come up with a solution... mind you, I said easy, but not intuitive. I can't possibly imagine this was intentional by design? I might be wrong, but I feel like this may have been overlooked due to how niche of a use-case this is... as my search results on the topic yielded nada. I feel like the default and intuitive behaviour in this case should be to use the FLIP animation's initial state and not final state. In my head, it makes the most sense that the animation is from initial state to final state, so if I'm changing the path of said animation, I expect to be accessing x and y of initial state as the start of the motionPath, and the end is the final state of said motionPath. As I am attempting to alter the path of the FLIP animation, there can't possibly be another explanation to this? Why would I want to alter the path AFTER the FLIP animation is complete?! I understand if this is just the default behaviour of a motionPath with a regular tween and it works well enough for that job... no need to change that. But for a FLIP animation, I think what I said above is most intuitive unless I'm missing something? If somehow there's a use-case more appropriate that makes the current behaviour as the intentional default for a motionPath with a FLIP animation, then perhaps GSAP should add a setting somewhere to allow the behaviour above as an option? TL;DR: What I'm saying is that the motionPath should be using the FLIP animation's initial state values (specifically, positioning) instead of the final state/DOM values/positioning by default as it is more intuitive. This was using GSAP v3.12.5.
  13. Ah... I am a little annoyed now. Right after I posted my last reply, I just caught something... that there's a .reverse() and a .revert() for timelines!!! This whole time I've been thinking they were one and the same. I've actually only used .reverse() on a timeline! I think .revert() is a very powerful tool that I've been missing! Mind elaborating on the difference between the two? Is it just that .revert() also resets the inline styles? Also, .revert() probably also causes an animation jump, right? Is .revert() the only timeline method (out of .reverse, .progress, .kill, .time, .clear(), .restart(), etc) that also resets inline styles? However (and correct me if I'm wrong), I imagine that .revert() is not sufficient on its own for something like this CodePen:https://codepen.io/GreenSock/pen/wvxbvjg Specifically, I'm referring to this line in the JS: text.appendChild(cursor) Because the original DOM state looks something like this: <span id="text"></span> <span id="cursor">|</span> And when that JS line executes, it will move the #cursor node inside of the #text node. So I don't imagine .revert() will undo that? Will there need to be some additional code logic to run after .revert() to undo that as well? I assume this might be a use case for gsap.context() because reverting the context would also revert the DOM structure?
  14. Exactly! One of the things I wasn't sure about for example is whether .kill() also got rid of the inline styles or not. And whether .revert() did that or not. But the main thing I've learned about .kill() is that it essentially leaves the animation playhead exactly where it's killed, and thus leaves the inline styles on the elements as well. Knowing this, once put to practice, I believe should significantly help me in figuring out exactly which method to choose when handling the spam clicking on my next GSAP task. This does bring to mind though, does .progress(0) also undo the inline styles added by the timeine? Correct. However, as far as production code goes, I can assure you that that's probably one of the simplest edge cases for me. ? But I definitely feel much better equipped to handle those other edge cases now. I mean that there probably isn't any shortcuts when it comes to handling spam clicking for many of the edge cases that I've ran into the past few months. See below for examples of what I mean. This one is probably the cleanest but I believe it only works if the content inside the tweens doesn't change, right? Annoyingly, the majority of my GSAP tasks involve dynamic content that changes on subsequent clicks. So this method wouldn't work with my earlier example for instance; the typewriter animation that pulls a different TextPlugin value through AJAX on each button click. To give you a brief idea of what I mean, let's say I'm running the following tween in a timeline on the press of a button: t1.to(_text, { text: { value: answer }, delay: 1, duration: 5, ease: 'none', stagger: .5, onUpdate: () => _text[0].appendChild(_cursor[0]), }); The tween here pulls an answer variable through AJAX and then animates "typing" the answer value for a duration of 5 seconds. The problem here, is that on subsequent clicks (spam or not), I simply wouldn't want to reverse this tween because it would take 5 seconds to reverse. Additionally, I also cannot use .restart here because it simply will not pull the fresh new value for answer (as expected). So this leaves me with no option but to .kill() the timeline, re-initialize its variable, and then add some other tween to maybe animate the _text node's parent to a height of 0 (over the span of 0.2s) for subsequent/spam clicks instead and then re-add the above tween (but with a fresh new value for the answer). I also do not think gsap.context() would handle this particular problem any better. Haha, that's the thing, I am not sure that there's one. I think for my edge cases (such as the one above), I'd just have no choice but to handle the problem as I described above. Unless maybe there was a way to fast forward the .reverse() call to the timeline? If I could maybe control the speed of how fast the .reverse() executes... I'm just spitballing though here haha. I hope the example above kinda gives you an idea of what I'm dealing with though. That being said, that tween is only half my problem in production code, I have another tween that has to be handled separately anyway. So if the SplitText CodePen I showed you was an edge case, then this is the edge case's overlord ?
  15. I was thinking that on subsequent clicks, I can revert parts of the timeline, kill the timeline, and then re-initialize it with brand new tweens... but maybe this is over-complicating things rather than making them simpler haha. Because the demo that I posted was a random demo that I picked up just to portray the .kill() on the timeline not working for me haha. But the one I was using in production code was the typewriter animation (that was also giving me trouble with killing the timeline on spam clicks). It just so happens that this one also manipulates the DOM... as it appends a cursor div to the end of another div in the onUpdate() of the tween. Call me Mr. Edge Case lol Ironically, that is literally why I started this post... because I felt like GSAP should be so easy to use, but it's giving me such a hard time nearly every time I've had to deal with spam clicks, so I must be doing something very wrong or missing something. Instead (and what I've learned today) is that it seems like I've just been working on edge case after edge case after edge case... which I'm not really surprised to learn because in this job it seems I've been working on edge cases with pretty much 70% of the plugins I've used. Thank you for your patience with me, Jack. I do believe it was well worth it. As at the very least, I've solidified my core understanding on how tweens work (whether that's with inline-styles, timeline/tween kills/reverts, etc). As for spam click handling, I'd hoped to find some shortcuts, but while I didn't really find any, I do think that my strengthened understanding of timeline/tween handling learned today should come in handy for the next GSAP task that involves any spam click handling. I look forward to the next GSAP task! And in spite of these issues, GSAP is still a joy to use and one of the greatest things to exist since sliced bread! Keep up the great work!
  16. Ah! Yes, that finally got through to me! Thanks for this example. I don't know why, but reading about the timeline playhead vs this just never truly clicked! Or maybe it did, but inline styles just always felt like a separate thing to deal with for some reason ? Is that possible in a timeline with multiple tweens? As in can I revert only specific tweens in a timeline (and in any order as opposed to the order they were added/created in the timeline) ? If so, then this is probably the key ingredient for all my woes with click handlers haha. Haha what brought me here was following this CodePen: this The only change to this I made, was that the TextPlugin's value was not a static one as used in this CodePen, but rather a dynamic variable pulled in through AJAX. Is this really that uncommon?! Did I require some clarification about how GSAP timelines/tweens work? Yes Did I inquire about how revert/kill works and their effects on the DOM? Yes Did I struggle to deliver the right questions initially? Yes Did I inquire about how CSS styles work on a DOM? NO Did I inquire about how to move element A inside element B or any DOM-related question? NO I'm sorry, but I will have to disagree with your last statement (and I find it quite offending in fact). If at some point my questions seemed like they weren't within GSAP's purview to you, and were logic questions, that is only because I was confused about GSAP's effects on the DOM. For example: If this answer is JavaScript logic to you, it is GSAP to me... if only because, let's see... the word "gsap" alone was mentioned in it 4 times! That is not to say that I haven't inquired about JavaScript logic before unknowingly on here, Blake was the legend that helped me out big time on here once, it is just that today (or anything within this ticket) was not one of those days.
  17. Hahaha, yes, you're right, my bad. I simply can't remember what I was going for with that CodePen animation! ? Understandable. But I guess what I meant is that are there scenarios where .kill() is not enough because there are leftover inline styles by the previous button click (timeline/tween animation) ? And if so, how would you best deal with that without causing an animation jump (since that's what clearProps and .revert would do) ? That sounds awesome. I've read about this before, initially, I thought this was for very advanced use cases of GSAP (like scenarios that implemented dozens of tweens)... but after what I've learned today, and correct me if I'm wrong, I'm thinking this would be good to use even for a couple of tweens and a plugin instance to solve a click/hover spam scenario. I appreciate the gsap.context() example. Though in that example, I tried switching the clickContext.revert() to clickContext.kill() just to see what that does, but that simply stops the animation completely. But I found that odd, considering that the context is re-initialized right after that, so why wouldn't it just re-run the animation? First, I'd like to say before answering this, that I've been detecting a subtle hint of hostility from you, Jack, for the past couple of responses or so. And so, I'd like to try and clear the air by saying that I am simply trying to seek more knowledge about how GSAP works and what it expects from me because I find myself falling into these click-handling traps more often than I feel like I should be. I am not trying to make your day miserable. So if I am asking too many questions (and that maybe annoying you?), I apologize. As for your question, I just feel like they're mentioned in more of an afterthought demeanor, like they're there, but don't have to be there... and if you're annoyed about my seemingly exaggerated number of CodePens that did not properly handle click-spamming on that page, I do not feel I exaggerated that; as there was exactly 2 CodePens with a click handler in them and one of them had no handling for click-spamming, that makes 50% of the CodePens! But again, I could be wrong about the importance of handling click-spamming, as they may truly be an afterthought when creating GSAP animations... and I'm happy to be corrected/informed. I'm not sure I understand this. Are you saying that GSAP is rarely used to animate content on the click of a button? Or that everyone who uses GSAP is a code wizard that knows how to handle click-spamming? I'm really curious to know because this scenario is like 99% of my use cases haha. So I either have a very repeatedly unique use case or everyone who uses GSAP knows something I don't ? Again, thanks for the detailed answers thus far, Jack. And I apologize for the massive block of texts (as I hate reading those myself). I guess I either have too many questions left un-asked from the last couple of years or some voodoo on this page makes my texts seem longer (I like to think it's the latter). Ah, haha. I'm definitely biased here because I very much hate auto-renewals. There's too many subscription based things nowadays so I cannot keep track if they were on auto-renew. And many services make you go through hoops in order to cancel an auto-renewing subscription (this is definitely not you guys but the companies that do this have definitely left a poor mouth taste for many).
  18. Let me preface this by saying that I appreciate the very thorough and detailed explanation with examples, Jack. Thank you for providing the above CodePen, because that was going to definitely be my next question. However, I've some feedback regarding this CodePen: 1) It seems that in the CodePen you've provided, while it resolves the splittext issue you mentioned, when spamming the button, it only restarts the animation from about half-way up as opposed to from the very bottom as expected. What could be causing that? 2) If the tween was just a .to() instead of the .fromTo() used in the CodePen, would the t1.kill() (to handle the button spam) still be sufficient or would there be a need for something like a gsap.set(element, {clearProps: 'all'}) to also be executed right after the t1.kill()? And I mean this question in general, not just specific to the splittext tween in the CodePen. Got it. Although, since most of my animations usually happen in the click/hover event of a button, I'd still have to initialize the timeline/tween variable outside of the handler anyway. So unless initializing a timeline variable is more resource costly than a tween variable, I might as well keep using timeline variables for consistency's sake (even if it's just for a single tween). After reading all of this, I guess I just wish there was more of a plug and play method of clearing everything added by a timeline... like a .kill() equivalent, but one that somehow also detects a splittext, textplugin, etc instance and reverts it. But that's probably more of a magic solution that doesn't exist. A more realistic solution is probably more examples for each of these plugins showing the proper way of handling the click/hover spam of a timeline/tween containing one of the above instances. I say this because after reading this: I went to GreenSock | Docs | Plugins | SplitText to see about how to detect if a splittext has already happened on an element and how to revert it prior to reading the follow-up CodePen you posted. This was nowhere to be found on the official documentation for the splittext plugin, let alone an example of handling a click/hover spam containing a splittext element. It might be worth adding that isSplitto the configurations properties on that page (maybe under a subsection labeled read-only properties or something). Additionally, I understand wanting to keep things simple and minimal... but some of the CodePens on that page have a click handler example that doesn't even do this spam check... and if they even do that check, they severely downplay the importance of it! That I feel like should be a must for any production-viable code snippet, otherwise it would be misleading and potentially more harmful than helpful. The first code snippet that I found on the SplitText page with a click handler that includes any killing of the timeline/splittext instance is the following one (under Nested elements and emojis): function kill(){ splitTextTimeline.clear().time(0); mySplitText.revert(); } $("#chars").click(function() { kill(); mySplitText.split({type:"chars, words"}) splitTextTimeline.from(mySplitText.chars, {duration: 0.6, scale:4, autoAlpha:0, rotationX:-180, transformOrigin:"100% 50%", ease:"back", stagger: 0.02}); }) As you can see, this snippet simply runs a mySplitText.revert() at every single click. Now this is different from your example wherein you check first if the SplitText instance has been split or not. So I'm assuming that attempting to revert the instance at each click is another valid approach to deal with click spamming because it will simply not revert the SplitText instance unless it has been split? Surprisingly, the code snippet right after the above one on that page, has a click handler that simply doesn't even check to kill the tween nor the SplitText instance! And the button only works on the first click... now I don't know if this is intentional, but I feel like the purpose of a button is to usually be clicked more than once unless it was a hyperlink taking you to another page. And if for some reason, adding the timeline/tween/Plugin instance kill statement is too complicated/irrelevant to include in the minimal demos on the plugins' page itself, then maybe my earlier idea of having a page dedicated solely to handling a click/hover spam of timelines/tweens and their plugin instance logic is worth adding after all. It might even save the moderators a decent amount of time to simply link to that page whenever a click/hover based spam question issue is posted. Maybe it's just me, but I feel like 99% of my issues are around this... even one example on how to handle the click/hover spam per plugin would probably solve at least 70% of my questions haha. I'm sorry if this feedback comes off a bit harsh, I'm not trying to sound unappreciative. I just feel very strongly about this. And I'd like GSAP to stay the best web developer tool out there! I'm bringing this up again since I feel like it might have gotten buried up there. I understand if this isn't something you can do, I just wanted to make sure my vote is added in favor of this (if there's any internal loop for this feedback haha).
  19. If this is supposed to work, then I'll have to create a CodePen to see if I can replicate it (this might be a different ticket if I don't find time soon enough). Explanations like these, and code snippets like the one below, make it seem so simple, when in reality... well I'll just show you. Also, the comment in the snippet above mentions that it's simpler to use gsap.to() in the sample above... but how would you handle the hover spam if you did that? Here's an attempt at a CodePen that managed to give me a headache: https://codepen.io/fuad-zeyad-tareq/pen/YzObmqE 1) The above CodePen works perfectly fine, right? Not even an animation jump when click spamming... but according to you, Jack, and to my own logical sense of things... t1.progress(1) should create an animation jump, but somehow, it doesn't here... 2) Let's try to replicate your code snippet from above by making a simple change to this CodePen. Let's simply remove .progress(1) so we'd end up with only t1.kill() inside the onclick handler. According to you, Jack, and to your code snippet above, this should be sufficient to handle click/hover spamming, right? Well try that for this Code snippet. With .progress(1) removed, it will freeze mid-animation when you spam click it... 3) Maybe our CodePen is a little more complex than your code snippet from above, so maybe the change we made in our attempt 2 above is incomplete. Upon further inspection, logic dictates to me that the following code snippet might be best put outside of the onclick handler: const split = new SplitText("ul li", { type: "lines" }); So in an attempt to still make the spam click handling work without .progress(1), let's also move the code snippet above to outside of the click handler and try again. Just to recap, we now should have something like this: let t1 = gsap.timeline(); const split = new SplitText("ul li", { type: "lines" }); $('.click-me').on('click', function() { if (t1) t1.kill(); t1 = gsap.timeline(); t1.fromTo(split.lines, { opacity: 0, rotationX: -120, force3D: true, transformOrigin: 'top center -150', }, { duration: 3, opacity: 1, rotationX: 0, stagger: .02, onComplete: function() { split.revert(); } } ); }); Again, according to you Jack, this should be enough to handle the spam clicking of a button. And you know what, at first glance, spam clicking now seems to work just fine (without even an animation jump!). However, if you wait for the animation to finish after the first click, and then try another click... it will not work. So why's t1.kill() not enough on its own here? And why's t1.progress(1).kill() the most valid approach as seen in the initial CodePen? This is why I think something like this should be a mandatory tutorial for anyone beginning work on a gsap timeline.
  20. Got it. Will keep that in mind! If this is supposed to work, then I'll have to create a CodePen to see if I can replicate it (this might be a different ticket if I don't find time soon enough). In the meantime, do you happen to have any tutorials (preferrably with CodePens) showing a side-by-side difference of when it is best to use t1.clear().kill(), t1.progress(1).kill(), t1.progress(0).kill(), t1.restart().kill(), etc. And maybe some more samples of handling the click spam of a timeline? I feel like I've a bit of a foggy confusion in this area that causes me to fall into traps that I'm hoping I can avoid (if not now then at least in the future). On another note, my membership renewal is coming up and I wanted to let you know that it would be a lot more enticing if there was some kind of a renewal discount of like 20% or so (ideally applied by default). It might seem dumb, but this kind of stuff is usually a good incentive for me lol. Otherwise, it feels like the logical thing to do would be to wait until the next enticing GSAP update to renew again since it's the same price as a brand new membership fee.
  21. So then this is a semantic/communication error on my end. I need the timeline to reset as well. And if I understood everything correctly, you need to tell the timeline to reset after killing it (and that can be through many ways). .progress(1) probably works best for my case because it would arrive at the expected end result (with all CSS properties added at the end), whereas .progress(0) fails mostly for me because it would reset the timeline to 0 before finishing to add the rest of said CSS properties to the DOM. So when the timeline runs again following a .progress(0), some properties (but not all) would be still there in the DOM added by the previous iteration of the timeline. If I understood all of the above correctly, this explains probably more than half my confusions and woes with timeline restarts! I'll have to experiment some more with other methods such as combining a t1.clear() with a t1.restart() (since those are probably cleaner to avoid that animation jump you mentioned). Thanks again Jack, this has been very enlightening. I'm excited to broaden my understanding of GSAP timelines!
  22. Because t1.kill() alone won't stop the timeline from executing if it's still executing while the button is clicked again, so I either have to precede it with a .progress(0) or .progress(1). However, most of the time .progress(0) just makes things worse for some reason (in such cases .progress(1) works). So for my understanding, in this scenario you mentioned, when should I restart the timeline? Right after clearing it or after adding the 8 seconds worth of animations? And is it an option to do t1.clear().time(0) or t1.clear().progress(0) in order to resolve this very issue? Fair enough. However, I do think this can be followed up with a question for clarification instead of jumping to a CodePen request only... after all, I didn't put so much effort into typing and perfecting a fully comprehensible (to the best of my capability) post, only to be met with a brick wall asking for a CodePen or nothing (in all 3 responses that followed). I'd like to stress the fact that I have no problem with persisting on a CodePen request, but making this the ONLY answer is something I take issue with. When many things could have been answered without it as you yourself have proficiently proven in your first response... unless you'd like to say that you're capable of unique understanding that others aren't... and I have a feeling that this is something that some might +1 about you! lol I may be spoiled to say this, but your response is the kind of (meeting me half-way) response I expected when I came here... you asked for a CodePen, but you also provided valuable clues and insights as to what might be going on. It might have been a wild guess from your end, but I'm the type of person who likes to experiment and fiddle around on their own before jumping to a blank slate and a CodePen. And wild but curated guesses from experts like you play a huge role in getting me closer, if not to a solution, then to a problem that I can actually understand and convey in a CodePen. Suffice to say, I was not at the point where I had enough information about my own problem when I began writing this post, and that is why I like to ask some high-level abstract questions on here first, prior to jumping into a CodePen. I hope this makes sense! Thanks again for keeping up with me, I appreciate it.
  23. Understood. However, my understanding of when to use t1.progress(1).kill() is in cases such as when a timeline is played on a button click and we want to prevent spamming the button click from breaking the timeline. Is this still the case? Good suggestion, I thought for sure that was what made more sense to use in my case. But it didn't work when running it in place of t1.progress(1).kill() or when running it after. This is exactly what I was looking to find out. I was looking for the most semantic/efficient approach and presumed that my killing and re-initializing the timeline variable to a new one, was not the semantic/traditional way to go about this. While I completely understand that, I'd more likely be inclined to cooperate if I felt that an attempt was at least made to answer some of my concerns that really don't require a demo such as the question answered by you as quoted above, which really covers my main concern (and this in turn saves me from having to debug this issue any further and/or create a demo at all!). 100% agreed! Except for scenarios like this one where I'm seeking a simple affirmation that "I'm not doing something wrong by redefining a timeline variable" and that "it's a perfectly valid approach (even preferred over others)", as you've mentioned. Would literally solve this ticket! Haha And I completely agree, which is why I would usually provide a Codepen once I've noticed that we're not arriving at any fruitful conclusion (or that I'm asked to provide one in a follow-up to a conversation that is leading to more confusion). The thing is, in this case, I feel I wasn't met half-way like I usually am. I was immediately asked to provide a CodePen... and when I provided a reason as to why I don't have one, I was met with a 2nd request to provide a CodePen, immediately, prior to a decent attempt at answering at least some of my questions. And then when I responded with this: I merely had a mild concern, and so by this point, I figured it's not worth hassling you guys anymore nor the time spent to write a CodePen, as I was simply exhausted by the time I figured out the solution to my problem in production. Haha And yet, I was met with a response that answered none of my concerns and only re-iterated the need for a CodePen (for the 3rd time in a row!)... I feel this is a bit too pushy, don't you? Your response was the exception here, so I appreciate that. That being said, I very much appreciate the community you guys have created, and love the standard of support you always manage to deliver (it's very rare and makes you one of the top if not the top support communities out there!). I appreciate your detailed and thorough response, Jack, and it has (once again!) delivered exactly what I needed; the peace of mind that I am not misusing the timeline variable by re-initializing it. ?
  24. I'll have to respectfully disagree. I have literally received helpful explanations on here with even less information provided before. Not every question requires code to be answered! I've provided that... twice! But you've both ignored 90% of my explanation and asked for code or nothing. What you're saying is that a simple question like "are there cases which would require a re-write of the timeline variable? And if so, are they few or many? Any examples would be nice." requires code from my end for you to answer? If so, I'll have to respectfully disagree. I feel you either wanna help your community achieve their best potential using your tools (by going above and beyond which has been my experience here up until now) or you wanna argue about something we both agree about but is not always an option... your call.
  25. I don't disagree with this, but I've already addressed why this isn't available. Also, I don't think any more of my code would reveal anything different as I've already identified what I believe is the choking point in it (as evidently portrayed by my provided solution above). Plus, I get a headache just thinking of trying to wrap my head around trying to replicate what I don't understand. ? At the risk of restating myself, I was hoping for more of an abstract discussion on the issue. But if you're not interested and/or unable to, I understand. Thanks for your time.
×
×
  • Create New...