diff --git a/src/components/ui/TalkieDialogueOverlay.tsx b/src/components/ui/TalkieDialogueOverlay.tsx index bc1b445..ce7100b 100644 --- a/src/components/ui/TalkieDialogueOverlay.tsx +++ b/src/components/ui/TalkieDialogueOverlay.tsx @@ -14,7 +14,16 @@ const TALKIE_REVEAL_STEPS = new Set([ "completed", ]); -function TalkieModel(): React.JSX.Element { +const TALKIE_REST_Y = -0.55; +const TALKIE_ACTIVE_Y = -0.18; +const TALKIE_FLOAT_Y_AMPLITUDE = 0.025; +const TALKIE_FLOAT_ROTATION_AMPLITUDE = THREE.MathUtils.degToRad(1.6); + +interface TalkieModelProps { + active: boolean; +} + +function TalkieModel({ active }: TalkieModelProps): React.JSX.Element { const { scene } = useGLTF(TALKIE_MODEL_PATH); const model = useMemo(() => scene.clone(true), [scene]); const groupRef = useRef(null); @@ -33,15 +42,26 @@ function TalkieModel(): React.JSX.Element { if (!groupRef.current) return; const t = clock.getElapsedTime(); - groupRef.current.rotation.z = Math.sin(t * 22) * 0.025; - groupRef.current.position.y = Math.sin(t * 6) * 0.012; + const floatY = Math.sin(t * 1.4) * TALKIE_FLOAT_Y_AMPLITUDE; + const targetY = (active ? TALKIE_ACTIVE_Y : TALKIE_REST_Y) + floatY; + groupRef.current.position.y = THREE.MathUtils.lerp( + groupRef.current.position.y, + targetY, + 0.14, + ); + + if (active) { + groupRef.current.rotation.z = Math.sin(t * 22) * 0.025; + } else { + groupRef.current.rotation.z = + Math.sin(t * 0.8) * TALKIE_FLOAT_ROTATION_AMPLITUDE; + } }); return ( - + @@ -73,11 +93,12 @@ export function TalkieDialogueOverlay(): React.JSX.Element | null { if (!isAfterReveal) return null; + const overlayClassName = isNarratorDialogue + ? "talkie-dialogue-overlay talkie-dialogue-overlay--active talkie-dialogue-overlay--raised" + : "talkie-dialogue-overlay"; + return ( -