let moveAnimating = false; let moveStart = null; let moveEnd = null; let contStart = null; let contEnd = null; let moveProgress = 0; const moveDuration = 0.2; // seconds let moveStartTime = 0; let fixedY = 45; function initCameras(renderer) { // Camera (Fixed Diagonal View) const aspect = window.innerWidth / window.innerHeight; perspCamera = new THREE.PerspectiveCamera(40, aspect, 1, 1000); camera = perspCamera; camera.position.set(25, 45, 25); camera.lookAt(0, 0, 0); } function initMotions(){ window.addEventListener('keydown', function(event) { }); // Restrict panning to X and Z only controls.addEventListener('change', function() { if (moveAnimating) return; // Don't update target while animating controls.target.y = 10; camera.position.y = fixedY; camera.position.y = Math.max(camera.position.y, 20); camera.position.y = Math.min(camera.position.y, 45); }); // --- Scroll wheel pans the camera forward/backward (along view direction) --- renderer.domElement.addEventListener('wheel', function(event) { event.preventDefault(); // Prevent default scrolling behavior if (!moveAnimating){ if (event.deltaY < 0 && camera.position.y <= 35) { // Scrolling up moveStart = camera.position.clone(); moveEnd = camera.position.clone().add(new THREE.Vector3(2, 10, 2)); contStart = controls.target.clone(); contEnd = controls.target.clone().add(new THREE.Vector3(2, 0, 2)); moveProgress = 0; moveStartTime = performance.now() / 1000; moveAnimating = true; } else if (event.deltaY > 0 && camera.position.y >= 30) { // Scrolling down moveStart = camera.position.clone(); moveEnd = camera.position.clone().add(new THREE.Vector3(-2, -10, -2)); contStart = controls.target.clone(); contEnd = controls.target.clone().add(new THREE.Vector3(-2, 0, -2)); moveProgress = 0; moveStartTime = performance.now() / 1000; moveAnimating = true; } } }, { passive: false }); } // --- Event Handlers --- function onWindowResize() { const aspect = window.innerWidth / window.innerHeight; perspCamera.aspect = aspect; perspCamera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); } function animateCamera() { if (moveAnimating) { const now = performance.now() / 1000; moveProgress = Math.min((now - moveStartTime) / moveDuration, 1); camera.position.lerpVectors(moveStart, moveEnd, moveProgress); controls.target.lerpVectors(contStart, contEnd, moveProgress); // Optional: move target too if (moveProgress >= 1) { moveAnimating = false; fixedY = camera.position.y; } controls.update(); } }