// GLB Logo loader - non-module version console.log('Loading GLB logo script...'); // Logo instances storage const logoInstances = new Map(); let darkMaterial, lightMaterial; // Wait for Three.js to load from CDN function waitForThreeJS(callback) { if (typeof THREE !== 'undefined') { console.log('Three.js is available'); callback(); } else { console.log('Waiting for Three.js to load...'); setTimeout(() => waitForThreeJS(callback), 100); } } // Load required Three.js modules function loadThreeJSModules() { return new Promise((resolve, reject) => { console.log('Loading GLTFLoader from CDN...'); // Load GLTFLoader - using the correct path for regular JS version const gltfScript = document.createElement('script'); gltfScript.src = 'https://cdn.jsdelivr.net/npm/three@0.160.0/examples/js/loaders/GLTFLoader.js'; gltfScript.onload = () => { console.log('GLTFLoader loaded successfully'); console.log('Loading DRACOLoader from CDN...'); // Load DRACOLoader - using the correct path for regular JS version const dracoScript = document.createElement('script'); dracoScript.src = 'https://cdn.jsdelivr.net/npm/three@0.160.0/examples/js/loaders/DRACOLoader.js'; dracoScript.onload = () => { console.log('DRACOLoader loaded successfully'); resolve(); }; dracoScript.onerror = (error) => { console.error('Failed to load DRACOLoader:', error); console.log('Continuing without DRACOLoader...'); resolve(); // Continue without DRACO support }; document.head.appendChild(dracoScript); }; gltfScript.onerror = (error) => { console.error('Failed to load GLTFLoader:', error); reject(error); }; document.head.appendChild(gltfScript); }); } function createMaterials() { console.log("Creating materials for GLB model..."); darkMaterial = new THREE.MeshPhysicalMaterial({ color: 0x453d2e, // Sand color for dark theme roughness: 0.24, metalness: 1.0, clearcoat: 0.48, clearcoatRoughness: 0.15, reflectivity: 1.2, }); lightMaterial = new THREE.MeshPhysicalMaterial({ color: 0x0b0213, // Dark Mulberry for light theme roughness: 0.28, metalness: 0.98, clearcoat: 0.52, clearcoatRoughness: 0.12, reflectivity: 1.0, }); console.log("Materials created successfully"); } function initGLBLogo(canvas) { console.log('initGLBLogo called for canvas:', canvas); const scene = new THREE.Scene(); console.log('Scene created'); // Create materials if not created yet if (!darkMaterial || !lightMaterial) { console.log('Creating materials...'); createMaterials(); console.log('Materials created'); } // Get canvas dimensions const computedStyle = window.getComputedStyle(canvas); let width = parseInt(computedStyle.width) || canvas.width || 200; let height = parseInt(computedStyle.height) || canvas.height || 200; // Force square dimensions for proper Möbius ring rendering const size = Math.max(width, height); width = size; height = size; // Initialize renderer const renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true, alpha: true }); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(width, height); renderer.setClearColor(0x000000, 0); console.log('Renderer initialized with size:', { width, height }); // Set up camera const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100); camera.position.set(0, 0, 1.8); camera.lookAt(0, 0, 0); // Sophisticated lighting setup const mainLight = new THREE.PointLight(0xffffff, 1.4); mainLight.position.set(0, 4, 1); scene.add(mainLight); const bottomLight = new THREE.PointLight(0x800080, 1.2, 12); bottomLight.position.set(0, -4, 1); scene.add(bottomLight); const leftLight = new THREE.PointLight(0x808000, 1.45, 5); leftLight.position.set(-5, 0, 4); scene.add(leftLight); scene.add(new THREE.AmbientLight(0xffffff, 0.45)); let mobius = null; // Load the Möbius ring model console.log('Setting up GLTFLoader...'); const loader = new THREE.GLTFLoader(); // Set up DRACOLoader if available if (THREE.DRACOLoader) { const dracoLoader = new THREE.DRACOLoader(); dracoLoader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/'); loader.setDRACOLoader(dracoLoader); console.log('DRACOLoader configured'); } console.log('GLTFLoader configured, loading GLB file...'); loader.load( "/logos/mobius-ring.glb", // Ensure absolute path (gltf) => { console.log("GLB loaded successfully for canvas:", canvas); console.log("GLB scene:", gltf.scene); mobius = gltf.scene; let meshCount = 0; mobius.traverse((child) => { if (child.isMesh) { // Start with dark theme material (default) child.material = darkMaterial.clone(); meshCount++; } }); console.log(`Applied materials to ${meshCount} meshes`); scene.add(mobius); console.log('Möbius GLB model added to scene'); // Initialize with current theme state const isDark = document.documentElement.classList.contains('dark'); console.log('Current theme is dark:', isDark); updateCanvasMaterial(mobius, isDark); }, (progress) => { if (progress.total > 0) { console.log("GLB loading progress:", Math.round(progress.loaded / progress.total * 100) + '%'); } }, (err) => { console.error("Error loading GLB logo:", err); console.error("Error details:", err.message); // Create fallback geometry console.log('Creating fallback Möbius ring geometry...'); function mobiusFunction(u, v, target) { u = u - 0.5; v = v * 2 * Math.PI; const majorRadius = 0.6; const minorRadius = 0.2; const x = (majorRadius + minorRadius * Math.cos(v / 2) * u) * Math.cos(v); const y = (majorRadius + minorRadius * Math.cos(v / 2) * u) * Math.sin(v); const z = minorRadius * Math.sin(v / 2) * u; target.set(x, y, z); } const fallbackGeometry = new THREE.ParametricGeometry(mobiusFunction, 50, 50); const fallbackMesh = new THREE.Mesh(fallbackGeometry, darkMaterial.clone()); scene.add(fallbackMesh); mobius = fallbackMesh; console.log('Fallback Möbius geometry created'); } ); // Animation loop function animate() { requestAnimationFrame(animate); if (mobius) { // Elegant rotation mobius.rotation.x += 0.005; mobius.rotation.y += -0.008; mobius.rotation.z += -0.003; } renderer.render(scene, camera); } animate(); console.log('Animation loop started'); // Store instance const instance = { canvas, renderer, scene, camera, mobius: () => mobius, setMobius: (mobiusScene) => { mobius = mobiusScene; } }; logoInstances.set(canvas, instance); return instance; } function updateCanvasMaterial(mobius, isDark) { if (mobius) { const targetMaterial = isDark ? darkMaterial : lightMaterial; console.log(`Updating material to:`, isDark ? 'dark' : 'light'); let meshCount = 0; if (mobius.traverse) { mobius.traverse((child) => { if (child.isMesh) { child.material = targetMaterial.clone(); meshCount++; } }); } else if (mobius.isMesh) { mobius.material = targetMaterial.clone(); meshCount = 1; } console.log(`Updated ${meshCount} mesh materials`); } } // Initialize all canvas elements with chorus-logo class function initAllGLBLogos() { console.log('initAllGLBLogos called - looking for canvas.chorus-logo elements'); // First load Three.js and required modules if (typeof THREE === 'undefined') { console.log('Loading Three.js from CDN...'); const script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js'; script.onload = function() { console.log('Three.js loaded from CDN'); loadThreeJSModules().then(() => { console.log('All Three.js modules loaded'); const canvases = document.querySelectorAll("canvas.chorus-logo"); console.log(`Found ${canvases.length} canvas elements with chorus-logo class`); canvases.forEach((canvas, index) => { console.log(`Initializing GLB logo ${index} for canvas:`, canvas); initGLBLogo(canvas); }); }).catch(error => { console.error('Failed to load Three.js modules:', error); }); }; script.onerror = function() { console.error('Failed to load Three.js from CDN'); }; document.head.appendChild(script); } else { loadThreeJSModules().then(() => { const canvases = document.querySelectorAll("canvas.chorus-logo"); console.log(`Found ${canvases.length} canvas elements with chorus-logo class`); canvases.forEach((canvas, index) => { console.log(`Initializing GLB logo ${index} for canvas:`, canvas); initGLBLogo(canvas); }); }).catch(error => { console.error('Failed to load Three.js modules:', error); }); } } // Function to update all logo materials based on theme function updateAllLogoMaterials(isDark) { console.log(`updateAllLogoMaterials called with isDark: ${isDark}`); console.log(`Number of logo instances: ${logoInstances.size}`); logoInstances.forEach((instance, canvas) => { const mobius = instance.mobius(); console.log(`Updating logo instance for canvas:`, canvas, `mobius exists:`, !!mobius); if (mobius) { updateCanvasMaterial(mobius, isDark); } }); } // Export functions for global access window.updateAllLogoMaterials = updateAllLogoMaterials; window.initAllGLBLogos = initAllGLBLogos; console.log('GLB logo script loaded, initAllGLBLogos available');