Jump to content
Search Community

ashthornton

Members
  • Posts

    16
  • Joined

  • Last visited

Posts posted by ashthornton

  1. 21 minutes ago, GreenSock said:

    I didn't quite follow that - are you saying that listening to "scroll" events and responding on requestAnimationFrame() actually causes lag somehow? Got any demos or other data that'd illustrate that? And does ASScroll do something special to accommodate it? 

     

    I meant that using window.scrollY/pageYOffset to set positions of objects in WebGL causes a lag between DOM and WebGL position.

     

    I've just replaced ASScroll with your smooth scroll implementation on my basic DOM/WebGL sync demo and it does seem to work perfectly fine without any lag. And having looked through the ScrollTrigger source code, it does seem to end up just using window.pageYOffset. This is interesting! Codepen here: 

    See the Pen 874833fdebc032bedd0cf61e9eac3ee9 by ashthornton (@ashthornton) on CodePen

     

    The idea behind performant smooth scroll has always been to create a 'virtual scroll' using the wheel delta to set the scroll position, since reading window.pageYOffset causes the browser to layout so its an expensive property to access in a requestAnimationFrame loop and then translate an element based on that.

     

    Looks like I have some investigating to do :) 

    • Like 1
  2. Hey, I'm the author of ASScroll so just thought I'd chime in here :)

     

    Just for clarification - the iframe issue is that once your mouse enters an iframe, the `wheel` event on the parent window stops firing since it's not linked to any sort of overscroll behaviour. It won't fire until your mouse leaves the iframe again, which is problematic especially on trackpads since the mouse will sort of stay in the same position as you try and continue to scroll past with two fingers.

     

    The reason ASScroll works in those edge cases like when hovering over an iframe or using the middle mouse button to scroll, is the same reason the GSAP smooth scroll implementation also works (as far as I can see).

     

    The GSAP version looks like it listens to the `scroll` window event and updates the transform accordingly. I would say that it exclusively listens to this event since I can see the native scrollbar matching the smoothed scroll position exactly, but I can also see some `wheel` events so it may be using a combination, like ASScroll.

     

    Using the native scroll position like this means that you're just extending the scroll functionality rather than overriding it, which is what the other smooth scroll libraries do, like Locomotive and smooth-scrollbar. They exclusively listen to the `wheel` event, so they need to essentially rebuild the entire native scroll functionality again. This means they use arbitrary values for when they manually recreate keyboard scrolling (arrow keys, pg up/down, home/end etc.) which won't match the scroll speed the user has defined in their OS - this also introduces a whole host of issues like now having to deal with keypresses when in an input field, for example. And they will never be able to deal with the iframe issue unless they also listen to the `scroll` event.

     

    So I think the difference between the GSAP smooth scroll implementation and ASScroll, is that ASScroll uses a hybrid setup - `wheel` if its available to provide the high-performance 'virtual scroll' setup, and `scroll` if `wheel` isn't available for whatever reason - like keyboard navigation, hovering an iframe, using a screen reader etc.

     

    I'd be curious to see how the GSAP version handles syncing DOM with WebGL for example, which nowadays is the primary requirement for having to use 'virtual scroll' since listening to `window.scrollY/pageYOffset` causes lag between the two.

    • Like 4
    • Thanks 1
  3. Thanks for taking the time to explain that @GreenSock, it definitely makes sense and I've now got a nice setup that allows me to create page entrance animations utilising ScrollTrigger.

     

    Really appreciate the whole library and you catering for us scroll-jackers ;) And on that, thanks for featuring my library in the docs! I know you made ScrollTrigger to avoid scroll-jacking, I similarly made ASScroll to fix the issues in every smooth scroll lib I've seen, they all seem to unnecessarily take over native functionality even down to manually mapping keyboard buttons to scroll, so I appreciate every bit of exposure for it :)

    • Thanks 1
  4. Ok I've updated that Codepen with a reduced example to make sure we're seeing the same thing. So in its current state, the h1s all turn red immediately. Do you also get the same result?

     

    All the h1s turn red immediately when using the singular .to tween. Even though the ScrollTrigger instance is disabled immediately after creation and enabled 2 seconds later in the .delayedCall. This is the unexpected behaviour as it's not waiting 2 seconds to enable.

     

    But if you disable the singular .to tween and enable the .timeline the h1s turn red after the set 2 seconds. This is the expected behaviour.

     

    Interestingly, with the singular tween enabled all h1s that are visible in the viewport immediately turn red, but if you scroll down before the 2 seconds you'll see they are still black and then turn red after the 2 second delay.

    • Like 1
  5. 31 minutes ago, GreenSock said:

    Can you elaborate? I have a feeling I may be misunderstanding, but one of the main purposes of applying a ScrollTrigger to an animation is so that the ScrollTrigger would control the animation (play, pause, scrub, whatever). It automatically pauses it initially. So why would it matter if you also paused it first? Like...how exactly are you wanting it to behave in an ideal world? If ScrollTrigger sees that you pause the tween on the outside, you want it to refuse to play/restart/scrub/whatever? It'd need to "watch" the tween to sense when you call play() and then...take control in which case it may or may not actually play depending on the scroll position? If so, that seems pretty odd to me (to call play() on an animation and it refuses to play). 

     

    My comment really was in response to the solution that ZachSaucier posted as I found it contradictory that you'd need to create a timeline that pauses itself as soon as it starts playing. It seemed that was the only way which was strange, hence the feedback, but having looked at your demo code I realised I must've been targeting the wrong thing/tween reference or something, I can't remember now! Disabling the scrollTrigger instance immediately after creation and enabling again later works.

     

    Thanks for clarifying!

    • Like 2
  6. I've had a look around to see if anyone else has asked about this but couldn't find anything in the sea of ScrollTrigger questions recently!

     

    Basically I want to know if there's a way to set up tweens for a page which have ScrollTrigger attached, but have the ScrollTrigger disabled/inactive until I say so.

     

    For example, when you're loading a page you'd build all your tweens, but you'd have a page loader/transition covering the page. Meaning the trigger elements are technically in view but you don't want them to trigger the tween until you've finished the loader/transition and hit go.

     

    I can't find anything in the docs apart from the enable/disable functions on a ScrollTrigger instance, but this doesn't seem to work, even if the tweens are paused before I run .enable().

  7. I've noticed that you'd of course have to specify a custom scroller property for every scrollTrigger you create and for typical virtual scroll setups that would be the same element each time. Is there a way to override that globally? If not I think that'd be super helpful in this scenario. It can then be overridden at the lower level when needed, and you'd update the global element again if navigating via PJAX for example.

  8. Setting it to 240 removes the throttle on my 144hz display but of course people with 240hz+ might see stuttering. To be honest, beyond 240 it just gets a bit ridiculous and I'm not even sure if the stutter would be visible when throttling from say 360hz (which was recently announced) down to 240.

     

    I think 240 is a good compromise :)

     

    All of this pushing crazy refresh rate numbers has me thinking

     

    images?q=tbn:ANd9GcSMAqyijf5JbuHBS5sCUjg

    • Like 1
    • Haha 1
  9. 1 hour ago, GreenSock said:
    1. GSAP is built on top of requestAnimationFrame by default and most browsers max out at dispatching those events 60 times per second. It's not a limitation that GSAP imposes. Most people can't even perceive more than 60fps. I'd hardly call 60fps "janky" :) 

     

    60fps definitely isn't janky and even on a 60hz+ refresh rate screen it looks smooth, i.e. when watching 60fps videos/gaming but it seems that GSAP's attempt to throttle to a maximum of 60 even though the browser might be able to go higher definitely causes a stutter that you wouldn't normally see.

     

    1 hour ago, GreenSock said:
    1.  GSAP v2 used exactly the same logic - I'm not sure why you think v2 was somehow better.  

     

    Not exactly, as far as I can see:

     

    Here in v2 https://github.com/greensock/GSAP/blob/2.1.3/src/uncompressed/TweenMax.js#L6479

     

    If _fps hasn't been set, which it isn't by default, it allows the next tick to be dispatched as soon as browser RAF is fired - bypassing any check of a negative overlap that might be caused by _gap

     

    Here in v3 https://github.com/greensock/GSAP/blob/master/src/gsap-core.js#L857

     

    That _fps check is removed so it relies solely on whether there is a negative overlap or not. Which does happen when RAF has fired more than once in 1/60 seconds.

     

    On a 60+hz display if you log out overlap you'll see negative values which will cause the conditional to be skipped and the internal event to not be dispatched.

     

    So setting _fps to -1 forces a positive overlap every time and we get an un-throttled loop.

     

    Hopefully that all makes sense and I've read the code right. If it does then you can see why setting fps to 120 or 144 would also remove the throttle but the reason I won't do that is because there are already higher refresh rate screens out there and I don't want to limit those.

     

    I can set up a reduced demo if you'd like but it'd just be a square translating across the screen or something then enabling and disabling gsap.ticker.fps(-1) on v3, then the same on v2 without any special config.

     

    Of course you need a screen with a refresh rate higher than 60hz to see any of this!

  10. On 1/21/2020 at 10:57 PM, GreenSock said:

    GSAP is time resolution-independent, meaning it calculates the values based on the exact time of the update. It does NOT assume that you'll run at 60fps and pre-calculate values or anything like that. With some animation engines, if your framerate slows down to 30fps, for example, when it was assuming you'd run at 60fps, all your animations end up taking twice as long (bad). Not GSAP. Even if your frame rate drops substantially (or increases), it'll always render the values where they're supposed to be based on the overall time, not FPS. It also has some advanced features like lag smoothing that are automatically enabled to heal from CPU spikes. And the timing mechanisms are identical in v2 and v3. 

     

    Does that answer your questions? 

     

    I'm really struggling to understand why you noticed a difference in v2 vs v3 but nobody else can and the only significant difference (which really shouldn't be significant at all in terms of performance) is that v2 calculates the matrix()/matrix3d() instead of using values like translate()/translate3d() + rotate(), etc. I'd actually think v3 would be a bit faster in that regard. 

     

    I've experienced this issue after migrating to v3 from v2 also. After some digging I found the difference was that GSAP is now defaulting to 60 fps if a manual override isn't provided: https://github.com/greensock/GSAP/blob/master/src/gsap-core.js#L843

     

    So on a screen with a refresh rate above 60hz GSAP tries to throttle the rAF loop resulting in janky animation.

     

    My workaround has been to set the fps to -1 like so: gsap.ticker.fps(-1)  

     

    Would it be possible for GSAP to allow an option to not limit the fps? Since >60hz screens are becoming more and more popular, particularly in mobiles, I think this is important.

×
×
  • Create New...