Refactoring: add Vite to serve JS modules

This commit is contained in:
Dejvino
2025-11-16 13:20:33 +01:00
parent 75c87c9d03
commit 1c2a3c6d3a
17 changed files with 1506 additions and 332 deletions
+110
View File
@@ -0,0 +1,110 @@
import * as THREE from 'three';
import { state } from '../state.js';
import { updateVcrDisplay } from '../vcr-display.js';
function updateCamera() {
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;
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 lookOffsetY = Math.cos(lookAtTime * 1.2) * lookAmplitude;
// Apply lookAt to the subtly shifted target
state.camera.lookAt(baseTargetX + lookOffsetX, baseTargetY + lookOffsetY, baseTargetZ);
}
function updateLampFlicker() {
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 = state.originalLampIntensity * (0.3 + Math.random() * 0.7);
state.lampLightSpot.intensity = lampLightIntensity;
state.lampLightPoint.intensity = lampLightIntensity;
} else if (state.lampLightPoint.intensity < state.originalLampIntensity) {
// Smoothly restore original intensity
let lampLightIntensity = THREE.MathUtils.lerp(state.lampLightPoint.intensity, state.originalLampIntensity, restoreRate);
state.lampLightSpot.intensity = lampLightIntensity;
state.lampLightPoint.intensity = lampLightIntensity;
}
}
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 updateVideo() {
if (state.videoTexture) {
state.videoTexture.needsUpdate = true;
}
}
function updateVcr() {
const currentTime = state.baseTime + state.videoElement.currentTime;
if (Math.abs(currentTime - state.lastUpdateTime) > 0.1) {
updateVcrDisplay(currentTime);
state.lastUpdateTime = currentTime;
}
if (currentTime - state.lastBlinkToggleTime > 0.5) { // Blink every 0.5 seconds
state.blinkState = !state.blinkState;
state.lastBlinkToggleTime = currentTime;
}
}
// --- Animation Loop ---
export function animate() {
requestAnimationFrame(animate);
state.effectsManager.update();
updateCamera();
updateLampFlicker();
updateScreenLight();
updateVideo();
updateVcr();
// 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);
}
+62
View File
@@ -0,0 +1,62 @@
import * as THREE from 'three';
import { state, initState } from '../state.js';
import { EffectsManager } from '../EffectsManager.js';
import { createSceneObjects } from '../scene.js';
import { animate, onWindowResize } from './animate.js';
import { loadVideoFile, playNextVideo } from '../video-player.js';
// --- Initialization ---
export function init() {
initState();
// 1. Scene Setup (Dark, Ambient)
state.scene = new THREE.Scene();
state.scene.background = new THREE.Color(0x000000);
// 2. Camera Setup
const FOV = 65;
state.camera = new THREE.PerspectiveCamera(FOV, window.innerWidth / window.innerHeight, 0.1, 1000);
state.camera.position.set(0, 1.5, 4);
// 3. Renderer Setup
state.renderer = new THREE.WebGLRenderer({ antialias: true });
state.renderer.setSize(window.innerWidth, window.innerHeight);
state.renderer.setPixelRatio(window.devicePixelRatio);
// Enable shadows on the renderer
state.renderer.shadowMap.enabled = true;
state.renderer.shadowMap.type = THREE.PCFSoftShadowMap; // Softer shadows
state.container.appendChild(state.renderer.domElement);
// 5. Build the entire scene with TV and surrounding objects
createSceneObjects();
// 6. Initialize all visual effects via the manager
state.effectsManager = new EffectsManager(state.scene);
// --- 8. Debug Visualization Helpers ---
// Visual aids for the light source positions
if (state.debugLight && THREE.PointLightHelper) {
const screenHelper = new THREE.PointLightHelper(state.screenLight, 0.1, 0xff0000); // Red for screen
state.scene.add(screenHelper);
// Lamp Helper will now work since lampLight is added to the scene
const lampHelperPoint = new THREE.PointLightHelper(state.lampLightPoint, 0.1, 0x00ff00); // Green for lamp
state.scene.add(lampHelperPoint);
}
// 9. Event Listeners
window.addEventListener('resize', onWindowResize, false);
state.fileInput.addEventListener('change', loadVideoFile);
// Button logic
state.loadTapeButton.addEventListener('click', () => {
state.fileInput.click();
});
// Auto-advance to the next video when the current one finishes.
state.videoElement.addEventListener('ended', playNextVideo);
// Start the animation loop
animate();
}