import './style.css' import * as THREE from 'three'; import { SceneLoader } from './sceneLoader.js'; import { createScene, setupLighting, setupControls } from './sceneSetup.js'; import { createModelFromPreloaded } from './modelManager.js'; import { currentModel, nextModel, mixer, nextMixer, isTransitioning, updateTransition, onMouseScroll, setCurrentModel, setMixer } from './transitionManager.js'; import { startBoldRoughnessAnimation, updateBoldRoughnessAnimation, updateInnovationGlassAnimation } from './animationManager.js'; // Fluid distortion imports import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js'; import { createFluidSimulation, FluidDistortionShader } from './fluidDistortion.js'; // Starfield import import { createStarfield } from './starfield.js'; // Initialize loader const sceneLoader = new SceneLoader(); sceneLoader.setLoadingMessage('Preparing Your Experience...'); // Create scene components const { scene, camera, renderer, composer } = createScene(); setupLighting(scene, camera); const controls = setupControls(camera, renderer); // Create starfield const starfield = createStarfield(scene); // Turntable animation settings const turntableSpeed = 0.5; // Store preloaded models let preloadedModels = {}; // Enhanced fluid simulation + distortion pass const dpr = renderer.getPixelRatio ? renderer.getPixelRatio() : Math.min(window.devicePixelRatio || 1, 2); const fluid = createFluidSimulation(renderer, dpr); const distortionPass = new ShaderPass(FluidDistortionShader); distortionPass.material.uniforms.tSim.value = fluid.getTexture(); distortionPass.material.uniforms.iResolution.value.set(window.innerWidth * dpr, window.innerHeight * dpr); distortionPass.material.uniforms.amount.value = 0.005; // Stronger distortion distortionPass.material.uniforms.chromaticAmount.value = 0.002; // Enhanced chromatic aberration // Enhanced lighting parameters distortionPass.material.uniforms.lightIntensity.value = 1.5; distortionPass.material.uniforms.lightColor.value.set(1, 1, 1); // Cool blue-white distortionPass.material.uniforms.normalStrength.value = 2.0; distortionPass.material.uniforms.ambientLight.value = 0.15; composer.addPass(distortionPass); // Enhanced pointer tracking const pointer = { x: -1, y: -1, strength: 0.0, prevX: -1, prevY: -1, trail: [], // Store trail positions for enhanced effect maxTrailLength: 5 }; // Mouse coordinates for starfield const mouse = new THREE.Vector2(); function toSimPixels(e) { const rect = renderer.domElement.getBoundingClientRect(); const x = (e.clientX - rect.left) * dpr; const y = (rect.height - (e.clientY - rect.top)) * dpr; return { x, y }; } renderer.domElement.addEventListener('pointermove', (e) => { const { x, y } = toSimPixels(e); const dx = (pointer.prevX < 0) ? 0 : Math.abs(x - pointer.prevX); const dy = (pointer.prevY < 0) ? 0 : Math.abs(y - pointer.prevY); const speed = Math.min(Math.sqrt(dx * dx + dy * dy) / (6.0 * dpr), 1.0); // More sensitive pointer.x = x; pointer.y = y; pointer.strength = speed * 1.2; // Enhanced strength pointer.prevX = x; pointer.prevY = y; // Update light position to follow cursor const rect = renderer.domElement.getBoundingClientRect(); const normalizedX = (e.clientX - rect.left) / rect.width; const normalizedY = 1.0 - (e.clientY - rect.top) / rect.height; // Flip Y distortionPass.material.uniforms.lightPosition.value.set(normalizedX, normalizedY, 1.0); // Update mouse coordinates for starfield mouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1; mouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1; }, { passive: true }); renderer.domElement.addEventListener('pointerleave', () => { pointer.x = -1; pointer.y = -1; pointer.strength = 0.0; mouse.x = -999; mouse.y = -999; // Reset light to center when mouse leaves distortionPass.material.uniforms.lightPosition.value.set(0.5, 0.5, 1.0); }, { passive: true }); // Initialize first scene function initializeScene() { console.log('Initializing first scene (bold)'); const { model, animMixer } = createModelFromPreloaded('bold', preloadedModels, camera, controls); setCurrentModel(model); setMixer(animMixer); scene.add(currentModel); startBoldRoughnessAnimation(true); console.log('Bold scene initialized'); } // Animation loop const clock = new THREE.Clock(); function animate() { requestAnimationFrame(animate); const delta = clock.getDelta(); // Update mixers if (mixer) mixer.update(delta); if (nextMixer) nextMixer.update(delta); // Update transition if (isTransitioning) { updateTransition(delta, scene); } // Turntable rotation if (currentModel) { currentModel.rotation.y += turntableSpeed * delta; } if (nextModel) { nextModel.rotation.y += turntableSpeed * delta; } // Update material animations updateBoldRoughnessAnimation(); updateInnovationGlassAnimation(); // Animate stars with cursor interaction starfield.animateStars(camera, mouse, delta); // Update enhanced fluid sim const nowSec = performance.now() / 1000; fluid.update(pointer.x, pointer.y, pointer.strength, nowSec); distortionPass.material.uniforms.tSim.value = fluid.getTexture(); controls.update(); composer.render(); } // Initialize the scene async function init() { try { console.log('Starting application initialization'); preloadedModels = await sceneLoader.loadAllModels(); console.log('All models loaded successfully'); initializeScene(); animate(); console.log('Animation loop started'); window.addEventListener('wheel', (event) => { onMouseScroll(event, preloadedModels, scene, camera, controls); }, { passive: true }); console.log('Scroll event listener attached'); } catch (error) { console.error('Failed to initialize scene:', error); sceneLoader.setLoadingMessage('Error loading experience. Please refresh.'); } } // Handle window resize window.addEventListener('resize', () => { console.log('Window resized'); const w = window.innerWidth; const h = window.innerHeight; camera.aspect = w / h; camera.updateProjectionMatrix(); renderer.setSize(w, h); composer.setSize(w, h); const pixelRatio = renderer.getPixelRatio ? renderer.getPixelRatio() : Math.min(window.devicePixelRatio || 1, 2); distortionPass.material.uniforms.iResolution.value.set(w * pixelRatio, h * pixelRatio); fluid.resize(w, h, pixelRatio); }); // Start the application init();