Jump to content

jesper.landberg last won the day on January 6 2019

jesper.landberg had the most liked content!


  • Posts

  • Joined

  • Last visited

  • Days Won


Posts posted by jesper.landberg

  1. 1 hour ago, OSUblake said:

    I don't think there is an easy way to figure that out. One problem is that you are updating everything inside a ticker function, but how often that updates is going to vary based refresh rate of your monitor and fps. If your monitor runs at 60fps and mine runs at 120fps, we're going to have wildly different target values after 1 second.


    I had to add in extra calculation here to normalize the framerate difference when doing lerp, but it's probably not 100% accurate.







    I tried lerping towards the target on click instead but since im wrapping it didnt work as I wanted, it probs would if I didnt do that tho, but would been hard getting an exact duration tho. In the end I achieved what I wanted doing some math in a shader (since its webgl). If u want to see, towards the end of the clip attached u can see that the grid item now snaps into place when opening/closing even if the grid is moving. which I struggled with using pure JS.




    • Like 1
  2. See the Codepen. Obviously when u click, obj animates to the value target had on click. But if I wanted obj to animate to whatever value target would have at the end of the 1 second duration, how would you approach that? My initial thought is doing a lerp, but I wanted to see if GSAP has some clever functionality for this case first. I think FLIP can do something similar? 


    Code from the Codepen:


    const target = { x: 0, y : 0 }
    const obj = { x: 0, y: 0 }
    const targetEl = document.querySelector('.js-target')
    const objEl = document.querySelector('.js-obj')
    objEl.textContent = `x: ${obj.x}, y: ${obj.y}`
    function tick() {
      target.x = gsap.utils.wrap(0, 1000, target.x + 1)
      target.y = gsap.utils.wrap(0, 1000, target.y + 1)
      targetEl.textContent = `x: ${target.x}, y: ${target.y}`
    document.addEventListener('click', () => {
        gsap.to(obj, {
          duration: 1,
          x: target.x, y: target.y,
          onUpdate: () => {
            objEl.textContent = `x: ${obj.x}, y: ${obj.y}`


    See the Pen caafcd930a74495c2c83fa0b50d98a9c by ReGGae (@ReGGae) on CodePen

  3. 54 minutes ago, OSUblake said:

    Hi Jesper!


    Looking for anything in particular? And do you have any code you can share? We might be able to critique it. 😉


    The new selector is really nice as you don't have to create a ref for every element.



    Here's a good post on how to make reusable animations.



    Registering all your plugins and configuring GSAP in a centralized location.


    useLayoutEffect can prevent FOUC, like with Flip and from/fromTo animations, but complains when being used with SSR. Here's a nice little hook to get around that.

    // use-isomorphic-layout-effect.js
    import { useLayoutEffect, useEffect } from 'react';
    const useIsomorphicLayoutEffect =
      typeof window !== 'undefined' ? useLayoutEffect : useEffect;
    export default useIsomorphicLayoutEffect;
    // app.js
    import useLayoutEffect from './use-isomorphic-layout-effect';
    function App() {
      useLayoutEffect(() => {
        console.log('hello there');
      }, []);
      return 'Hello world';




    This is a great start, thanks Blake! No code to share just yet, just starting out testing Next, and wanted to make sure I start out properly:P

    • Like 1
  4. 2 minutes ago, ZachSaucier said:

    Hey Jesper. In the above case it would make sense to use the onLeave and onEnterBack callbacks to fire tweens:

    const endAnim = gsap.to(elem, { alpha: 0, paused: true });
    const tl = gsap.timeline({
      scrollTrigger: {
        // Pin true and other stuff
        scrub: true,
        onLeave: () => endAnim.play(),
        onEnterBack: () => endAnim.reverse()
    .to(otherElem, { yPercent: -100 })

    If you need to do it mid animation you could use a .call() but then you'd have to add conditional logic for the direction inside of the function. Maybe in the onUpdate of the ScrollTrigger you get the direction then use that in your callback:

    const endAnim = gsap.to(elem, { alpha: 0, paused: true });
    let direction = 1;
    function getDir(self) {
      direction = self.direction;
    // in the ScrollTrigger vars
    onUpdate: getDir
    // add the .call
    tl.call(() => {
      if(direction > 0) {
      } else {



    Thanks @ZachSaucier, the direction one fits my needs, thx!

    • Like 1
  5. Hi,


    Trying out ScrollTrigger, which seems awesome. Testing out pinning atm and works great. Just wondering in what way you would recommend doing non-scrubbed tweens in a scrubbed timeline, like:

    const tl = gsap.timeline({
    	scrollTrigger: {
          	// Pin true and other stuff
          	scrub: true
    .to(otherElem, { yPercent: -100 })
    .to(elem, { alpha: 1 }) // Non scrubbed


    Currently I tried doing the below, but not sure how I would approach when it goes in reverse direction


    const tl = gsap.timeline({
    	scrollTrigger: {
          	// Pin true and other stuff
          	scrub: true
    .to(otherElem, { yPercent: -100 })
    .add(() => {
    	gsap.to(elem, { alpha: 0 })


  6. 10 hours ago, GreenSock said:

    @jesper.landberg I read your question a few times and I'm still not quite sure what you're asking. Did you read through the docs and watch the [new] video already? That might clear things up. 


    Basically the scrollerProxy() method lets you say "hey, ScrollTrigger, for this particular scroller element (like 'body' or '.container'), please use these methods to interact with it instead of the standard ones because I'm gonna customize things". So your scrollTop in that configuration object should be a FUNCTION that can get or set the scrollTop. So when ScrollTrigger tries to discern the scrollTop of that element, it'll call that function and you can return whatever value you want, and ScrollTrigger will use that. 


    Is it clearer now? 


    There are 3 different demos on the docs page. Hopefully those serve as decent templates. Let me know if you have any other questions. Better yet, if you've got a reduced test case where you're trying to make something work (but it isn't working), please provide that. I'm sure it'll illuminate things for me so I better understand what you're asking. 


    Sorry as usual I suck at explaining my issues haha:) but ur answer still managed to clear it up for me and my personal smooth scroll now works fine with this:) Thanks!

    • Like 1
  7. @GreenSock hey, so i'm checking out some scrollProxy examples, and just have a question, what does the passed element do? Is there any reason we can't just send our custom scroll position in? Is the proxy element the transformed element? Like In my case where I have multiple scroll sections (pages are divided into sections and each has their own transforms, which is being transformed when the section is visible) I don't have the one transformed proxy. 


    scrollerProxy(".proxy", { <!-- what does this do here? -->
      scrollTop: mySmoothScrollPos,


  8. On 6/28/2020 at 9:14 AM, GeS said:


    Dear Jesper, please tell me what you used to create the transition effect. I’ve been trying to recreate the distortion of the divble block for a long time so that it is rounded on the sides using CSS, but I still can’t make it as smooth as on your site. Recently, I have constantly come across sites where they easily use a similar script. How will I be able to change the standard divblock when I go to the page? here is another great example where this move is used when we point to projects and go through the pages https://www.martinehrlich.com/ I will be incredibly happy if you tell me how you made such a transition?


    Hey, i put together a quick codepen demonstrating how to do it with WebGL.

    See the Pen rNxpVEd?editors=0010 by ReGGae (@ReGGae) on CodePen

    • Like 3
  9. 2 minutes ago, GreenSock said:

    How would that be helpful? Like...can you help us understand the desired outcome? If you're trying to use ScrollTrigger to control an animation according to certain start/end positions, wouldn't it be simpler to just feed your lerped value into the animation's progress()? What would you be looking for ScrollTrigger to do for you if you're already calculating scroll-related values on your own that are different than the actual scroll position of the page/scrollbar? I'm probably missing something obvious. 


    Well I would assume ScrollTrigger uses cached boundingRects of elements, then comparing that to the scroll value (I might be totally wrong tho) ? In that case why wouldn't it be helpful to allow ppl to pass their own scroll value? 

    Pseudo code:

    // In a raf

    I have my own solution where I do what u say, pass a progress value based on start/end values using my lerped scroll to the progress() method. But with this obviously goes checking if the element is in viewport, doing the calculations etc etc. And ScrollTrigger does all this plus much more than my own solution, so obviously it would be helpful? 

  10. 3 minutes ago, ZachSaucier said:

    Hey Jesper. What do you mean by "inject" your own scroll values? 


    ScrollTriggers have a .scroll() method where you can set the scroll position of the scroller being used if that's what you're asking about.


    Hey, basically so I can use it with my own virtual scroll, with my lerped scroll value, instead of using the default event (scroll using scrollTop?).

  11. On 2/29/2020 at 8:11 AM, GreenSock said:

    Aha! I think I found what you were talking about, @jesper.landberg. It was a tricky thing with immediateRender and order-of-operation but it should be fixed in the next release which you can preview at https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js


    Would you mind trying that in your project and verifying that it's working well for you now? Sorry about any confusion there - it was very difficult to reproduce but with enough attempts I managed to stumble across it. :)


    Hey sorry for the late reply. But yes after updating to the latest version all my issues seem to be gone:)

    • Thanks 1
  12. 10 minutes ago, ZachSaucier said:

    A .set() is always immediate, it doesn't matter about immediateRender. I get the same behavior on your pen with all versions of GSAP (2 and 3). 


    The reason for this is that your timeline is paused, which means it never started, not even a little bit. That means that the .set() call (and all parts of your timeline) is not reached because the timeline's progress is not greater than 0.


    You could force the timeline to start a tiny bit by using tl.seek(0.001); or something like that which could be necessary depending on the exact effect that you need (though I can't imagine a scenario where it'd be necessary given you can use repeatRefresh), but more commonly you just use a regular .set() call outside of the timeline and then do your animations in the timeline:


    Does that make sense?

    I see, have this behaviour changed since 3.0.1 then? Just found it a bird weird that everything went crazy after updating without touching the code:P

  13. 35 minutes ago, GreenSock said:

    I'm super curious about this and I'm eager to see a reduced test case. I can't seem to reproduce the issue either but I'm sure I'm just missing something and once we see the reduced test case it'll become clear. 


    I'm confident it has nothing to do with SplitText.


    @jesper.landberg I did do a bunch of work to fix some complex timeline-related timing issues in recent updates so I wonder if there's something in there that caused an unintended side effect. But again, all my tests seem to be passing. If you're seeing different behavior in early 3.x versions, it was either a bug that got fixed or (more likely since you're more of an advanced user) it's a pesky new one that needs squashing which I'd like to do promptly, so any help you could offer would be fantastic. 


    I think this illustrates my issue. the defaults immediateRender doesn't seem to apply on the .set? is this correct behaviour? Have I missed something about this in the release docs maybe?:) 

    See the Pen 0b7cfd3fd2f0e15ffd381920c4701048?editors=0010 by ReGGae (@ReGGae) on CodePen

  14. 6 hours ago, ZachSaucier said:

    Hey Jesper.

    It seems fine to me: 


    Can you please produce a minimal demo reproducing the error?


    It's super weird, immediateRender is deffo not happening (or well it looks like it isn't) on any timeline on the whole site i'm building. Reverting back to 3.0.1 makes it work tho.


    Didn't update my splitText plugin tho, not sure if that can have some side-effects on things? But it's just not on split animations. Anyway, il try to see if I can reproduce it later on a pen or something.

  15. Updated from 3.0.1 to 3.2.2 and now my stuff isn't rendered before play() is called.


    Example code:

    tl = gsap.timeline({ 
      paused: true,
      defaults: {
        immediateRender: true
    .set(parent, { overflow: 'hidden' })
    .from(child, { yPercent: 100 }, 0}
    setTimeout(() => { tl.play() }, 2000)


  16. @andsavu @ZachSaucier It's indeed made with WebGL, with most of the magic happening in custom shaders. It's really a bit to much to get into without writing an article about it, but if you @andsavu want to learn creating these kind of things i'd recommend some of the following resources:





    Also https://tympanus.net/codrops/ have some great tutorials on the topic.

    Oh and @ZachSaucier thx for the resize heads-up, will fix it:)


    • Like 5
  17. On 1/16/2020 at 11:25 PM, Shrug ¯\_(ツ)_/¯ said:

    Welcome to the forum @asilva I don't think any perceived sarcasm was intended, this forum is a very friendly place.



    Oddly that webflow demo loads Tweenmax but unless I am overlooking things or blind it appears any reference to GSAP in the code was removed or never called? Interestingly it seems derived from the below codepen by @@jesper.landberg which does use GSAP, but neither appear to call Draggable unless I blindly overlooked it.




    Don’t know much about webflow but it appears you can clone that project into your own account from the below link and play with/modify it.





    If you have questions specific to webflow or how to implement that example along with other webflow features, then I would probably suggest asking on the webflow forums as that is specific to webflow.


    Reason u aint seeing any gsap called (I guess) is because my slider actually didn't use gsap, in my pen it was only used for the transition and the other non-slider effects. I guess whoever made the webflow demo just added the dependencies from my pen.

    • Like 1
  18. In functions that are called quite often I usually do something like this:


    if (tl) {
    tl = new TimelineLite()


    Is that better or worse than just...

    return new TimelineLite()

    Might be a silly question just want to know if my way is more performant/optimal/worse in any way versus the below.