Problems (Lag) while doing cinematic shots in R3F using GSAP

Good day everyone. I am building an interactive kids story experience and I have this situation where I am trying to set up a react three fiber project that has different scenes inside, switched based on a currentScene state along with some camera animations for the shots. Currently i am facing a good deal of lag during this switch no matter the hardware.

Here i am importing all my scenes with the switching logic
App.jsx

const sceneMap = {
    1: Scene1,
    2: Scene2,
    3: Scene3,
    4: Scene4,
    5: Scene5,
    6: Scene6,
};

const SceneComponent = ({ num, shotNumberRef }) => {
    const Scene = sceneMap[num] || Scene1;

    return <Scene shotNumber={shotNumberRef.current}\ />;
};

const App = () => {
    const [currentScene, setCurrentScene] = useState(0);
    const shotNumberRef = useRef(0);

.
.
.

            <Canvas camera={{ position: [53, 8, 15], fov: 40 }}>

                <SceneComponent num={currentScene} shotNumberRef={shotNumberRef} handleBlimpClick={handleBlimpClick} />

            </Canvas>


This file controls the global timeline using gsap.
TimelineController.jsx

        const t = gsap.timeline();
        t.to( {}, { duration: 6.0, onStart: () => { setCurrentScene([2]); shotNumberRef.current = 1; }, immediateRender: true, })
            .to( {}, { duration: 9.5, onStart: () => { setCurrentScene([4]); shotNumberRef.current = 1; }, immediateRender: true, },)
            .to( {}, { duration: 2.5, onStart: () => { setCurrentScene([2]); shotNumberRef.current = 2; }, immediateRender: true, },)
            .to( {}, { duration: 6.0, onStart: () => { setCurrentScene([4]); shotNumberRef.current = 2; }, immediateRender: true, },)
            .to( {}, { duration: 4.0, onStart: () => { setCurrentScene([4]); shotNumberRef.current = 3; }, immediateRender: true, },)
            .to( {}, { duration: 14, onStart: () => { setCurrentScene(2); shotNumberRef.current = 3;}, immediateRender: true,},)


This is an example of the camera animation involved based on shotNumber.
Scene files:

    useGSAP(() => {
        if (shotNumber == 1) {
            gsap.fromTo(
                camera,
                {
                    fov: 10,
                },
                {
                    fov: 28,
                    duration: 3,
                    onUpdateParams: [camera],
                    onUpdate() {
                        if (!this.isActive()) return;
                        camera.updateProjectionMatrix();
                    },
                },
            );
        }
    }, [camera]);

This lag is only evident using gsap timeline, and not when using debug tools to switch the scene.

Here’s a sample recording.

I would be really grateful if someone could help me debug this.

1 Like

I overcame a similar problem. I referenced various examples for a reduced config… but conflicts in usage resulted in stuttering. I organized a more thorough call sequence, but I remember clearAllTweens (pardon pseudocode) being the silver bullet, in addition to:

  • canvas sizes & destroy methods: affect RAM & GC respectively.
  • proper and complete usage of parameters: transition may fail in unexpected ways when partial or invalid parameters are supplied.
  • callbacks onEnd vs onAfterEnd (apology for pseudocode) may be subtly infectious.
  • official vendored usage may differ from generic commonalities. Similarly, interoperability of gsap (or tweenjs) between versions may influence behaviors. I found migrating to the latest supported addon was easier than ad hoc mitigation.

In your case, you tween a camera position/fov. But you entirely replace a scene after a duration. Maybe you should only clear a specific tween, if tweening is the right word at all.

Cheers,
Bo “Cheers” Cyprus

1 Like