import * as THREE from 'three'; import { state } from '../state.js'; import { updateScreenEffect } from '../scene/magic-mirror.js' import sceneFeatureManager from '../scene/SceneFeatureManager.js'; function updateCamera() { const globalTime = Date.now() * 0.0001; const lookAtTime = Date.now() * 0.0002; const camAmplitude = 1.0; const lookAmplitude = 8.0; // Base Camera Position in front of the TV const baseX = 0; const baseY = 1.6; const baseZ = -10.0; // Base LookAt target (Center of the screen) const baseTargetX = 0; const baseTargetY = 1.6; const baseTargetZ = -30.0; // Camera Position Offsets (Drift) const camOffsetX = Math.sin(globalTime * 3.1) * camAmplitude; const camOffsetY = Math.cos(globalTime * 2.5) * camAmplitude * 0.1; const camOffsetZ = Math.cos(globalTime * 3.2) * camAmplitude; state.camera.position.x = baseX + camOffsetX; state.camera.position.y = baseY + camOffsetY; state.camera.position.z = baseZ + camOffsetZ; // LookAt Target Offsets (Subtle Gaze Shift) const lookOffsetX = Math.sin(lookAtTime * 1.5) * lookAmplitude; const lookOffsetZ = Math.cos(lookAtTime * 2.5) * lookAmplitude; const lookOffsetY = Math.cos(lookAtTime * 1.2) * lookAmplitude * 0.5; // Apply lookAt to the subtly shifted target state.camera.lookAt(baseTargetX + lookOffsetX, baseTargetY + lookOffsetY, baseTargetZ + lookOffsetZ); } function updateScreenLight() { if (state.isVideoLoaded && state.screenLight.intensity > 0) { const pulseTarget = state.originalScreenIntensity + (Math.random() - 0.5) * state.screenIntensityPulse; state.screenLight.intensity = THREE.MathUtils.lerp(state.screenLight.intensity, pulseTarget, 0.1); const lightTime = Date.now() * 0.0001; const radius = 0.01; const centerX = 0; const centerY = 1.5; state.screenLight.position.x = centerX + Math.cos(lightTime) * radius; state.screenLight.position.y = centerY + Math.sin(lightTime * 1.5) * radius * 0.5; // Slightly different freq for Y } } function updateShaderTime() { if (state.tvScreen && state.tvScreen.material.uniforms && state.tvScreen.material.uniforms.u_time) { state.tvScreen.material.uniforms.u_time.value = state.clock.getElapsedTime(); } } function updateVideo() { if (state.videoTexture) { state.videoTexture.needsUpdate = true; } } // --- Animation Loop --- export function animate() { requestAnimationFrame(animate); const deltaTime = 1; sceneFeatureManager.update(deltaTime); state.effectsManager.update(); updateCamera(); updateScreenLight(); updateVideo(); updateShaderTime(); updateScreenEffect(); // RENDER! state.renderer.render(state.scene, state.camera); } // --- Window Resize Handler --- export function onWindowResize() { state.camera.aspect = window.innerWidth / window.innerHeight; state.camera.updateProjectionMatrix(); state.renderer.setSize(window.innerWidth, window.innerHeight); }