# React Three Fiber camera transition

**URL:** <https://discourse.threejs.org/t/react-three-fiber-camera-transition/56743>\
**Category:** Questions\
**Tags:** animation\
**Created:** [October 7, 2023, 7:01am UTC](https://discourse.threejs.org/t/react-three-fiber-camera-transition/56743 "2023-10-07T07:01:34Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Obada\_Qasem](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/obada_qasem/32/40662_2.png) [@Obada\_Qasem](https://discourse.threejs.org/u/Obada_Qasem)\
**Post date:** [October 7, 2023, 7:01am UTC](https://discourse.threejs.org/t/react-three-fiber-camera-transition/56743/1 "2023-10-07T07:01:35Z")

</div>

I spent the whole day really finding why my camera transitions are not working, I am all ears to here you nice solutions here is the code “The Animation is in the intro function”:

import React, { Suspense, useEffect, useRef, useState } from ‘react’;  
import \* as swipeAnimation from ‘./Swipe.json’;  
import { Canvas, useFrame } from ‘@react-three/fiber’;  
import { easeCubic } from ‘d3-ease’;  
import {  
Reflector,  
useTexture,  
PerspectiveCamera,  
Text  
} from ‘@react-three/drei’;  
import { IntroDef } from “…/…/Avatars/IntroDef”;  
import \* as THREE from ‘three’;  
import Lottie from “lottie-react”;

const cameraPositions = [  
[0, 3, 100],  
[20, 10, 80],  
[-20, 5, 75],  
[10, 12, 90]  
];

const timings = [5000, 3000, 4000, 6000];

export default function IntroAvatar() {  
const defaultOptions = {  
loop: true,  
autoplay: true,  
animationData: swipeAnimation.default,  
};

```
const characterRef = useRef();
const cameraRef = useRef(); // Declare a camera reference
const [cameraPosition, setCameraPosition] = useState({ x: 0, y: 3, z: 100 });
const [currentPosition, setCurrentPosition] = useState(0);

const handleTransition = () => {
    let nextPosition = (currentPosition + 1);
    setCurrentPosition(nextPosition);
    setCameraPosition({x: cameraPositions[nextPosition][0],y: cameraPositions[nextPosition][1],z: cameraPositions[nextPosition][2]});

};

useEffect(() => {
    if(currentPosition<timings.length) {
        const interval = setTimeout(handleTransition, timings[currentPosition]);
        console.log(currentPosition);
        return () => clearTimeout(interval);
    }
}, [currentPosition]);

return (
    <div className={'intro-avatar-3d'}>
        <div className="swipe-animation">
            <Lottie options={defaultOptions} animationData={swipeAnimation.default} />
        </div>
        <Canvas concurrent gl={{ alpha: true }} pixelRatio={[1, 1.5]}>
            <perspectiveCamera ref={cameraRef} position={cameraPosition} fov={15} />
            <color attach="background" args={['black']} />
            <fog attach="fog" args={['black', 15, 20]} />
            <Suspense fallback={null}>
                <group position={[0, -1, 0]}>
                    <IntroDef characterRef={characterRef} rotation={[0, 0, 0]} scale={[1, 1, 1]} />
                    <VideoText character={characterRef} position={[0, 1.3, -1]} />
                    <Ground />
                </group>
                <Intro cameraRef={cameraRef} targetPosition={cameraPosition} />
            </Suspense>
        </Canvas>
    </div>
);

```

}

function Ground() {  
const [floor, normal] = useTexture([‘/textures/reflect/wooden\_diff.jpg’, ‘/textures/reflect/wooden\_nordxl.jpg’]);  
return (  
\<Reflector blur={[400, 100]} resolution={1024} args={[10, 10]} mirror={0.5} mixBlur={6} mixStrength={1.5} rotation={[-Math.PI / 2, 0, Math.PI / 2]}\>  
{(Material, props) =\> \<Material color=“#a0a0a0” metalness={0.4} normalScale={[2, 2]} {…props} /\>}  
  
);  
}

function VideoText(props) {  
const textRef = useRef();  
const [distance, setDistance] = useState(100);  
const [spacing, setSpacing] = useState(1);

```
function lerp(a, b, t) {
    return a + t * (b - a);
}

useFrame(() => {
    const characterPosition = props.character.current.position;
    const newDistance = characterPosition.distanceTo(textRef.current.position);

    const targetSpacing = newDistance < 2 ? 10 : 1;
    const t = easeCubic(0.3);
    const newSpacing = lerp(spacing, targetSpacing, t);

    setSpacing(newSpacing);
    setDistance(newDistance);
});

const renderedText = `WELCOME TO${' '.repeat(Math.round(spacing))}MY PORTFOLIO!`;

return (
    <Text ref={textRef} font="/intro.ttf" fontSize={0.7} color={'#0e758f'} letterSpacing={0.1} {...props}>
        {renderedText}
        <meshBasicMaterial toneMapped={false} />
    </Text>
);

```

}

function Intro(props) {  
const { cameraRef, targetPosition } = props;

```
return useFrame(() => {
    if (cameraRef.current) {

        cameraRef.current.position.lerp(new THREE.Vector3(targetPosition.x, targetPosition.y, targetPosition.z), 0.05);
        cameraRef.current.lookAt(0, 0, 0);
        cameraRef.current.updateProjectionMatrix();

    }
});

```

}

---

<div class="post-metadata">

**Author:** ![drcmda](https://avatars.discourse-cdn.com/v4/letter/d/91b2a8/32.png) [@drcmda](https://discourse.threejs.org/u/drcmda)\
**Post date:** [October 7, 2023, 7:13am UTC](https://discourse.threejs.org/t/react-three-fiber-camera-transition/56743/2 "2023-10-07T07:13:16Z")

</div>

it’s too much unrelated code. i would isolate the issue with just the camera move. don’t even need to setTimeout stuff for that, just make sure you get the lerping right.

btw, i have been using [GitHub - yomotsu/camera-controls: A camera control for three.js, similar to THREE.OrbitControls yet supports smooth transitions and more features.](https://github.com/yomotsu/camera-controls) recently to move the camera, it made it really easy. it has a drei helper as well. for instance  
[Enter portals - CodeSandbox](https://codesandbox.io/s/9m4tpc)
