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

Found 117 results

  1. Hi @gunhee and welcome to the GSAP Forums! There is a difference between the page you linked and the codepen demo. The codepen is using an actual 3D animation while it seems that the page is using just a scale on the container. Here is a simple demo I whipped to emulate the URL you posted: https://codepen.io/GreenSock/pen/dyrJKqp Hopefully this helps. Happy Tweening!
  2. Hi everyone, I'm in the middle of a bit of a pickle on a web project I'm working on and could really use your expertise. I've got this website where I'm using SWUP for page transitions, which necessitated me to have my main element position fixed and apply the scrolling behavior directly to it. It works well for the most part, except I'm running into a hiccup with GSAP's ScrollTrigger. Here's the nub of it: the ScrollTrigger's start marker, which I need to stick to the top of the viewport, has a mind of its own. It seems to be taking a leisurely stroll up the screen whenever I scroll, thanks to the inertia from Lenis, before snapping back into place. This isn't quite the behavior I was hoping for—I need that marker to be steadfast at the top, come what may with the scrolling. For a clearer picture, I've whipped up a CodePen to showcase what's happening... I've tried to outsmart it by dynamically recalculating the start position and even attempting to offset it based on Lenis' scroll position, but no dice so far. Does anyone have experience taming this kind of behavior? How can I anchor the ScrollTrigger start marker to the top of the viewport so that it's immune to the whims of Lenis-induced inertia? Any nudge in the right direction would be a lifesaver! Cheers!
  3. There's also a helper function that lets you define exactly how many decimal places you want, and it'll add the commas for you: https://gsap.com/docs/v3/HelperFunctions/helpers/formatNumber I'm not sure why you were applying snapping and also a stagger that had no actual stagger value but just an onUpdate - I think this would be much cleaner: https://codepen.io/GreenSock/pen/JjzjXWx?editors=0010 And actually, I like @Carl's increment functionality, but I think it's important to allow padded decimal values so that things don't appear to get longer/shorter (often it's handy to force a certain number of decimal places and pad the extra spots with 0), so I whipped together this function that'll return a formatting function: function getFormatter(increment, pad) { let snap = gsap.utils.snap(increment), exp = /\B(?=(\d{3})+(?!\d))/g, snapWithCommas = value => (snap(+value) + "").replace(exp, ","), whole = increment % 1 === 0, decimals = whole ? 0 : ((increment + "").split(".")[1] || "0").length; return !pad || whole ? snapWithCommas : value => { let s = snapWithCommas(value), i = s.indexOf("."); ~i || (i = s.length); return s.substr(0, i) + "." + (s.substr(i + 1, s.length - i - 1) + "00000000").substr(0, decimals); }; } Usage: let formatter = getFormatter(0.01, true); // increment by 0.01, always pad so that there are 2 decimal places console.log(formatter(5000.1)); // 5,000.10 Here's a fork with that in place: https://codepen.io/GreenSock/pen/mdodEyW?editors=0010 Have fun!
  4. Hi, You can use GSAP's Clamp utility method to prevent the circle from moving out of the bounds. Here is a super simple demo I whipped: https://codepen.io/GreenSock/pen/VwgqrGm https://gsap.com/docs/v3/GSAP/UtilityMethods/clamp() Hopefully this helps. Happy Tweening!
  5. Here, I enhanced the helper function more and whipped together an example that'll just "play" when the top hits the center of the viewport, and reverses when the bottom hits the center in reverse: https://codepen.io/GreenSock/pen/QWYdgjG?editors=0010 It should make things super easy and configurable. You can even set an fps number in the config. 👍
  6. By the way, I'm not at all familiar with Font Awesome, but I googled and quickly whipped together a simple CodePen that shows that it seems to work fine with animating the color using GSAP: https://codepen.io/GreenSock/pen/rNPxZvp
  7. Hey GSAP Helper! Thanks a bunch for getting back to me! I've whipped up a quick demo of my site using StackBlitz. You can check it out here! Let me know if you can view the code. Going to take a deeper look into gsap.context() as well. Looking forward to hearing your thoughts!
  8. Hi @sunil kumar sorry I don't have time to fix the whole animation, so I've whipped something up quickly to show what working with ScrollTrigger should look like. Your attempt is not wrong, but is overcomplicating things, which means you have to build a lot of functionality your self, which you get for free when working the intended way. First things first. I've add some CSS to your layout to have all the elements stack on top of each other, this is the position I want all the sections to end up. This makes it really easy because I can to a simple .from() tween to animate the sections from some where to this position. https://codepen.io/mvaneijgen/pen/vYQoZXv?editors=0010 The best thing to do when working with ScrollTrigger is to remove it! This seems counter intuitive, but ScrollTrigger is just animating something on scroll, so just focus on the animation at first and only when you're happy with the animation add ScrollTrigger back in. This way you can focus on one part at a time and it will save a lot of headache when debugging. I've created a timeline (instead of having one for each section) for all sections and then I focus on what I want them all to do (again this is not correct at the moment, but it shows you how it could work) https://codepen.io/mvaneijgen/pen/dyQxRNg?editors=0010 If the animation is done that will be the time I enable ScrollTrigger and only then. If at any point something is not 100% working I disable the next step and go back to the previous one, so if the animation is not correct I disable ScrollTrigger and if the layout is not correct I disable GSAP and go back to just CSS. https://codepen.io/mvaneijgen/pen/ZEmgyKK?editors=0010 Some resources, check out this video from the Greensock YouTube channel. It kinda explains what I'm trying to say, but in video form Also check out our own @Carl's stagger video, you will need this if you want to have things happen at the same time And right now everything happens in the .forEach() loop, this is great, but can over complicate things a bit. Personally I like to write things out manually eg. give each section a class with section-1, section-2, ect and write it out manually. because you probably want to first section to be already in view when the animation starts. If you write it out manually, you really get a feel for what things you want to happen and this way you can see patterns emerge which you can optimize to .forEach() loops. Hope it helps and happy tweening!
  9. Hi @No Dead Fish welcome to the forum! Can you give us a bit more. What element needs to be the parent of what element, is there any additional CSS, you use jQuery, any particular version? I've whipped up the following, but I'm just guessing. Sharing your JS is great, but it is just 1/3 of the whole issue. https://codepen.io/mvaneijgen/pen/VwVJNQj?editors=0010
  10. By the way, this is something I whipped up in another thread: https://codepen.io/GreenSock/pen/RwLepdQ (In case it's helpful...but maybe it isn't).
  11. Hi @manast. GSAP animations are far more dynamic than video playback - it's not as simplistic as "play and pause". The playhead can move in all sorts of ways: Obviously normal play()/pause() Set the progress() or totalProgress() Set time() or totalTime() seek() Adjust the timeScale() so it'll play much faster or slower reverse() Adjust any of the above on an animation's PARENT (or any ancestor) which would automatically trickle down to affect the descendants. How would you accommodate all of those? For example, let's say we implemented exactly what you're suggesting so that some kind of callback got fired onPlay() or onPause() or onSeek()... let tween = gsap.to("#id", { x: 1000, onPlay: myPlayFunc, onPause: myPauseFunc, onSeek: mySeekFunc }); But... let tl = gsap.timeline(); tl.add(tween, 1); tl.seek(1.5); // should onSeek() be called on the child even though this happens on the parent? tl.time(1.8); // should onSeek() get called here too? tl.timeScale(3); // uh oh...now the playhead of the video will be totally out of sync tl.pause(); // should the child's onPause() get called even though it's not technically paused but it acts like it only because the parent's playhead is paused? tl.reverse(); // playback is resumed, but it's going backwards so would the child's onPlay() get called? If you're playing the video as a result, obviously the playhead will be going the opposite direction Or even more confusingly, what if someone does this?: tween.pause(); // obviously fires the onPause() // now tween the playhead with another tween such that functionally it appears to be playing even though it is paused gsap.to(tween, { time: tween.duration(), duration: tween.duration(), ease: "none" }); As a convenience, I just whipped up this helper function for you: function mediaTimeline(media, config) { typeof(media) === "string" && (media = document.querySelector(media)); let duration = media.duration, onUpdate = config && config.onUpdate, tl = gsap.timeline({ paused: true, onUpdate() { if (tl.paused() || Math.abs(tl.time() * duration - media.currentTime) > 0.5) { media.currentTime = tl.time() * duration; } onUpdate && onUpdate.call(tl); } }), updateDuration = () => { duration = media.duration; tl.timeScale(1 / duration); }, pause = tl.pause, play = tl.play; tl.set({}, {}, 1); media.addEventListener("durationchange", updateDuration); updateDuration(); media.onplay = () => tl.play(); media.onpause = () => tl.pause(); media.ontimeupdate = () => { tl.time(media.currentTime / duration, true); } tl.pause = function() { media.pause(); pause.apply(tl, arguments); }; tl.play = function() { media.play(); play.apply(tl, arguments); if (arguments.length) { media.currentTime = arguments[0]; } } tl.media = media; return tl; } Just feed in a media element and it'll return a timeline that's properly linked up with that media so that if you pause/play the timeline, it'll handle doing that to the media too. And if you play/pause the media, it'll handle the timeline too. The timeline is 1 second long and you should always populate it accordingly (so that your animations are placed such that they end on or before 1 second) so that: You don't have to wait for the media to load its meta data before being able to populate the timeline with animations in the proper ratios You can just build all your animations with the proper ratios and no matter what the duration is, everything will stretch/squish to play proportionally. It'll dynamically adjust the timeScale() of the timeline according to the media's duration (when it's loaded). So if your media is 10 seconds long, it'll play at a timeScale() of 1/10 (0.1). Here's a simple demo: https://codepen.io/GreenSock/pen/xxQrGBY?editors=0010 I hope that helps!
  12. That's because when you convertToPaths(), it must literally create a whole new element for each <circle> and swap it into the DOM. So you were setting up all your animations to target the original <circle> elements...and then swapping all those out of the DOM for new elements which aren't animated. So all you'd need to do is call the convertToPaths() BEFORE you create all your animations. That being said, I don't think you need to do any morphing at all since the shape you're "morphing" to is also a circle, thus you could simplify things by just scaling/moving the elements. If you morph, you'll need to adjust for the movement you're doing on the motionPath since the morphing just animates the raw coordinates but you're moving the elements, so they wouldn't be aligned anymore. It's totally fixable, of course, but I just think morphing is a waste of time here. I noticed your paths don't converge on the same spot either. You should probably fix your SVG artwork to resolve that. There's also a helper function I whipped together to make it possible to keep elements in the viewport as you're scrolling down. Normally we don't do this type of custom development in these forums for free, but I was curious and liked the challenge so I did it as a courtesy: https://codepen.io/GreenSock/pen/YzRGaMa?editors=0010 Hopefully something in there is helpful and gets you headed in the right direction. Have fun! And thanks for being a Club GreenSock member. ?
  13. Here's a helper function I whipped together for handling lazy loading stuff: function handleLazyLoad(config={}) { let lazyImages = gsap.utils.toArray("img[loading='lazy']"), timeout = gsap.delayedCall(config.timeout || 1, ScrollTrigger.refresh).pause(), lazyMode = config.lazy !== false, imgLoaded = lazyImages.length, onImgLoad = () => lazyMode ? timeout.restart(true) : --imgLoaded || ScrollTrigger.refresh(); lazyImages.forEach((img, i) => { lazyMode || (img.loading = "eager"); img.naturalWidth ? onImgLoad() : img.addEventListener("load", onImgLoad); }); } // usage: you can optionally set lazy to false to change all images to load="eager". timeout is how many seconds it throttles the loading events that call ScrollTrigger.refresh() handleLazyLoad({ lazy: false, timeout: 1 }); Basically you just call the method and it'll manage calling ScrollTrigger.refresh() for you at the appropriate time. You can optionally pass in a config object to set everything to NOT be lazy (lazy: false) and you can also control how long it waits after each image loads to call ScrollTrigger.refresh(). For example, if 5 images load in quick succession, you shouldn't need to call ScrollTrigger.refresh() 5 times. By default, it waits 1 second to see if another one loads. If another one does, it starts the timer over again...so when 1 second elapses when no more images have loaded, it'll fire ScrollTrigger.refresh(). That improves performance. But again, I recommend not doing lazy loading. I definitely would not use that function you wrote - it's extremely inefficient. Literally on every single scroll event (those fire a LOT during scroll), it is doing CPU-intensive calculations to map all the position of every image. The function I provided above is many, many times more efficient.
  14. Welcome, @wzrdKB Having things wrap around the other side like that is actually pretty tricky to pull off due to logic stuff. We whipped together a helper function in the docs that should make it a whole lot easier: https://greensock.com/docs/v3/HelperFunctions#loop Good luck!
  15. That looks to me like you could just pin the container <div> and then animate the rotation of its child and make the transformOrigin pretty low. We don't normally do this kind of thing (it's well beyond the scope of help we can provide in these forums), but I was curious so I whipped together a very quick demo that might help get you moving in the right direction: https://codepen.io/GreenSock/pen/WNaxQLg?editors=0010 I hope that's useful. If you've got any GSAP-specific questions, we're happy to help with those.
  16. I think you might be over-engineering there. Normally we don't craft custom solutions like this in these free forums, but I was curious so I whipped together a different approach you could take: https://codepen.io/GreenSock/pen/jOvgrMG?editors=1010 Hopefully it at least gets you going in the right direction.
  17. calc() values like that aren't supported in transforms because GSAP already has to normalize a bunch of stuff for you, break apart each component, etc. and you can't really interpolate between string values like "50px" and "calc(100% - 100px)" because the structure of the data is totally different. There are multiple ways to do what you're asking, but I suspect there's a much cleaner/better way to approach this. Can you explain why you're using a calc() value here? Once I understand your goal (and why you wouldn't use a normal value), I'll be able to offer better advice. Here's a demo with a helper function I whipped together: https://codepen.io/GreenSock/pen/NWLLVyW?editors=0010 But again, I strongly suspect there will be a better, cleaner solution once I hear the "why" behind your calculated value. I already have some other ideas that I'd reach for instead of that helper function in most cases. A minimal demo (like a CodePen) will go a LONG way toward getting you a substantive, accurate answer.
  18. Hi @PStemper. It sounds like you must be using a super old version of GSAP (GSAP 3+ doesn't use matrix values). Do you have a minimal demo that illustrates the problem you're facing? Just something very simple - a draggable <div> or something(?) Here's a quick one I whipped together that shows how simple it is to get the x/y. https://codepen.io/GreenSock/pen/jOvKBQW?editors=0010 Also, keep in mind that... The x/y values ARE transforms. They are baked into the matrix. So you can't just remove the transforms and get the x/y. Think of the x, y, scaleX, scaleY, rotation (and all transforms) are baked into the matrix()/matrix3d(). The Draggable instance itself has "x" and "y" properties you can read You can use gsap.getProperty() anytime to get the x or y or any property of a particular element. Even if there was a matrix applied. Does that help?
  19. I don't know of anything out of the box. It's kind of a complicated question because scroll implementations vary by browsers and the feature sets are not completely unified. Not to mention that it can be annoyingly difficult to work with scroll in the first place. In the infinite scroll / trackpad scenario, I assume that once the user has stopped their physical motion, the velocity of the page scroll will always decrease. Therefore, we know if a new scroll has been initiated if the velocity of the page on the current tick is greater than on the previous tick. For every tick, or in our case in onChange, we compare the current velocity to the previous velocity and then save it for the next tick. I roughly tried this, and the issue I ran into was that there is an acceleration period for trackpads. It takes several ticks to reach maximum velocity. This causes the system to detect a new scroll multiple times for a single scroll. In the ideal solution, we would observe for velocity increases and then start watching for a decrease to know that the interaction was completed. In a less ideal solution I whipped together just now; we can instead see if the animation is playing and only say there is a new scroll if that is the case. onChange: function(self) { if (animating) return; const currVel = Math.abs(self.velocityY) if (prevVel < currVel) { newScroll = true; console.log(prevVel, currVel, "new scroll"); } prevVel = currVel; }, onDown: () => !animating && newScroll && gotoSection(currentIndex - 1, -1), onUp: () => !animating && newScroll && gotoSection(currentIndex + 1, 1), This works all right compared to the ideal. Not sure how much better you can get with it. I'd figure out the ideal but it's quite a bit of work and might be funky on various devices. https://codepen.io/StevenStavrakis/pen/XWPVMvw
  20. Here's a plugin I whipped together for you that lets you animate scaleZ in GSAP 3: gsap.registerPlugin({ name: "scaleZ", priority: -1, // make it run last so that the other transforms are already applied init(target, value) { target._gsap || gsap.set(target, {x: "+=0"}); // force creation let cache = this.cache = target._gsap; if (!("scaleZ" in cache)) { cache.scaleZ = 1; let oldRender = cache.renderTransform; cache.renderTransform = (ratio, data) => { oldRender(ratio, data); // takes care of everything except scaleZ() target.style.transform += " scaleZ(" + data.scaleZ + ")"; } } this.add(cache, "scaleZ", cache.scaleZ, value); this._props.push("scaleZ"); }, render(ratio, data) { let pt = data._pt; while (pt) { pt.r(ratio, pt.d); pt = pt._next; } data.cache.renderTransform(ratio, data.cache); } }); And here it is in action: https://codepen.io/GreenSock/pen/KKxzjJX?editors=0010 That way, you just load that plugin once and it works with all your tweens without needing to add any onUpdates or anything. Does that help?
  21. Revisiting this old thread to share a fancy helper function I whipped together that simplifies a lot of this and even makes it draggable/spinnable with inertia (disclaimer: InertiaPlugin requires a Club GreenSock membership): https://codepen.io/GreenSock/pen/JjZdPWj?editors=0010
  22. I'm not sure why you're loading a SUPER old version of the files (in addition to a more recent version) and you had invalid markup and a few other odd things in there, but maybe this is what you meant?: https://codepen.io/GreenSock/pen/bGKbLEm?editors=0010 We don't typically provide "build-to-order" solutions, but this was pretty straightforward so I just whipped it together for you. I hope it helps.
  23. I whipped together a shuffle function for you that uses Flip and staggers things: https://codepen.io/GreenSock/pen/VwxXKPB?editors=0010 I hope that helps.
  24. Here's a fork with a helper function I whipped together that should make this easier: https://codepen.io/GreenSock/pen/bGMLGJb?editors=0010
  25. I couldn't help myself - I whipped together a helper function that'll draw a pie chart piece with a bunch of animatable properties like startAngle, endAngle, radius, cx, cy: https://codepen.io/GreenSock/pen/eYMRGJo?editors=0010 You should be able to wire that up to ScrollTrigger quite easily. If you get stuck, just post a minimal demo. I hope that helps.
×
×
  • Create New...