Jump to content


  • Posts

  • Joined

  • Last visited

Everything posted by jh3y

  1. Thanks for sharing them @Shrug ¯\_(ツ)_/¯ 🙏 Yeah, if I were doing a "Click to spin", I think I'd have already built it and moved on haha. But, the issue here was more about syncing with Draggable and Inertia. I want people to be able to grab and spin the wheel. It's an additional mechanic to the demo I'm presenting.
  2. Thanks for the replies people! 🤙 Sorry if I wasn't clear @Rodrigo, I had an idea about what I was going to do for the Draggable part. It was animating the little ticker part so it syncs up with the inertia of the wheel I hadn't attempted in my head yet 😅 @Cassiehas come in with an awesome starting point! 🙏 That's pretty much there. I guess it'll just be a case of fiddling with the keyframes/timing of the ticker so I can almost scrub the ticking/clicking. It won't have to be super accurate for the demo I'm presenting. But, I'm always curious how close we can get with these things or what crafty techniques come out of exploring. – Jhey \ʕ •ᴥ•ʔ/
  3. Hey y'all! 👋 I've tried digging around in the forums a bit for kinda what I'm looking for but some of the threads are pretty old and I'm wondering if there's maybe a newer/easier way to achieve this effect. What I'm looking to do is create a spinning wheel that will land on a section with maybe some bounce back. My first thoughts are GSAP Draggable with rotation type and inertia which will get me most of the way. But, it's that little ticker piece at the top. How would you think to approach that? And potentially have it push back when the acceleration is slowing down from the inertia? Is it purely a case of tapping into the callbacks and trying to work it out based on the state of the Draggable? And could you somehow sync a repeating animation of the ticker to sync with the acceleration of the Draggable? I'm just sort of putting it out there. I haven't sat down to properly put something together yet. Attached is a very rudimentary CodePen with Draggable and Inertia in place. But, these were the first ideas that came to mind for approaching it. And there may be a much cleverer way of achieving it. Thanks for all you're doing! – Jhey ʕ •ᴥ•ʔ
  4. Update:: Got it working how I wanted 🙌 https://codepen.io/jh3y/pen/PoyEGwE
  5. You know what? I think that's all it needed, an `immediateRender` in the `fromTo`. Then you can change things however you like. I had my `immediateRender` in the wrong place d'uh 🤦‍♂️ Thanks Carl! 🤙 A little further up in the code I log the loop times in an Array to use by counting the `index` so should be good on that part 🤞 See if I can actually build the rest of the demo now 😬
  6. Hey y'all! 👋 Got an odd one. I could be missing something straightforward. But, in this pen, I'm animating a set of squares on a trail on a canvas. I want to create a seamless loop so I've constructed the timeline by looping over the squares three times and then tweening the `totalTime`. In the code, It currently tweens from `totalTime: 0` to `totalTime: 7` and the entire timeline is shown as expected. But, as soon as I tweak the `totalTime` values, mainly the starting value, it breaks the animation window that I'd expect to see 🤔 Not sure if I'm missing something clear and obvious. But, the technique should work in this scenario I imagine. The looping code is at the bottom, try changing the initial `totalTime` to something like `1` and it doesn't show the `TRAIL` timeline window of `1` to `7`. Are my timings off? Or, do I perhaps need to do something different when working with plain Objects like this? Thanks in advance! – Jhey const TRAIL_LOOP = gsap.fromTo( TRAIL, { totalTime: 0 }, { totalTime: 7, repeat: -1, ease: 'none', duration: 6, } )
  7. Howdy y'all! 👋 Had a comment on CSS Tricks today about the article for this technique: https://css-tricks.com/going-meta-gsap-the-quest-for-perfect-infinite-scrolling/ Has something changed dramatically between versions to introduce these breaks? Or is there a property I need to update or add potentially? The other solution I could see is pinning the GSAP version in all the demos for that article to ~3.7.0 I think 🤔
  8. Yeah, I _think_ we mean the same thing 😅 My terminology may be slightly off but I'm pretty sure we are on the same frequency there ✨ Thanks Jack! ✨ ʕ •ᴥ•ʔ/
  9. Hey Jack 👋 Sorry – I've taken a couple of days off before starting a new role this coming week. That solution is super clear and I love it! It's a great spin on the article too for showing learning process and how we've got to this solution. Kinda like the "Meta GSAP" article (Which could totally be redone with Observer now, right? Awesome!) I really like this solution because of it's simplicity. If I were to put another element such as a custom drag handle, and use Draggable for that bound to the input like I had originally, it would update the value and the Inertia would be triggered too, right? I think that's correct. I may have not worded it right but I'm pretty sure that works too, haha. Can't wait to finish off the article! \ʕ •ᴥ•ʔ/ Thanks again for everything!
  10. This makes perfect sense. I'll get that other demo fixed up to use the new API too ✨ Thanks! \ʕ •ᴥ•ʔ/
  11. That was a seamless switch 🙌
  12. And that won't be removed? Also, "that" demo could be converted to use this API? Rad! I'll share today.
  13. This is great! And perfect timing 😅 And will be great for the article too! I could totally make this into an "Observe" demo. I'm assuming this is the tool that has been "renamed" from something else that I may have made a demo for? Thanks Jack! 🙏 \ʕ •ᴥ•ʔ/
  14. Oh wow. That is much smaller. And I like that wrapYoyo! TIL. The only issues I see here are: - I want to plug into the "collision" so I can play a noise and bump the input itself from left to right based on the velocity too. Can you detect when a wrap happens inside "onUpdate"? - If I click the track, it applies the velocity which I wouldn't necessarily want as I want that to only happen after a "drag". With this original demo, it has the "correct" behavior. But, it has the drawback of me trying to keep that element in sync with the slider thumb. I was thinking with the "Draggable" way, I'd be able to easily keep a "faux" thumb in place by updating it's position based on the input value. But, that isn't an important part here. Just something I was thinking of doing. Thanks for teaching me something new! Again! 🙏 The best part being that I've kinda written an article using Draggable. But, it's kinda cool that I can steer it in a different direction. I love mentioning the forum powers! Jhey ʕ •ᴥ•ʔ
  15. UPDATE:: I've recreated the demo with the way I'm trying to create it without React so it's less hassle working out what's going on 😅 But yeah, if you swing it hard one way it will only bounce once like the velocity can't update quick enough. Hoping it's an "easy" solution 🙏 https://codepen.io/jh3y/pen/GRyEeYp/07ca6efd5c422ec124855582d1f82e80
  16. Hey y'all! 👋 I've been playing with this demo some more and attempting to create it without a "proxy" element in the DOM. It works for the "most" part but the velocity seems a little off with the Inertia compared to the one above. But, that's not the main issue I'm encountering. The issue is calculating the bounce back based on the value of the input. If I animate the value of the input or drag it so that it should bounce, it gets stuck on the end as if other tweens are hanging on if that makes sense? It's like it can't keep up with itself or the tracker velocity is hanging. For example, if you bounce it off one end where you expect it to bounce off the other, it hangs. Any ideas @OSUblake && @GreenSock https://codepen.io/jh3y/pen/abEWPOo Look forward to seeing what you think on this one. Could it be the way I'm using the `inertia`? Previously, this was set on `x` because I was moving an element. Would I instead need to map this to the input values perhaps? Jhey ʕ •ᴥ•ʔ
  17. Hey y'all! 👋 Looks like `startDrag` was the piece of magic I was looking for 🙌 Thanks for sharing that one. I think this solves the issue of trying to align the slider proxy handle with the slider thumb because wherever you click, it will align, which is perfect ✨ Happy to be here! Thank you for both of your inputs. Love learning new parts of the API to solve these little challenges 💚 TIL "startDrag" 💪 Now I can start writing this one up 😅 Thanks again! \ʕ •ᴥ•ʔ/
  18. Hey y'all! I've been thinking to write something up about this demo. But, I feel like there's a more robust way for me to handle dragging on the input regardless of where the slider thumb is 🤔 I've tried putting in place a "Proxy" element (.slider__proxy) and I'm updating based on that. However, if you were to click the track somewhere away from the thumb, would it be possible to somehow trigger "drag" mode and move the slider thumb and proxy into place? I feel like I'm overcomplicating it somewhat seeing as a range input already has a drag handle kinda built in. But yeah, I was keen to know if there was a better approach to what I've done with it. Jhey ʕ •ᴥ•ʔ
  19. Hey! Actually, this solution makes a lot more sense. Thank you. I wanted to cover it for the demo/article and updating in the `inputs` callback would fit better I think 🙏 Thanks! \ʕ •ᴥ•ʔ/
  20. Hey y'all! ✨ Thank you @Cassie 🙏 One more query on this demo 😁 I've got it pretty much there where I want it. There's one thing I can't seem to make work nicely. It's setting `aria-hidden` on the numbers as they slide in and out 🤔 I've been trying this but it is a little inconsistent for me. Sometimes it works, sometimes it leaves some with the wrong values. Would it make sense to maybe do this outside of the timeline and work out which digits need the attribute applied when doing the scrub instead? (Maybe I've answered my own question there 😅) const DIGI_TIMELINE = gsap .timeline() .set(DIGIT, { yPercent: 0, attr: { 'aria-hidden': 'true', }, }) .to(DIGIT, { yPercent: 100, delay: i * COEFF, duration: 1, onStart: () => { gsap.set(DIGIT, { attr: { 'aria-hidden': 'false', }, }) }, }) .to(DIGIT, { delay: COEFF - 1, yPercent: 200, duration: 1, clearProps: 'all', onStart: () => { gsap.set(DIGIT, { attr: { 'aria-hidden': 'true', }, }) }, }) Anyways, hope you've all had an awesome weekend. Here's the demo! It's part of a series I'm doing where it's about debunking Instagram Reels/TikTok where someone shows how easy it is to make a design in Figma but it doesn't show the reality on the dev side of making said thing 😅 https://codepen.io/jh3y/pen/XWzmGad ʕ´•ᴥ•`ʔ
  21. Not at all! I love some humble pie ☺️ It's the best way to learn. I'll always take suggestions and discussions. 1. Totally! 💯 Sorry, the code is a little rough and I'd left them in as I was playing with variations trying to get it working with things like `delay: 2` etc. Sorry for that! 2. Ahh yes, that would make sense too. I guess in my head I see each timeline like its own little block/animation component 😅 3. Yes! Love this. Now the position param threw me to start with because I was in a bit of a rush. Without a label it broke and of course I needed `0` 😅. The simplified version is much nicer and again this was kind of my bad, sorry. I'd left it rough as I was playing with different eases for the effect I want. Ahh, I see that `clearProps` usage now and this is much nicer too! 4. This is a rad tip. Kinda shows the magnitude of what GSAP covers because although I've used `progress` in the past, I'd completely forgotten about it haha. Trying to spend more time documenting things I make this year for this reason 😅 Appreciate the kind words massively! I'll keep creating for sure. Love sharing and challenging ha. If I don't hear from you, have a great weekend! \ʕ •ᴥ•ʔ/
  22. Yes!! `progress` was what I was looking for! Thank you for reminding me of that one @OSUblake 🙏 \ʕ •ᴥ•ʔ/
  23. Think I've worked out a way. Needed another timeline to scrub the playhead of `MANIPULATOR`. Then I'm using a `delayedCall` to get the ball rolling ✨ const SCRUB = gsap.to(MANIPULATOR, { totalTime: 0, duration: 0, paused: true, ease: 'none' }) SCRUB.vars.totalTime = 4 SCRUB.invalidate().restart() gsap.delayedCall(2, () => MANIPULATOR.play()) There is likely a cleaner way to do this. The idea being that I'm going to be scrubbing a timeline composed of a few timelines and need to show the current state. I'll keep tinkering 🤓
  24. Hey y'all 👋 Looping through a set of numbers infinitely by tweening `totalTime` on a timeline. But, how do I show the current state while it's `paused`? I'm setting `TL.totalTime(1)` here but nothing shows. Do I need to do something with `immediateRender`? I'm going to be scrubbing this timeline with another control so it will remain paused. I've tried the `invalidate().restart()` manoeuvre but I'm not having much luck... import gsap from 'https://cdn.skypack.dev/gsap' const TL = gsap.timeline({ paused: true, }) const DIGITS = gsap.utils.toArray('.digit') const PADDED_DIGITS = [...DIGITS, DIGITS[0]] for (let i = 0; i < PADDED_DIGITS.length; i++) { const DIGIT = PADDED_DIGITS[i] const DIGI_TIMELINE = gsap.timeline({ paused: false, onComplete: () => gsap.set(DIGIT, { clearProps: true }) }) DIGI_TIMELINE .set(DIGIT, { yPercent: 0, }) .to(DIGIT, { yPercent: 100, delay: i, duration: 1 }) .to(DIGIT, { yPercent: 200, duration: 1 }) TL.add(DIGI_TIMELINE, '- 0.5') } const MANIPULATOR = gsap.timeline({ delay: 2, paused: true, }) .fromTo(TL, { totalTime: 1, }, { totalTime: 11, duration: 4, ease: 'none', repeat: -1, }) TL.totalTime(1) Thanks in advance! Sure I'm missing something obvious. ʕ ᵒ ᴥ ᵒʔ Setting `MANIPULATOR` to `paused: false` plays the timeline as expected. But, I'd like to see the playhead state when it's paused.
  25. Hey Jack @GreenSock Yep, I never assumed it would be recalculating on each replay 😅 It would work similar to other plugins, etc. My timelines were being generated in a function as were my flips 👍 But, that's the part that had tripped me up. The window resizes, I kill the timeline, and regenerate it within a debounced handler. debounce(() => { // Timeline that was generated with a function MAIN.kill() // Clear all the Flip setting of initial positions gsap.set('li', { clearProps: 'all' }) // Set them all again to the new positions of the things to Flip to. setFlips() // Regenerate the timeline. MAIN = genFlips() // ScrollTrigger stuffz window.scrollTo(0, 0) TRIGGER.disable() gsap.delayedCall(1, TRIGGER.enable) }, 250) Storing the progress wouldn't be necessary as ScrollTrigger's refresh would assign the scrub to the correct position on the timeline 👍 But, what was missing was regenerating the loop head for ScrollTrigger to scrub the time. All I needed was to kill the loop head and regenerate it 👍 Fixed. https://codepen.io/jh3y/pen/XWpvyxr