Jump to content


  • Posts

  • Joined

  • Last visited

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

Eunomiac's Achievements

  1. I definitely hear and understand everything that's been said on the difficulty of managing expectations of assistance, but I think this may have been lost in the shuffle (of course, me putting it in parentheses and presenting it as an afterthought may have had something to do with that ). Because there's certainly the potential for a great deal of frustration when, on one hand, the forum rules request that community members spend time creating a CodePen demo to illustrate their problem while, on the other hand, there's the very real "risk" that all that work will prove to have been in vain --- as @GreenSock put it: ... which only exacerbates the problem. To be clear, I'm not complaining about any particular treatment I've received --- the frustration I describe above happened only once to me, and my every other experience here has been wonderful --- but I wanted to shine a light on this specific issue in particular. Moreover, it may be difficult for you to get a good read on just how many people have been frustrated by similar experiences if most people react the same way I did: grumble and silently depart, bemoaning the time wasted. I wish I had a solution, and perhaps it isn't as much of a concern as I'm making it out to be, but definitely something to be aware of!
  2. While I'm here, and on the subject of potential ways to make this awesome community even better, I've been thinking for a while now that a less "official" forum for discussing and seeking advice/inspiration on particular projects or designs would make a nice complement to the main help forum: a place where there's no expectation of assistance from the GSAP team, but where the community itself could provide its own help and advice. It's where, for example, people who post requests for help on coding logic (i.e. outside the ambit of "issues relating to gsap functionality only") could be referred. (After dutifully heeding instructions by spending an hour and a half on a CodePen demo, receiving a referral to such a forum in reply would be much less painful than being told one's question is an issue of code logic, not GSAP, and is thus ineligible for assistance. I've since recovered , but I should confess that particular experience didn't represent this community well!)
  3. I feel this might be the most important thing I've found on the Internet all year. Thank you!
  4. Hot damn, that's definitely getting added to my toolbox, thanks! I don't think I'll be animating 50 items at once like I did in my demo, but another challenge I'm just about to tackle involves scaling the timeScale of a Timeline based on the proximity of the mouse cursor, so I'll be experimenting with whether quickSetter will help with that! Just to clarify, though: The issues you raised are true regardless of whether you're animating objects via class instances, or more conventionally via selectors/HTMLElements, yes? By which I mean, you aren't describing issues that I'm introducing by animating things via class methods, correct?
  5. Well, that was certainly a lot easier than I expected! I was about to ask some follow-up questions, then decided to see if I could answer them on my own, using the pens you posted as my guide. Here's the CodePen I ended up with. I think it does a nice job of extending the pens you posted to class syntax, as well as showing that this also works with multiple objects animated in a single Tween, even with a stagger. Perhaps someone like me might find it helpful down the road? I did have one question as I was working on it: Are there any performance or best-practices issues with my use of gsap.set within the setters that will be targeted by the tween (e.g. set posX(x) { gsap.set(this.elem$, {x}) }? I just want to confirm there aren't any recursion issues or other potential consequences of "nesting" gsap calls in such a way? https://codepen.io/eunomiac/pen/gOvRWNg?editors=0011
  6. I'm working on a module for a virtual tabletop app (Foundry VTT), which provides an HTML sandbox for rendering game items. I'm representing these rendered objects as instances of classes I've defined. I'm currently implementing GSAP functionality simply by defining an "elem" field on these classes to hold a reference to the HTMLElement object, which I pass to gsap as one would expect: gsap.to(myClassInstance.elem, {...}) However, my module is growing more complex (surprise) and I've found myself wishing that, instead of only passing the HTMLElement, I could pass the whole object as a target: gsap.to(myClassInstance, {...}). Is it possible, by defining the right set of methods, getters, setters and fields in my custom class (as aliases or overrides), that I can "trick" gsap into thinking those instances are valid targets, i.e. by making sure that I've provided aliases for any fields or methods gsap expects to be there? (Unfortunately, I have to extend my classes from a Foundry base class, so I can't, say, extend the HTMLElement class --- which I assume would work.) If this is possible, how might I get a list of the methods and fields gsap expects to exist, and that I'd thus need aliases for --- at least regarding the basic to / from / fromTo Tweens, as well as Timelines? (I have .d.ts TypeScript files for the GSAP types, so perhaps that's where I should look for those necessary fields/methods?) In case I'm stuck in the mire of an X/Y problem, let me back up slightly and describe my intentions: I want to be able to send multiple instances of my classes (as an array of objects) as targets to a single gsap Tween, so that I can stagger their animations (among other things), without having to animate each one separately. And, for reasons related to Foundry's architecture and the way I've defined my classes, it isn't always feasible for me to simply convert my objects to elements (e.g. gsap.to(myClassInstances.map((obj) => obj.elem), {...})) --- not to mention I have some unique methods/fields on my objects that I'd love to have access to within gsap's callback functions, without having to change the callbackScope. (Hope it's okay that I've left out a demo; I didn't think one would be necessary or helpful with this particular question!)
  7. The following effect ... gsap.registerEffect({ name: "brighten", effect: (targets, config) => gsap.to(targets, { color: C.html.colors.fgBright, scale: 1.25, duration: config.duration, onReverseComplete() { gsap.set(this.targets, {clearProps: "transform"}) } }), defaults: {duration: 0.25}, extendTimeline: true } ... results in the following console error when run: gsap-core.js:84 Invalid property clearProps set to transform Missing plugin? gsap.registerPlugin() _missingPlugin @ gsap-core.js:84 _addPropTween @ gsap-core.js:2644 _initTween @ gsap-core.js:2819 _attemptInitTween @ gsap-core.js:433 _renderZeroDurationTween @ gsap-core.js:469 render @ gsap-core.js:3030 Tween @ gsap-core.js:3004 set @ gsap-core.js:3277 I've copied the gsap.set() syntax directly from the CSSPlugin docs which, as far as I understand, is integrated into gsap core and doesn't need to be registered (though I registered it anyways, to no avail). Any insights as to why I'm getting this error and what I can do about it is, as always, very much appreciated! (I didn't think a codepen demo was necessary for such a specific question, but please let me know if I should provide one!)
  8. Just to clarify one thing, which I think @OSUblake already touched on: .rawTime() and .totalTime() should only be different if both of the following are true: the timeline has a finite .totalDuration() (i.e. it includes no infinite repeats), and the timeline's playhead is located beyond its .totalDuration() Does this mean that a timeline's playhead continues to advance after the timeline has reached its conclusion and fired its .onComplete() callback, such that the .rawTime() of any timeline will continue to increment until the timeline is explicitly .pause()'d, .reverse()'d or otherwise altered? Follow-up Question: Is it possible to derive that "1.5" value (i.e. the "duration with one repeat") from any of the Timeline properties/methods? Or is it something you just have to manually code in?
  9. Excellent, and thank you --- it never occurred to me to refer to the timeline duration directly, which seems a bit obvious in hindsight!
  10. I have in my example a simple timeline with the following structure: .to(DOT, <expand to full size>, 0) .to(DOT, <repeatedly pulse>, ">") .to(TEXT, <spread out characters>, "<") Normally, when I do hover animations like this, I simply call the .reverse() method on the "mouseleave" event. However, when I do this with a timeline that includes a repeating component (the second .to() in my example), reversing the timeline reverse-animates through all previous loops of that repeating tween, leading to an excessively-long hover-off animation. I thought I could just use an onReverse() callback and, within that, jump the playhead location to the end of the first repeat (so that, when it continues backwards to the start of the timeline, it only runs through one cycle of that repeating tween). But, according to the docs, such a callback doesn't exist. I then thought I could use the onRepeat() callback to reset the playhead to the start of the repeating animation each time it repeats, but then I figured I was too far into the weeds and that I should come here to discover a more elegant way to do this! What is the proper way to pull this off? Much thanks in advance for any help you can provide!
  11. I have a variable number of rotating circles (though the demo only includes two), each of which contain several Draggable dice in "orbit" around the circles' centers. I want to be able to drag and toss (with inertia) the dice from one circle to another, and have them snap into orbit when they arrive. But, try as I might, I can't figure out how to get the snapping to work accurately! I've commented up (hopefully without too much rambling; I have been known to go on... kind of like I'm doing here...) a mini demo per the forum instructions that should clearly illustrate my problem. The first fifty lines or so are setup and initialization, which I've done my best to collect into a closure (so you can "Fold All" everything to jump to the Draggable code, where I'm pretty sure I've made my mistakes). Any help is, once again, very much appreciated! (PS: I've also noticed that my dice are ever-so-slightly offset from the dashed rings they should be orbiting on. I'm not sure if this is a GSAP issue or something unrelated, but if it's the former, I'd really appreciate some insight into that minor issue, too!)
  12. Yeah, I agree with you there: Best to be consistent. Plus, the more I learn about GSAP, the deeper in love I fall. *swoon* Thanks once again for your help! As a quick update, I'm well on my way to implementing that game mechanic I described --- check out that spiffy CodePen example I posted to see how far I've come --- I'm finding GSAP to be very grokkable, plus the documentation is amazing!
  13. Thank you for your reply! Firstly, I apologize for the length of the codepen example; I certainly didn't attach it expecting a full code review, just saw the field in the post form and filled it in for completeness' sake --- I assumed I was making a fairly basic error that could be solved from my description and the bit of code I copied into the post proper. And in that, at least, I was right! Your advice was exactly what I needed to solve my problem --- thanks again! Just one clarification regarding the positioning of elements: When I go on to apply some (non-Draggable) animations to the container elements that my Draggables will be snapping to, are you recommending that I animate them through GSAP and not, for example, through CSS keyframes or the like?
  14. I'm trying to create a game mechanic where players grab and toss dice to and from each other's home circles. However, I can't seem to set the initial positions of the dice to within the player circles without creating an offset to their snapping. This image illustrates what I mean: The large circles are the player home circles, and the smaller green circles are the dice. The dice should all snap to the player circles after a throw, but are offset as shown (the dice in the player circles haven't been thrown yet, and are where they were initially positioned). If I don't initialize the dice positions (i.e. they all default to the top left of the screen), then the snapping works perfectly, so I know it has something to do with my confusion over offset()/position() and the snap property. I've linked to my CodePen, but here is where I suspect I'm making my mistake --- either in setting the dice offset, or in how I'm applying the snap coordinates ("wiggle" is just a simple position randomizer, to spread the dice out a bit): const [die] = Draggable.create( $(`<div id="${dieID}" />`) .appendTo("body") .css({ "position": "absolute", "background": `radial-gradient(ellipse, #FFFFFF, ${color} 90%)`, "height": 20, "width": 20, "border-radius": 10, "border": `3px solid ${color}` }) .offset({ // If I comment out this offset, the snapping works, but I'd like to initialize // the dice to start in one of the circles (not at the top left of the document) left: wiggle($(circle).offset().left, $(circle).width(), 0.6), top: wiggle($(circle).offset().top, $(circle).height(), 0.6) }), { dragResistance: 0.65, type: "x,y", inertia: true, snap: { points: function(point) { const closestCircle = getClosestToPoint({ posX: point.x, posY: point.y }, CIRCLES, this.startCircle ?? false); return { x: wiggle($(closestCircle).offset().left, $(closestCircle).width(), 0.6), y: wiggle($(closestCircle).offset().top, $(closestCircle).height(), 0.6) } } }, // ... events } Any help is much appreciated, and thank you in advance!