diff --git a/tv-player/index.html b/tv-player/index.html index 4b86fa8..33a696e 100644 --- a/tv-player/index.html +++ b/tv-player/index.html @@ -52,225 +52,10 @@ + - diff --git a/tv-player/src/animate.js b/tv-player/src/animate.js new file mode 100644 index 0000000..5929cf0 --- /dev/null +++ b/tv-player/src/animate.js @@ -0,0 +1,128 @@ +// --- Animation Loop --- +function animate() { + requestAnimationFrame(animate); + + // 1. Dust animation: slow downward drift + if (dust) { + const positions = dust.geometry.attributes.position.array; + for (let i = 1; i < positions.length; i += 3) { + positions[i] -= 0.001; + if (positions[i] < -2) { + positions[i] = 8; + } + } + dust.geometry.attributes.position.needsUpdate = true; + } + + // 2. Camera movement (Gentle, random hovering) + const globalTime = Date.now() * 0.00005; + const lookAtTime = Date.now() * 0.00003; + + const camAmplitude = 0.7; + const lookAmplitude = 0.05; + + // Base Camera Position in front of the TV + const baseX = -0.5; + const baseY = 1.5; + const baseZ = 2.5; + + // Base LookAt target (Center of the screen) + const baseTargetX = -0.7; + const baseTargetY = 1.7; + const baseTargetZ = -0.3; + + // Camera Position Offsets (Drift) + const camOffsetX = Math.sin(globalTime * 3.1) * camAmplitude; + const camOffsetY = Math.cos(globalTime * 2.5) * camAmplitude * 0.4; + const camOffsetZ = Math.cos(globalTime * 3.2) * camAmplitude * 1.4; + + camera.position.x = baseX + camOffsetX; + camera.position.y = baseY + camOffsetY; + camera.position.z = baseZ + camOffsetZ; + + // LookAt Target Offsets (Subtle Gaze Shift) + const lookOffsetX = Math.sin(lookAtTime * 1.5) * lookAmplitude; + const lookOffsetY = Math.cos(lookAtTime * 1.2) * lookAmplitude; + + // Apply lookAt to the subtly shifted target + camera.lookAt( + baseTargetX + lookOffsetX, + baseTargetY + lookOffsetY, + baseTargetZ + ); + + // 3. Lamp Flicker Effect + const flickerChance = 0.995; + const restoreRate = 0.15; + + if (Math.random() > flickerChance) { + // Flickers quickly to a dimmer random value (between 0.3 and 1.05) + let lampLightIntensity = originalLampIntensity * (0.3 + Math.random() * 0.7); + lampLightSpot.intensity = lampLightIntensity; + lampLightPoint.intensity = lampLightIntensity; + } else if (lampLightPoint.intensity < originalLampIntensity) { + // Smoothly restore original intensity + let lampLightIntensity = THREE.MathUtils.lerp(lampLightPoint.intensity, originalLampIntensity, restoreRate); + lampLightSpot.intensity = lampLightIntensity; + lampLightPoint.intensity = lampLightIntensity; + } + + // 4. Screen Light Pulse and Movement Effect (Updated) + if (isVideoLoaded && screenLight.intensity > 0) { + // A. Pulse Effect (Intensity Fluctuation) + // Generate a small random fluctuation for the pulse (Range: 1.35 to 1.65 around base 1.5) + const pulseTarget = originalScreenIntensity + (Math.random() - 0.5) * screenIntensityPulse; + // Smoothly interpolate towards the new target fluctuation + screenLight.intensity = THREE.MathUtils.lerp(screenLight.intensity, pulseTarget, 0.1); + + // B. Movement Effect (Subtle circle around the screen center - circling the room area) + const lightTime = Date.now() * 0.0001; + const radius = 0.01; + const centerX = 0; + const centerY = 1.5; + //const centerZ = 1.2; // Use the updated Z position of the light source + + // Move the light in a subtle, erratic circle + screenLight.position.x = centerX + Math.cos(lightTime) * radius; + screenLight.position.y = centerY + Math.sin(lightTime * 1.5) * radius * 0.5; // Slightly different freq for Y + //screenLight.position.z = centerZ; // Keep Z constant at the screen light plane + } + + // 5. Update video texture (essential to grab the next frame) + if (videoTexture) { + videoTexture.needsUpdate = true; + + // Update time display in the animation loop + if (isVideoLoaded && videoElement.readyState >= 3) { + const currentTime = formatTime(videoElement.currentTime); + const duration = formatTime(videoElement.duration); + console.info(`Tape ${currentVideoIndex + 1} of ${videoUrls.length}. Time: ${currentTime} / ${duration}`); + } + } + + updateFlies(); + + const currentTime = baseTime + videoElement.currentTime; + + // Simulate playback time + if (Math.abs(currentTime - lastUpdateTime) > 0.1) { + updateVcrDisplay(currentTime); + lastUpdateTime = currentTime; + } + + // Blink the colon every second + if (currentTime - lastBlinkToggleTime > 0.5) { // Blink every 0.5 seconds + blinkState = !blinkState; + lastBlinkToggleTime = currentTime; + } + + // RENDER! + renderer.render(scene, camera); +} + +// --- Window Resize Handler --- +function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + renderer.setSize(window.innerWidth, window.innerHeight); +} \ No newline at end of file diff --git a/tv-player/src/init.js b/tv-player/src/init.js index 37d2134..ad64fe2 100644 --- a/tv-player/src/init.js +++ b/tv-player/src/init.js @@ -62,3 +62,6 @@ function init() { // Start the animation loop animate(); } + +// Start everything on window load +window.onload = init;