Jump to content
Search Community

Search the Community

Showing results for 'whipped' in content posted in GSAP.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • GreenSock Forums
    • GSAP
    • Banner Animation
    • Jobs & Freelance
  • Flash / ActionScript Archive
    • GSAP (Flash)
    • Loading (Flash)
    • TransformManager (Flash)

Product Groups

  • Club GreenSock
  • TransformManager
  • Supercharge

Categories

There are no results to display.


Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Personal Website


Twitter


CodePen


Company Website


Location


Interests

  1. I'm curious - is this for a class assignment or something? It looks remarkably similar to this other forums post: Well, I got intrigued and "whipped together" an effect (@PointC will appreciate that term) that'll make it super simple to zoom into certain parts of an element by animating the xPercent and yPercent and scale - you just tell it where on the image to zoom into like origin: [0.25, 0.8] would zoom into the spot that's 25% from the left, and 80% from the top (x and y axis). It automatically caps things so that the edges don't collapse toward the center, thus if you do [1, 1], you won't end up with the bottom right corner in the center of the area. Here's a CodePen that shows the effect: https://codepen.io/GreenSock/pen/bGgQjyo?editors=0010 Does that help?
  2. Welcome to the forums, @anaelyts. It'd be super helpful if you could just isolate the one thing you're struggling with and eliminate all the extra fluff like the clipPath, opacities, all the extra images, etc. because it's just kinda hard to follow exactly what you're saying the problem is. I'll offer a few thoughts... As you probably know, you're using a non-standard order of transforms which makes things tricky. One of the big benefits of GSAP is it lets you independently control each part of the transforms (x, y, scaleX, scaleY, rotation, etc.) which requires that they be applied in a consistent order. You're setting things via a string on the "transform" property which, again, we strongly recommend against because you lose all the performance and some of the accuracy benefits that GSAP offers. It's forced to apply those transforms and then have the browser return a computed matrix() or matrix3d() which it then must parse, and as you discovered the browser always reports those as px-based (you lose any responsive units like vw, vh, %, etc.). You directly set the element.style.transform but never told GSAP that it should parseTransform again (because you threw off the cached values). So GSAP will continue to use the cached values, making it appear as though it ignored your style.transform direct set on subsequent animations. You can set parseTransform: true on a subsequent tween to tell GSAP to clear out its cached transforms on that element. If you really need to set the transform components in a non-standard order, I whipped together an experimental plugin that lets you define the order in a comma-delimited "transformOrder" list that you'd add your tween(s): // caveat: you must define each individual component in the list that you want rendered, so "scaleX,scaleY" instead of "scale", and "translateX,translateY" instead of "translate". // example for just 2D stuff would be transformOrder: "x,y,rotation,skewX,skewY,scaleX,scaleY,perspective" gsap.registerPlugin({ name: "transformOrder", priority: -100, // make it run AFTER other properties update (transforms) register(core, Plugin) { const cache = {}, propToAlias = {x: "translateX", y: "translateY", rotation: "rotate", rotationX: "rotateX", rotationY: "rotateY", transformPerspective: "perspective"}, aliasToProp = {translateX: "x", translateY: "y", rotate: "rotation", rotateX: "rotationX", rotateY: "rotationY", perspective: "transformPerspective"}, getFunc = template => { let props = template.split(",").map(p => aliasToProp[p.trim()] || p.trim()), transforms = props.map(p => propToAlias[p] || p), l = props.length, func = (ratio, data) => { let t = "", i = 0; for (; i < l; i++) { t += transforms[i] + "(" + data[props[i]] + ") "; } data.target.style.transform = t; }; cache[template] = func; // use a cache to boost performance so that we don't have to keep re-creating the function for targets that share the same transformOrder. return func; }; Plugin.prototype.init = function(target, vars) { this.func = cache[vars] || getFunc(vars); this.cache = gsap.core.getCache(target); } }, render(ratio, data) { data.func(ratio, data.cache); }, init: true }); Then you'd add it to your tween like: gsap.to(".box", { x: "-51%", scale: 0.63, rotation: -5, transformPerspective: "6vw" duration: 3, transformOrder: "transformPerspective,scaleX,scaleY,rotation,x,y" }); And that basically overrides the normal rendering order. And in GSAP 3, you can use units on things like x, y, etc., it should work okay to include those in the individual components. I hope that helps!
  3. Hi, Sorry this slipped through the cracks. Honestly I don't know what to tell you. I whipped a quick sample using Next and GSAP and it seems to be working as expected: https://codesandbox.io/s/vibrant-cerf-d16uv?file=/pages/index.js Perhaps the issue resides in the usage of styled components or another package in your setup, but that's beyond what we can do around here. Try removing styled components and use either regular classes or styles declarations using objects (like I did in the sample), if CSS in JS is a must in the project. Hopefully this helps. Happy Tweening!!!
  4. I whipped together a helper function that was loosely inspired by Chris's work there, and it has the following tweaks: Improved performance in the way it handles scrubbing You can add any ScrollTrigger-related value to the object you pass in (trigger, start, end, onEnter, onLeave, onUpdate, markers, whatever.) so you get tons of flexibility https://greensock.com/docs/v3/HelperFunctions#lottie https://codepen.io/GreenSock/pen/QWdjEbx?editors=0010 ?
  5. An individual tween does record the starting values internally, yes, so that it can very quickly interpolate and of course you could reverse() your animation. But you're asking to animate back to a previous state from an entirely different tween, right? There are a bunch of ways to do that, here are a couple and I whipped together a few helper functions you could tap into: https://codepen.io/GreenSock/pen/6e52ec5d383a1f71256beec9ab3a90f2?editors=0010 This function lets you pass in some targets, a comma-delimited list of CSS properties, and optionally a vars object (which could contain things like duration, ease, onComplete, etc.) and it'll record the current values in a vars object so you can easily pass that into a tween later to animate back to them: // records the current CSS properties in a vars object so we can animate back to them easily function propsToVars(targets, props, vars) { let data = []; props = props.split(","); vars = vars || {}; gsap.utils.toArray(targets).forEach((target, i) => { let d = data[i] = {}, get = gsap.getProperty(target); props.forEach(p => d[p] = get(p)); }); props.forEach(p => vars[p] = i => data[i][p]); return vars; } And here's a function you could pass a list of targets to, a comma-delimited list of property names, and optionally a vars object to and it'll remove those properties inline and animate back to the native state accordingly (it uses the previous propsToVars() function too): // eliminates the inline CSS properties (in the comma-delimited "props" list) and animates to that state function toNative(targets, props, vars) { vars = propsToVars(targets, props, vars); gsap.set(targets, {clearProps: true}); return gsap.from(targets, vars); } You could use the Flip plugin instead if you prefer. LOTS of ways to do it. Does that help?
  6. Hey Shane! You may be able to use a custom snap function to do this sort of thing. If you can provide a minimal demo with a basic setup of what you're trying to do, we may be able to offer some suggestions. A circle is much easier than an irregular shape, that's for sure. Here's a quick demo I whipped together for you: https://codepen.io/GreenSock/pen/LYZBaoR?editors=0010
  7. Here's a SpriteSheet helper function I whipped together to accommodate more complex situations like this. You'll need to load/format the data to match what I did (or edit my function), but hopefully it at least gets you moving in the right direction (I slapped some labels on the frames of the first two sheets): https://codepen.io/GreenSock/pen/4299f8616fdf0f87df155c9624bd2604?editors=0010 function SpriteSheet(container, data, onLoad) { container = gsap.utils.toArray(container)[0]; let progress = 0, frames = 0, lookup = [], loading = [], loadingQueue = e => loading.splice(loading.indexOf(e.target), 1) && !loading.length && onLoad && onLoad(), curSheet, curIndex, img; gsap.set(container, {overflow: "hidden", position: gsap.getProperty(container, "position") === "absolute" ? "absolute" : "relative"}); data.forEach((sheet, index) => { img = document.createElement("img"); loading.push(img); img.addEventListener("load", loadingQueue); img.setAttribute("src", sheet.file); gsap.set(img, {position: "absolute", top: 0, left: 0, visibility: index ? "hidden" : "inherit"}); container.appendChild(img); sheet.img = img; sheet.framesBefore = frames; let i = sheet.frames.length; frames += i; while (i--) { lookup.push(index); } }); frames--; this.progress = function(value) { if (arguments.length) { let lookupIndex = ~~(value * frames + 0.5), sheet, frame; if (lookupIndex !== curIndex) { curIndex = lookupIndex; sheet = data[lookup[curIndex]]; frame = sheet.frames[curIndex - sheet.framesBefore]; if (sheet !== curSheet) { curSheet && (curSheet.img.style.visibility = "hidden"); sheet.img.style.visibility = "inherit"; container.style.width = frame.w + "px"; container.style.height = frame.h + "px"; curSheet = sheet; } curSheet.img.style.transform = "translate(" + -frame.x + "px, " + -frame.y + "px)"; } progress = value; } return progress; }; this.frame = function(value) { arguments.length && this.progress(--value / frames); return ~~(progress * frames + 0.5); }; this.progress(0); } So your data could look like this (just the first two): let data = [{ file: "https://assets.codepen.io/16327/01-Bulldozer-0.png", frames: [ {"x":0,"y":0,"w":782,"h":414}, {"x":782,"y":0,"w":782,"h":414}, {"x":0,"y":414,"w":782,"h":414}, {"x":782,"y":414,"w":782,"h":414}, {"x":0,"y":828,"w":782,"h":414}, {"x":782,"y":828,"w":782,"h":414}, {"x":0,"y":1242,"w":782,"h":414}, {"x":782,"y":1242,"w":782,"h":414} ] }, { file: "https://assets.codepen.io/16327/01-Bulldozer-1.png", frames: [ {"x":0,"y":0,"w":782,"h":414}, {"x":782,"y":0,"w":782,"h":414}, {"x":0,"y":414,"w":782,"h":414}, {"x":782,"y":414,"w":782,"h":414}, {"x":0,"y":828,"w":782,"h":414}, {"x":782,"y":828,"w":782,"h":414}, {"x":0,"y":1242,"w":782,"h":414}, {"x":782,"y":1242,"w":782,"h":414} ] }]; Usage: let sheet = new SpriteSheet(".spritesheet", data, () => { gsap.to(sheet, {progress: 0.8, duration: 2, ease: "none"}); }); So you give it a container element and the data, and it'll load an <img> for each spritesheet file, and fire the onLoad when they're all loaded. Then you can simply animate the "progress" of that SpriteSheet object or the "frame" value (whatever you find more convenient) and it'll handle shifting around the images and showing/hiding them. Is that what you're looking for?
  8. Just for clarity, the whole point of .batch() is that it will batch the callbacks, meaning that (for example) if you scroll really fast that could result in multiple elements entering/leaving the viewport, so ScrollTrigger will batch those together into an Array and pass those to the callback. It looks like your code was assuming there would only be ONE element passed in. See what I mean? You'd just need to alter your code to accommodate the batching. Here's one that @ZachSaucier whipped together: https://codepen.io/GreenSock/pen/VwaJrYE?editors=0010 Does that clear things up?
  9. I re-read things and I think I understand what you're asking for - a "none" option (not-matching). Here's a helper function I whipped up that should deliver that kind of thing - you'd use it just like ScrollTrigger.matchMedia(): function matchMediaOrNot(vars) { let queries = [], copy = {}, isMatching, notMatchingFunc = vars.none, check = () => { let i = queries.length; while (i--) { if (queries[i].matches) { isMatching || ScrollTrigger.revert(false, "none"); isMatching = true; return; } } isMatching = false; return notMatchingFunc(); }, wrap = func => () => { check(); let result = func(); return () => check() || result; }, p; for (p in vars) { (p !== "none") && queries.push(window.matchMedia(p)); copy[p] = wrap(vars[p]); } ScrollTrigger.matchMedia(copy); check(); } Usage: matchMediaOrNot({ "(max-width: 1024px)": function() { console.log("1") }, "(min-width: 1025px) and (min-aspect-ratio: 4/3) and (max-aspect-ratio: 2/1)": function() { console.log("2") }, "(min-width: 1025px) and (max-aspect-ratio: 4/3)": function() { console.log("3") }, "none": function() { console.log("not matching!"); }, }); Does that deliver what you wanted?
  10. @ddi-web-team @Sygol @Yannis Yannakopoulos I whipped together a helper function that should make this quite easy. Check it out in this CodePen: https://codepen.io/GreenSock/pen/823312ec3785be7b25315ec2efd517d8?editors=0010 We may end up adding it as a static method on ScrollTrigger if there's enough interest. What do you think?
  11. GreenSock

    steppedEase helper

    If your goal is to call a callback only when each step occurs in the ease, you could tap into the onUpdate. Here's a helper function I whipped together for you: https://codepen.io/GreenSock/pen/YzybVQo?editors=0010 function myCallback() { console.log("changed!"); } gsap.to(".box", { y: "-=50", ease: "steps(16)", duration: 5, onUpdate: onStep(myCallback) }); function onStep(callback) { var last = 0; return function() { this.ratio !== last && callback.call(this); last = this.ratio; }; } Is that what you're looking for? But like the other guys said, there's probably a better way to accomplish what you're after; we're not sure WHY you're asking for something like this so once we understand better we can offer some advice. Most likely a stagger is a good fit.
  12. Here's a helper function I whipped up that'll automatically add multi-purpose getter/setter methods to your object without the "get" and "set" in front: function wrapSetters(target, names) { if (names) { names.split(",").forEach(name => { let cappedName = name.charAt(0).toUpperCase() + name.substr(1), setter = target["set" + cappedName], getter = target["get" + cappedName]; (setter && getter) || console.warn("No getter/setter defined for", name); target[name] = function(value) { return arguments.length ? setter.call(target, value) : getter.call(target); }; }); } else { Object.keys(target).forEach(name => { let getter, setter; if (name.substr(0, 3) === "set" && (getter = target["get" + name.substr(3)])) { setter = target[name]; target[name.charAt(3).toLowerCase() + name.substr(4)] = function(value) { return arguments.length ? setter.call(target, value) : getter.call(target); }; } }); } } Usage: var obj = { _opacity: 0, setOpacity(value) { this._opacity = value; }, getOpacity() { return this._opacity; } }; wrapSetters(obj); // <- loops through all enumerable properties, finds any that start with "set" and have a matching "get" function, adds a new function without the get/set for convenience... gsap.to(obj, {opacity: 1, duration: 2, ease: "none", onUpdate: () => console.log(obj.getOpacity())}); // -OR- you can feed in a comma-delimited list of property names (without the get/set in front) and it'll just do those: wrapSetters(obj, "opacity"); So basically, with that helper function your tweening code could be as concise as this from now on... gsap.to(wrapSetters(obj), {opacity: 1, duration: 3}); gsap.to(wrapSetters(obj2), {x: 100, duration: 1}); ... And you should only need to run that function once on each object you're animating. Zach's method is also an excellent solution. I just figured that we've had a few people ask about this now, so a helper method might...um...help
  13. GreenSock

    DynamicProps

    Ah, DynamicProps was way back from the ActionScript days Typically you could just recreate the tween each time the "target" object moves to a new position (and don't forget to set overwrite: true or overwrite: "auto" so that the previous one is killed). But if you need a single tween instance so that it definitely ends after a certain amount of time and the ease gets adjusted on-the-fly, I whipped together a helper function that you can feed into a modifier, as demonstrated here: https://codepen.io/GreenSock/pen/1ed6118d993bac95e12d3236cc836f9e?editors=0010 Notice when you drag the red dot, the blue will start animating there no matter where you move it, and it'll always end up exactly on top of it after 5 seconds (the duration of the tween). Of course when the tween ends, it doesn't keep following it. Helper function: // the "getter" can be a function with your own logic OR you can pass in another target whose property should be copied. function getDynamicProp(prop, getter) { let ratio = 0, result, initted, copy, unit; if (typeof(getter) !== "function") { copy = (typeof(getter) === "string") ? document.querySelector(getter) : getter; getter = () => gsap.getProperty(copy, prop); } return function(value, target) { if (this.ratio !== ratio || !initted) { let end = parseFloat(getter()), factor = (this.ratio == 1 || ratio == 1) ? 0 : 1 - ((this.ratio - ratio) / (1 - ratio)); if (!initted) { unit = typeof(value) === "string" ? gsap.utils.getUnit(value) : 0; initted = true; } result = (end - ((end - gsap.getProperty(target, prop)) * factor)) + unit; ratio = this.ratio; } return result; }; } Usage example: gsap.to("#box", { x: "+=1", // these values don't matter - we'll override them with modifiers. These are placeholders. y: "+=1", duration: 5, modifiers: { x: getDynamicProp("x", this.target), y: getDynamicProp("y", this.target) } }); You can define your own getter functions if you want. This isn't an "official" plugin or solution or anything, but hopefully it gets you what you need. Thanks for being a Club GreenSock member! ? Does that help?
  14. Inspired by your post, I whipped together an unofficial ClassNamePlugin for GSAP 3 which you can see here: https://codepen.io/GreenSock/pen/BaNRejV?editors=0010 Feel free to use that in your projects but it's not something we plan to actively support or promise that it'll work flawlessly in every case. But it should be pretty rock solid for most use cases. Thanks for being a Club GreenSock member!
  15. Blake is right - the cape flapping isn't done by a single plugin or anything like that - it's pretty advanced and wasn't intended to be a "cookie-cutter" solution for others to use. I just whipped that together for that particular animation. Of course you can use MorphSVGPlugin to morph between shapes, but that's not the same as what I'm doing in that cape-flapping animation. And no, it's not ThreeJS at all. It's pure SVG and some custom logic for the flapping. Thanks for joining Club GreenSock! I hope the tools serve you well. Let us know if you need anything else. Happy tweening!
  16. Yeah, here's what I whipped together for if I end up switching: let shuffle = a => { for (let j, v, i = a.length; i; j = ~~(Math.random() * i), v = a[--i], a[i] = a[j], a[j] = v); return a; } Which is still certainly more verbose than: let shuffle = a => a.sort(() => .5 - Math.random()) Again, if anyone has a real-world scenario where that 2nd one doesn't deliver desirable results in an animation context, I'd love to see it.
  17. This isn't really a GSAP issue, but I love challenges like this... The problem is that you're calculating things based on the global coordinate system which is what getBoundingClientRect() uses, but your elements are nested inside of a transformed parent, so it throws all those measurements off. For example, if getBoundingClientRect() shows that the elements are 100px away from each other, but they're inside a container that's scaled to 0.5, they're actually 200px away from each other according to their local coordinate system. When you start nesting things in DIFFERENT parents, it gets even more complex. I'm not aware of any other tool out there that does these calculations for you...but I have good news. There's a secret MotionPathPlugin.getGlobalMatrix() method that's like magic for situations like this. I whipped together a function that you can feed two elements to and it'll spit back the gap according to the fromElement's parent coordinate space (which is what you need in order to move it correctly). Here's a fork of your codepen: https://codepen.io/GreenSock/pen/dyPaRRw?editors=0010 In your demo, try nesting the "drag me" element in a completely different element, and transform things in funky ways - it should still perfectly line up their top left corners when you release. ? And here's another codepen that shows a bunch of nested elements with various transforms and we're able to pin the red dot on the top left corner of the inner-most element: https://codepen.io/GreenSock/pen/65112f4c320a2175d043cc626e6479d8 I hope that helps!
  18. Well as @PointC mentions above you can use ScrollMagic, he actually wrote a guest article (tutorial) on it which can be found here. But ScrollMagic appears behind regarding support for IntersectionObserver and GSAP 3 as seen in these few examples. https://github.com/janpaepke/ScrollMagic/pull/920 — GSAP 3 https://github.com/janpaepke/ScrollMagic/issues/918 — GSAP 3 https://github.com/janpaepke/ScrollMagic/issues/751 — IntersectionObserver Alternatively there is scrollama which does use IntersectionObserver. It is quite similar to ScrollMagic and continues to recieve updates. I have not tested it yet with GSAP 3, so do let us know how that goes if you (or anyone else) do so. I’m slightly surprised @GreenSock hasn’t just made one of his infamous and clever ’whipped up” helper functions leveraging IntersectionObserver for passing in GSAP timelines or tweens. So the staff can stop saying "ScrollMagic is not a GSAP product" here on the forum and that it might not be the best option (ha, ha), instead just point all references to that in house approach. ? You can also simply use vanilla IntersectionObserver on your own without the need for a library, you will find plenty of examples here within the forum.
  19. I whipped together an effect that you can reuse in GSAP 3 and it's totally configurable: https://codepen.io/GreenSock/pen/JjjqMYX?editors=0010 Here's the effect (you just copy this once into your project and then use it as much as you want): gsap.registerEffect({ name: "curveBetween", effect: (targets, config) => { let gap = (element1, element2) => { //returns the x/y gap between element1 and element2 in terms of viewport pixels. let b1 = gsap.utils.toArray(element1)[0].getBoundingClientRect(), b2 = gsap.utils.toArray(element2)[0].getBoundingClientRect(); return {x: b2.left - b1.left, y:b2.top - b1.top}; }, curveBetween = (elementToAnimate, fromElement, toElement) => { let startGap = gap(elementToAnimate, fromElement), endGap = gap(fromElement, toElement), startX = startGap.x + gsap.getProperty(elementToAnimate, "x"), startY = startGap.y + gsap.getProperty(elementToAnimate, "y"), angle = Math.atan2(endGap.y, endGap.x) + Math.PI / 2, lengthFactor = Math.sqrt(endGap.x * endGap.x + endGap.y * endGap.y) / 2 * config.strength; return gsap.fromTo(elementToAnimate, { x: startX, y: startY }, { motionPath: [{ x: (startX + endGap.x / 2) + Math.cos(angle) * lengthFactor, y: (startY + endGap.y / 2) + Math.sin(angle) * lengthFactor }, { x: startX + endGap.x, y: startY + endGap.y }], duration: config.duration, onComplete: config.onComplete, immediateRender: config.immediateRender, delay: config.delay, ease: config.ease }); }, tl = gsap.timeline(); targets.forEach(target => tl.add(curveBetween(target, config.from, config.to), 0)); return tl; }, plugins: "motionPath", defaults: { duration: 2, strength: 1, delay:0 } }); And then to use it, you'd do something like this: gsap.effects.curveBetween("#rect-2", { from: "#rect-1", to: "#rect-3", delay: 1, strength: 1 // strength can be a negative number to make it curve in the opposite direction! }); If you want it to curve out more, increase the strength value. Make it negative if you want it to go the other direction. Is this what you're looking for?
  20. Hi @Exhumator, If you want to generate a random number that isn't the same as the last one, take this snippet whipped by @GreenSock* https://codepen.io/mikeK/pen/jjZYbN *https://greensock.com/forums/topic/20151-morph-cycle-between-array-of-paths Happy tweening ... Mikel
  21. I like the SteppedEase approach, but if you really need to limit the entire update of a tween to a certain FPS, you could do something like this: https://codepen.io/GreenSock/pen/2b4554531b20a9876dac381beea741e2 Here's the utility function I whipped together, so you can just pass a tween/timeline instance in, along with the desired FPS, and it'll do it all for you: function throttleAnimation(animation, fps) { var ticker = TweenLite.ticker, time = ticker.time, frameLength = 1 / fps, frame = 0, update = function() { var newTime = ticker.time - time, newFrame = ~~(newTime / frameLength); if (frame !== newFrame) { frame = newFrame; animation.time(newTime); if (animation.progress() === 1) { ticker.removeEventListener("tick", update); } } }; animation.pause(); ticker.addEventListener("tick", update); } Does that help?
  22. Here's a helper function I whipped up that'll spit back the appropriate index number: function findPositionIndex(elements, x, y) { if (typeof(elements) === "string") { elements = document.querySelectorAll(elements); } var max = -Infinity, cols = 0, l = elements.length, factors = {center:0.5, bottom:1, right:1}, rows; while (max < (max = elements[cols++].getBoundingClientRect().left) && cols < l) { } cols--; rows = (l / cols) | 0; return Math.floor((factors[y] || 0) * rows) * cols + (Math.floor((factors[x] || 0) * cols + 0.5) || 1) - 1; } So you'd use it like this: tl.staggerTo(".box", 1, { scale:0.1, stagger: { amount:1.5, grid:"auto", from:findPositionIndex(".box", "center", "top") } }); Here's a codepen: https://codepen.io/GreenSock/pen/BegYXV?editors=0010 Does that help?
  23. Just so you know, you can use any of the bonus plugins on codepen for free. We created special trial versions which are all listed here: https://codepen.io/GreenSock/full/OPqpRJ/ I whipped together a helper function that'll simply invert an ease for you. Just feed in the ease and it'll spit back a new one that's inverted: https://codepen.io/GreenSock/pen/rgROxY?editors=0010 Here's the function: //feed in an ease and get back a new inverted version of it. function invertEase(ease) { if (typeof(ease) === "string") { ease = CustomEase.get(ease); } return function(p) { return 1 - ease.getRatio(1 - p); }; } Does that help?
  24. The jump is completely normal because of the way transforms work (totally unrelated to GSAP). If you scale something from its bottom left corner, it ends up at a completely different place than if you scale it from its upper right corner. If you want to change it dynamically without the jump, you'd need to compensate its translation (x/y). Here's a fork of your codepen that uses a function I whipped together for that purpose: https://codepen.io/GreenSock/pen/ffd4d338f911617756aa1daaa96d8c5d?editors=0010 The function is: function smoothOriginChange(element, transformOrigin) { if (typeof(element) === "string") { element = document.querySelector(element); } var before = element.getBoundingClientRect(); element.style.transformOrigin = transformOrigin; var after = element.getBoundingClientRect(); TweenLite.set(element, {x:"+=" + (before.left - after.left), y:"+=" + (before.top - after.top)}); } Does that help?
  25. Hi @H0BB5, Look at this post - maybe a stimulus. There is a so called 'whipped together helper function': just wiggle a path Kind regards Mikel
×
×
  • Create New...