Search code examples
javascriptgsap

gsap rotation - how to avoid sharp transitions


Could someone help me make this swing more fluently, without this sharp transitions from one direction to another? The animation should be like a swing on wind.

const 	stepDuration = 0.5, wing = '#wing';
gsap.set(wing, {transformOrigin: "50% 0%", rotation: 15})
const walk = () => {gsap.timeline({repeat: -1, defaults: { ease: "circ.inOut", duration: stepDuration }})
    .add('start')
	.to(wing, { rotation: -15 })
    .to(wing, { rotation: 15 })
}
window.onload = () => {walk()};
svg {
  position: fixed;
  left: 50vw;
  top: 25px;
  width: 70%;
  height: 70%;
  animation: a01 9s;
  background: #0099cc;
}

#wing {
  fill: gold;
  transform-origin: top center;
  animation: awinga 25s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.0.4/gsap.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/MotionPathPlugin.min.js?v=15"></script>

   <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" version="1.1" viewBox="0 0 1280 720">
      <path id='wing' d="M100 0 L150 0 L150 300 L100 300 Z" />
    </svg>

<script>

</script>


Solution

  • What you want is basically a tweening/easing function that tapers out at the start and at the end, without a sharp gradient in between. The reason of your jerking is because for the circ.inOut easing, there is basically an infinitesimally small period of time where the gradient is infinite (right at the 50% mark), which causes the sharp jerking you see when it's mid-tween (right when your element rotates past the vertical midline):

    circ.inOut has to steep transition

    Therefore, you should pick an easing function that doesn't have that abrupt change in the middle, e.g. power1.inOut or the likes of it:

    [power1.inOut has a gentler in-between gradient[2]

    const 	stepDuration = 0.5, wing = '#wing';
    gsap.set(wing, {transformOrigin: "50% 0%", rotation: 15})
    const walk = () => {gsap.timeline({repeat: -1, defaults: { ease: "power1.inOut", duration: stepDuration }})
        .add('start')
    	.to(wing, { rotation: -15 })
        .to(wing, { rotation: 15 })
    }
    window.onload = () => {walk()};
    svg {
      position: fixed;
      left: 50vw;
      top: 25px;
      width: 70%;
      height: 70%;
      animation: a01 9s;
      background: #0099cc;
    }
    
    #wing {
      fill: gold;
      transform-origin: top center;
      animation: awinga 25s;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.0.4/gsap.min.js"></script>
    <script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/MotionPathPlugin.min.js?v=15"></script>
    
       <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" version="1.1" viewBox="0 0 1280 720">
          <path id='wing' d="M100 0 L150 0 L150 300 L100 300 Z" />
        </svg>
    
    <script>
    
    </script>