diff --git a/app/components/maps/LoadedReplays.tsx b/app/components/maps/LoadedReplays.tsx
index 6e51696a..be108eed 100644
--- a/app/components/maps/LoadedReplays.tsx
+++ b/app/components/maps/LoadedReplays.tsx
@@ -220,6 +220,11 @@ const LoadedReplays = ({
onChange={(e: RadioChangeEvent) => { timeLineGlobal.cameraMode = e.target.value; }}
className="flex gap-4"
>
+ {timeLineGlobal.followedReplay && (
+
+ Lock
+
+ )}
Target
diff --git a/app/components/viewer/ReplayCars.tsx b/app/components/viewer/ReplayCars.tsx
index 5fc65fa6..2557535e 100644
--- a/app/components/viewer/ReplayCars.tsx
+++ b/app/components/viewer/ReplayCars.tsx
@@ -43,6 +43,9 @@ const ReplayCar = ({
let curSample = replay.samples[0];
const smoothSample: ReplayDataPoint = { ...replay.samples[0] };
+ // keep track of the camera mode switches
+ let prevCamMode = timeLineGlobal.cameraMode;
+
// Get own material from loaded car model
const carMesh: THREE.Mesh = fbx.children[0] as THREE.Mesh;
const material: THREE.MeshPhongMaterial = carMesh.material as THREE.MeshPhongMaterial;
@@ -109,6 +112,21 @@ const ReplayCar = ({
if (orbitControlsRef && orbitControlsRef.current) {
orbitControlsRef.current.target.lerp(smoothSample.position, 0.2);
+ if (timeLineGlobal.cameraMode === CameraMode.Lock) {
+ // Set camPosRef to camera position only once
+ if (prevCamMode !== timeLineGlobal.cameraMode) {
+ camPosRef.current.position.set(
+ camera.position.x - mesh.current.position.x,
+ camera.position.y - mesh.current.position.y,
+ camera.position.z - mesh.current.position.z,
+ );
+ }
+ // move camera to camPosMesh world position
+ const camWorldPos: THREE.Vector3 = new THREE.Vector3();
+ camPosRef.current.getWorldPosition(camWorldPos);
+ camera.position.lerp(camWorldPos, 0.3);
+ }
+
if (timeLineGlobal.cameraMode === CameraMode.Follow) {
// move camPosMesh to Follow position
camPosRef.current.rotation.setFromQuaternion(carRotation);
@@ -142,6 +160,7 @@ const ReplayCar = ({
} else {
stadiumCarMesh.current.scale.lerp(new THREE.Vector3(0.01, 0.01, 0.01), 0.2);
}
+ prevCamMode = timeLineGlobal.cameraMode;
}
});
diff --git a/app/lib/contexts/SettingsContext.tsx b/app/lib/contexts/SettingsContext.tsx
index f02a9a38..868887ac 100644
--- a/app/lib/contexts/SettingsContext.tsx
+++ b/app/lib/contexts/SettingsContext.tsx
@@ -6,6 +6,7 @@ import { LineType, LineTypes } from '../../components/viewer/ReplayLines';
export enum CameraMode {
Target,
Follow,
+ Lock
}
export interface SettingsContextProps {