Search code examples
javascriptreactjsanimationreact-three-fiberanimejs

React Three Fiber curve-based animation


I was just wondering if is it possible to use a library like tween or animejs to increment a value in a curve-based

With that I meant to increment a value from n to x using an easing curve.

My ultimate goal is to make like a acceleration animation to the camera so I would like to use like a "ease-in-out" CSS equivalent animation.

I tried to use anime.js to increment a property of an object and then update the position of the camera

const animRef = useRef(null);
let animValue = {
  value: 0,
}

useEffect(() => {
    animRef.current = anime({
      targets: animValue,
      value: 10,
      easing: 'easeInOutQuad',
      autoplay: false, // So I can use a custom RAF loop
      update: function (anim) {
        // animValue.value <- here the value is updated
      },
    });
})

useFrame(({clock}) => {
    // Using a custom RAF loop
    animRef.current.tick(clock.elapsedTime)
    // animValue.value <- Here the value is always 0
    cameraRef.current.position.z += animValue.value
})

but the value property wont be incremented, the tick call is working but it is not updating the object property outside the anime.update function.

If there's another way approach my goal I will gladly listen


Solution

  • you can use anime, gsap etc. react-spring would probably be better. gasp/anime, watch out how you store their handles and anim-objects. local state is always kept in useState(() => new Foo()). other than that, the easiest is lerp/damp, because they're inbuilt in threejs.

    useFrame(() => {
      ref.current.opacity = THREE.MathUtils.lerp(ref.current.opacity, condition ? 1 : 0, 0.1)
    

    as for your code, you will loose references. state inside the render function will be lost next render. use useref or usestate. i have never tried anime before but you have to take into consideration that a component re-renders, as in, it's called multiple times.

    const x = useRef({ value: 0 })
    useEffect(() => {
      anime({ targets: x.current, ... })
    }, [])