import React, { useRef, useEffect, useState, useCallback } from 'react'
import { AudioEngine } from '../engine/AudioEngine'
import { 
  ParticleSystemParams, 
  ParticleSphere, 
  DEFAULT_FREQUENCY_RANGES, 
  DEFAULT_SPHERE_PARAMS,
  FogParams
} from '../types/visualization'
import { NoiseGenerator, BeatManager, generateNewNoiseScale } from '../utils/noise'
import configLoader from '../utils/configLoader'

interface WorldTreeVisualizerProps {
  audioEngine: AudioEngine | null
}

// ENTRONAUT INTEGRATION: Symbolic Emergence Field Analysis
interface EntronautState {
  sefaScore: Float32Array
  emergenceField: Float32Array
  adaptiveParams: {
    damping: Float32Array
    diffusion: Float32Array
    coupling: Float32Array
  }
  informationMetrics: {
    complexity: number
    emergence: number
    coherence: number
  }
}

// Advanced 3D Particle System Visualizer - Enhanced with Entronaut SEFA
export const WorldTreeVisualizer: React.FC<WorldTreeVisualizerProps> = ({ audioEngine }) => {
  const canvasRef = useRef<HTMLCanvasElement>(null)
  const animationRef = useRef<number>()
  const lastTimeRef = useRef<number>(0)
  
  // Three.js core objects
  const sceneRef = useRef<any>()
  const rendererRef = useRef<any>()
  const cameraRef = useRef<any>()
  const controlsRef = useRef<any>()
  
  // Advanced visualization state
  const spheresRef = useRef<ParticleSphere[]>([])
  const noiseGeneratorRef = useRef<NoiseGenerator>()
  const beatManagerRef = useRef<BeatManager>()
  const tendrilSystemRef = useRef<any>()
  const dysonSphereRef = useRef<any>()
  
  // ENTRONAUT: Symbolic emergence tracking
  const entronautStateRef = useRef<EntronautState>()
  
  // State for UI controls
  const [isVisualizationReady, setIsVisualizationReady] = useState(false)
  const [activeSpheresCount, setActiveSpheresCount] = useState(5) // All spheres active by default
  const [cymateGeometry, setCymateGeometry] = useState(true)
  const [entronautEnabled, setEntronautEnabled] = useState(true)
  const [adaptiveCoupling, setAdaptiveCoupling] = useState(true)
  const [performanceMode, setPerformanceMode] = useState(false)
  const [controlsCollapsed, setControlsCollapsed] = useState(true)
  const [cameraControlsEnabled, setCameraControlsEnabled] = useState(true)
  const [autoRotate, setAutoRotate] = useState(false)
  const [aboutCollapsed, setAboutCollapsed] = useState(true)
  const [tendrilsEnabled, setTendrilsEnabled] = useState(true)
  const [tendrilDensity, setTendrilDensity] = useState(0.3)
  const [dysonSphereEnabled, setDysonSphereEnabled] = useState(true)
  const [vineGrowthRate, setVineGrowthRate] = useState(0.02)
  const [vineComplexity, setVineComplexity] = useState(24)
  const [showStartupInfo, setShowStartupInfo] = useState(true)
  const [fogParams, setFogParams] = useState<FogParams>({
    enabled: true,
    color: '#000000',
    near: 2.7,
    far: 3.7
  })

  // Store state (currently minimal, expanded as needed)
  // const { playback } = useNexusStore()
  
  // Simplified performance monitoring - no complex optimizer
  const [performanceStats, setPerformanceStats] = useState({
    fps: 60,
    particleCount: 0,
    lastFpsUpdate: 0,
    frameCount: 0
  })

  // Hidden Auto-Refresh System
  const autoRefreshRef = useRef({
    lastRefresh: 0,
    refreshInterval: 120000, // 2 minutes base interval
    performanceDegradationCount: 0,
    particleHealthChecks: 0,
    emergencyResetCount: 0,
    isRefreshing: false
  })

  // Monitor particle system health
  const checkParticleHealth = useCallback(() => {
    if (!spheresRef.current) return true
    
    let healthyParticles = 0
    let totalParticles = 0
    
    spheresRef.current.forEach(sphere => {
      if (!sphere.params.enabled) return
      
      const { positions, velocities } = sphere
      const particleCount = sphere.params.particleCount
      totalParticles += particleCount
      
      for (let i = 0; i < particleCount; i++) {
        const i3 = i * 3
        const x = positions[i3]
        const y = positions[i3 + 1]
        const z = positions[i3 + 2]
        const vx = velocities[i3]
        const vy = velocities[i3 + 1]
        const vz = velocities[i3 + 2]
        
        // Check if particle is healthy (finite values, reasonable position/velocity)
        if (isFinite(x) && isFinite(y) && isFinite(z) && 
            isFinite(vx) && isFinite(vy) && isFinite(vz)) {
          const dist = Math.sqrt(x*x + y*y + z*z)
          const vel = Math.sqrt(vx*vx + vy*vy + vz*vz)
          
          if (dist < 10 && vel < 1) { // Reasonable bounds
            healthyParticles++
          }
        }
      }
    })
    
    const healthRatio = totalParticles > 0 ? healthyParticles / totalParticles : 1
    return healthRatio > 0.85 // 85% healthy particles threshold
  }, [])

  // Perform hidden refresh of particle systems
  const performHiddenRefresh = useCallback(async (force = false) => {
    if (autoRefreshRef.current.isRefreshing && !force) return
    
    autoRefreshRef.current.isRefreshing = true
    console.log('🔄 Performing hidden system refresh...')
    
    try {
      // Gradual refresh to avoid frame drops
      for (let sphereIndex = 0; sphereIndex < spheresRef.current.length; sphereIndex++) {
        const sphere = spheresRef.current[sphereIndex]
        if (!sphere.params.enabled) continue
        
        // Refresh 20% of particles at a time over 5 frames
        const particleCount = sphere.params.particleCount
        const batchSize = Math.floor(particleCount * 0.2)
        
        for (let batch = 0; batch < 5; batch++) {
          const startIdx = batch * batchSize
          const endIdx = Math.min(startIdx + batchSize, particleCount)
          
          // Reset particles in this batch
          for (let i = startIdx; i < endIdx; i++) {
            const i3 = i * 3
            const radius = sphere.params.sphereRadius * sphere.params.innerSphereRadius
            const theta = Math.random() * Math.PI * 2
            const phi = Math.acos(2 * Math.random() - 1)
            const r = Math.cbrt(Math.random()) * radius

            sphere.positions[i3] = r * Math.sin(phi) * Math.cos(theta)
            sphere.positions[i3 + 1] = r * Math.sin(phi) * Math.sin(theta)
            sphere.positions[i3 + 2] = r * Math.cos(phi)

            sphere.velocities[i3] = 0
            sphere.velocities[i3 + 1] = 0
            sphere.velocities[i3 + 2] = 0

            sphere.lifetimes[i] = Math.random() * sphere.params.particleLifetime
            sphere.beatEffects[i] = 0
          }
          
          // Wait one frame between batches to maintain smooth animation
          if (batch < 4) {
            await new Promise(resolve => requestAnimationFrame(() => resolve(undefined)))
          }
        }
        
                 // Note: Geometry updates are handled by the main animation loop
      }
      
      // Reset counters
      autoRefreshRef.current.performanceDegradationCount = 0
      autoRefreshRef.current.emergencyResetCount = 0
      autoRefreshRef.current.lastRefresh = Date.now()
      
      console.log('✅ Hidden refresh completed successfully')
    } catch (error) {
      console.warn('⚠️ Hidden refresh error:', error)
    } finally {
      autoRefreshRef.current.isRefreshing = false
    }
  }, [])

  // ENTRONAUT: Initialize emergence field analysis - SIMPLIFIED for performance
  const initializeEntronaut = useCallback(() => {
    // Simplified - basic structure for UI display only
    console.log('🧠 Entronaut SEFA system simplified for performance')
    entronautStateRef.current = {
      sefaScore: new Float32Array(0),
      emergenceField: new Float32Array(0),
      adaptiveParams: {
        damping: new Float32Array(0),
        diffusion: new Float32Array(0),
        coupling: new Float32Array(0)
      },
      informationMetrics: {
        complexity: 0,
        emergence: 0,
        coherence: 0
      }
    }
  }, [])

  // ENTRONAUT: Analyze audio - SIMPLIFIED
  const analyzeSymbolicEmergence = useCallback((audioData: any, _currentTime: number) => {
    // Simplified - only basic metrics without complex calculations
    if (!entronautStateRef.current || !entronautEnabled) return
    
    // Just update basic metrics without heavy computation
    const { informationMetrics } = entronautStateRef.current
    informationMetrics.complexity = audioData.overallAmplitude || 0
    informationMetrics.emergence = audioData.beatDetected ? 1.0 : 0.1
    informationMetrics.coherence = (audioData.deepEnergy + audioData.midEnergy + audioData.highEnergy) / 3.0
    
  }, [entronautEnabled])

  // ENTRONAUT: Apply adaptive coupling - SIMPLIFIED
  const applyEntronautCoupling = useCallback((_sphere: ParticleSphere, _particleIndex: number) => {
    // Return simple defaults - no complex field calculations
    return { damping: 0.95, diffusion: 0.008, coupling: 0.02 }
  }, [])

  // Initialize Three.js scene and particle systems
  const initializeVisualization = useCallback(async () => {
    if (!canvasRef.current) return

    console.log('🎨 Initializing advanced particle visualization with Entronaut SEFA...')

    try {
      // Dynamically import Three.js
      const THREE = await import('three')
      
      // Create scene
      const scene = new THREE.Scene()
      scene.background = new THREE.Color(0x000000)
      sceneRef.current = scene

      // Create camera
      const camera = new THREE.PerspectiveCamera(
        75, 
        window.innerWidth / window.innerHeight, 
        0.1, 
        1000
      )
      camera.position.set(0, 0, 2.5)
      cameraRef.current = camera

      // Create renderer
      const renderer = new THREE.WebGLRenderer({ 
        canvas: canvasRef.current!,
        antialias: true 
      })
      renderer.setSize(window.innerWidth, window.innerHeight)
      rendererRef.current = renderer

      // Initialize camera controls
      const { OrbitControls } = await import('three/examples/jsm/controls/OrbitControls.js')
      const controls = new OrbitControls(camera, renderer.domElement)
      
      // Configure controls
      controls.enableDamping = true
      controls.dampingFactor = 0.05
      controls.enableZoom = true
      controls.enablePan = true
      controls.enableRotate = true
      
      // Set limits
      controls.maxDistance = 50
      controls.minDistance = 0.1
      controls.maxPolarAngle = Math.PI // Allow full rotation
      
      // Auto-rotate settings
      controls.autoRotate = autoRotate
      controls.autoRotateSpeed = 0.5
      
      // Prevent controls from interfering with UI elements
      controls.addEventListener('change', () => {
        // Only update if camera controls are enabled
        if (!cameraControlsEnabled) {
          controls.enabled = false
        }
      })
      
      controlsRef.current = controls

      // Initialize noise generator and beat manager
      noiseGeneratorRef.current = new NoiseGenerator()
      beatManagerRef.current = new BeatManager()

      // Initialize Entronaut
      initializeEntronaut()

      // Create particle spheres
      await createParticleSpheres(THREE, scene)

      // Create dynamic tendril system
      if (tendrilsEnabled) {
        await createTendrilSystem(THREE, scene)
      }

      // Create Dyson sphere/growing vines system
      if (dysonSphereEnabled) {
        await createDysonSphere(THREE, scene)
      }

      // Setup fog
      updateFog(THREE)

      setIsVisualizationReady(true)
      console.log('✅ Advanced particle visualization with Entronaut initialized')

    } catch (error) {
      console.error('❌ Failed to initialize visualization:', error)
    }
  }, [initializeEntronaut])

  // Create multiple particle sphere systems
  const createParticleSpheres = useCallback(async (THREE: any, scene: any) => {
    const spheres: ParticleSphere[] = []

    // Load organic color schemes from config
    const config = configLoader.getConfig()
    const configColorSchemes = (config as any)?.colors?.sphereColorSchemes

    // Enhanced organic color schemes for each sphere
    const colorSchemes = configColorSchemes || [
      { start: '#2d5016', end: '#7d4f39' }, // Deep forest to iron oxide (sub-bass)
      { start: '#8b5a2b', end: '#4a6741' }, // Earth brown to vine green (bass)
      { start: '#cd853f', end: '#556b2f' }, // Sandy brown to moss green (mid)
      { start: '#daa520', end: '#2e8b57' }, // Gold leaf to sea green (high-mid)
      { start: '#b8860b', end: '#20b2aa' }  // Burnished gold to teal depth (high)
    ]

    for (let i = 0; i < 5; i++) {
      const sphereParams: ParticleSystemParams = {
        ...DEFAULT_SPHERE_PARAMS,
        enabled: true, // All spheres enabled by default
        ...DEFAULT_FREQUENCY_RANGES[i] || DEFAULT_FREQUENCY_RANGES[0],
        colorStart: colorSchemes[i].start,
        colorEnd: colorSchemes[i].end,
        // Enhanced settings for organic, rich visuals
        particleCount: 15000, // Increased for more density
        turbulenceStrength: 0.006, // Reduced for more organic movement
        beatStrength: 0.015, // Gentler beat response for organic feel
        noiseScale: 2.5 + i * 0.3, // Smoother noise variation
        sphereRadius: 1.0 + i * 0.06, // More subtle spatial variation
        rotationSpeedMax: 0.04 + i * 0.006, // Slower, more organic rotation
        particleLifetime: 12.0 + i * 2.0 // Longer lifetimes for stability
      }

      const sphere = await createParticleSphere(THREE, scene, i, sphereParams)
      spheres.push(sphere)
    }

    spheresRef.current = spheres
    console.log(`🔮 Created ${spheres.length} particle sphere systems`)
  }, [])

  // Create dynamic tendril system that connects particles
  const createTendrilSystem = useCallback(async (THREE: any, scene: any) => {
    if (!tendrilsEnabled) return

    console.log('🌿 Creating dynamic tendril system...')
    
    // Create tendril network between particles
    const maxTendrils = 2000 // Maximum number of tendrils
    const maxTendrilLength = 0.8 // Maximum distance for tendril connections
    const tendrilSegments = 8 // Segments per tendril for smooth curves
    
    // Create tendril geometry
    const tendrilGeometry = new THREE.BufferGeometry()
    const tendrilPositions = new Float32Array(maxTendrils * tendrilSegments * 6) // 2 points per segment
    const tendrilColors = new Float32Array(maxTendrils * tendrilSegments * 6) // RGB for each point
    const tendrilOpacities = new Float32Array(maxTendrils * tendrilSegments * 2) // Alpha for each point
    
    // Initialize with empty data
    tendrilPositions.fill(0)
    tendrilColors.fill(0.3) // Dim gold base
    tendrilOpacities.fill(0)
    
    tendrilGeometry.setAttribute('position', new THREE.BufferAttribute(tendrilPositions, 3))
    tendrilGeometry.setAttribute('color', new THREE.BufferAttribute(tendrilColors, 3))
    tendrilGeometry.setAttribute('alpha', new THREE.BufferAttribute(tendrilOpacities, 1))
    
    // Create custom shader material for tendrils
    const tendrilMaterial = new THREE.ShaderMaterial({
      uniforms: {
        time: { value: 0.0 },
        sefaField: { value: 0.0 },
        audioEnergy: { value: 0.0 }
      },
      vertexShader: `
        attribute float alpha;
        varying float vAlpha;
        varying vec3 vColor;
        uniform float time;
        uniform float sefaField;
        uniform float audioEnergy;
        
        void main() {
          vAlpha = alpha * (0.3 + 0.7 * sin(time * 2.0 + position.x * 10.0));
          vColor = color * (0.5 + 0.5 * audioEnergy);
          
          vec3 pos = position;
          // Add SEFA-driven undulation
          pos += 0.02 * sefaField * sin(time * 3.0 + position.y * 15.0) * normal;
          
          gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
        }
      `,
      fragmentShader: `
        varying float vAlpha;
        varying vec3 vColor;
        
        void main() {
          // Create glowing tendril effect
          float glow = 1.0 - length(gl_PointCoord - vec2(0.5));
          glow = pow(glow, 2.0);
          
          gl_FragColor = vec4(vColor, vAlpha * glow);
        }
      `,
      transparent: true,
      blending: THREE.AdditiveBlending,
      side: THREE.DoubleSide
    })
    
    // Create tendril line system
    const tendrilLines = new THREE.LineSegments(tendrilGeometry, tendrilMaterial)
    tendrilLines.userData = { type: 'tendrils' }
    scene.add(tendrilLines)
    
    tendrilSystemRef.current = {
      geometry: tendrilGeometry,
      material: tendrilMaterial,
      lines: tendrilLines,
      positions: tendrilPositions,
      colors: tendrilColors,
      opacities: tendrilOpacities,
      maxTendrils,
      maxTendrilLength,
      tendrilSegments,
      lastUpdate: 0
    }
    
    console.log('✅ Dynamic tendril system created')
  }, [tendrilsEnabled])

  // Create Dyson sphere/growing vines system
  const createDysonSphere = useCallback(async (THREE: any, scene: any) => {
    if (!dysonSphereEnabled) return

    console.log('🌿 Creating Dyson sphere growing vines system...')
    
    const config = configLoader.getConfig()
    const dysonConfig = (config as any)?.dysonSphere
    const colors = (config as any)?.colors?.dysonVines
    
    if (!dysonConfig || !colors) {
      console.warn('Dyson sphere configuration missing')
      return
    }
    
    // Initialize vine system
    const maxVines = vineComplexity
    const maxSegments = dysonConfig.vines.maxSegmentsPerVine
    const sphereRadius = dysonConfig.vines.sphereRadius
    
    // Create vine geometry
    const vineGeometry = new THREE.BufferGeometry()
    const vinePositions = new Float32Array(maxVines * maxSegments * 6) // Line segments
    const vineColors = new Float32Array(maxVines * maxSegments * 6)
    const vineOpacities = new Float32Array(maxVines * maxSegments * 2)
    
    // Initialize with empty data
    vinePositions.fill(0)
    vineColors.fill(0)
    vineOpacities.fill(0)
    
    vineGeometry.setAttribute('position', new THREE.BufferAttribute(vinePositions, 3))
    vineGeometry.setAttribute('color', new THREE.BufferAttribute(vineColors, 3))
    vineGeometry.setAttribute('alpha', new THREE.BufferAttribute(vineOpacities, 1))
    
    // Create node geometry for connection points
    const nodeGeometry = new THREE.SphereGeometry(dysonConfig.nodes.nodeSize, 8, 6)
    const nodeMaterial = new THREE.MeshBasicMaterial({
      color: new THREE.Color(colors.nodeColor),
      transparent: true,
      opacity: 0.8
    })
    
    // Create vine shader material
    const vineMaterial = new THREE.ShaderMaterial({
      uniforms: {
        time: { value: 0.0 },
        growthProgress: { value: 0.0 },
        audioEnergy: { value: 0.0 },
        emergenceField: { value: 0.0 },
        vineGlow: { value: dysonConfig.visual.vineGlow },
        primaryColor: { value: new THREE.Color(colors.primaryVine) },
        secondaryColor: { value: new THREE.Color(colors.secondaryVine) },
        highlightColor: { value: new THREE.Color(colors.vineHighlight) }
      },
      vertexShader: `
        attribute float alpha;
        varying float vAlpha;
        varying vec3 vColor;
        varying vec3 vPosition;
        uniform float time;
        uniform float growthProgress;
        uniform float audioEnergy;
        uniform vec3 primaryColor;
        uniform vec3 secondaryColor;
        uniform vec3 highlightColor;
        
        void main() {
          vAlpha = alpha * (0.4 + 0.6 * sin(time * 2.0 + position.x * 8.0));
          vPosition = position;
          
          // Organic color blending
          float colorMix = sin(time * 1.5 + position.y * 6.0) * 0.5 + 0.5;
          vColor = mix(primaryColor, secondaryColor, colorMix);
          vColor = mix(vColor, highlightColor, audioEnergy * 0.3);
          
          vec3 pos = position;
          // Add organic growth undulation
          float growth = min(1.0, growthProgress + sin(time * 0.5) * 0.1);
          pos *= growth;
          
          // Audio-reactive pulsing
          pos += 0.01 * audioEnergy * sin(time * 4.0 + length(position) * 12.0) * normalize(position);
          
          gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
        }
      `,
      fragmentShader: `
        varying float vAlpha;
        varying vec3 vColor;
        varying vec3 vPosition;
        uniform float vineGlow;
        
        void main() {
          // Distance-based glow effect
          float dist = length(vPosition);
          float glow = 1.0 / (1.0 + dist * 2.0);
          glow = pow(glow, vineGlow);
          
          // Organic pulsing opacity
          float pulse = sin(dist * 8.0 - time * 3.0) * 0.3 + 0.7;
          
          gl_FragColor = vec4(vColor * glow, vAlpha * pulse);
        }
      `,
      transparent: true,
      blending: THREE.AdditiveBlending,
      side: THREE.DoubleSide
    })
    
    // Create vine line system
    const vineLines = new THREE.LineSegments(vineGeometry, vineMaterial)
    vineLines.userData = { type: 'dysonVines' }
    scene.add(vineLines)
    
    // Create node instances
    const nodeInstances = []
    for (let i = 0; i < dysonConfig.nodes.nodeCount; i++) {
      const node = new THREE.Mesh(nodeGeometry, nodeMaterial.clone())
      node.userData = { type: 'dysonNode', index: i }
      scene.add(node)
      nodeInstances.push(node)
    }
    
    // Initialize vine growth data
    const vineData = {
      vines: [] as any[],
      growthProgress: 0,
      lastUpdate: 0
    }
    
    // Create initial vine seeds
    for (let i = 0; i < dysonConfig.growth.seedPoints; i++) {
      const theta = (i / dysonConfig.growth.seedPoints) * Math.PI * 2
      const phi = Math.acos(2 * Math.random() - 1)
      
      const startPos = {
        x: sphereRadius * Math.sin(phi) * Math.cos(theta),
        y: sphereRadius * Math.sin(phi) * Math.sin(theta),
        z: sphereRadius * Math.cos(phi)
      }
      
      vineData.vines.push({
        segments: [startPos],
        growth: 0,
        direction: { x: Math.random() - 0.5, y: Math.random() - 0.5, z: Math.random() - 0.5 },
        branches: [],
        maturity: 0,
        energy: Math.random()
      })
    }
    
    dysonSphereRef.current = {
      vineGeometry,
      vineMaterial,
      vineLines,
      nodeGeometry,
      nodeInstances,
      vinePositions,
      vineColors,
      vineOpacities,
      vineData,
      maxVines,
      maxSegments,
      sphereRadius,
      lastUpdate: 0,
      config: dysonConfig,
      colors
    }
    
    console.log('✅ Dyson sphere growing vines system created')
  }, [dysonSphereEnabled, vineComplexity])

  // Create individual particle sphere
  const createParticleSphere = async (
    THREE: any, 
    scene: any, 
    index: number, 
    params: ParticleSystemParams
  ): Promise<ParticleSphere> => {
    
    // Create geometry and buffers
    const geometry = new THREE.BufferGeometry()
    const positions = new Float32Array(params.particleCount * 3)
    const colors = new Float32Array(params.particleCount * 3)
    const velocities = new Float32Array(params.particleCount * 3)
    const basePositions = new Float32Array(params.particleCount * 3)
    const lifetimes = new Float32Array(params.particleCount)
    const maxLifetimes = new Float32Array(params.particleCount)
    const beatEffects = new Float32Array(params.particleCount)

    // Initialize particles
    for (let i = 0; i < params.particleCount; i++) {
      const i3 = i * 3
      const radius = THREE.MathUtils.lerp(0, params.sphereRadius, params.innerSphereRadius)
      const theta = Math.random() * Math.PI * 2
      const phi = Math.acos(2 * Math.random() - 1)
      const r = Math.cbrt(Math.random()) * radius

      const x = r * Math.sin(phi) * Math.cos(theta)
      const y = r * Math.sin(phi) * Math.sin(theta)
      const z = r * Math.cos(phi)

      positions[i3] = x
      positions[i3 + 1] = y
      positions[i3 + 2] = z

      basePositions[i3] = x
      basePositions[i3 + 1] = y
      basePositions[i3 + 2] = z

      velocities[i3] = 0
      velocities[i3 + 1] = 0
      velocities[i3 + 2] = 0

      const lt = Math.random() * params.particleLifetime
      lifetimes[i] = lt
      maxLifetimes[i] = lt
      beatEffects[i] = 0
    }

    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
    geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3))

    // Create material with organic styling
    const material = new THREE.PointsMaterial({
      size: params.particleSize * (0.8 + index * 0.05), // Subtle size variation per sphere
      vertexColors: true,
      transparent: true,
      opacity: 0.85 - index * 0.05, // Decreasing opacity for depth
      blending: THREE.AdditiveBlending,
      fog: true,
      sizeAttenuation: true // Natural size falloff with distance
    })

    // Create particle system
    const particleSystem = new THREE.Points(geometry, material)
    particleSystem.visible = params.enabled
    particleSystem.userData = { sphereIndex: index }  // Critical: Link to sphere
    scene.add(particleSystem)

    // Create sphere object
    const sphere: ParticleSphere = {
      index,
      params,
      positions,
      velocities,
      basePositions,
      lifetimes,
      maxLifetimes,
      beatEffects,
      colors,
      lastNoiseScale: params.noiseScale,
      lastValidVolume: 0,
      lastRotationSpeed: 0,
      peakDetection: {
        energyHistory: [],
        historyLength: 30,
        lastPeakTime: 0,
        minTimeBetweenPeaks: 200
      }
    }

    // Update colors
    updateSphereColors(THREE, sphere)

    return sphere
  }

  // Update sphere colors with organic palette blending
  const updateSphereColors = (THREE: any, sphere: ParticleSphere) => {
    const color1 = new THREE.Color(sphere.params.colorStart)
    const color2 = new THREE.Color(sphere.params.colorEnd)
    
    // Load organic palette for enhanced blending
    const config = configLoader.getConfig()
    const organicPalette = (config as any)?.colors?.organicPalette
    
    for (let i = 0; i < sphere.params.particleCount; i++) {
      const t = i / sphere.params.particleCount
      
      // Base color interpolation
      let r = color1.r * (1 - t) + color2.r * t
      let g = color1.g * (1 - t) + color2.g * t
      let b = color1.b * (1 - t) + color2.b * t
      
      // Apply organic palette enhancement if available
      if (organicPalette && entronautEnabled) {
        const emergence = entronautStateRef.current?.informationMetrics?.emergence || 0
        
        // Blend with organic colors based on SEFA emergence
        const organicInfluence = emergence * 0.3
        
        // Choose organic color based on frequency range
        let organicColor
        if (sphere.index === 0) { // Sub-bass -> deep forest/bronze
          organicColor = hexToRgb(organicPalette.deepForest) || { r: 0.18, g: 0.31, b: 0.09 }
        } else if (sphere.index === 1) { // Bass -> earth brown/copper
          organicColor = hexToRgb(organicPalette.earthBrown) || { r: 0.54, g: 0.27, b: 0.07 }
        } else if (sphere.index === 2) { // Mid -> copper glow/gold
          organicColor = hexToRgb(organicPalette.copperGlow) || { r: 0.72, g: 0.45, b: 0.20 }
        } else if (sphere.index === 3) { // High-mid -> gold leaf/moss
          organicColor = hexToRgb(organicPalette.goldLeaf) || { r: 0.85, g: 0.65, b: 0.13 }
        } else { // High -> teal depth/amber
          organicColor = hexToRgb(organicPalette.tealDepth) || { r: 0.13, g: 0.70, b: 0.67 }
        }
        
        // Blend with organic color
        r = r * (1 - organicInfluence) + organicColor.r * organicInfluence
        g = g * (1 - organicInfluence) + organicColor.g * organicInfluence
        b = b * (1 - organicInfluence) + organicColor.b * organicInfluence
      }
      
      sphere.colors[i * 3] = r
      sphere.colors[i * 3 + 1] = g
      sphere.colors[i * 3 + 2] = b
    }
  }

  // Update fog
  const updateFog = (THREE: any) => {
    if (!sceneRef.current) return

    if (!fogParams.enabled) {
      sceneRef.current.fog = null
    } else {
      const color = new THREE.Color(fogParams.color)
      sceneRef.current.fog = new THREE.Fog(color, fogParams.near, fogParams.far)
    }
  }

  // Main animation loop
  const animate = useCallback((currentTime: number) => {
    if (!isVisualizationReady || !rendererRef.current || !sceneRef.current || !cameraRef.current) {
      animationRef.current = requestAnimationFrame(animate)
      return
    }

    const deltaTime = lastTimeRef.current ? (currentTime - lastTimeRef.current) / 1000 : 0
    lastTimeRef.current = currentTime

    // Check if audio is playing and hide startup info
    if (showStartupInfo && audioEngine) {
      const audioData = audioEngine.getAudioData()
      if (audioData.overallAmplitude > 0.01) {
        setShowStartupInfo(false)
      }
    }

    // Enhanced FPS monitoring with auto-refresh triggers
    setPerformanceStats(prev => {
      const frameCount = prev.frameCount + 1
      const timeSinceLastUpdate = currentTime - prev.lastFpsUpdate
      
      if (timeSinceLastUpdate > 1000) { // Update FPS every second
        const fps = Math.round(frameCount * 1000 / timeSinceLastUpdate)
        const totalParticles = spheresRef.current.reduce((sum, sphere) => 
          sum + (sphere.params.enabled ? sphere.params.particleCount : 0), 0)
        
        // Hidden Auto-Refresh Logic
        const autoRefresh = autoRefreshRef.current
        const now = Date.now()
        
        // Check for performance degradation
        if (fps < 30) {
          autoRefresh.performanceDegradationCount++
        } else {
          autoRefresh.performanceDegradationCount = Math.max(0, autoRefresh.performanceDegradationCount - 1)
        }
        
        // Check particle health every 5 seconds
        if (frameCount % 5 === 0) {
          autoRefresh.particleHealthChecks++
          const isHealthy = checkParticleHealth()
          
          if (!isHealthy) {
            autoRefresh.emergencyResetCount++
          }
        }
        
        // Trigger hidden refresh if conditions are met
        const timeSinceLastRefresh = now - autoRefresh.lastRefresh
        const shouldRefresh = (
          // Periodic refresh (every 2 minutes base)
          timeSinceLastRefresh > autoRefresh.refreshInterval ||
          // Performance degradation (3 consecutive low FPS readings)
          autoRefresh.performanceDegradationCount >= 3 ||
          // Particle health issues (2 consecutive unhealthy checks)
          autoRefresh.emergencyResetCount >= 2
        )
        
        if (shouldRefresh && !autoRefresh.isRefreshing) {
          // Adjust refresh interval based on performance
          if (autoRefresh.performanceDegradationCount >= 3) {
            autoRefresh.refreshInterval = 60000 // 1 minute for poor performance
          } else if (fps > 45) {
            autoRefresh.refreshInterval = 180000 // 3 minutes for good performance
          } else {
            autoRefresh.refreshInterval = 120000 // 2 minutes default
          }
          
          // Perform refresh without blocking the main thread
          setTimeout(() => performHiddenRefresh(), 100)
        }
        
        return {
          fps,
          particleCount: totalParticles,
          lastFpsUpdate: currentTime,
          frameCount: 0
        }
      }
      
      return { ...prev, frameCount }
    })

    // Update camera controls
    if (controlsRef.current) {
      controlsRef.current.enabled = cameraControlsEnabled
      controlsRef.current.autoRotate = autoRotate && cameraControlsEnabled
      if (cameraControlsEnabled) {
        controlsRef.current.update()
      }
    }

    // Update beat manager
    beatManagerRef.current?.update(deltaTime)

    // ENTRONAUT: Analyze emergence patterns in audio data (reduced frequency for performance)
    if (audioEngine && entronautEnabled && (Math.floor(currentTime * 0.01) % 3 === 0)) { // Run every 3rd frame
      const audioData = audioEngine.getAudioData()
      if (Math.random() < 0.005) { // Reduced logging frequency
        console.log('🧠 SEFA Analysis - Audio Data:', {
          deepEnergy: audioData.deepEnergy,
          midEnergy: audioData.midEnergy,
          highEnergy: audioData.highEnergy,
          overallAmplitude: audioData.overallAmplitude,
          beatDetected: audioData.beatDetected
        })
      }
      analyzeSymbolicEmergence(audioData, currentTime)
    }

    // Update particle spheres
    updateParticleSpheres(currentTime, deltaTime)

    // Update dynamic tendrils
    updateTendrilSystem(currentTime, deltaTime)

    // Update Dyson sphere/growing vines
    updateDysonSphere(currentTime, deltaTime)

    // Render scene
    rendererRef.current.render(sceneRef.current, cameraRef.current)
    
    animationRef.current = requestAnimationFrame(animate)
  }, [isVisualizationReady, audioEngine, entronautEnabled, analyzeSymbolicEmergence])

  // Update all particle spheres with inter-sphere communication
  const updateParticleSpheres = (currentTime: number, deltaTime: number) => {
    if (!audioEngine || !noiseGeneratorRef.current || !beatManagerRef.current) return

    // Calculate global emergence state for inter-sphere communication
    const globalEmergence = entronautStateRef.current ? 
      entronautStateRef.current.informationMetrics.emergence : 0
    const globalComplexity = entronautStateRef.current ? 
      entronautStateRef.current.informationMetrics.complexity : 0

    spheresRef.current.forEach((sphere, sphereIndex) => {
      if (!sphere.params.enabled) return

      // Get audio data for this sphere
      const audioData = audioEngine.getAdvancedAudioData(sphere)
      
      // Add debug logging for the first sphere
      if (sphere.index === 0 && Math.random() < 0.01) { // 1% chance to log
        console.log('🎯 Audio data for sphere 0:', {
          rangeEnergy: audioData.rangeEnergy,
          rangeEnergyBeat: audioData.rangeEnergyBeat,
          peakDetected: audioData.peakDetected,
          beatThreshold: sphere.params.beatThreshold
        })
      }

      // OPTIMIZED INTER-SPHERE COMMUNICATION (run less frequently)
      if (entronautEnabled && adaptiveCoupling && (sphereIndex === 0 || Math.random() < 0.1)) {
        // Simplified sphere influence with reduced frequency
        let avgNoiseScale = 0
        let activeNeighbors = 0
        
        spheresRef.current.forEach((otherSphere, otherIndex) => {
          if (otherIndex !== sphereIndex && otherSphere.params.enabled) {
            avgNoiseScale += otherSphere.params.noiseScale
            activeNeighbors++
          }
        })
        
        if (activeNeighbors > 0) {
          avgNoiseScale /= activeNeighbors
          const networkInfluence = globalEmergence * 0.1 // Reduced influence
          sphere.params.noiseScale = sphere.params.noiseScale * (1 - networkInfluence) + 
                                   avgNoiseScale * networkInfluence
        }
        
        // Simplified synchronization
        const syncPulse = globalComplexity * 0.2
        sphere.params.turbulenceStrength *= (1 + syncPulse)
      }

      // Handle peak detection and dynamic noise scaling
      if (audioData.peakDetected && sphere.params.dynamicNoiseScale) {
        sphere.params.noiseScale = generateNewNoiseScale(sphere.params, sphere.lastNoiseScale)
        sphere.lastNoiseScale = sphere.params.noiseScale
      }

      // Beat detection and wave triggering
      const beatDetected = audioData.rangeEnergyBeat > sphere.params.beatThreshold
      if (beatDetected && !beatManagerRef.current!.isWaveActive && sphere.params.beatStrength > 0) {
        beatManagerRef.current!.triggerWave(audioData.rangeEnergyBeat)
      }

      // Update particles
      updateSphereParticles(sphere, currentTime, deltaTime, beatDetected)

      // Update rotation based on audio
      updateSphereRotation(sphere, audioData)
    })
  }

  // Update dynamic tendril system with performance optimization
  const updateTendrilSystem = (currentTime: number, _deltaTime: number) => {
    if (!tendrilsEnabled || !tendrilSystemRef.current || !audioEngine || !entronautStateRef.current) return

    // Performance optimization for tendril system
    const adaptiveLevel = 1.0 // Simplified - no performance monitoring

    const tendrilSystem = tendrilSystemRef.current
    const { positions, colors, opacities, maxTendrils, maxTendrilLength, tendrilSegments } = tendrilSystem

    // Update shader uniforms
    const audioData = audioEngine.getAudioData()
    const sefaMetrics = entronautStateRef.current.informationMetrics
    
    tendrilSystem.material.uniforms.time.value = currentTime * 0.001
    tendrilSystem.material.uniforms.sefaField.value = sefaMetrics.emergence
    tendrilSystem.material.uniforms.audioEnergy.value = audioData.overallAmplitude || 0

    // Only update connections periodically for performance
    if (currentTime - tendrilSystem.lastUpdate < 100) return // Update every 100ms
    tendrilSystem.lastUpdate = currentTime

    let tendrilIndex = 0
    const performanceMultiplier = Math.max(0.2, adaptiveLevel) // Minimum 20% tendrils even at low performance
    const activeTendrils = Math.floor(maxTendrils * tendrilDensity * performanceMultiplier * (0.5 + 0.5 * audioData.overallAmplitude))

    // Reset all positions
    positions.fill(0)
    opacities.fill(0)

    // Create connections between particles from different spheres
    for (let sphereA = 0; sphereA < spheresRef.current.length && tendrilIndex < activeTendrils; sphereA++) {
      const sphere1 = spheresRef.current[sphereA]
      if (!sphere1.params.enabled) continue

      for (let sphereB = sphereA + 1; sphereB < spheresRef.current.length && tendrilIndex < activeTendrils; sphereB++) {
        const sphere2 = spheresRef.current[sphereB]
        if (!sphere2.params.enabled) continue

        // Sample particles from each sphere
        const sampleCount = Math.min(10, Math.floor(sphere1.params.particleCount / 1000))
        
        for (let i = 0; i < sampleCount && tendrilIndex < activeTendrils; i++) {
          const p1Index = Math.floor(Math.random() * sphere1.params.particleCount)
          const p2Index = Math.floor(Math.random() * sphere2.params.particleCount)

          const p1x = sphere1.positions[p1Index * 3]
          const p1y = sphere1.positions[p1Index * 3 + 1]
          const p1z = sphere1.positions[p1Index * 3 + 2]

          const p2x = sphere2.positions[p2Index * 3]
          const p2y = sphere2.positions[p2Index * 3 + 1]
          const p2z = sphere2.positions[p2Index * 3 + 2]

          const distance = Math.sqrt(
            (p2x - p1x) ** 2 + (p2y - p1y) ** 2 + (p2z - p1z) ** 2
          )

          // Only create tendril if particles are within range
          if (distance < maxTendrilLength) {
            // Calculate SEFA influence on tendril strength
            const fieldWidth = 32
            const fieldX = Math.floor(((p1x + p2x) * 0.5 + 1) * 0.5 * fieldWidth)
            const fieldY = Math.floor(((p1y + p2y) * 0.5 + 1) * 0.5 * fieldWidth)
            const sefaIndex = Math.max(0, Math.min(
              entronautStateRef.current.sefaScore.length - 1,
              fieldY * fieldWidth + fieldX
            ))
            const sefaStrength = entronautStateRef.current.sefaScore[sefaIndex]

            // Create curved tendril with multiple segments
            for (let segment = 0; segment < tendrilSegments - 1; segment++) {
              const t1 = segment / (tendrilSegments - 1)
              const t2 = (segment + 1) / (tendrilSegments - 1)

              // Calculate curved path with SEFA-driven undulation
              const curve1 = getCurvedTendrilPoint(p1x, p1y, p1z, p2x, p2y, p2z, t1, currentTime, sefaStrength)
              const curve2 = getCurvedTendrilPoint(p1x, p1y, p1z, p2x, p2y, p2z, t2, currentTime, sefaStrength)

              const baseIndex = tendrilIndex * tendrilSegments * 6 + segment * 6

              // Set positions for line segment
              positions[baseIndex] = curve1.x
              positions[baseIndex + 1] = curve1.y
              positions[baseIndex + 2] = curve1.z
              positions[baseIndex + 3] = curve2.x
              positions[baseIndex + 4] = curve2.y
              positions[baseIndex + 5] = curve2.z

                        // Set colors based on frequency and SEFA with organic palette blending
          const colorIntensity = 0.4 + 0.6 * sefaStrength // More subtle intensity range
          const freq1Color = getFrequencyColor(sphere1.params.minFrequency, colorIntensity)
          const freq2Color = getFrequencyColor(sphere2.params.minFrequency, colorIntensity)
          
          // Blend colors organically
          const blendFactor = Math.sin(currentTime * 0.0008 + distance * 5) * 0.5 + 0.5
          
          colors[baseIndex] = freq1Color.r * (1 - blendFactor) + freq2Color.r * blendFactor
          colors[baseIndex + 1] = freq1Color.g * (1 - blendFactor) + freq2Color.g * blendFactor
          colors[baseIndex + 2] = freq1Color.b * (1 - blendFactor) + freq2Color.b * blendFactor
          colors[baseIndex + 3] = freq2Color.r * (1 - blendFactor) + freq1Color.r * blendFactor
          colors[baseIndex + 4] = freq2Color.g * (1 - blendFactor) + freq1Color.g * blendFactor
          colors[baseIndex + 5] = freq2Color.b * (1 - blendFactor) + freq1Color.b * blendFactor

              // Set opacity based on audio energy and distance
              const opacity = (1 - distance / maxTendrilLength) * sefaStrength * audioData.overallAmplitude
              const opacityIndex = tendrilIndex * tendrilSegments * 2 + segment * 2
              opacities[opacityIndex] = opacity
              opacities[opacityIndex + 1] = opacity
            }

            tendrilIndex++
          }
        }
      }
    }

    // Mark geometry for update
    tendrilSystem.geometry.attributes.position.needsUpdate = true
    tendrilSystem.geometry.attributes.color.needsUpdate = true
    tendrilSystem.geometry.attributes.alpha.needsUpdate = true
  }

  // Update Dyson sphere/growing vines system with performance optimization
  const updateDysonSphere = (currentTime: number, deltaTime: number) => {
    if (!dysonSphereEnabled || !dysonSphereRef.current || !audioEngine) return

    // Performance optimization for Dyson sphere
    // Simplified - no dynamic update frequency

    const dysonSystem = dysonSphereRef.current
    const { vineMaterial, vinePositions, vineColors, vineOpacities, vineData, config, colors } = dysonSystem

    // Update shader uniforms
    const audioData = audioEngine.getAudioData()
    const sefaMetrics = entronautStateRef.current?.informationMetrics || { emergence: 0, complexity: 0 }
    
    vineMaterial.uniforms.time.value = currentTime * 0.001
    vineMaterial.uniforms.audioEnergy.value = audioData.overallAmplitude || 0
    vineMaterial.uniforms.emergenceField.value = sefaMetrics.emergence
    vineMaterial.uniforms.growthProgress.value = vineData.growthProgress

    // Only update vine growth periodically for performance
    if (currentTime - dysonSystem.lastUpdate < 50) return // Update every 50ms
    dysonSystem.lastUpdate = currentTime

    // Update vine growth
    vineData.growthProgress = Math.min(1.0, vineData.growthProgress + vineGrowthRate * deltaTime)

    let vineIndex = 0
    
    // Reset all positions
    vinePositions.fill(0)
    vineOpacities.fill(0)

    // Update each vine
    vineData.vines.forEach((vine: any, vIndex: number) => {
      if (vineIndex >= dysonSystem.maxVines) return

      // Grow vine segments based on audio energy and SEFA
      const audioInfluence = (audioData.overallAmplitude || 0) * config.vines.audioReactivity
      const growthRate = config.vines.growthSpeed * (1 + audioInfluence) * vineData.growthProgress
      
      vine.growth += growthRate * deltaTime
      vine.maturity = Math.min(1.0, vine.maturity + deltaTime / config.growth.maturityTime)

      // Add new segments as vine grows
      if (vine.growth > 1.0 && vine.segments.length < config.vines.maxSegmentsPerVine) {
        vine.growth = 0
        
        const lastSegment = vine.segments[vine.segments.length - 1]
        
        // Calculate organic growth direction
        const centerForce = {
          x: -lastSegment.x * 0.1,
          y: -lastSegment.y * 0.1,
          z: -lastSegment.z * 0.1
        }
        
        // Add curvature and organic variation
        vine.direction.x += (Math.random() - 0.5) * config.vines.organicVariation + centerForce.x
        vine.direction.y += (Math.random() - 0.5) * config.vines.organicVariation + centerForce.y
        vine.direction.z += (Math.random() - 0.5) * config.vines.organicVariation + centerForce.z
        
        // Normalize direction
        const dirLength = Math.sqrt(vine.direction.x ** 2 + vine.direction.y ** 2 + vine.direction.z ** 2)
        if (dirLength > 0) {
          vine.direction.x /= dirLength
          vine.direction.y /= dirLength
          vine.direction.z /= dirLength
        }
        
        // Create new segment
        const segmentLength = 0.1 + sefaMetrics.emergence * 0.05
        const newSegment = {
          x: lastSegment.x + vine.direction.x * segmentLength,
          y: lastSegment.y + vine.direction.y * segmentLength,
          z: lastSegment.z + vine.direction.z * segmentLength
        }
        
        vine.segments.push(newSegment)
        
        // Update node positions
        if (dysonSystem.nodeInstances[vIndex]) {
          dysonSystem.nodeInstances[vIndex].position.set(newSegment.x, newSegment.y, newSegment.z)
          
          // Update node material based on audio
          const nodeMat = dysonSystem.nodeInstances[vIndex].material as any
          nodeMat.opacity = 0.5 + 0.5 * audioData.overallAmplitude
          nodeMat.color.setHex(parseInt(colors.nodeColor.replace('#', ''), 16))
        }
      }

      // Render vine segments
      for (let i = 0; i < vine.segments.length - 1 && vineIndex < dysonSystem.maxVines; i++) {
        const segment1 = vine.segments[i]
        const segment2 = vine.segments[i + 1]
        
        const baseIndex = vineIndex * 6
        
        // Set positions for line segment
        vinePositions[baseIndex] = segment1.x
        vinePositions[baseIndex + 1] = segment1.y
        vinePositions[baseIndex + 2] = segment1.z
        vinePositions[baseIndex + 3] = segment2.x
        vinePositions[baseIndex + 4] = segment2.y
        vinePositions[baseIndex + 5] = segment2.z

        // Set colors based on maturity and audio
        const maturityColor = vine.maturity
        const audioColor = audioData.overallAmplitude || 0
        
        const primaryColor = hexToRgb(colors.primaryVine)
        const secondaryColor = hexToRgb(colors.secondaryVine)
        const highlightColor = hexToRgb(colors.vineHighlight)
        
        if (primaryColor && secondaryColor && highlightColor) {
          const blendedColor = {
            r: primaryColor.r * (1 - maturityColor) + secondaryColor.r * maturityColor,
            g: primaryColor.g * (1 - maturityColor) + secondaryColor.g * maturityColor,
            b: primaryColor.b * (1 - maturityColor) + secondaryColor.b * maturityColor
          }
          
          // Apply audio highlight
          blendedColor.r = Math.min(1, blendedColor.r + highlightColor.r * audioColor * 0.3)
          blendedColor.g = Math.min(1, blendedColor.g + highlightColor.g * audioColor * 0.3)
          blendedColor.b = Math.min(1, blendedColor.b + highlightColor.b * audioColor * 0.3)
          
          vineColors[baseIndex] = blendedColor.r
          vineColors[baseIndex + 1] = blendedColor.g
          vineColors[baseIndex + 2] = blendedColor.b
          vineColors[baseIndex + 3] = blendedColor.r
          vineColors[baseIndex + 4] = blendedColor.g
          vineColors[baseIndex + 5] = blendedColor.b
        }

        // Set opacity based on growth and audio
        const opacity = vine.maturity * (0.6 + 0.4 * audioData.overallAmplitude)
        const opacityIndex = vineIndex * 2
        vineOpacities[opacityIndex] = opacity
        vineOpacities[opacityIndex + 1] = opacity

        vineIndex++
      }
    })

    // Mark geometry for update
    dysonSystem.vineGeometry.attributes.position.needsUpdate = true
    dysonSystem.vineGeometry.attributes.color.needsUpdate = true
    dysonSystem.vineGeometry.attributes.alpha.needsUpdate = true
  }

  // Helper function to convert hex color to RGB
  const hexToRgb = (hex: string) => {
    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
    return result ? {
      r: parseInt(result[1], 16) / 255,
      g: parseInt(result[2], 16) / 255,
      b: parseInt(result[3], 16) / 255
    } : null
  }

  // Helper function to create curved tendril points
  const getCurvedTendrilPoint = (x1: number, y1: number, z1: number, x2: number, y2: number, z2: number, t: number, time: number, sefaStrength: number) => {
    // Linear interpolation
    const x = x1 + (x2 - x1) * t
    const y = y1 + (y2 - y1) * t
    const z = z1 + (z2 - z1) * t

    // Add curvature and SEFA-driven undulation
    const midPoint = t * (1 - t) * 4 // Peaks at t=0.5
    const curve = midPoint * 0.2 * sefaStrength
    const undulation = 0.05 * sefaStrength * Math.sin(time * 0.002 + t * 10)

    return {
      x: x + curve * Math.sin(time * 0.001 + t * 5) + undulation,
      y: y + curve * Math.cos(time * 0.001 + t * 5) + undulation * 0.5,
      z: z + curve * Math.sin(time * 0.0015 + t * 3) + undulation * 0.3
    }
  }

  // Helper function to get frequency-based color with organic palette
  const getFrequencyColor = (frequency: number, intensity: number) => {
    const config = configLoader.getConfig()
    const organicBlend = (config as any)?.colors?.tendrilColors?.organicBlend
    
    if (organicBlend) {
      const normalizedFreq = Math.min(1, frequency / 10000)
      
      // Use organic color blending
      let color
      if (normalizedFreq < 0.2) {
        color = organicBlend.forest // Deep greens for low frequencies
      } else if (normalizedFreq < 0.4) {
        color = organicBlend.bronze // Bronze for low-mid frequencies
      } else if (normalizedFreq < 0.6) {
        color = organicBlend.copper // Copper for mid frequencies
      } else if (normalizedFreq < 0.8) {
        color = organicBlend.gold // Gold for high-mid frequencies
      } else {
        color = organicBlend.teal // Teal for high frequencies
      }
      
      return {
        r: color[0] * intensity,
        g: color[1] * intensity,
        b: color[2] * intensity
      }
    }
    
    // Fallback to original calculation
    const normalizedFreq = Math.min(1, frequency / 10000)
    return {
      r: (0.8 + 0.2 * normalizedFreq) * intensity,
      g: (0.6 + 0.4 * Math.sin(normalizedFreq * Math.PI)) * intensity,
      b: (0.2 + 0.8 * (1 - normalizedFreq)) * intensity
    }
  }

  // Organic cymatic pattern generator - creates natural, sound-driven formations
  const getCymatePattern = useCallback((x: number, y: number, z: number, frequency: number, time: number) => {
    // Create organic patterns inspired by natural growth and cymatics
    const r = Math.sqrt(x*x + y*y + z*z)
    const theta = Math.atan2(y, x)
    const phi = Math.acos(z / (r || 1))
    
    // Frequency-based pattern selection with organic variation
    const freqFactor = frequency / 1000
    const pattern = Math.floor(freqFactor) % 5 // Added 5th pattern
    
    let patternX = 0, patternY = 0, patternZ = 0
    
    // Load config for cymatic pattern settings
    const config = configLoader.getConfig()
    const cymateConfig = (config as any)?.cymatics?.patterns
    
    switch (pattern) {
      case 0: // Organic radial waves (tree rings, water ripples)
        const radialFreq = cymateConfig?.radialWaves?.frequencyFactor || 0.08
        const radialPetals = cymateConfig?.radialWaves?.petalCount || 6
        const radialPattern = Math.sin(r * radialFreq + time * 0.8) * Math.cos(theta * radialPetals + time * 0.3)
        patternX = radialPattern * Math.cos(theta) * 0.7
        patternY = radialPattern * Math.sin(theta) * 0.7
        patternZ = Math.sin(phi * 3 + time * 0.4) * (cymateConfig?.radialWaves?.amplitudeZ || 0.4)
        break
        
      case 1: // Natural spiral harmonics (nautilus, plant growth)
        const l = Math.max(1, Math.floor(freqFactor * 0.4) + 1)
        const m = Math.floor(freqFactor * 0.25)
        const spiralFactor = 1 + 0.3 * Math.sin(time * 0.6)
        patternX = Math.sin(l * phi * spiralFactor) * Math.cos(m * theta + time * 0.7)
        patternY = Math.sin(l * phi * spiralFactor) * Math.sin(m * theta + time * 0.7)
        patternZ = Math.cos(l * phi) * Math.sin(time * 1.2) * 0.6
        break
        
      case 2: // Organic lattice (honeycomb, crystal growth)
        const latticeFreq = cymateConfig?.geometricLattice?.frequencyFactor || 0.15
        const organic = 0.8 + 0.2 * Math.sin(time * 0.5)
        patternX = (Math.sin(x * latticeFreq + time * 0.6) + Math.sin(y * latticeFreq * 1.1)) * organic
        patternY = (Math.sin(y * latticeFreq + time * 0.8) + Math.sin(z * latticeFreq * 0.9)) * organic
        patternZ = (Math.sin(z * latticeFreq + time * 0.7) + Math.sin(x * latticeFreq * 1.05)) * organic
        break
        
      case 3: // Enhanced flower of life (sacred geometry)
        const flowerFreq = cymateConfig?.flowerOfLife?.frequencyFactor || 0.12
        const basePetals = cymateConfig?.flowerOfLife?.basePetals || 6
        const petalVariation = cymateConfig?.flowerOfLife?.petalVariation || 0.1
        const flowerPetals = basePetals + Math.floor(freqFactor * petalVariation * 10)
        const bloom = 0.7 + 0.3 * Math.sin(time * 0.4)
        patternX = Math.sin(theta * flowerPetals + time * 0.5) * Math.sin(r * flowerFreq) * bloom
        patternY = Math.cos(theta * flowerPetals + time * 0.5) * Math.sin(r * flowerFreq) * bloom
        patternZ = Math.sin(phi * flowerPetals * 0.7 + time * 0.6) * (cymateConfig?.flowerOfLife?.amplitudeZ || 0.25)
        break
        
      case 4: // New: Organic vine growth pattern
        const vineFreq = freqFactor * 0.1
        const vineSpiral = theta + r * 0.5 + time * 0.3
        const growth = 0.6 + 0.4 * Math.sin(time * 0.35)
        patternX = Math.sin(vineSpiral) * Math.exp(-r * 0.2) * growth
        patternY = Math.cos(vineSpiral) * Math.exp(-r * 0.2) * growth
        patternZ = Math.sin(r * vineFreq + time * 0.5) * 0.4 * growth
        break
    }
    
    // Organic breathing effect with natural variation
    const breathing = cymateConfig?.breathing
    const breathingSpeed = breathing?.speed || 0.4
    const intensityBase = breathing?.intensityBase || 0.25
    const intensityVariation = breathing?.intensityVariation || 0.6
    
    const intensity = intensityBase + intensityVariation * Math.sin(time * breathingSpeed) * 
                     (0.8 + 0.2 * Math.sin(time * breathingSpeed * 0.7)) // Natural variation
    
    return {
      x: patternX * intensity,
      y: patternY * intensity,
      z: patternZ * intensity
    }
  }, [cymateGeometry])

  // Update individual sphere particles with performance optimization
  const updateSphereParticles = (
    sphere: ParticleSphere, 
    currentTime: number, 
    deltaTime: number, 
    beatDetected: boolean
  ) => {
    const { params, positions, velocities, lifetimes, beatEffects } = sphere
    const noise = noiseGeneratorRef.current!
    const beatManager = beatManagerRef.current!
    
    // Performance optimization: Skip heavy calculations if needed
    const adaptiveLevel = 1.0 // Simplified - no performance monitoring
    
    // Frame skipping for low performance - simplified

    // STABILITY: Clamp deltaTime to prevent integration instability
    const clampedDeltaTime = Math.min(deltaTime, 1/30) // Max 30 FPS equivalent timestep
    const config = configLoader.getConfig()
    const maxVelocity = config?.visualization?.physics?.maxVelocity || 0.1
    const stabilityThreshold = config?.visualization?.physics?.stabilityThreshold || 10.0

    // Adaptive particle count based on performance
    const adaptiveParticleCount = Math.min(params.particleCount, 
      adaptiveLevel * 15000) // Simplified - no dynamic particle count
    
    // Level of detail calculation
    const particleUpdateStep = Math.max(1, Math.floor(1 / adaptiveLevel))
    
    for (let i = 0; i < adaptiveParticleCount; i += particleUpdateStep) {
      const i3 = i * 3

      let x = positions[i3]
      let y = positions[i3 + 1]
      let z = positions[i3 + 2]

      let vx = velocities[i3]
      let vy = velocities[i3 + 1]
      let vz = velocities[i3 + 2]

      let lt = lifetimes[i]
      let be = beatEffects[i]

      // STABILITY: Check for NaN or infinite values
      if (!isFinite(x) || !isFinite(y) || !isFinite(z) || 
          !isFinite(vx) || !isFinite(vy) || !isFinite(vz)) {
        // Reset particle to safe position
        const theta = Math.random() * Math.PI * 2
        const phi = Math.acos(2 * Math.random() - 1)
        const r = Math.cbrt(Math.random()) * params.sphereRadius * 0.5
        
        x = r * Math.sin(phi) * Math.cos(theta)
        y = r * Math.sin(phi) * Math.sin(theta)
        z = r * Math.cos(phi)
        
        vx = vy = vz = 0
        console.warn(`🚨 Particle ${i} reset due to invalid values`)
      }

      // STABILITY: Check distance from origin - emergency containment
      const distFromOrigin = Math.sqrt(x*x + y*y + z*z)
      if (distFromOrigin > stabilityThreshold) {
        // Pull particle back to safe zone
        const pullFactor = 0.1
        x *= pullFactor
        y *= pullFactor
        z *= pullFactor
        vx *= 0.1 // Severe velocity damping
        vy *= 0.1
        vz *= 0.1
        console.warn(`🚨 Particle ${i} emergency reset - distance: ${distFromOrigin.toFixed(2)}`)
      }

      // Update lifetime
      lt -= clampedDeltaTime

      // Calculate distance and sphere radius early for use in forces
      const dist = Math.sqrt(x*x + y*y + z*z)
      const sphereRadius = params.sphereRadius
      
      // Define containment zones for use throughout particle update
      const coreZone = sphereRadius * 0.4      // Core zone - natural movement
      const innerZone = sphereRadius * 0.65    // Inner zone - gentle forces
      const boundaryZone = sphereRadius * 0.8  // Warning zone - medium forces  
      const dangerZone = sphereRadius * 0.92   // Danger zone - strong forces
      const emergencyZone = sphereRadius * 0.98 // Emergency zone - very strong forces
      const hardBoundary = sphereRadius * 1.02 // Hard boundary - immediate reset

      // Apply noise-based turbulence with distance-based scaling
      const ns = params.noiseScale * adaptiveLevel // Scale noise with performance
      const speed = params.noiseSpeed
      const timeFactor = currentTime * 0.001
      
      // Calculate noise values directly - no caching overhead
      const noiseValues = {
        x: noise.noise3D(x * ns + timeFactor * speed, y * ns, z * ns),
        y: noise.noise3D(x * ns, y * ns + timeFactor * speed, z * ns),
        z: noise.noise3D(x * ns, y * ns, z * ns + timeFactor * speed)
      }
      
      const noiseX = noiseValues.x
      const noiseY = noiseValues.y
      const noiseZ = noiseValues.z

      // STABILITY: Scale turbulence by performance, distance, and containment zones
      const performanceScale = Math.min(1.0, 60 * clampedDeltaTime) // Scale down for low FPS
      
      // Scale turbulence to maintain audio reactivity while preventing boundary escape
      const distanceScale = Math.max(0.3, 1 - (dist / sphereRadius) * 0.6) // Less aggressive reduction
      
      const turbulenceScale = params.turbulenceStrength * performanceScale * distanceScale * 0.9 // Preserve more turbulence
      
      vx += noiseX * turbulenceScale
      vy += noiseY * turbulenceScale
      vz += noiseZ * turbulenceScale

      // Apply beat effects
      if (beatDetected) {
        be = 1.0
      }
      be *= 0.95

      if (be > 0.01) {
        const dist = Math.sqrt(x*x + y*y + z*z)
        if (dist > 0) {
          const dx = x / dist
          const dy = y / dist
          const dz = z / dist

          // Modified beat force to prevent dispersion with stronger containment awareness
          const baseBeatForce = be * params.beatStrength * 0.8 // Increased to preserve audio reactivity
          
          // Use containment zones already defined above
          
          if (dist < coreZone) {
            // Normal outward beat force in core zone only
            const beatForce = baseBeatForce
            vx += dx * beatForce
            vy += dy * beatForce
            vz += dz * beatForce
          } else if (dist < innerZone) {
            // Reduced outward beat force in inner zone
            const beatForce = baseBeatForce * 0.6
            vx += dx * beatForce
            vy += dy * beatForce
            vz += dz * beatForce
          } else if (dist < boundaryZone) {
            // Tangential beat force in boundary zone to add movement without outward push
            const tangentX = -dy
            const tangentY = dx
            const tangentZ = dz * 0.1 // Minimal Z movement
            
            const beatForce = baseBeatForce * 0.4
            vx += tangentX * beatForce
            vy += tangentY * beatForce
            vz += tangentZ * beatForce
          } else if (dist < dangerZone) {
            // Inward beat force in danger zone to pull particles back
            const beatForce = baseBeatForce * 0.6
            vx -= dx * beatForce
            vy -= dy * beatForce
            vz -= dz * beatForce
          } else {
            // Strong inward beat force beyond danger zone
            const beatForce = baseBeatForce * 1.2
            vx -= dx * beatForce
            vy -= dy * beatForce
            vz -= dz * beatForce
          }
        }
      }

      // Apply wave forces with strong containment awareness
      const waveForce = beatManager.getWaveForce({ x, y, z })
      if (waveForce > 0 && dist > 0) {
        const dx = x / dist
        const dy = y / dist
        const dz = z / dist

        // Balance wave force intensity to preserve audio reactivity while maintaining containment
        const baseWaveIntensity = 0.0006 // Increased to preserve audio reactivity
        
        // Use containment zones already defined above for wave behavior
        
        let waveIntensity = baseWaveIntensity
        let waveDirection = 1 // 1 = outward, -1 = inward, 0 = tangential
        
        if (dist < coreZone) {
          // Normal outward waves in core
          waveIntensity = baseWaveIntensity
          waveDirection = 1
        } else if (dist < innerZone) {
          // Reduced outward waves in inner zone
          waveIntensity = baseWaveIntensity * 0.6
          waveDirection = 1
        } else if (dist < boundaryZone) {
          // Tangential waves in boundary zone
          waveIntensity = baseWaveIntensity * 0.3
          // Create tangential force instead of radial
          const tangentX = -dy
          const tangentY = dx
          const tangentZ = 0
          
          vx += tangentX * waveForce * waveIntensity
          vy += tangentY * waveForce * waveIntensity
          vz += tangentZ * waveForce * waveIntensity
          waveDirection = 0 // Skip radial application below
        } else {
          // Inward waves beyond boundary zone
          waveIntensity = baseWaveIntensity * 0.8
          waveDirection = -1
        }
        
        // Apply radial wave force if not tangential
        if (waveDirection !== 0) {
          vx += dx * waveForce * waveIntensity * waveDirection
          vy += dy * waveForce * waveIntensity * waveDirection
          vz += dz * waveForce * waveIntensity * waveDirection
        }
      }

      // Cymatic geometry patterns - sound-driven geometric formations with containment awareness
      if (cymateGeometry && audioEngine) {
        const freq = sphere.params.minFrequency + 
          (sphere.params.maxFrequency - sphere.params.minFrequency) * 0.5
        
        // Create geometric patterns based on frequency
        const geometricPattern = getCymatePattern(x, y, z, freq, currentTime * 0.001)
        
        // Scale cymatic intensity to balance audio reactivity with containment
        let cymateScale = 1.0
        if (dist > boundaryZone) {
          // Moderate reduction near boundaries while preserving some reactivity
          cymateScale = 0.4
        } else if (dist > coreZone) {
          // Gentle reduction outside core
          cymateScale = 1.0 - ((dist - coreZone) / (boundaryZone - coreZone)) * 0.4
        }
        
        // Maintain stronger cymatic intensity for audio reactivity
        const organicIntensity = 0.0012 * cymateScale * (0.8 + 0.2 * Math.sin(currentTime * 0.0005))
        vx += geometricPattern.x * organicIntensity
        vy += geometricPattern.y * organicIntensity  
        vz += geometricPattern.z * organicIntensity
      }

      // Update positions
      x += vx
      y += vy
      z += vz

      // ENTRONAUT: Apply enhanced biomimetic coupling parameters
      const entronautParams = applyEntronautCoupling(sphere, i)
      
      // Optimized living entity behavior: adaptive computational load
      const entronautStep = Math.max(10, Math.floor(30 / adaptiveLevel)) // More aggressive stepping at low performance
      if (entronautEnabled && adaptiveCoupling && (i % entronautStep === 0)) { // Adaptive step size
        // Simplified flocking behavior with fewer neighbor checks
        let avgVx = 0, avgVy = 0, avgVz = 0
        let neighborCount = 0
        const flockRadius = 0.25
        
        // Check only a few nearby particles for performance
        for (let j = Math.max(0, i - 20); j < Math.min(params.particleCount, i + 20); j += 5) {
          if (j === i) continue
          const j3 = j * 3
          const dx = positions[j3] - x
          const dy = positions[j3 + 1] - y
          const dz = positions[j3 + 2] - z
          const distSq = dx*dx + dy*dy + dz*dz // Use squared distance to avoid sqrt
          
          if (distSq < flockRadius * flockRadius && distSq > 0) {
            avgVx += velocities[j3]
            avgVy += velocities[j3 + 1]
            avgVz += velocities[j3 + 2]
            neighborCount++
          }
        }
        
        if (neighborCount > 0) {
          avgVx /= neighborCount
          avgVy /= neighborCount
          avgVz /= neighborCount
          
          // Reduce flocking influence to prevent convergence and preserve individuality
          const flockInfluence = entronautParams.coupling * 0.08 // Reduced from 0.2
          
          // Add some randomness to promote emergence rather than convergence
          const emergenceRandomness = (Math.random() - 0.5) * 0.001
          
          vx += (avgVx - vx) * flockInfluence + emergenceRandomness
          vy += (avgVy - vy) * flockInfluence + emergenceRandomness
          vz += (avgVz - vz) * flockInfluence + emergenceRandomness
        }
      }
      
      // Light metabolic pulsing to add organic variation without dampening
      if (entronautEnabled && adaptiveCoupling) {
        const metabolicPulse = entronautParams.diffusion * 0.3 // Reduced from 0.5
        const timeVariation = currentTime * 0.0001 // Add time-based variation
        vx += metabolicPulse * Math.cos(i * 0.01 + timeVariation)
        vy += metabolicPulse * Math.sin(i * 0.01 + timeVariation)
        vz += metabolicPulse * Math.sin(i * 0.007 + timeVariation) * 0.5 // Add Z variation
      }
      
      // STABILITY: Velocity clamping to prevent runaway particles
      const velocity = Math.sqrt(vx*vx + vy*vy + vz*vz)
      if (velocity > maxVelocity) {
        const scale = maxVelocity / velocity
        vx *= scale
        vy *= scale
        vz *= scale
      }

      // Apply adaptive drag/damping with preservation of audio reactivity
      let dampingFactor = entronautParams.damping
      
      // Only apply extra damping in extreme zones to preserve energy
      if (dist > emergencyZone) {
        dampingFactor *= 0.9 // Light extra damping only near hard boundary
      }
      
      // Use less aggressive velocity decay to maintain particle liveliness
      const velocityDecay = config?.visualization?.physics?.velocityDecay || 0.998 // Increased from 0.995
      dampingFactor = Math.max(dampingFactor, velocityDecay) // Use max to preserve energy
      
      vx *= dampingFactor
      vy *= dampingFactor
      vz *= dampingFactor

      // ENHANCED MULTI-LAYER CONTAINMENT SYSTEM
      // (dist, sphereRadius, and containment zones already calculated above)
      
      // HARD BOUNDARY - Immediate containment for escaped particles
      if (dist > hardBoundary) {
        // Immediately pull particle back to safe zone
        const pullbackFactor = 0.7 // Pull back to 70% of sphere radius
        const safeRadius = sphereRadius * pullbackFactor
        const safeX = (x / dist) * safeRadius
        const safeY = (y / dist) * safeRadius
        const safeZ = (z / dist) * safeRadius
        
        x = safeX
        y = safeY
        z = safeZ
        
        // Zero velocities for escaped particles
        vx *= 0.1
        vy *= 0.1
        vz *= 0.1
        
        console.warn(`🚨 Particle ${i} hard reset - distance: ${dist.toFixed(2)}`)
      }
      // EMERGENCY ZONE - Very strong containment
      else if (dist > emergencyZone && dist > 0) {
        const dx = x / dist
        const dy = y / dist
        const dz = z / dist
        
        // Very strong inward force
        const emergencyForce = (dist - emergencyZone) / (hardBoundary - emergencyZone) * 0.025
        vx -= dx * emergencyForce
        vy -= dy * emergencyForce
        vz -= dz * emergencyForce
        
        // Strong velocity damping
        const dampingFactor = 0.7
        vx *= dampingFactor
        vy *= dampingFactor
        vz *= dampingFactor
      }
      // DANGER ZONE - Strong containment
      else if (dist > dangerZone && dist > 0) {
        const dx = x / dist
        const dy = y / dist
        const dz = z / dist
        
        // Strong inward force
        const dangerForce = (dist - dangerZone) / (emergencyZone - dangerZone) * 0.015
        vx -= dx * dangerForce
        vy -= dy * dangerForce
        vz -= dz * dangerForce
        
        // Medium velocity damping
        const dampingFactor = 0.85
        vx *= dampingFactor
        vy *= dampingFactor
        vz *= dampingFactor
      }
      // BOUNDARY ZONE - Medium containment
      else if (dist > boundaryZone && dist > 0) {
        const dx = x / dist
        const dy = y / dist
        const dz = z / dist
        
        // Medium inward force
        const boundaryForce = (dist - boundaryZone) / (dangerZone - boundaryZone) * 0.008
        vx -= dx * boundaryForce
        vy -= dy * boundaryForce
        vz -= dz * boundaryForce
        
        // Light velocity damping
        const dampingFactor = 0.92
        vx *= dampingFactor
        vy *= dampingFactor
        vz *= dampingFactor
      }
      // INNER ZONE - Gentle containment
      else if (dist > innerZone && dist > 0) {
        const dx = x / dist
        const dy = y / dist
        const dz = z / dist
        
        // Gentle inward force
        const innerForce = (dist - innerZone) / (boundaryZone - innerZone) * 0.003
        vx -= dx * innerForce
        vy -= dy * innerForce
        vz -= dz * innerForce
      }
      
      // GENTLE CENTER BIAS - Only for particles very far from center
      if (dist > sphereRadius * 0.9 && dist > 0) {
        const dx = x / dist
        const dy = y / dist
        const dz = z / dist
        
        // Very gentle pull only when approaching boundaries
        const centerBias = (dist - sphereRadius * 0.9) / (sphereRadius * 0.1) * 0.0008
        vx -= dx * centerBias
        vy -= dy * centerBias
        vz -= dz * centerBias
      }
      
      // VELOCITY CLAMPING - Less restrictive to preserve audio reactivity
      let maxVel = config?.visualization?.physics?.maxVelocity || 0.025 // Increased base velocity
      
      if (dist > emergencyZone) {
        maxVel *= 0.6 // Moderate limit only in emergency zone
      } else if (dist > dangerZone) {
        maxVel *= 0.8 // Light limit in danger zone
      }
      
      const velMag = Math.sqrt(vx*vx + vy*vy + vz*vz)
      if (velMag > maxVel) {
        const scale = maxVel / velMag
        vx *= scale
        vy *= scale
        vz *= scale
      }

      // Respawn dead particles
      if (lt <= 0) {
        const radius = params.sphereRadius * params.innerSphereRadius
        const theta = Math.random() * Math.PI * 2
        const phi = Math.acos(2 * Math.random() - 1)
        const r = Math.cbrt(Math.random()) * radius

        x = r * Math.sin(phi) * Math.cos(theta)
        y = r * Math.sin(phi) * Math.sin(theta)
        z = r * Math.cos(phi)

        vx = 0
        vy = 0
        vz = 0

        lt = Math.random() * params.particleLifetime
        be = 0
      }

      // Final stability check before updating arrays
      const finalDist = Math.sqrt(x*x + y*y + z*z)
      const finalVel = Math.sqrt(vx*vx + vy*vy + vz*vz)
      
      // Emergency stability check
      if (finalDist > sphereRadius * 1.5 || finalVel > 0.1 || !isFinite(finalDist) || !isFinite(finalVel)) {
        // Emergency reset - place particle safely in core zone
        const safeRadius = sphereRadius * 0.3
        const theta = Math.random() * Math.PI * 2
        const phi = Math.acos(2 * Math.random() - 1)
        const r = Math.cbrt(Math.random()) * safeRadius
        
        x = r * Math.sin(phi) * Math.cos(theta)
        y = r * Math.sin(phi) * Math.sin(theta)
        z = r * Math.cos(phi)
        
        vx = 0
        vy = 0
        vz = 0
        
        console.warn(`🚨 Emergency stability reset for particle ${i} - dist: ${finalDist.toFixed(2)}, vel: ${finalVel.toFixed(3)}`)
      }

      // Update arrays
      positions[i3] = x
      positions[i3 + 1] = y
      positions[i3 + 2] = z

      velocities[i3] = vx
      velocities[i3 + 1] = vy
      velocities[i3 + 2] = vz

      lifetimes[i] = lt
      beatEffects[i] = be
    }

    // Mark geometry for update
    if (sceneRef.current) {
      const particleSystem = sceneRef.current.children.find((child: any) => 
        child.userData?.sphereIndex === sphere.index
      ) as any
      if (particleSystem?.geometry) {
        particleSystem.geometry.attributes.position.needsUpdate = true
      }
    }
  }

  // Update sphere rotation based on audio
  const updateSphereRotation = (sphere: ParticleSphere, _audioData: any) => {
    if (!audioEngine) return

    const volumeData = audioEngine.getSmoothVolume(
      sphere.lastValidVolume, 
      sphere.params.volumeChangeThreshold
    )

    if (volumeData.shouldUpdate) {
      const targetRotationSpeed = sphere.params.rotationSpeedMin + 
        (sphere.params.rotationSpeedMax - sphere.params.rotationSpeedMin) * volumeData.volume

      sphere.lastRotationSpeed = sphere.params.rotationSpeed + 
        (targetRotationSpeed - sphere.params.rotationSpeed) * sphere.params.rotationSmoothness

      sphere.lastValidVolume = volumeData.volume
    }

    // Apply rotation
    if (sceneRef.current) {
      const particleSystem = sceneRef.current.children.find((child: any) => 
        child.userData?.sphereIndex === sphere.index
      ) as any
      if (particleSystem) {
        particleSystem.rotation.y += sphere.lastRotationSpeed
      }
    }
  }

  // Camera control functions
  const resetCameraPosition = useCallback(() => {
    if (!cameraRef.current || !controlsRef.current) return
    
    cameraRef.current.position.set(0, 0, 2.5)
    controlsRef.current.target.set(0, 0, 0)
    controlsRef.current.update()
  }, [])

  const setCameraPreset = useCallback((preset: 'default' | 'inside' | 'far' | 'top' | 'side') => {
    if (!cameraRef.current || !controlsRef.current) return
    
    switch (preset) {
      case 'default':
        cameraRef.current.position.set(0, 0, 2.5)
        break
      case 'inside':
        cameraRef.current.position.set(0, 0, 0.5)
        break
      case 'far':
        cameraRef.current.position.set(0, 0, 8)
        break
      case 'top':
        cameraRef.current.position.set(0, 5, 0)
        break
      case 'side':
        cameraRef.current.position.set(5, 0, 0)
        break
    }
    
    controlsRef.current.target.set(0, 0, 0)
    controlsRef.current.update()
  }, [])

  // Handle window resize
  const handleResize = useCallback(() => {
    if (!cameraRef.current || !rendererRef.current) return

    cameraRef.current.aspect = window.innerWidth / window.innerHeight
    cameraRef.current.updateProjectionMatrix()
    rendererRef.current.setSize(window.innerWidth, window.innerHeight)
    
    // Update controls on resize
    if (controlsRef.current) {
      controlsRef.current.handleResize?.()
    }
  }, [])

  // Initialize on mount
  useEffect(() => {
    initializeVisualization()
    window.addEventListener('resize', handleResize)

    // Listen for camera control disable events from audio dock
    const handleCameraControlToggle = (event: CustomEvent) => {
      if (controlsRef.current) {
        controlsRef.current.enabled = !event.detail && cameraControlsEnabled
      }
    }

    window.addEventListener('disableCameraControls', handleCameraControlToggle as EventListener)

    return () => {
      window.removeEventListener('resize', handleResize)
      window.removeEventListener('disableCameraControls', handleCameraControlToggle as EventListener)
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current)
      }
      if (controlsRef.current) {
        controlsRef.current.dispose()
      }
    }
  }, [initializeVisualization, handleResize, cameraControlsEnabled])

  // Start animation when ready
  useEffect(() => {
    if (isVisualizationReady) {
      animationRef.current = requestAnimationFrame(animate)
    }
    return () => {
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current)
      }
    }
  }, [isVisualizationReady, animate])

  return (
    <div className="world-tree-visualizer">
      <canvas
        ref={canvasRef}
        className="visualization-canvas"
        style={{
          position: 'absolute',
          top: 0,
          left: 0,
          width: '100%',
          height: '100%',
          background: '#0D0A07',
          pointerEvents: 'auto'
        }}
        onMouseEnter={() => {
          // Enable camera controls when mouse enters visualization area
          if (controlsRef.current && cameraControlsEnabled) {
            controlsRef.current.enabled = true
          }
        }}
      />
      
      {/* Compact Controls Panel */}
      <div 
        className="particle-controls ancient-panel"
        style={{
          position: 'fixed',
          bottom: '20px',
          right: '20px',
          zIndex: 1000,
          background: 'linear-gradient(135deg, var(--marble-dark), var(--teal-dark))',
          borderRadius: '8px',
          color: 'var(--copper-light)',
          fontFamily: 'Metamorphous, serif',
          maxWidth: '280px',
          maxHeight: '75vh',
          transition: 'all 0.4s ease-in-out',
          transform: controlsCollapsed ? 'translateX(calc(100% - 55px))' : 'translateX(0)',
          backdropFilter: 'blur(15px)',
          border: '2px solid var(--copper-medium)',
          pointerEvents: 'auto',
          boxShadow: '0 0 20px var(--copper-dark), inset 0 0 10px var(--teal-dark)',
          display: 'flex',
          flexDirection: 'column'
        }}
        onMouseEnter={() => {
          // Disable camera controls when mouse enters controls panel
          const event = new CustomEvent('disableCameraControls', { detail: true })
          window.dispatchEvent(event)
        }}
        onMouseLeave={() => {
          // Re-enable camera controls when mouse leaves controls panel
          const event = new CustomEvent('disableCameraControls', { detail: false })
          window.dispatchEvent(event)
        }}
      >
        {/* Collapse/Expand Toggle */}
        <button
          onClick={() => setControlsCollapsed(!controlsCollapsed)}
          onMouseEnter={(e) => {
            e.currentTarget.style.transform = 'translateY(-50%) scale(1.1)'
            e.currentTarget.style.borderColor = 'var(--transmission-glow)'
            e.currentTarget.style.boxShadow = '0 0 15px var(--transmission-glow)'
          }}
          onMouseLeave={(e) => {
            e.currentTarget.style.transform = 'translateY(-50%) scale(1)'
            e.currentTarget.style.borderColor = 'var(--copper-medium)'
            e.currentTarget.style.boxShadow = '0 0 5px var(--copper-bright)'
          }}
          style={{
            position: 'absolute',
            left: controlsCollapsed ? '8px' : '-30px',
            top: '50%',
            transform: 'translateY(-50%)',
            background: 'linear-gradient(135deg, var(--teal-dark), var(--marble-dark))',
            border: '2px solid var(--copper-medium)',
            borderRadius: '50%',
            width: '28px',
            height: '28px',
            color: 'var(--copper-bright)',
            cursor: 'pointer',
            fontSize: '12px',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            backdropFilter: 'blur(15px)',
            transition: 'all 0.4s ease-in-out',
            zIndex: 1001,
            fontFamily: 'Uncial Antiqua, serif',
            boxShadow: '0 0 5px var(--copper-bright)'
          }}
          title={controlsCollapsed ? 'Expand Transmission Interface' : 'Collapse Interface'}
        >
          {controlsCollapsed ? '⟨' : '⟩'}
        </button>

        {/* Collapsed State Indicator */}
        {controlsCollapsed && (
          <div style={{
            padding: '12px 8px',
            textAlign: 'center',
            fontSize: '9px',
            lineHeight: '1.1',
            opacity: 1,
            transition: 'opacity 0.3s ease-in-out 0.2s',
            fontFamily: 'Uncial Antiqua, serif'
          }}>
            <div className="rune" style={{ fontSize: '14px', color: 'var(--copper-bright)' }}>⟐</div>
            <div style={{ fontSize: '7px', marginTop: '2px', color: 'var(--copper-medium)' }}>
              entity<br/>interface
            </div>
          </div>
        )}

        {/* Full Controls Panel */}
        <div style={{
          padding: controlsCollapsed ? '0' : '20px 20px 0 20px',
          opacity: controlsCollapsed ? 0 : 1,
          transition: 'opacity 0.3s ease-in-out 0.1s',
          pointerEvents: controlsCollapsed ? 'none' : 'auto',
          maxHeight: controlsCollapsed ? '0' : 'auto',
          overflow: 'hidden',
          flexShrink: 0
        }}>
          <h3 className="ancient-title" style={{ 
            marginBottom: '10px', 
            fontSize: '16px', 
            textAlign: 'center',
            fontFamily: 'Metamorphous, serif'
          }}>
            <span className="rune">⟐</span> Liminal Sessions <span className="rune">⟐</span>
          </h3>
          <div className="transmission-text" style={{ 
            textAlign: 'center', 
            fontSize: '9px', 
            marginBottom: '15px', 
            opacity: 0.9,
            fontFamily: 'Uncial Antiqua, serif' 
          }}>
            ≈ intercepted transmission ≈<br/>
            ◦ audio-reactive entity ◦
          </div>
        </div>

        {/* Scrollable Content Area */}
        <div style={{
          padding: controlsCollapsed ? '0' : '0 20px 20px 20px',
          opacity: controlsCollapsed ? 0 : 1,
          transition: 'opacity 0.3s ease-in-out 0.1s',
          pointerEvents: controlsCollapsed ? 'none' : 'auto',
          maxHeight: controlsCollapsed ? '0' : 'calc(75vh - 120px)',
          overflow: controlsCollapsed ? 'hidden' : 'auto',
          overflowY: controlsCollapsed ? 'hidden' : 'scroll',
          flexGrow: 1,
          // Custom scrollbar styling for better aesthetics
          scrollbarWidth: 'thin',
          scrollbarColor: 'var(--copper-medium) transparent'
        }}
        // Custom webkit scrollbar styles
        onMouseEnter={(e) => {
          e.currentTarget.style.setProperty('--webkit-scrollbar-width', '6px')
          e.currentTarget.style.setProperty('--webkit-scrollbar-track-background', 'transparent')
          e.currentTarget.style.setProperty('--webkit-scrollbar-thumb-background', 'var(--copper-medium)')
          e.currentTarget.style.setProperty('--webkit-scrollbar-thumb-border-radius', '3px')
        }}
        >
          <style>{`
            .particle-controls::-webkit-scrollbar {
              width: 6px;
            }
            .particle-controls::-webkit-scrollbar-track {
              background: transparent;
            }
            .particle-controls::-webkit-scrollbar-thumb {
              background: var(--copper-medium);
              border-radius: 3px;
            }
            .particle-controls::-webkit-scrollbar-thumb:hover {
              background: var(--copper-bright);
            }
          `}</style>
        
        <div style={{ marginBottom: '10px' }}>
          <label className="runic-text" style={{ 
            display: 'block', 
            marginBottom: '5px', 
            fontSize: '11px',
            color: 'var(--copper-bright)'
          }}>
            <span className="rune">◯</span> active entities: {activeSpheresCount}
          </label>
          <input
            type="range"
            min="1"
            max="5"
            value={activeSpheresCount}
            onChange={(e) => {
              const count = parseInt(e.target.value)
              setActiveSpheresCount(count)
              spheresRef.current.forEach((sphere, index) => {
                sphere.params.enabled = index < count
                if (sceneRef.current) {
                  const particleSystem = sceneRef.current.children.find((child: any) => 
                    child.userData?.sphereIndex === sphere.index
                  ) as any
                  if (particleSystem) {
                    particleSystem.visible = sphere.params.enabled
                  }
                }
              })
            }}
            style={{ width: '100%' }}
          />
        </div>

        <div style={{ marginBottom: '10px' }}>
          <label className="runic-text" style={{ 
            display: 'block', 
            marginBottom: '5px', 
            fontSize: '11px',
            color: 'var(--copper-bright)'
          }}>
            <input
              type="checkbox"
              checked={cymateGeometry}
              onChange={(e) => setCymateGeometry(e.target.checked)}
              style={{ marginRight: '8px' }}
            />
            <span className="rune">◈</span> cymatic patterns
          </label>
        </div>

        <div style={{ marginBottom: '10px' }}>
          <label className="runic-text" style={{ 
            display: 'block', 
            marginBottom: '5px', 
            fontSize: '11px',
            color: 'var(--copper-bright)'
          }}>
            <input
              type="checkbox"
              checked={tendrilsEnabled}
              onChange={(e) => setTendrilsEnabled(e.target.checked)}
              style={{ marginRight: '8px' }}
            />
            <span className="rune">⟨⟩</span> neural tendrils
          </label>
        </div>

        <div style={{ marginBottom: '10px' }}>
          <label className="runic-text" style={{ 
            display: 'block', 
            marginBottom: '5px', 
            fontSize: '11px',
            color: 'var(--copper-bright)'
          }}>
            <span className="rune">≋</span> neural density: {Math.round(tendrilDensity * 100)}%
          </label>
          <input
            type="range"
            min="0.1"
            max="1.0"
            step="0.1"
            value={tendrilDensity}
            onChange={(e) => setTendrilDensity(parseFloat(e.target.value))}
            disabled={!tendrilsEnabled}
            style={{ width: '100%' }}
          />
        </div>

        <div style={{ marginBottom: '10px' }}>
          <label className="runic-text" style={{ 
            display: 'block', 
            marginBottom: '5px', 
            fontSize: '11px',
            color: 'var(--copper-bright)'
          }}>
            <input
              type="checkbox"
              checked={dysonSphereEnabled}
              onChange={(e) => setDysonSphereEnabled(e.target.checked)}
              style={{ marginRight: '8px' }}
            />
            <span className="rune">🌿</span> growing vines
          </label>
        </div>

        <div style={{ marginBottom: '10px' }}>
          <label className="runic-text" style={{ 
            display: 'block', 
            marginBottom: '5px', 
            fontSize: '11px',
            color: 'var(--copper-bright)'
          }}>
            <span className="rune">🌱</span> vine complexity: {vineComplexity}
          </label>
          <input
            type="range"
            min="8"
            max="48"
            step="4"
            value={vineComplexity}
            onChange={(e) => setVineComplexity(parseInt(e.target.value))}
            disabled={!dysonSphereEnabled}
            style={{ width: '100%' }}
          />
        </div>

        <div style={{ marginBottom: '10px' }}>
          <label className="runic-text" style={{ 
            display: 'block', 
            marginBottom: '5px', 
            fontSize: '11px',
            color: 'var(--copper-bright)'
          }}>
            <span className="rune">⟲</span> growth rate: {Math.round(vineGrowthRate * 1000)}%
          </label>
          <input
            type="range"
            min="0.005"
            max="0.05"
            step="0.005"
            value={vineGrowthRate}
            onChange={(e) => setVineGrowthRate(parseFloat(e.target.value))}
            disabled={!dysonSphereEnabled}
            style={{ width: '100%' }}
          />
        </div>

        <div style={{ marginBottom: '10px' }}>
          <label className="runic-text" style={{ 
            display: 'block', 
            marginBottom: '5px', 
            fontSize: '11px',
            color: 'var(--copper-bright)'
          }}>
            <input
              type="checkbox"
              checked={entronautEnabled}
              onChange={(e) => setEntronautEnabled(e.target.checked)}
              style={{ marginRight: '8px' }}
            />
            <span className="rune">⟐</span> entronaut sefa
          </label>
        </div>

        <div style={{ marginBottom: '10px' }}>
          <label className="runic-text" style={{ 
            display: 'block', 
            marginBottom: '5px', 
            fontSize: '11px',
            color: 'var(--copper-bright)'
          }}>
            <input
              type="checkbox"
              checked={adaptiveCoupling}
              onChange={(e) => setAdaptiveCoupling(e.target.checked)}
              disabled={!entronautEnabled || performanceMode}
              style={{ marginRight: '8px' }}
            />
            <span className="rune">⧨</span> adaptive coupling
          </label>
        </div>

        <div style={{ marginBottom: '10px' }}>
          <label className="runic-text" style={{ 
            display: 'block', 
            marginBottom: '5px', 
            fontSize: '11px',
            color: 'var(--copper-bright)'
          }}>
            <input
              type="checkbox"
              checked={performanceMode}
              onChange={(e) => {
                setPerformanceMode(e.target.checked)
                if (e.target.checked) {
                  setAdaptiveCoupling(false)
                  setEntronautEnabled(false)
                }
              }}
              style={{ marginRight: '8px' }}
            />
            <span className="rune">⚡</span> performance mode
          </label>
        </div>

        {/* Performance Stats Display */}
        <div style={{ 
          marginBottom: '10px', 
          padding: '8px', 
          background: 'rgba(0,0,0,0.3)', 
          borderRadius: '4px',
          border: '1px solid var(--copper-dark)'
        }}>
          <div className="runic-text" style={{ 
            fontSize: '9px', 
            lineHeight: '1.3',
            color: 'var(--copper-medium)'
          }}>
            <div><span className="rune">⚡</span> quality: 100%</div>
            <div><span className="rune">🖥️</span> particles: {performanceStats.particleCount.toLocaleString()}</div>
            <div style={{ 
              color: performanceStats.fps < 30 ? 'var(--error-rust)' : 
                     performanceStats.fps < 45 ? 'var(--warning-copper)' : 'var(--transmission-glow)' 
            }}>
              <span className="rune">📊</span> performance: {performanceStats.fps >= 45 ? 'optimal' : performanceStats.fps >= 30 ? 'good' : 'stressed'}
            </div>
          </div>
        </div>

        {/* Manual Refresh Button */}
        <div style={{ marginBottom: '15px' }}>
          <button
            onClick={() => performHiddenRefresh(true)}
            disabled={autoRefreshRef.current.isRefreshing}
            style={{
              width: '100%',
              padding: '8px 12px',
              background: autoRefreshRef.current.isRefreshing 
                ? 'linear-gradient(135deg, var(--copper-dark), var(--teal-dark))' 
                : 'linear-gradient(135deg, var(--marble-dark), var(--copper-medium))',
              border: '2px solid var(--copper-medium)',
              borderRadius: '6px',
              color: autoRefreshRef.current.isRefreshing ? 'var(--copper-medium)' : 'var(--copper-bright)',
              fontFamily: 'Uncial Antiqua, serif',
              fontSize: '10px',
              cursor: autoRefreshRef.current.isRefreshing ? 'not-allowed' : 'pointer',
              transition: 'all 0.3s ease-in-out',
              backdropFilter: 'blur(5px)',
              opacity: autoRefreshRef.current.isRefreshing ? 0.6 : 1,
              textShadow: '0 1px 2px rgba(0,0,0,0.5)'
            }}
            onMouseEnter={(e) => {
              if (!autoRefreshRef.current.isRefreshing) {
                e.currentTarget.style.borderColor = 'var(--transmission-glow)'
                e.currentTarget.style.background = 'linear-gradient(135deg, var(--copper-medium), var(--transmission-glow))'
                e.currentTarget.style.color = 'var(--marble-light)'
                e.currentTarget.style.transform = 'scale(1.02)'
                e.currentTarget.style.boxShadow = '0 4px 15px var(--transmission-glow)33'
              }
            }}
            onMouseLeave={(e) => {
              if (!autoRefreshRef.current.isRefreshing) {
                e.currentTarget.style.borderColor = 'var(--copper-medium)'
                e.currentTarget.style.background = 'linear-gradient(135deg, var(--marble-dark), var(--copper-medium))'
                e.currentTarget.style.color = 'var(--copper-bright)'
                e.currentTarget.style.transform = 'scale(1)'
                e.currentTarget.style.boxShadow = 'none'
              }
            }}
          >
            <span className="rune" style={{ marginRight: '6px' }}>
              {autoRefreshRef.current.isRefreshing ? '⧗' : '⟲'}
            </span>
            {autoRefreshRef.current.isRefreshing ? 'restoring equilibrium...' : 'reset particle fields'}
          </button>
        </div>

        <div style={{ marginBottom: '10px' }}>
          <label style={{ display: 'block', marginBottom: '5px', fontSize: '12px' }}>
            <input
              type="checkbox"
              checked={cameraControlsEnabled}
              onChange={(e) => setCameraControlsEnabled(e.target.checked)}
              style={{ marginRight: '8px' }}
            />
            Camera Controls
          </label>
        </div>

        <div style={{ marginBottom: '10px' }}>
          <label style={{ display: 'block', marginBottom: '5px', fontSize: '12px' }}>
            <input
              type="checkbox"
              checked={autoRotate}
              onChange={(e) => setAutoRotate(e.target.checked)}
              disabled={!cameraControlsEnabled}
              style={{ marginRight: '8px' }}
            />
            Auto Rotate
          </label>
        </div>

        {/* Camera Preset Buttons */}
        {cameraControlsEnabled && (
          <div style={{ marginBottom: '10px' }}>
            <div style={{ fontSize: '11px', marginBottom: '5px', color: '#FFD700' }}>Camera Presets:</div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '4px' }}>
              <button
                onClick={() => setCameraPreset('default')}
                style={{
                  background: 'rgba(255, 215, 0, 0.2)',
                  border: '1px solid rgba(255, 215, 0, 0.4)',
                  color: '#FFD700',
                  padding: '4px 8px',
                  borderRadius: '4px',
                  fontSize: '9px',
                  cursor: 'pointer'
                }}
              >
                Default
              </button>
              <button
                onClick={() => setCameraPreset('inside')}
                style={{
                  background: 'rgba(255, 215, 0, 0.2)',
                  border: '1px solid rgba(255, 215, 0, 0.4)',
                  color: '#FFD700',
                  padding: '4px 8px',
                  borderRadius: '4px',
                  fontSize: '9px',
                  cursor: 'pointer'
                }}
              >
                Inside
              </button>
              <button
                onClick={() => setCameraPreset('far')}
                style={{
                  background: 'rgba(255, 215, 0, 0.2)',
                  border: '1px solid rgba(255, 215, 0, 0.4)',
                  color: '#FFD700',
                  padding: '4px 8px',
                  borderRadius: '4px',
                  fontSize: '9px',
                  cursor: 'pointer'
                }}
              >
                Far View
              </button>
              <button
                onClick={() => setCameraPreset('top')}
                style={{
                  background: 'rgba(255, 215, 0, 0.2)',
                  border: '1px solid rgba(255, 215, 0, 0.4)',
                  color: '#FFD700',
                  padding: '4px 8px',
                  borderRadius: '4px',
                  fontSize: '9px',
                  cursor: 'pointer'
                }}
              >
                Top View
              </button>
            </div>
            <button
              onClick={resetCameraPosition}
              style={{
                background: 'rgba(255, 215, 0, 0.3)',
                border: '1px solid rgba(255, 215, 0, 0.5)',
                color: '#FFD700',
                padding: '4px 8px',
                borderRadius: '4px',
                fontSize: '9px',
                cursor: 'pointer',
                width: '100%',
                marginTop: '4px'
              }}
            >
              Reset Camera
            </button>
          </div>
        )}

        <div style={{ marginBottom: '10px' }}>
          <label style={{ display: 'block', marginBottom: '5px', fontSize: '12px' }}>
            <input
              type="checkbox"
              checked={fogParams.enabled}
              onChange={async (e) => {
                setFogParams(prev => ({ ...prev, enabled: e.target.checked }))
                const THREE = await import('three')
                updateFog(THREE)
              }}
              style={{ marginRight: '8px' }}
            />
            Fog Effect
          </label>
        </div>

                <div className="transmission-text" style={{ 
          fontSize: '9px', 
          opacity: 0.9, 
          marginTop: '15px', 
          lineHeight: '1.4',
          fontFamily: 'Uncial Antiqua, serif',
          color: 'var(--copper-medium)'
        }}>
          <div>◦ audio-reactive ◦ | ≋ beat-detection ≋ | ⟐ dynamic-noise ⟐</div>
          <div style={{ marginTop: '5px' }}>
            <span className="rune">◯</span> {spheresRef.current.filter(s => s.params.enabled).length} entities | 
            <span className="rune">✦</span> {performanceStats.particleCount.toLocaleString()} particles
          </div>
          <div style={{ 
            marginTop: '5px', 
            color: performanceStats.fps < 30 ? 'var(--error-rust)' : performanceStats.fps < 45 ? 'var(--warning-copper)' : 'var(--transmission-glow)' 
          }}>
            <span className="rune">⧨</span> {performanceStats.fps} fps | transmission {performanceStats.fps >= 45 ? 'stable' : performanceStats.fps >= 30 ? 'fluctuating' : 'unstable'}
          </div>
          {cymateGeometry && <div style={{ marginTop: '3px' }}><span className="rune">◈</span> cymatic patterns active</div>}
          {tendrilsEnabled && <div style={{ marginTop: '3px' }}><span className="rune">⟨⟩</span> neural tendrils ({Math.round(tendrilDensity * 100)}% density)</div>}
          {dysonSphereEnabled && <div style={{ marginTop: '3px' }}><span className="rune">🌿</span> growing vines ({vineComplexity} complexity, {Math.round(vineGrowthRate * 1000)}% growth)</div>}
          {cameraControlsEnabled && (
            <div style={{ marginTop: '3px', fontSize: '8px', color: 'var(--teal-light)' }}>
              <span className="rune">⟐</span> observer: orbit | zoom | pan
            </div>
          )}
          {entronautEnabled && (
            <div style={{ marginTop: '5px', fontSize: '8px', lineHeight: '1.3' }}>
              <div><span className="rune">⟐</span> sefa analysis: {entronautStateRef.current ? 'active' : 'initializing'}</div>
              {entronautStateRef.current && (
                <>
                  <div>complexity: {(entronautStateRef.current.informationMetrics.complexity * 100).toFixed(1)}%</div>
                  <div>emergence: {(entronautStateRef.current.informationMetrics.emergence * 100).toFixed(1)}%</div>
                  <div>coherence: {(entronautStateRef.current.informationMetrics.coherence * 100).toFixed(1)}%</div>
                  {adaptiveCoupling && (
                    <div style={{ marginTop: '3px', color: 'var(--teal-light)' }}>
                      <span className="rune">⧨</span> biomimetic coupling active
                    </div>
                  )}
                </>
              )}
            </div>
          )}
          <div style={{ marginTop: '5px', fontSize: '8px', opacity: 0.8 }}>
            <div>sub-bass (20-80hz) | bass (120-250hz) | mid (250-800hz)</div>
            <div>high-mid (1k-4khz) | high (5k-10khz)</div>
          </div>
        </div>
        </div>
      </div>

      {/* About Section - Expanded Clickable Widget */}
      <div 
        className="about-section ancient-panel" 
        onClick={() => setAboutCollapsed(!aboutCollapsed)}
        style={{
          position: 'fixed',
          bottom: aboutCollapsed ? '20px' : '5%',
          left: aboutCollapsed ? '50%' : '50%',
          transform: aboutCollapsed ? 'translateX(-50%) translateY(calc(100% - 75px))' : 'translateX(-50%) translateY(0)',
          zIndex: 1000,
          background: 'linear-gradient(135deg, var(--marble-dark), var(--teal-dark))',
          borderRadius: aboutCollapsed ? '10px' : '15px',
          color: 'var(--copper-light)',
          fontFamily: 'Metamorphous, serif',
          width: aboutCollapsed ? '420px' : '90vw',
          minWidth: aboutCollapsed ? '420px' : '800px',
          maxWidth: aboutCollapsed ? '420px' : '1200px',
          height: aboutCollapsed ? 'auto' : '80vh',
          maxHeight: aboutCollapsed ? 'none' : '80vh',
          transition: 'all 0.5s ease-in-out',
          backdropFilter: 'blur(20px)',
          border: '2px solid var(--copper-medium)',
          pointerEvents: 'auto',
          boxShadow: aboutCollapsed 
            ? '0 4px 20px var(--copper-dark), inset 0 0 15px var(--teal-dark)' 
            : '0 10px 40px rgba(0, 0, 0, 0.7), inset 0 0 25px var(--teal-dark)',
          cursor: 'pointer',
          overflow: aboutCollapsed ? 'visible' : 'hidden'
        }}
        onMouseEnter={(e) => {
          // Disable camera controls when mouse enters about section
          const event = new CustomEvent('disableCameraControls', { detail: true })
          window.dispatchEvent(event)
          // Add hover effect
          e.currentTarget.style.borderColor = 'var(--transmission-glow)'
          e.currentTarget.style.boxShadow = '0 6px 25px var(--transmission-glow)'
        }}
        onMouseLeave={(e) => {
          // Re-enable camera controls when mouse leaves about section
          const event = new CustomEvent('disableCameraControls', { detail: false })
          window.dispatchEvent(event)
          // Remove hover effect
          e.currentTarget.style.borderColor = 'var(--copper-medium)'
          e.currentTarget.style.boxShadow = '0 4px 20px var(--copper-dark)'
        }}
      >
        {/* Collapsed State - Clickable Widget */}
        {aboutCollapsed && (
          <div style={{
            padding: '18px 25px',
            textAlign: 'center',
            fontSize: '12px',
            lineHeight: '1.4',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            gap: '12px',
            minHeight: '55px'
          }}>
            <div className="rune" style={{ fontSize: '20px', color: 'var(--copper-bright)' }}>⟐</div>
            <div style={{ 
              flex: 1,
              display: 'flex',
              flexDirection: 'column',
              alignItems: 'center',
              gap: '3px'
            }}>
              <div className="ancient-title" style={{ 
                fontSize: '13px', 
                color: 'var(--copper-bright)', 
                fontWeight: 'bold',
                fontFamily: 'Metamorphous, serif' 
              }}>
                - liminal sessions -
              </div>
              <div className="runic-text" style={{ 
                fontSize: '9px', 
                color: 'var(--copper-medium)', 
                opacity: 0.9,
                fontFamily: 'Uncial Antiqua, serif'
              }}>
                ◦ click to access entity data ◦
              </div>
            </div>
            <div className="rune" style={{ fontSize: '14px', opacity: 0.7, color: 'var(--transmission-glow)' }}>⟨</div>
          </div>
        )}

        {/* Expanded State - Full About Panel */}
        {!aboutCollapsed && (
          <div style={{
            padding: '30px 40px',
            transition: 'all 0.3s ease-in-out',
            position: 'relative',
            height: '100%',
            display: 'flex',
            flexDirection: 'column',
            overflow: 'auto'
          }}>
            {/* Subtle Logo Background */}
            <div style={{
              position: 'absolute',
              top: 0,
              left: 0,
              right: 0,
              bottom: 0,
              backgroundImage: 'url(/images/logo.webp)',
              backgroundSize: '200px 200px',
              backgroundRepeat: 'no-repeat',
              backgroundPosition: 'top right 40px',
              opacity: 0.15,
              borderRadius: '15px',
              pointerEvents: 'none'
            }} />
            
            {/* Content Overlay */}
            <div style={{
              position: 'relative',
              zIndex: 2,
              flexGrow: 1,
              display: 'flex',
              flexDirection: 'column'
            }}>
              <div style={{
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'space-between',
                marginBottom: '25px',
                paddingBottom: '15px',
                borderBottom: '1px solid var(--copper-dark)'
              }}>
                <h3 className="ancient-title" style={{ 
                  margin: 0, 
                  fontSize: '28px', 
                  textAlign: 'center', 
                  flex: 1,
                  fontFamily: 'Metamorphous, serif',
                  color: 'var(--copper-bright)',
                  textShadow: '0 2px 4px rgba(0,0,0,0.5)'
                }}>
                  <span className="rune" style={{ fontSize: '32px' }}>⟐</span> Liminal Sessions <span className="rune" style={{ fontSize: '32px' }}>⟐</span>
                </h3>
                <div className="rune" style={{ 
                  fontSize: '20px', 
                  opacity: 0.7, 
                  color: 'var(--transmission-glow)',
                  cursor: 'pointer',
                  transition: 'all 0.2s ease',
                  padding: '5px'
                }}
                onMouseEnter={(e) => {
                  e.currentTarget.style.opacity = '1'
                  e.currentTarget.style.transform = 'scale(1.1)'
                }}
                onMouseLeave={(e) => {
                  e.currentTarget.style.opacity = '0.7'
                  e.currentTarget.style.transform = 'scale(1)'
                }}
                >⟩</div>
              </div>
              
              <div style={{
                display: 'grid',
                gridTemplateColumns: '1fr',
                gap: '20px',
                flexGrow: 1
              }}>
                <div className="transmission-text" style={{ 
                  fontSize: '16px', 
                  lineHeight: '1.8', 
                  fontFamily: 'Uncial Antiqua, serif',
                  color: 'var(--copper-light)',
                  textShadow: '0 1px 2px rgba(0,0,0,0.3)'
                }}>
                  <p style={{ 
                    marginBottom: '20px',
                    fontSize: '18px',
                    fontWeight: 'bold',
                    color: 'var(--copper-bright)'
                  }}>
                    Liminal Sessions emerges from the spaces between heartbeats, where ancient algorithms carved themselves into stone before mathematics had names.
                  </p>
                  
                  <p style={{ marginBottom: '20px' }}>
                    Their sound excavates frequencies buried beneath millennia of sediment, translating the geometric hymns that echo in empty cathedrals and forgotten temples. Through acoustic brutality and primordial precision, they channel the conversations between wood and metal, breath and bone, time and its shadows.
                  </p>
                  
                  <p style={{ marginBottom: '20px' }}>
                    The music arrives as if summoned from depths where djent mathematics merge with earth's oldest songs. Each composition becomes an archaeological expedition into the strata of sound, where rhythm serves as both excavation tool and ancient map.
                  </p>
                  
                  <p style={{ 
                    fontSize: '14px', 
                    opacity: 0.9,
                    fontStyle: 'italic',
                    color: 'var(--transmission-glow)'
                  }}>
                    They are archaeologists of sound, unearthing the sacred geometry that binds chaos to rhythm in the liminal space where all echoes converge.
                  </p>
                </div>

                <div style={{
                  background: 'rgba(0,0,0,0.3)',
                  padding: '20px',
                  borderRadius: '10px',
                  border: '1px solid var(--copper-dark)'
                }}>
                  <h4 style={{
                    fontSize: '18px',
                    color: 'var(--copper-bright)',
                    marginBottom: '15px',
                    fontFamily: 'Metamorphous, serif'
                  }}>
                    <span className="rune">◈</span> Transmission Properties
                  </h4>
                  <div className="runic-text" style={{ 
                    fontSize: '14px', 
                    opacity: 0.9, 
                    lineHeight: '1.6',
                    fontFamily: 'Uncial Antiqua, serif',
                    color: 'var(--copper-medium)',
                    display: 'grid',
                    gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
                    gap: '10px'
                  }}>
                    <div><span className="rune">♪</span> ambient electronic resonance</div>
                    <div><span className="rune">◯</span> audio-visual emergence field</div>
                    <div><span className="rune">≋</span> real-time particle dynamics</div>
                    <div><span className="rune">⟐</span> symbolic emergence field analysis</div>
                    <div><span className="rune">⧨</span> biomimetic coupling systems</div>
                    <div><span className="rune">◈</span> cymatic pattern generation</div>
                  </div>
                </div>

                <div style={{
                  textAlign: 'center',
                  padding: '15px',
                  fontSize: '12px',
                  color: 'var(--copper-medium)',
                  fontFamily: 'Uncial Antiqua, serif',
                  opacity: 0.8,
                  borderTop: '1px solid var(--copper-dark)',
                  marginTop: 'auto'
                }}>
                  ◦ click anywhere to close and return to visualization ◦
                </div>
              </div>
            </div>
          </div>
        )}
      </div>

      {/* Startup Info Message */}
      {showStartupInfo && (
        <div style={{
          position: 'fixed',
          top: '50%',
          left: '50%',
          transform: 'translate(-50%, -50%)',
          zIndex: 999,
          background: 'linear-gradient(135deg, var(--marble-dark), var(--teal-dark))',
          border: '2px solid var(--copper-medium)',
          borderRadius: '15px',
          padding: '30px 40px',
          maxWidth: '500px',
          width: '90%',
          textAlign: 'center',
          backdropFilter: 'blur(20px)',
          boxShadow: '0 10px 30px rgba(0, 0, 0, 0.7), inset 0 0 20px var(--teal-dark)',
          color: 'var(--copper-light)',
          fontFamily: 'Metamorphous, serif',
          animation: 'fadeInPulse 2s ease-out'
        }}>
          <div className="rune" style={{ 
            fontSize: '48px', 
            color: 'var(--copper-bright)',
            marginBottom: '20px',
            display: 'block'
          }}>⟐</div>
          
          <h3 style={{
            fontSize: '24px',
            marginBottom: '20px',
            color: 'var(--copper-bright)',
            fontFamily: 'Metamorphous, serif',
            textShadow: '0 2px 4px rgba(0,0,0,0.5)'
          }}>
            Visualization Awaiting Signal
          </h3>
          
          <div style={{
            fontSize: '16px',
            lineHeight: '1.6',
            marginBottom: '25px',
            color: 'var(--copper-medium)',
            fontFamily: 'Uncial Antiqua, serif'
          }}>
            <p style={{ marginBottom: '15px' }}>
              The particle field remains dormant until audio transmission begins.
            </p>
            <p>
              <strong style={{ color: 'var(--copper-bright)' }}>Press the play button</strong> or <strong style={{ color: 'var(--copper-bright)' }}>select a track</strong> from the audio interface to activate the visualization.
            </p>
          </div>
          
          <div style={{
            fontSize: '12px',
            color: 'var(--transmission-glow)',
            fontFamily: 'Uncial Antiqua, serif',
            opacity: 0.9
          }}>
            ◦ this message will disappear once audio begins ◦
          </div>
          
          <button
            onClick={() => setShowStartupInfo(false)}
            style={{
              position: 'absolute',
              top: '15px',
              right: '15px',
              background: 'transparent',
              border: '1px solid var(--copper-medium)',
              borderRadius: '50%',
              width: '30px',
              height: '30px',
              color: 'var(--copper-medium)',
              cursor: 'pointer',
              fontSize: '14px',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              transition: 'all 0.2s ease'
            }}
            onMouseEnter={(e) => {
              e.currentTarget.style.borderColor = 'var(--transmission-glow)'
              e.currentTarget.style.color = 'var(--transmission-glow)'
              e.currentTarget.style.background = 'rgba(255, 215, 0, 0.1)'
            }}
            onMouseLeave={(e) => {
              e.currentTarget.style.borderColor = 'var(--copper-medium)'
              e.currentTarget.style.color = 'var(--copper-medium)'
              e.currentTarget.style.background = 'transparent'
            }}
            title="Dismiss message"
          >
            ×
          </button>
        </div>
      )}

      {/* Floating Refresh Button - Top Right */}
      <div style={{
        position: 'fixed',
        top: '80px', // Below social glyphs
        right: '20px',
        zIndex: 1000
      }}>
        <button
          onClick={async () => {
            // Force complete refresh of all particle systems
            await performHiddenRefresh(true)
            
            // Additional hard reset for all spheres
            spheresRef.current.forEach((sphere) => {
              if (!sphere.params.enabled) return
              
              const particleCount = sphere.params.particleCount
              
              // Complete reset of all particle data
              for (let i = 0; i < particleCount; i++) {
                const i3 = i * 3
                const radius = sphere.params.sphereRadius * sphere.params.innerSphereRadius
                const theta = Math.random() * Math.PI * 2
                const phi = Math.acos(2 * Math.random() - 1)
                const r = Math.cbrt(Math.random()) * radius

                // Reset positions to sphere center
                sphere.positions[i3] = r * Math.sin(phi) * Math.cos(theta)
                sphere.positions[i3 + 1] = r * Math.sin(phi) * Math.sin(theta)
                sphere.positions[i3 + 2] = r * Math.cos(phi)

                // Zero all velocities
                sphere.velocities[i3] = 0
                sphere.velocities[i3 + 1] = 0
                sphere.velocities[i3 + 2] = 0

                // Reset base positions
                sphere.basePositions[i3] = sphere.positions[i3]
                sphere.basePositions[i3 + 1] = sphere.positions[i3 + 1]
                sphere.basePositions[i3 + 2] = sphere.positions[i3 + 2]

                // Reset lifetimes and effects
                sphere.lifetimes[i] = Math.random() * sphere.params.particleLifetime
                sphere.maxLifetimes[i] = sphere.lifetimes[i]
                sphere.beatEffects[i] = 0
              }
              
              // Reset sphere-level parameters
              sphere.lastNoiseScale = sphere.params.noiseScale
              sphere.lastValidVolume = 0
              sphere.lastRotationSpeed = 0
              sphere.peakDetection.energyHistory = []
              sphere.peakDetection.lastPeakTime = 0
            })
            
            // Reset beat manager
            if (beatManagerRef.current) {
              beatManagerRef.current.currentWaveRadius = 0
              beatManagerRef.current.waveStrength = 0
              beatManagerRef.current.isWaveActive = false
            }
            
            // Reset timing
            lastTimeRef.current = 0
            
            console.log('🔄 Complete visualizer refresh executed')
          }}
          disabled={autoRefreshRef.current.isRefreshing}
          style={{
            width: '50px',
            height: '50px',
            borderRadius: '50%',
            background: autoRefreshRef.current.isRefreshing 
              ? 'linear-gradient(135deg, var(--copper-dark), var(--teal-dark))' 
              : 'linear-gradient(135deg, rgba(0, 0, 0, 0.8), rgba(255, 215, 0, 0.3))',
            border: autoRefreshRef.current.isRefreshing 
              ? '2px solid var(--copper-medium)' 
              : '1px solid rgba(255, 215, 0, 0.2)',
            color: autoRefreshRef.current.isRefreshing ? 'var(--copper-medium)' : '#FFD700',
            fontFamily: 'Cinzel, serif',
            fontSize: '18px',
            cursor: autoRefreshRef.current.isRefreshing ? 'not-allowed' : 'pointer',
            transition: 'all 0.3s ease-in-out',
            backdropFilter: 'blur(10px)',
            opacity: autoRefreshRef.current.isRefreshing ? 0.6 : 1,
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            boxShadow: autoRefreshRef.current.isRefreshing 
              ? '0 2px 8px rgba(0, 0, 0, 0.3)' 
              : '0 2px 8px rgba(0, 0, 0, 0.3)',
            position: 'relative'
          }}
          onMouseEnter={(e) => {
            if (!autoRefreshRef.current.isRefreshing) {
              e.currentTarget.style.borderColor = 'var(--transmission-glow)'
              e.currentTarget.style.background = 'linear-gradient(135deg, rgba(255, 215, 0, 0.2), rgba(255, 215, 0, 0.4))'
              e.currentTarget.style.color = 'var(--transmission-glow)'
              e.currentTarget.style.transform = 'scale(1.05)'
              e.currentTarget.style.boxShadow = '0 4px 15px rgba(255, 215, 0, 0.3)'
              // Show tooltip
              const tooltip = e.currentTarget.querySelector('.refresh-tooltip') as HTMLElement
              if (tooltip) tooltip.style.opacity = '1'
            }
          }}
          onMouseLeave={(e) => {
            if (!autoRefreshRef.current.isRefreshing) {
              e.currentTarget.style.borderColor = 'rgba(255, 215, 0, 0.2)'
              e.currentTarget.style.background = 'linear-gradient(135deg, rgba(0, 0, 0, 0.8), rgba(255, 215, 0, 0.3))'
              e.currentTarget.style.color = '#FFD700'
              e.currentTarget.style.transform = 'scale(1)'
              e.currentTarget.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.3)'
              // Hide tooltip
              const tooltip = e.currentTarget.querySelector('.refresh-tooltip') as HTMLElement
              if (tooltip) tooltip.style.opacity = '0'
            }
          }}
          title={autoRefreshRef.current.isRefreshing ? 'Restoring particle equilibrium...' : 'Reset Particle Fields'}
        >
          <span style={{ 
            animation: autoRefreshRef.current.isRefreshing ? 'spin 1s linear infinite' : 'none',
            display: 'inline-block'
          }}>
            {autoRefreshRef.current.isRefreshing ? '⧗' : '⟲'}
          </span>
          
          {/* Tooltip */}
          <div 
            className="refresh-tooltip"
            style={{
              position: 'absolute',
              top: '60px',
              left: '50%',
              transform: 'translateX(-50%)',
              background: 'rgba(0, 0, 0, 0.95)',
              color: '#FFD700',
              padding: '6px 10px',
              borderRadius: '6px',
              fontSize: '10px',
              fontWeight: 'bold',
              whiteSpace: 'nowrap',
              border: '1px solid rgba(255, 215, 0, 0.3)',
              backdropFilter: 'blur(10px)',
              opacity: 0,
              pointerEvents: 'none',
              transition: 'opacity 0.2s ease-out',
              fontFamily: 'Uncial Antiqua, serif'
            }}
          >
            {autoRefreshRef.current.isRefreshing ? 'restoring equilibrium' : 'reset particles'}
            {/* Tooltip Arrow */}
            <div style={{
              position: 'absolute',
              bottom: '100%',
              left: '50%',
              transform: 'translateX(-50%)',
              width: 0,
              height: 0,
              borderLeft: '5px solid transparent',
              borderRight: '5px solid transparent',
              borderBottom: '5px solid rgba(255, 215, 0, 0.3)'
            }} />
          </div>
        </button>
        
        {/* Add CSS animation for spinning */}
        <style>
          {`
            @keyframes spin {
              from { transform: rotate(0deg); }
              to { transform: rotate(360deg); }
            }
          `}
        </style>
      </div>
    </div>
  )
} 