  // Import Three.js as ES modules
  import * as THREE from 'three';
  import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
  import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
  import { FBXLoader } from 'three/addons/loaders/FBXLoader.js';
  import { STLLoader } from 'three/addons/loaders/STLLoader.js';
  import * as SkeletonUtils from 'three/addons/utils/SkeletonUtils.js';
  
  // Make available globally for the rest of the code
  window.THREE = THREE;
  window.GLTFLoader = GLTFLoader;
  window.OBJLoader = OBJLoader;
  window.FBXLoader = FBXLoader;
  window.STLLoader = STLLoader;
  window.SkeletonUtils = SkeletonUtils;
  
  // =========================
  // START SCREEN SHADER BACKGROUND
  // =========================
  (async function initStartBackground() {
    // Check play mode directly from URL (isPlayMode variable isn't defined yet at this point)
    const urlCheck = new URLSearchParams(window.location.search);
    const inPlayMode = ['play', 'standalone'].includes(urlCheck.get('mode'));
    
    // Skip background shader in play mode - not needed and saves resources
    if (inPlayMode) {
      console.log('[StartBg] Skipping in play mode');
      return;
    }
    
    const canvas = document.getElementById('startBgCanvas');
    if (!canvas) return;
    
    // Skip background shader on mobile to save GPU resources
    const isMobileDevice = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
                           (navigator.maxTouchPoints > 1);
    if (isMobileDevice) {
      console.log('[StartBg] Skipping on mobile for performance');
      canvas.style.background = 'radial-gradient(ellipse at center, #1a1a2e 0%, #0b0d12 100%)';
      return;
    }
    
    // Note: shader0.glsl is optional - we have a fallback shader embedded below
    let shaderCode = '';
    try {
      const res = await fetch('/assets/shaders/shader0.glsl');
      if (res.ok) {
        shaderCode = await res.text();
      } else {
        console.log('[StartBg] shader0.glsl not found, using fallback');
      }
    } catch (e) {
      console.log('[StartBg] Could not load background shader, using fallback');
    }
    
    // Extract just the mainImage function (skip metadata comments)
    const mainImageMatch = shaderCode.match(/(#define[\s\S]*)?void\s+mainImage[\s\S]*/);
    const shaderBody = mainImageMatch ? mainImageMatch[0] : shaderCode;
    
    // Create renderer
    const renderer = new THREE.WebGLRenderer({ canvas, alpha: false, antialias: false });
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.5));
    
    function resize() {
      renderer.setSize(window.innerWidth, window.innerHeight);
    }
    resize();
    window.addEventListener('resize', resize);
    
    // Create shader material with center offset for Alice's position
    const fragmentShader = `
      precision highp float;
      uniform float iTime;
      uniform vec2 iResolution;
      uniform vec2 iCenter;
      uniform float iBass;
      uniform float iMid;
      uniform float iTreble;
      
      // Default param values for background display
      float uSpeed = 0.8;
      float uRotSpeed = 0.2;
      float uRings = 25.0;
      float uRingWidth = 0.12;
      float uRadius = 1.0;
      float uTwist = 0.4;
      float uWobble = 0.15;
      float uHueShift = 0.0;
      float uGlow = 0.6;
      float uPulse = 0.3;
      
      #define PI 3.14159265359
      #define TAU 6.28318530718

      void mainImage(out vec4 fragColor, in vec2 fragCoord) {
          // Offset UV to center on Alice's chest
          vec2 uv = (fragCoord - iCenter) / iResolution.y;
          
          float t = iTime;
          float audioReact = iBass * uPulse;
          
          float angle = atan(uv.y, uv.x);
          float radius = length(uv);
          
          float wobble = sin(angle * 3.0 + t * 2.0) * uWobble * 0.1;
          radius += wobble;
          
          float z = 1.0 / (radius + 0.1);
          z += t * uSpeed + audioReact * 0.5;
          
          angle += z * uTwist + t * uRotSpeed;
          
          float rings = fract(z * uRings * 0.1);
          float ringPattern = smoothstep(0.0, uRingWidth, rings) * smoothstep(uRingWidth * 2.0, uRingWidth, rings);
          
          float segments = 8.0;
          float radialLines = abs(sin(angle * segments)) * 0.5 + 0.5;
          
          float tunnelDist = abs(radius - uRadius * 0.3);
          float tunnelGlow = exp(-tunnelDist * 8.0) * uGlow;
          
          float hue = fract(z * 0.05 + angle / TAU + uHueShift + t * 0.1);
          vec3 col = 0.5 + 0.5 * cos(TAU * (hue + vec3(0.0, 0.33, 0.67)));
          
          float pattern = ringPattern * 0.7 + radialLines * 0.3;
          pattern *= tunnelGlow;
          
          pattern += iBass * 0.3 * exp(-radius * 3.0);
          
          col *= pattern;
          
          float fog = exp(-z * 0.02);
          col *= fog;
          
          float vig = 1.0 - radius * 0.5;
          col *= vig;
          
          col += vec3(0.1, 0.05, 0.2) * exp(-radius * 5.0) * (0.5 + iTreble);
          
          fragColor = vec4(clamp(col, 0.0, 1.0), 1.0);
      }
      
      void main() {
        vec4 fragColor;
        mainImage(fragColor, gl_FragCoord.xy);
        gl_FragColor = fragColor;
      }
    `;
    
    const vertexShader = `
      void main() {
        gl_Position = vec4(position, 1.0);
      }
    `;
    
    // Calculate center point where Alice's chest is
    // Reference: X:1110, Y:84 on a 1920x1080 screen
    function getAliceCenter() {
      const w = window.innerWidth;
      const h = window.innerHeight;
      // Scale from reference resolution (1920x1080)
      const refW = 1920, refH = 1080;
      const refX = 1110, refY = 84;
      // In WebGL, Y=0 is at bottom, so flip Y
      const x = (refX / refW) * w;
      const y = h - (refY / refH) * h;
      return new THREE.Vector2(x, y);
    }
    
    const material = new THREE.ShaderMaterial({
      vertexShader,
      fragmentShader,
      uniforms: {
        iTime: { value: 0 },
        iResolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
        iCenter: { value: getAliceCenter() },
        iBass: { value: 0 },
        iMid: { value: 0 },
        iTreble: { value: 0 }
      },
      depthTest: false,
      depthWrite: false
    });
    
    // Create fullscreen quad
    const scene = new THREE.Scene();
    const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
    const geometry = new THREE.PlaneGeometry(2, 2);
    const quad = new THREE.Mesh(geometry, material);
    scene.add(quad);
    
    // Animation loop
    let startTime = performance.now();
    let animationId = null;
    
    function animate() {
      const overlay = document.getElementById('startOverlay');
      if (!overlay || overlay.style.display === 'none') {
        // Stop animation when start screen is hidden
        if (animationId) cancelAnimationFrame(animationId);
        renderer.dispose();
        return;
      }
      
      animationId = requestAnimationFrame(animate);
      
      const elapsed = (performance.now() - startTime) / 1000;
      material.uniforms.iTime.value = elapsed;
      material.uniforms.iResolution.value.set(window.innerWidth, window.innerHeight);
      
      // Update center to track Alice's position on resize
      const center = getAliceCenter();
      material.uniforms.iCenter.value.set(center.x, center.y);
      
      // Subtle fake audio reactivity
      material.uniforms.iBass.value = 0.3 + Math.sin(elapsed * 1.2) * 0.2;
      material.uniforms.iMid.value = 0.3 + Math.sin(elapsed * 1.7) * 0.15;
      material.uniforms.iTreble.value = 0.3 + Math.sin(elapsed * 2.1) * 0.15;
      
      renderer.render(scene, camera);
    }
    
    animate();
    window.startBgCleanup = () => {
      if (animationId) cancelAnimationFrame(animationId);
      renderer.dispose();
    };
  })();
