+
Controls:
+
+ Mode: {fullControlMode ? 'FULL CONTROL' : 'ROTATION ONLY'}
+
+
* Left-click/Touch + drag: Rotate
+ {fullControlMode && (
+ <>
+
* Right-click + drag: Pan
+
* Scroll: Zoom
+ >
+ )}
+
* Ctrl+Alt+Enter: Toggle full control
+
* Ctrl+Alt+D: Toggle debug panel
+
+
Camera:
+
Position: [{cameraInfo.cameraPosition.map((v) => v.toFixed(2)).join(', ')}]
+
Target: [{cameraInfo.target.map((v) => v.toFixed(2)).join(', ')}]
+
Zoom: {cameraInfo.zoom.toFixed(2)}
+
+
Model:
+
Position: [{modelInfo.position.map((v) => v.toFixed(2)).join(', ')}]
+
Rotation: [{modelInfo.rotation.map((v) => v.toFixed(2)).join(', ')}]
+
Scale: {modelInfo.scale.toFixed(2)}
+
+ );
+}
diff --git a/src/apps/officer-web/Screens/Dashboard/Layout/DuckAvatar/DuckAvatar.tsx b/src/apps/officer-web/Screens/Dashboard/Layout/DuckAvatar/DuckAvatar.tsx
new file mode 100644
index 00000000..f0f90e83
--- /dev/null
+++ b/src/apps/officer-web/Screens/Dashboard/Layout/DuckAvatar/DuckAvatar.tsx
@@ -0,0 +1,118 @@
+import { Canvas, useThree } from '@react-three/fiber';
+import { OrbitControls } from '@react-three/drei';
+import { useEffect, useState, useRef } from 'react';
+import { DuckModel } from './DuckModel';
+import { DebugPanel } from './DebugPanel';
+
+type CameraInfoProps = {
+ onUpdate: (info: { cameraPosition: number[]; target: number[]; zoom: number }) => void;
+ initialTarget: [number, number, number];
+ fullControlMode: boolean;
+ initialPosition: [number, number, number];
+};
+
+function CameraInfo({ onUpdate, initialTarget, fullControlMode, initialPosition }: CameraInfoProps) {
+ const { camera } = useThree();
+ const controlsRef = useRef