{"version":3,"file":"camera-lod-BKH3g8TR.js","sources":["../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/constants.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/geometry-utils.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/refactor/render/PhotorealInterior.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/refactor/vr/XRSurfaceRig.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/hud-info-store.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/sun-calculator.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/celestial-frame.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/refactor/async/frameClock.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/refactor/async/scheduler/BudgetScheduler.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/edge-stitch-topology.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/tri-tile.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/animation-loop.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/tile-visibility-tracker.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/photogrammetry.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/photogrammetry-manager.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/tritree-manager.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/surface-ground-support.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/Constants.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/utils/ArrayBoxUtilities.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/utils/nodeBufferUtils.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/build/computeBoundsUtils.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/build/splitUtils.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/build/sortUtils.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/build/buildTree.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/utils/PrimitivePool.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/utils/BufferStack.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/cast/shapecast.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/cast/bvhcast.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/BVHTraversalHelper.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/BVH.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/utils/BufferUtils.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/build/geometryUtils.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/GeometryBVH.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/math/SeparatingAxisBounds.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/math/MathUtilities.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/math/ExtendedTriangle.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/math/OrientedBox.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/utils/ExtendedTrianglePool.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/cast/closestPointToPoint.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/utils/ThreeRayIntersectUtilities.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/utils/TriangleUtilities.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/utils/iterationUtils.generated.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/cast/refit.generated.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/utils/intersectUtils.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/utils/iterationUtils_indirect.generated.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/cast/raycast.generated.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/cast/raycastFirst.generated.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/cast/intersectsGeometry.generated.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/cast/closestPointToGeometry.generated.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/cast/refit_indirect.generated.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/cast/raycast_indirect.generated.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/cast/raycastFirst_indirect.generated.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/cast/intersectsGeometry_indirect.generated.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/cast/closestPointToGeometry_indirect.generated.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/utils/GeometryRayIntersectUtilities.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/MeshBVH.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/LineBVH.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/PointsBVH.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/ObjectBVH.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/core/SkinnedMeshBVH.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/objects/BVHHelper.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/debug/Debug.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/utils/ExtensionUtilities.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/webgl/VertexAttributeTexture.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/webgl/MeshBVHUniformStruct.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/utils/StaticGeometryGenerator.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/webgl/glsl/common_functions.glsl.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/webgl/glsl/bvh_distance_functions.glsl.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/webgl/glsl/bvh_ray_functions.glsl.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/webgl/glsl/bvh_struct_definitions.glsl.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/node_modules/.pnpm/three-mesh-bvh@0.9.17_three@0.185.1/node_modules/three-mesh-bvh/src/index.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/surface-capsule-collider.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/orbit-drag-projection.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/refactor/tiles/PhotorealSamplingMatrices.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/refactor/ui/SceneLocationIndicator.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/device-sensors.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/surface-camera-controller.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/audio-sfx.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/refactor/async/hover/HoverDispatcher.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/refactor/async/workers/WorkerPoolMetrics.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/refactor/async/workers/WorkerPool.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/refactor/async/AsyncHarness.js","../../../../home/roko/Documents/Projects/Adjacent/noclip-unified/earth/modules/event-manager.js"],"sourcesContent":["/**\n * Physical and astronomical constants for Earth globe visualization\n * All distance units are in meters (1 unit = 1 meter)\n *\n * Uses WGS84 ellipsoid for compatibility with @takram/three-atmosphere library.\n * The atmosphere library expects terrain at WGS84 radii for proper rendering.\n */\n\nimport {\n  getBackendApiBase,\n  hasBackendOverride,\n  isLocalRuntime,\n  resolveBackendApiUrl\n} from '../refactor/shared/backend.js';\n\n// Angular conversion\nexport const DEG2RAD = Math.PI / 180;\nexport const RAD2DEG = 180 / Math.PI;\n\n// WGS84 Ellipsoid - matches @takram/three-geospatial Ellipsoid.WGS84\n// These values MUST match the atmosphere library defaults for proper rendering\nexport const WGS84_SEMI_MAJOR_AXIS = 6_378_137; // Equatorial radius (meters)\nexport const WGS84_SEMI_MINOR_AXIS = 6_356_752.3142451793; // Polar radius (meters)\nexport const WGS84_MEAN_RADIUS = (2 * WGS84_SEMI_MAJOR_AXIS + WGS84_SEMI_MINOR_AXIS) / 3; // ~6,371 km\n\n// For spherical approximation, use equatorial radius (matches atmosphere library)\nexport const EARTH_RADIUS_M = WGS84_SEMI_MAJOR_AXIS;\nexport const PLANET_RADIUS = EARTH_RADIUS_M;\n\n// Atmosphere library defaults (for reference)\n// AtmosphereParameters.DEFAULT.bottomRadius = 6,360,000\n// AtmosphereParameters.DEFAULT.topRadius = 6,420,000\n// The 18km difference between WGS84 equatorial (6,378km) and atmosphere bottom (6,360km)\n// means terrain is slightly \"above\" the atmosphere base - this is intentional and\n// the library's correctAltitude handles this.\nexport const SUN_RADIUS_M = 696_000_000; // 696,000 km\nexport const SUN_EARTH_DISTANCE_M = 149_597_870_700; // 1 AU = ~149.6 million km\n// Apparent solar half-angle at 1 AU. Shaders use its sine as the physically\n// bounded penumbra around the geometric day/night horizon.\nexport const SUN_ANGULAR_RADIUS_RAD = Math.asin(\n  SUN_RADIUS_M / SUN_EARTH_DISTANCE_M\n);\nexport const SUN_ANGULAR_RADIUS_SIN =\n  SUN_RADIUS_M / SUN_EARTH_DISTANCE_M;\n\n// Moon physical/orbital constants\nexport const MOON_RADIUS_M = 1_737_400; // meters\nexport const MOON_DISTANCE_M = 384_400_000; // average distance to moon (meters)\nexport const MOON_ORBIT_INCLINATION_RAD = 5.145 * DEG2RAD; // Inclination to ecliptic\nexport const MOON_ASCENDING_NODE_RAD = 125.08 * DEG2RAD; // Longitude of ascending node at J2000\nexport const MOON_ARG_PERIGEE_RAD = 318.15 * DEG2RAD; // Argument of perigee at J2000\nexport const MOON_MEAN_ANOMALY0_RAD = 134.963 * DEG2RAD; // Mean anomaly at J2000\nexport const MOON_MEAN_MOTION_RAD_PER_DAY = 13.064993 * DEG2RAD; // deg/day → rad/day\n\n// Camera rendering constants\nexport const CAMERA_NEAR = 0.1;\nexport const CAMERA_FAR = SUN_EARTH_DISTANCE_M * 2; // Far enough to see the sun\n// Earth navigation spans the Earth–Moon system and beyond, within the retained\n// astronomical clipping range. URL read/write must accept this same envelope.\nexport const EARTH_ORBIT_MAX_DISTANCE_M = SUN_EARTH_DISTANCE_M;\nexport const VIEW_ALTITUDE_MIN_M = -500;\nexport const VIEW_ALTITUDE_MAX_M = EARTH_ORBIT_MAX_DISTANCE_M;\n\n// Altitude thresholds (in meters)\nexport const ALT_30K_UNITS = 30_000;\nexport const ALT_10K_UNITS = 10_000;\n\n// Terrain rendering\n// NOTE: At 1.0 (realistic), terrain is barely visible at planetary scale\n// Increase for testing/visualization (e.g., 100-500 for dramatic effect)\nexport const ELEVATION_EXAGGERATION = 1.0;\nexport const MAX_TILE_LEVEL = 18; // Maximum LOD for finest terrain detail (supports level 22 imagery)\n\n// Wayback WMTS imagery\nconst WAYBACK_ROOT =\n  'https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery';\nconst WAYBACK_WMTS_CAPABILITIES_PATH = 'MapServer/WMTS/1.0.0/WMTSCapabilities.xml';\nconst WAYBACK_WMTS_ROOT_PATH = 'WMTS/1.0.0/default028mm/MapServer';\n\nconst isUnsafeCrossOriginWaybackProxy = () => {\n  if (typeof window === 'undefined') return false;\n  if (!hasBackendOverride()) return false;\n\n  try {\n    const backendBase = getBackendApiBase();\n    const backendUrl = new URL(backendBase, window.location.origin);\n    if (backendUrl.origin === window.location.origin) return false;\n\n    const backendHost = (backendUrl.hostname || '').toLowerCase();\n    const pageHost = (window.location.hostname || '').toLowerCase();\n\n    // Tunnel backends often miss CORS headers for binary passthrough imagery.\n    if (backendHost.endsWith('trycloudflare.com')) return true;\n    // Prefer direct Wayback on production web host when backend override is cross-origin.\n    if (pageHost.endsWith('noclip.org')) return true;\n  } catch {\n    return false;\n  }\n  return false;\n};\n\nconst shouldUseWaybackProxy = () => {\n  if (typeof window === 'undefined') return false;\n  if (isLocalRuntime() && !hasBackendOverride()) return false;\n  if (isUnsafeCrossOriginWaybackProxy()) return false;\n  return true;\n};\n\nconst buildWaybackUrl = (path) => {\n  const normalized = String(path || '').replace(/^\\/+/, '');\n  if (!normalized) return WAYBACK_ROOT;\n  if (shouldUseWaybackProxy()) {\n    return resolveBackendApiUrl(`/wayback/${normalized}`);\n  }\n  return `${WAYBACK_ROOT}/${normalized}`;\n};\n\nexport const WAYBACK_WMTS_CAPABILITIES = buildWaybackUrl(WAYBACK_WMTS_CAPABILITIES_PATH);\nexport const DEFAULT_WAYBACK_VERSION = 'latest';\n\nexport const AXIAL_TILT_DEG = 23.4397;\nexport const AXIAL_TILT_RAD = AXIAL_TILT_DEG * DEG2RAD;\n\n// Atmosphere (meters, scattering coefficients in 1/m)\nexport const ATMOSPHERE_HEIGHT_M = 100_000;\nexport const ATMOSPHERE_RADIUS_M = PLANET_RADIUS + ATMOSPHERE_HEIGHT_M;\nexport const RAYLEIGH_SCALE_HEIGHT_M = 8000;\nexport const MIE_SCALE_HEIGHT_M = 1200;\nexport const BETA_RAYLEIGH = [5.8e-6, 13.5e-6, 33.1e-6];\nexport const BETA_MIE = [21e-6, 21e-6, 21e-6];\nexport const MIE_G = 0.76;\n\n// Prime meridian alignment offset\n// This offset ensures that longitude 0° (Greenwich) aligns with the texture\n// Set to 0 if your texture's prime meridian is already at +Z when rotation.y = 0\nexport const EARTH_PRIME_MERIDIAN_OFFSET_RAD = 0;\n\n// NKN network\nexport const DEFAULT_FORWARDER =\n    'forwarder.5d7bdb47e1c757508d28f5726469afa1f7c93bd037a1940aa0dab97ab421c833';\n\n// Imagery service\nexport const WMTS_ROOT = buildWaybackUrl(WAYBACK_WMTS_ROOT_PATH);\n","/**\n * Geometric utilities for coordinate transformations and ray-sphere intersections\n */\n\nimport * as THREE from 'three';\nimport {\n    PLANET_RADIUS,\n    RAD2DEG,\n    AXIAL_TILT_RAD,\n    EARTH_PRIME_MERIDIAN_OFFSET_RAD,\n    WGS84_SEMI_MAJOR_AXIS,\n    WGS84_SEMI_MINOR_AXIS\n} from './constants.js';\n\n/**\n * Convert a normalized direction vector to latitude/longitude in degrees\n * @param {THREE.Vector3} dir - Normalized direction vector\n * @returns {{latDeg: number, lonDeg: number}} Latitude and longitude in degrees\n */\nconst UNTILT_AXIS = new THREE.Vector3(0, 0, 1);\nconst UNTILT_QUAT = new THREE.Quaternion().setFromAxisAngle(UNTILT_AXIS, AXIAL_TILT_RAD);\nconst _tmpDir = new THREE.Vector3();\nconst _tmpQuat = new THREE.Quaternion();\nconst _ellipsoidTmpDir = new THREE.Vector3();\nconst _ellipsoidTmpQuat = new THREE.Quaternion();\nconst _ellipsoidTmpOrigin = new THREE.Vector3();\nconst _ellipsoidTmpDir2 = new THREE.Vector3();\nconst _ellipsoidTmpPos = new THREE.Vector3();\nconst _ellipsoidTmpQuat2 = new THREE.Quaternion();\nconst WGS84_A2 = WGS84_SEMI_MAJOR_AXIS * WGS84_SEMI_MAJOR_AXIS;\nconst WGS84_B2 = WGS84_SEMI_MINOR_AXIS * WGS84_SEMI_MINOR_AXIS;\n\n// WGS84 eccentricity squared — used to convert between geodetic and geocentric\n// directions. On the ellipsoid, the direction from center to a surface point at\n// geodetic latitude φ has Y component (1-e²)·sin(φ) instead of sin(φ).\nconst WGS84_E2 = 1 - WGS84_B2 / WGS84_A2;          // ≈ 0.00669438\nconst WGS84_ONE_MINUS_E2 = 1 - WGS84_E2;            // ≈ 0.99330562\n\nfunction _alignEquatorial(dir) {\n    return dir.clone().applyQuaternion(UNTILT_QUAT);\n}\n\n/**\n * Compute local sun angles (altitude, azimuth, incidence) at a surface point.\n * IMPORTANT: This function expects inputs in the WORLD (ecliptic) frame.\n * - surfaceDir should be in world space (tilted Earth group's local direction)\n * - sunDir should be in world space (ecliptic frame, from getSunDirectionEcliptic)\n *\n * The function internally transforms to the equatorial frame for lat/lon consistency.\n *\n * @param {THREE.Vector3} surfaceDir - normalized world-space direction from planet center\n * @param {THREE.Vector3} sunDir - normalized world-space (ecliptic) direction from Earth to Sun\n * @returns {{altitude: number, azimuth: number, incidence: number}} angles in radians\n */\nexport function computeLocalSunAngles(surfaceDir, sunDir) {\n    if (!surfaceDir || !sunDir) {\n        return { altitude: 0, azimuth: 0, incidence: Math.PI / 2 };\n    }\n\n    // Transform both vectors from world (ecliptic) to equatorial frame\n    // This \"untilts\" them so we can work in Earth's local coordinate system\n    const up = surfaceDir.clone().applyQuaternion(UNTILT_QUAT).normalize();\n    const sunEq = sunDir.clone().applyQuaternion(UNTILT_QUAT).normalize();\n\n    // Build local east/north axes in equatorial frame\n    const worldUp = new THREE.Vector3(0, 1, 0);\n    let east = new THREE.Vector3().crossVectors(worldUp, up);\n    if (east.lengthSq() < 1e-6) {\n        // At pole, pick arbitrary east\n        east = new THREE.Vector3(1, 0, 0);\n    } else {\n        east.normalize();\n    }\n    const north = new THREE.Vector3().crossVectors(up, east).normalize();\n\n    const alt = Math.asin(THREE.MathUtils.clamp(sunEq.dot(up), -1, 1));\n    const az = Math.atan2(sunEq.dot(east), sunEq.dot(north)); // from north, eastward\n    const incidence = Math.acos(THREE.MathUtils.clamp(sunDir.dot(surfaceDir), -1, 1));\n\n    return { altitude: alt, azimuth: az, incidence };\n}\n\nexport function dirToLatLon(dir) {\n    const aligned = _alignEquatorial(dir);\n    const rxz = Math.sqrt(aligned.x * aligned.x + aligned.z * aligned.z);\n    const lat = Math.atan2(aligned.y / WGS84_ONE_MINUS_E2, rxz);\n    const lon = Math.atan2(aligned.x, aligned.z);\n    return {\n        latDeg: THREE.MathUtils.radToDeg(lat),\n        lonDeg: THREE.MathUtils.radToDeg(lon)\n    };\n}\n\n/**\n * Convert a local (planet-fixed) direction vector to latitude/longitude in degrees\n * @param {THREE.Vector3} dir - Normalized direction vector in planet-local space\n * @returns {{latDeg: number, lonDeg: number}} Latitude and longitude in degrees\n */\nexport function dirToLatLonLocal(dir, target = {}) {\n    const rxz = Math.sqrt(dir.x * dir.x + dir.z * dir.z);\n    const lat = Math.atan2(dir.y / WGS84_ONE_MINUS_E2, rxz);\n    let lon = Math.atan2(dir.x, dir.z) + (EARTH_PRIME_MERIDIAN_OFFSET_RAD || 0);\n    lon = THREE.MathUtils.euclideanModulo(lon + Math.PI, Math.PI * 2) - Math.PI;\n    target.latDeg = THREE.MathUtils.radToDeg(lat);\n    target.lonDeg = THREE.MathUtils.radToDeg(lon);\n    return target;\n}\n\n/**\n * Convert a world position vector to latitude/longitude in degrees\n * @param {THREE.Vector3} vec - World position vector\n * @returns {{latDeg: number, lonDeg: number}|null} Latitude and longitude in degrees, or null if invalid\n */\nexport function worldPosToLatLon(vec) {\n    const r = vec.length();\n    if (!r) return null;\n    const normalized = _alignEquatorial(vec.clone().normalize());\n    const rxz = Math.sqrt(normalized.x * normalized.x + normalized.z * normalized.z);\n    const lat = Math.atan2(normalized.y / WGS84_ONE_MINUS_E2, rxz);\n    const lon = Math.atan2(normalized.x, normalized.z);\n    return { latDeg: lat * RAD2DEG, lonDeg: lon * RAD2DEG };\n}\n\n/**\n * Convert a world position vector to latitude/longitude in degrees (Earth-fixed)\n * @param {THREE.Vector3} vec - World position vector\n * @param {THREE.Object3D} planetGroup - Planet group with axial tilt and rotation applied\n * @returns {{latDeg: number, lonDeg: number}|null} Latitude and longitude in degrees, or null if invalid\n */\nexport function worldPosToLatLonLocal(vec, planetGroup) {\n    const r = vec.length();\n    if (!r) return null;\n\n    _tmpDir.copy(vec).normalize();\n    if (planetGroup && planetGroup.getWorldQuaternion) {\n        planetGroup.getWorldQuaternion(_tmpQuat);\n        _tmpQuat.invert();\n        _tmpDir.applyQuaternion(_tmpQuat);\n    }\n\n    return dirToLatLonLocal(_tmpDir);\n}\n\n/**\n * Convert geodetic latitude/longitude to a local (planet-fixed) direction vector.\n * Returns the direction from planet center to the WGS84 ellipsoid surface at\n * the given geodetic coordinates. This is the inverse of dirToLatLonLocal.\n * @param {number} latDeg - Geodetic latitude in degrees\n * @param {number} lonDeg - Longitude in degrees\n * @returns {THREE.Vector3} Normalized direction vector in planet-local space\n */\nexport function latLonToLocalDir(latDeg, lonDeg, target = null) {\n    const lat = latDeg * (Math.PI / 180);\n    const lon = lonDeg * (Math.PI / 180);\n\n    // Adjust for prime meridian offset\n    const adjustedLon = lon - (EARTH_PRIME_MERIDIAN_OFFSET_RAD || 0);\n\n    // Convert geodetic lat/lon to direction from center to ellipsoid surface.\n    // The (1-e²) factor on Y converts from geodetic to geocentric direction,\n    // matching the WGS84 ellipsoid shape used by ECEF and 3D tile systems.\n    const r = Math.cos(lat);\n    const x = r * Math.sin(adjustedLon);\n    const y = WGS84_ONE_MINUS_E2 * Math.sin(lat);\n    const z = r * Math.cos(adjustedLon);\n\n    // Hot geometry builders can supply a reusable vector. Keeping the\n    // allocation-free path here avoids a Vector3 for every GeoJSON edge while\n    // retaining the original fresh-vector behaviour for all existing callers.\n    return (target || new THREE.Vector3()).set(x, y, z).normalize();\n}\n\n/**\n * Compute WGS84 ellipsoid radius for a planet-local direction.\n * @param {THREE.Vector3} dir - Normalized local direction vector\n * @returns {number} Radius in meters at that direction\n */\nexport function ellipsoidRadiusForLocalDir(dir) {\n    if (!dir) return PLANET_RADIUS;\n    const x = dir.x || 0;\n    const y = dir.y || 0;\n    const z = dir.z || 0;\n    const xx = x * x + z * z;\n    const yy = y * y;\n    const denom = (xx / WGS84_A2) + (yy / WGS84_B2);\n    if (!Number.isFinite(denom) || denom <= 0) return PLANET_RADIUS;\n    return 1 / Math.sqrt(denom);\n}\n\n/**\n * Compute WGS84 ellipsoid radius for a world-space direction or position.\n * Applies the inverse planet group rotation to get local direction when provided.\n * @param {THREE.Vector3} vec - World direction or position\n * @param {THREE.Object3D|null} planetGroup - Planet group with rotation applied\n * @returns {number} Radius in meters at that direction\n */\nexport function ellipsoidRadiusForWorldDir(vec, planetGroup = null) {\n    if (!vec) return PLANET_RADIUS;\n    _ellipsoidTmpDir.copy(vec);\n    if (planetGroup?.getWorldQuaternion) {\n        planetGroup.getWorldQuaternion(_ellipsoidTmpQuat);\n        _ellipsoidTmpQuat.invert();\n        _ellipsoidTmpDir.applyQuaternion(_ellipsoidTmpQuat);\n    }\n    if (_ellipsoidTmpDir.lengthSq() > 0) {\n        _ellipsoidTmpDir.normalize();\n    }\n    return ellipsoidRadiusForLocalDir(_ellipsoidTmpDir);\n}\n\n/**\n * Calculate ray-sphere intersection point\n * @param {THREE.Vector3} origin - Ray origin\n * @param {THREE.Vector3} dir - Ray direction (will be normalized)\n * @param {number} radius - Sphere radius (default: PLANET_RADIUS)\n * @returns {THREE.Vector3|null} Intersection point, or null if no intersection\n */\nexport function raySphereIntersection(origin, dir, radius = PLANET_RADIUS) {\n    const o = origin.clone();\n    const d = dir.clone().normalize();\n    const b = o.dot(d);\n    const c = o.lengthSq() - radius * radius;\n    const disc = b * b - c;\n    if (disc < 0) return null;\n    let t = -b - Math.sqrt(disc);\n    if (t < 0) t = -b + Math.sqrt(disc);\n    if (t < 0) return null;\n    return o.add(d.multiplyScalar(t));\n}\n\n/**\n * Calculate ray-ellipsoid intersection point (WGS84 by default).\n * Supports optional planetGroup transform (rotation + translation).\n * @param {THREE.Vector3} origin - Ray origin in world space\n * @param {THREE.Vector3} dir - Ray direction (world space)\n * @param {THREE.Object3D|null} planetGroup - Planet group with rotation applied\n * @param {number} a - Semi-major axis (equatorial radius)\n * @param {number} b - Semi-minor axis (polar radius)\n * @returns {THREE.Vector3|null} Intersection point in world space, or null if no intersection\n */\nexport function rayEllipsoidIntersection(\n    origin,\n    dir,\n    planetGroup = null,\n    a = WGS84_SEMI_MAJOR_AXIS,\n    b = WGS84_SEMI_MINOR_AXIS\n) {\n    if (!origin || !dir) return null;\n    if (!Number.isFinite(a) || !Number.isFinite(b) || a <= 0 || b <= 0) return null;\n\n    const o = _ellipsoidTmpOrigin.copy(origin);\n    const d = _ellipsoidTmpDir2.copy(dir).normalize();\n\n    // Transform ray into planet-local frame if planetGroup is provided\n    if (planetGroup?.getWorldQuaternion) {\n        planetGroup.getWorldQuaternion(_ellipsoidTmpQuat2);\n        const worldPos = _ellipsoidTmpPos;\n        planetGroup.getWorldPosition(worldPos);\n        o.sub(worldPos);\n        _ellipsoidTmpQuat2.invert();\n        o.applyQuaternion(_ellipsoidTmpQuat2);\n        d.applyQuaternion(_ellipsoidTmpQuat2);\n    }\n\n    const invA = 1 / a;\n    const invB = 1 / b;\n    const ox = o.x * invA;\n    const oy = o.y * invB;\n    const oz = o.z * invA;\n    const dx = d.x * invA;\n    const dy = d.y * invB;\n    const dz = d.z * invA;\n\n    const A = dx * dx + dy * dy + dz * dz;\n    const B = 2 * (ox * dx + oy * dy + oz * dz);\n    const C = ox * ox + oy * oy + oz * oz - 1;\n    const disc = B * B - 4 * A * C;\n    if (disc < 0 || !Number.isFinite(disc)) return null;\n\n    const sqrtDisc = Math.sqrt(disc);\n    let t = (-B - sqrtDisc) / (2 * A);\n    if (t < 0) {\n        t = (-B + sqrtDisc) / (2 * A);\n    }\n    if (t < 0 || !Number.isFinite(t)) return null;\n\n    const hitLocal = o.add(d.multiplyScalar(t));\n\n    if (planetGroup?.getWorldQuaternion) {\n        _ellipsoidTmpQuat2.invert();\n        hitLocal.applyQuaternion(_ellipsoidTmpQuat2);\n        hitLocal.add(_ellipsoidTmpPos);\n    }\n\n    return hitLocal.clone();\n}\n\n/**\n * Vincenty inverse formula for WGS84 ellipsoid distance.\n * @param {number} lat1Deg\n * @param {number} lon1Deg\n * @param {number} lat2Deg\n * @param {number} lon2Deg\n * @returns {number} Distance in meters\n */\nexport function geodesicDistanceWGS84(lat1Deg, lon1Deg, lat2Deg, lon2Deg) {\n    if (!Number.isFinite(lat1Deg) || !Number.isFinite(lon1Deg) ||\n        !Number.isFinite(lat2Deg) || !Number.isFinite(lon2Deg)) {\n        return NaN;\n    }\n\n    const a = WGS84_SEMI_MAJOR_AXIS;\n    const b = WGS84_SEMI_MINOR_AXIS;\n    const f = (a - b) / a;\n\n    const phi1 = lat1Deg * (Math.PI / 180);\n    const phi2 = lat2Deg * (Math.PI / 180);\n    const L = (lon2Deg - lon1Deg) * (Math.PI / 180);\n\n    const U1 = Math.atan((1 - f) * Math.tan(phi1));\n    const U2 = Math.atan((1 - f) * Math.tan(phi2));\n    const sinU1 = Math.sin(U1);\n    const cosU1 = Math.cos(U1);\n    const sinU2 = Math.sin(U2);\n    const cosU2 = Math.cos(U2);\n\n    let lambda = L;\n    // Always evaluate at least once, including north/south motion on the\n    // same meridian (L === 0). Skipping the loop reported all such travel as 0m.\n    let lambdaPrev = Infinity;\n    let iter = 0;\n    let sinSigma = 0;\n    let cosSigma = 0;\n    let sigma = 0;\n    let sinAlpha = 0;\n    let cosSqAlpha = 0;\n    let cos2SigmaM = 0;\n\n    while (iter < 200 && Math.abs(lambda - lambdaPrev) > 1e-12) {\n        iter++;\n        const sinLambda = Math.sin(lambda);\n        const cosLambda = Math.cos(lambda);\n        const t1 = cosU2 * sinLambda;\n        const t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;\n        sinSigma = Math.sqrt(t1 * t1 + t2 * t2);\n        if (sinSigma === 0) return 0;\n        cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;\n        sigma = Math.atan2(sinSigma, cosSigma);\n        sinAlpha = (cosU1 * cosU2 * sinLambda) / sinSigma;\n        cosSqAlpha = 1 - sinAlpha * sinAlpha;\n        cos2SigmaM = cosSqAlpha !== 0\n            ? (cosSigma - (2 * sinU1 * sinU2) / cosSqAlpha)\n            : 0;\n        const C = (f / 16) * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));\n        lambdaPrev = lambda;\n        lambda = L + (1 - C) * f * sinAlpha * (\n            sigma +\n            C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM))\n        );\n    }\n\n    if (iter >= 200) {\n        // Fallback to spherical approximation if Vincenty fails to converge\n        const meanR = (2 * a + b) / 3;\n        const dLat = (lat2Deg - lat1Deg) * (Math.PI / 180);\n        const dLon = (lon2Deg - lon1Deg) * (Math.PI / 180);\n        const sinDLat = Math.sin(dLat * 0.5);\n        const sinDLon = Math.sin(dLon * 0.5);\n        const hav = sinDLat * sinDLat + Math.cos(phi1) * Math.cos(phi2) * sinDLon * sinDLon;\n        return 2 * meanR * Math.asin(Math.min(1, Math.sqrt(hav)));\n    }\n\n    const uSq = (cosSqAlpha * (a * a - b * b)) / (b * b);\n    const A = 1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));\n    const B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));\n    const deltaSigma = B * sinSigma * (\n        cos2SigmaM +\n        (B / 4) * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -\n        (B / 6) * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM))\n    );\n    return b * A * (sigma - deltaSigma);\n}\n\n/**\n * Vincenty direct formula (destination point) for WGS84 ellipsoid.\n * @param {number} latDeg\n * @param {number} lonDeg\n * @param {number} bearingDeg\n * @param {number} distanceM\n * @returns {{latDeg:number, lonDeg:number}|null}\n */\nexport function geodesicDestinationWGS84(latDeg, lonDeg, bearingDeg, distanceM) {\n    if (!Number.isFinite(latDeg) || !Number.isFinite(lonDeg) ||\n        !Number.isFinite(bearingDeg) || !Number.isFinite(distanceM)) {\n        return null;\n    }\n\n    const a = WGS84_SEMI_MAJOR_AXIS;\n    const b = WGS84_SEMI_MINOR_AXIS;\n    const f = (a - b) / a;\n\n    const alpha1 = bearingDeg * (Math.PI / 180);\n    const sinAlpha1 = Math.sin(alpha1);\n    const cosAlpha1 = Math.cos(alpha1);\n    const phi1 = latDeg * (Math.PI / 180);\n    const U1 = Math.atan((1 - f) * Math.tan(phi1));\n    const sinU1 = Math.sin(U1);\n    const cosU1 = Math.cos(U1);\n\n    const sigma1 = Math.atan2(Math.tan(U1), cosAlpha1);\n    const sinAlpha = cosU1 * sinAlpha1;\n    const cosSqAlpha = 1 - sinAlpha * sinAlpha;\n    const uSq = (cosSqAlpha * (a * a - b * b)) / (b * b);\n    const A = 1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));\n    const B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));\n\n    let sigma = distanceM / (b * A);\n    let sigmaPrev = 0;\n    let sinSigma = 0;\n    let cosSigma = 0;\n    let cos2SigmaM = 0;\n    let iter = 0;\n\n    while (iter < 200 && Math.abs(sigma - sigmaPrev) > 1e-12) {\n        iter++;\n        cos2SigmaM = Math.cos(2 * sigma1 + sigma);\n        sinSigma = Math.sin(sigma);\n        cosSigma = Math.cos(sigma);\n        const deltaSigma = B * sinSigma * (\n            cos2SigmaM +\n            (B / 4) * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -\n            (B / 6) * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM))\n        );\n        sigmaPrev = sigma;\n        sigma = distanceM / (b * A) + deltaSigma;\n    }\n\n    const tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;\n    const phi2 = Math.atan2(\n        sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,\n        (1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp)\n    );\n    const lambda = Math.atan2(\n        sinSigma * sinAlpha1,\n        cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1\n    );\n    const C = (f / 16) * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));\n    const L = lambda - (1 - C) * f * sinAlpha *\n        (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));\n\n    const lon2 = (lonDeg * (Math.PI / 180)) + L;\n    const lat2Deg = phi2 * (180 / Math.PI);\n    let lon2Deg = lon2 * (180 / Math.PI);\n    lon2Deg = THREE.MathUtils.euclideanModulo(lon2Deg + 180, 360) - 180;\n\n    return { latDeg: lat2Deg, lonDeg: lon2Deg };\n}\n\n/**\n * Initial bearing (forward azimuth) from point 1 to point 2 on the\n * WGS84-approximated sphere, in degrees from north (clockwise).\n * Uses the spherical formula — accurate to ~0.5% for typical Earth-scale\n * inputs; we don't need Vincenty-direct level of precision here because\n * the bearing is rendered as a UI cue, not used for navigation.\n *\n * @param {number} lat1Deg\n * @param {number} lon1Deg\n * @param {number} lat2Deg\n * @param {number} lon2Deg\n * @returns {number} Bearing in degrees in [0, 360).\n */\nexport function geodesicBearing(lat1Deg, lon1Deg, lat2Deg, lon2Deg) {\n    if (!Number.isFinite(lat1Deg) || !Number.isFinite(lon1Deg) ||\n        !Number.isFinite(lat2Deg) || !Number.isFinite(lon2Deg)) {\n        return NaN;\n    }\n    const phi1 = lat1Deg * (Math.PI / 180);\n    const phi2 = lat2Deg * (Math.PI / 180);\n    const dLon = (lon2Deg - lon1Deg) * (Math.PI / 180);\n    const y = Math.sin(dLon) * Math.cos(phi2);\n    const x = Math.cos(phi1) * Math.sin(phi2) -\n              Math.sin(phi1) * Math.cos(phi2) * Math.cos(dLon);\n    const brg = Math.atan2(y, x) * (180 / Math.PI);\n    return (brg + 360) % 360;\n}\n\n/**\n * Sample N points along the great-circle arc from start → end (inclusive\n * of both endpoints when steps ≥ 2). Used by the draw layer to make\n * surface-following polylines look like real geodesics rather than\n * planar segments cutting through the ellipsoid.\n *\n * @param {{lat:number,lon:number}|[number,number]} start - {lat,lon} or [lon,lat]\n * @param {{lat:number,lon:number}|[number,number]} end\n * @param {number} steps - Number of points to emit (≥ 2).\n * @returns {Array<{lat:number,lon:number}>}\n */\nexport function interpolateGreatCircle(start, end, steps = 16) {\n    const s = _normalisePoint(start);\n    const e = _normalisePoint(end);\n    if (!s || !e) return [];\n    const n = Math.max(2, Math.floor(steps));\n\n    const phi1 = s.lat * (Math.PI / 180);\n    const lam1 = s.lon * (Math.PI / 180);\n    const phi2 = e.lat * (Math.PI / 180);\n    const lam2 = e.lon * (Math.PI / 180);\n\n    const sinPhi1 = Math.sin(phi1);\n    const cosPhi1 = Math.cos(phi1);\n    const sinPhi2 = Math.sin(phi2);\n    const cosPhi2 = Math.cos(phi2);\n    const cosDLam = Math.cos(lam2 - lam1);\n\n    const cosD = sinPhi1 * sinPhi2 + cosPhi1 * cosPhi2 * cosDLam;\n    const d = Math.acos(Math.max(-1, Math.min(1, cosD)));\n    const out = new Array(n);\n\n    if (d < 1e-9) {\n        for (let i = 0; i < n; i++) out[i] = { lat: s.lat, lon: s.lon };\n        return out;\n    }\n\n    const sinD = Math.sin(d);\n    for (let i = 0; i < n; i++) {\n        const f = i / (n - 1);\n        const A = Math.sin((1 - f) * d) / sinD;\n        const B = Math.sin(f * d) / sinD;\n        const x = A * cosPhi1 * Math.cos(lam1) + B * cosPhi2 * Math.cos(lam2);\n        const y = A * cosPhi1 * Math.sin(lam1) + B * cosPhi2 * Math.sin(lam2);\n        const z = A * sinPhi1 + B * sinPhi2;\n        const phi = Math.atan2(z, Math.sqrt(x * x + y * y));\n        const lam = Math.atan2(y, x);\n        out[i] = {\n            lat: phi * (180 / Math.PI),\n            lon: ((lam * (180 / Math.PI)) + 540) % 360 - 180,\n        };\n    }\n    return out;\n}\n\nfunction _normalisePoint(p) {\n    if (!p) return null;\n    if (Array.isArray(p) && p.length >= 2) {\n        return { lat: Number(p[1]), lon: Number(p[0]) };\n    }\n    if (typeof p === 'object') {\n        const lat = Number(p.lat ?? p.latDeg);\n        const lon = Number(p.lon ?? p.lng ?? p.lonDeg);\n        if (Number.isFinite(lat) && Number.isFinite(lon)) return { lat, lon };\n    }\n    return null;\n}\n\n/**\n * Geodesic polygon area on the WGS84-approximated sphere using the\n * spherical-excess formula (Karney/2011 simplification of L'Huilier).\n * Result is in square metres. Sign is positive for shapes that wind\n * counter-clockwise; we return absolute value for caller-friendliness.\n *\n * Coords accept either `[lon, lat]` (GeoJSON) or `{lat,lon}`. The first\n * and last vertex don't need to match; the polygon is implicitly closed.\n *\n * Near the poles (|lat| ≥ 89.99°) we clamp inputs to avoid the\n * Math.tan blow-up. Tests cover this in `geometry-utils.test.mjs`.\n *\n * @param {Array} coords\n * @returns {number} Area in m² (always ≥ 0).\n */\nexport function geodesicArea(coords) {\n    if (!Array.isArray(coords) || coords.length < 3) return 0;\n    const pts = coords.map(_normalisePoint).filter(Boolean);\n    if (pts.length < 3) return 0;\n\n    // Use the average of WGS84 axes as the sphere radius. For continental-\n    // scale polygons this gives <0.5% error vs full ellipsoidal area;\n    // anyone needing better can drop in @turf/area at the call site.\n    const R = (2 * WGS84_SEMI_MAJOR_AXIS + WGS84_SEMI_MINOR_AXIS) / 3;\n    const D2R = Math.PI / 180;\n    const CLAMP_LAT = 89.99;\n\n    let total = 0;\n    const n = pts.length;\n    for (let i = 0; i < n; i++) {\n        const p1 = pts[i];\n        const p2 = pts[(i + 1) % n];\n        const lat1 = Math.max(-CLAMP_LAT, Math.min(CLAMP_LAT, p1.lat)) * D2R;\n        const lat2 = Math.max(-CLAMP_LAT, Math.min(CLAMP_LAT, p2.lat)) * D2R;\n        const dLon = (p2.lon - p1.lon) * D2R;\n        total += dLon * (2 + Math.sin(lat1) + Math.sin(lat2));\n    }\n    return Math.abs(total * R * R / 2);\n}\n\n/**\n * Convert longitude/latitude to Web Mercator tile coordinates\n * @param {number} lonDeg - Longitude in degrees\n * @param {number} latDeg - Latitude in degrees\n * @param {number} z - Zoom level\n * @returns {{x: number, y: number, cx: number, cy: number, n: number}} Tile coordinates\n */\nexport function lonLatToTileCoords(lonDeg, latDeg, z) {\n    // Clamp to WebMercator valid latitude range (prevents Infinity/NaN near poles)\n    const MAX_LAT = 85.05112878;\n    const EPS = 1e-5;\n    latDeg = Math.max(-MAX_LAT + EPS, Math.min(MAX_LAT - EPS, latDeg));\n\n    const latRad = latDeg * Math.PI / 180;\n    const n = Math.pow(2, z);\n\n    // cx,cy are in tile-space units (0..n)\n    const cx = (lonDeg + 180) / 360 * n;\n    let cy = (1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2 * n;\n    // Ensure poles map to the last valid Mercator row instead of overflowing\n    cy = Math.max(0, Math.min(n - 1, cy));\n\n    const x = Math.floor(cx);\n    const y = Math.floor(cy);\n    return { x, y, cx, cy, n };\n}\n\n/**\n * Leak-free update of a persistent line/trail BufferGeometry.\n *\n * Replacing a geometry attribute with `setAttribute(name, new BufferAttribute())`\n * does NOT free the previous attribute's GPU WebGLBuffer in three.js — those\n * buffers leak until the context is lost. Trail overlays (aircraft, satellite,\n * maritime) rebuild their persistent line geometry on every update, so doing so\n * leaked GPU memory continuously and crashed long sessions. (The leak is in raw\n * attribute buffers, which `renderer.info` does not count, so it is invisible to\n * heap/geometry/texture probes.)\n *\n * This updates in place when the existing attribute array is large enough\n * (uploads via bufferSubData, no allocation, no leak). When the geometry must\n * grow, it disposes the geometry ONCE first so three.js frees the old buffers,\n * then re-creates the attributes. Trail lengths stabilise at their cap within a\n * few frames, after which every update is a cheap in-place rewrite.\n *\n * @param {THREE.BufferGeometry} geometry\n * @param {Array<{name:string, array:Float32Array|Int32Array, itemSize:number}>} specs\n */\n/**\n * Update a SINGLE named attribute on a geometry without leaking its GPU buffer.\n *\n * Use when the geometry has other attributes that must NOT be disposed (e.g.\n * terrain tiles whose uv2 is re-applied on every imagery refresh while position/\n * normal/index stay put). Replacing the attribute with a fresh BufferAttribute\n * leaks the previous WebGLBuffer; this writes in place when the length is\n * unchanged (the normal case — vertex count is fixed) and only re-creates on a\n * genuine length change (rare).\n *\n * @param {THREE.BufferGeometry} geometry\n * @param {string} name\n * @param {Float32Array|Int32Array|Uint16Array} array\n * @param {number} itemSize\n */\nexport function updateAttributeInPlace(geometry, name, array, itemSize) {\n    if (!geometry || !array) return;\n    const existing = geometry.getAttribute(name);\n    if (existing && existing.array.length === array.length) {\n        existing.array.set(array);\n        existing.needsUpdate = true;\n    } else {\n        geometry.setAttribute(name, new THREE.BufferAttribute(array, itemSize));\n    }\n}\n\nexport function updateTrailAttributes(geometry, specs) {\n    if (!geometry || !Array.isArray(specs) || specs.length === 0) return;\n    // Reuse the existing GPU buffers (in-place upload) only when every attribute\n    // length matches exactly — the steady-state case once a trail reaches its\n    // sample cap. Any size change (grow or shrink) disposes the geometry first\n    // so three.js frees the old WebGLBuffers, then re-creates the attributes.\n    let sameShape = true;\n    for (const spec of specs) {\n        const existing = geometry.getAttribute(spec.name);\n        if (!existing || existing.array.length !== spec.array.length) {\n            sameShape = false;\n            break;\n        }\n    }\n    if (sameShape) {\n        for (const spec of specs) {\n            const attr = geometry.getAttribute(spec.name);\n            attr.array.set(spec.array);\n            attr.needsUpdate = true;\n        }\n    } else {\n        geometry.dispose();\n        for (const spec of specs) {\n            geometry.setAttribute(spec.name, new THREE.BufferAttribute(spec.array, spec.itemSize));\n        }\n    }\n}\n","import * as THREE from 'three';\n\nconst sameFootprint = (local, direction, radius) => direction\n    && local.distanceToSquared(direction) * radius * radius <= .12 * .12;\n\n/** Read existing verified pedestrian contact, never roofs, stale LODs or a DEM guess.\n * An observer inside opaque ground receives no exterior radiance in any direction.\n * This analytic solid has pixel-exact coverage without a faceted Earth-sized mesh.\n */\nexport function photorealInteriorState(controller, worldPosition) {\n    if (controller?.cameraMode !== 'surface' || !worldPosition\n        || !controller.terrainTileGroup?.visible || controller._oceanState?.underwater) return false;\n    const sequence = controller.terrainTileGroup.userData?.photoModelChangeSeq | 0;\n    const local = controller._interiorCheckDirection ||= new THREE.Vector3();\n    controller._toPlanetLocalDirection(worldPosition, local).normalize();\n    const flight = controller._photoFlightGroundR, center = controller._photoFlightCenterR;\n    if (Number.isFinite(flight) && flight > 1e6 && Number.isFinite(center)\n        && controller._photoFlightGroundModelSeq === sequence && controller._photoFlightCenterModelSeq === sequence\n        && sameFootprint(local, controller._photoFlightGroundLocalDir, flight) && sameFootprint(local, controller._photoFlightCenterLocalDir, flight)\n        && worldPosition.length() < Math.min(flight, center) - .025) return true;\n    if (controller._groundTruthCacheWalkable !== true) return false;\n    const radius = controller._groundTruthCacheR;\n    if (!Number.isFinite(radius) || radius < 1e6 || !controller._groundTruthCacheLocalDir\n        || controller._groundTruthSampleModelSeq !== sequence || !sameFootprint(local, controller._groundTruthCacheLocalDir, radius)) return false;\n    // Held contact can suppress a tiny downward LOD correction. A current\n    // center hit must independently agree that the observer is inside ground.\n    if (controller._photoCenterSkinModelSeq !== controller._groundTruthSampleModelSeq) return false;\n    const skin = controller._getPhotoCenterSkinRadiusForDirection(worldPosition);\n    return Number.isFinite(skin) && worldPosition.length() < Math.min(radius, skin) - .025;\n}\n\n/** One opaque final frame only while inside measured ground. No texture, light,\n * reflection, atmosphere pass, readback, task clock or additional world renderer.\n * Clip-space geometry also avoids subtracting Earth-radius float32 coordinates.\n */\nexport class PhotorealInteriorRenderer {\n    constructor() {\n        this.scene = new THREE.Scene();\n        this.scene.background = new THREE.Color(0);\n        this.geometry = new THREE.BufferGeometry();\n        this.geometry.setAttribute('position', new THREE.Float32BufferAttribute([-1,-1,0, 3,-1,0, -1,3,0], 3));\n        this.material = new THREE.ShaderMaterial({\n            vertexShader: 'void main(){gl_Position=vec4(position.xy,0.0,1.0);}',\n            fragmentShader: 'void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}',\n            depthTest: false, depthWrite: true, toneMapped: false, fog: false,\n        });\n        const solid = new THREE.Mesh(this.geometry, this.material);\n        solid.frustumCulled = false;\n        this.scene.add(solid);\n    }\n\n    render(renderer, camera) {\n        if (!renderer.xr?.isPresenting) renderer.setRenderTarget(null);\n        renderer.render(this.scene, camera);\n    }\n\n    dispose() { this.geometry.dispose(); this.material.dispose(); this.scene.clear(); }\n}\n","import * as THREE from 'three';\n\n/** World-space navigation anchor above a room-space native XR camera. */\nexport class XRSurfaceRig {\n  constructor(rig, camera) {\n    this.rig = rig;\n    this.camera = camera;\n    // Camera, not Object3D: lookAt must use camera-forward (-Z).\n    this.anchor = new THREE.PerspectiveCamera();\n    camera.updateWorldMatrix(true, false);\n    camera.getWorldPosition(this.anchor.position);\n    camera.getWorldQuaternion(this.anchor.quaternion);\n    this.anchor.up.copy(camera.up);\n    this._savedRig = rig.matrix.clone();\n    this._savedProjection = {};\n    for (const key of ['near', 'far', 'fov', 'aspect', 'zoom']) this._savedProjection[key] = camera[key];\n    this._roomOrigin = new THREE.Vector3();\n    this._roomHeadingInverse = new THREE.Quaternion();\n    this._worldPosition = new THREE.Vector3();\n    this._worldQuaternion = new THREE.Quaternion();\n    this._viewerWorldPosition = new THREE.Vector3();\n    this._eyePosition = new THREE.Vector3();\n    this._hasViewerPosition = false;\n    this._turnViewerWorld = new THREE.Vector3();\n    this._turnViewerLocal = new THREE.Vector3();\n    this._forward = new THREE.Vector3();\n    this._right = new THREE.Vector3();\n    this._back = new THREE.Vector3();\n    this._up = new THREE.Vector3(0, 1, 0);\n    this._unitScale = new THREE.Vector3(1, 1, 1);\n    this._basis = new THREE.Matrix4();\n    this._matrix = new THREE.Matrix4();\n    this.calibrated = false;\n  }\n\n  /** Level the navigation frame, never the tracked head's pitch/roll. */\n  level(up, forward) {\n    this.anchor.up.copy(up).normalize();\n    this._forward.copy(forward).addScaledVector(this.anchor.up, -forward.dot(this.anchor.up));\n    if (this._forward.lengthSq() < 1e-10) {\n      this._forward.set(Math.abs(this.anchor.up.x) < 0.9 ? 1 : 0, 0, Math.abs(this.anchor.up.x) < 0.9 ? 0 : 1);\n      this._forward.addScaledVector(this.anchor.up, -this._forward.dot(this.anchor.up));\n    }\n    this._forward.normalize();\n    this._right.crossVectors(this._forward, this.anchor.up).normalize();\n    this._back.copy(this._forward).negate();\n    this._basis.makeBasis(this._right, this.anchor.up, this._back);\n    this.anchor.quaternion.setFromRotationMatrix(this._basis);\n  }\n\n  /** Calibrate once from the *viewer centre*, not Three's stereo union camera. */\n  calibrate(viewerTransform) {\n    if (this.calibrated || !viewerTransform) return;\n    this._roomOrigin.copy(viewerTransform.position);\n    this._worldQuaternion.copy(viewerTransform.orientation);\n    this._forward.set(0, 0, -1).applyQuaternion(this._worldQuaternion);\n    const yaw = this._forward.x ** 2 + this._forward.z ** 2 > 1e-10\n      ? Math.atan2(-this._forward.x, -this._forward.z) : 0;\n    this._roomHeadingInverse.setFromAxisAngle(this._up, -yaw);\n    this.calibrated = true;\n  }\n\n  apply() {\n    this._worldQuaternion.copy(this.anchor.quaternion).multiply(this._roomHeadingInverse);\n    // Composition itself preserves entry altitude. Once local-floor\n    // calibration is available the surface controller may deliberately mate\n    // the reference origin to verified terrain before applying this again.\n    this._worldPosition.copy(this._roomOrigin).applyQuaternion(this._worldQuaternion).negate().add(this.anchor.position);\n    this._matrix.compose(this._worldPosition, this._worldQuaternion, this._unitScale);\n    if (this.rig.parent) {\n      this.rig.parent.updateWorldMatrix(true, false);\n      this._basis.copy(this.rig.parent.matrixWorld).invert();\n      this._matrix.premultiply(this._basis);\n    }\n    this._matrix.decompose(this.rig.position, this.rig.quaternion, this.rig.scale);\n    this.rig.updateWorldMatrix(true, true);\n  }\n\n  sync(xr, { rigApplied = false } = {}) {\n    const frame = xr?.getFrame?.();\n    if (!frame) return false;\n    let calibratedNow = false;\n    if (!this.calibrated) {\n      const space = xr.getReferenceSpace();\n      const pose = space && frame.getViewerPose(space);\n      if (!pose) return false;\n      this.calibrate(pose.transform);\n      calibratedNow = true;\n    }\n    // The shared surface controller commits this exact rig immediately before\n    // syncing. Reuse that publication, including controller/hand descendants.\n    // First calibration changes the room transform and must still apply again.\n    // Standalone callers retain the original immediate-publication default.\n    if (rigApplied !== true || calibratedNow) this.apply();\n    // Public Three API: update both eyes, their union frustum and the user\n    // camera before terrain/sky consumers, not only inside renderer.render.\n    xr.updateCamera(this.camera);\n    // Three's user camera is the stereo-union culling camera, not the physical\n    // eye centre. Retain the centre so repeated exit/re-entry cannot accumulate\n    // its artificial backward IPD/frustum offset as geographic movement.\n    const eyes = xr.getCamera().cameras;\n    if (eyes.length) {\n      this._viewerWorldPosition.set(0, 0, 0);\n      for (const eye of eyes) this._viewerWorldPosition.add(this._eyePosition.setFromMatrixPosition(eye.matrixWorld));\n      this._viewerWorldPosition.multiplyScalar(1 / eyes.length);\n      this._hasViewerPosition = true;\n    }\n    return true;\n  }\n\n  /**\n   * Return the calibrated viewer offset from the XR reference-space origin in\n   * the Earth/world frame. In a local-floor space its radial component is the\n   * user's real eye height. Keeping this separate from `anchor` is important:\n   * the anchor is navigation state, while the native pose is room-scale input.\n   */\n  getReferenceViewerOffsetWorld(target = new THREE.Vector3()) {\n    if (!this.calibrated) return null;\n    this._worldQuaternion.copy(this.anchor.quaternion).multiply(this._roomHeadingInverse);\n    return target.copy(this._roomOrigin).applyQuaternion(this._worldQuaternion);\n  }\n\n  beginTurn() {\n    this._turnViewerWorld.copy(this._hasViewerPosition ? this._viewerWorldPosition : this.anchor.position);\n    this._turnViewerLocal.copy(this._turnViewerWorld);\n    this.rig.worldToLocal(this._turnViewerLocal);\n  }\n\n  endTurn() {\n    this._worldQuaternion.copy(this.anchor.quaternion).multiply(this._roomHeadingInverse).invert();\n    this._roomOrigin.copy(this._turnViewerWorld).sub(this.anchor.position).applyQuaternion(this._worldQuaternion);\n    this._roomOrigin.negate().add(this._turnViewerLocal);\n    this.apply();\n  }\n\n  restore() {\n    const { camera, rig } = this;\n    camera.updateWorldMatrix(true, false);\n    this._matrix.copy(camera.matrixWorld);\n    if (this._hasViewerPosition) this._matrix.setPosition(this._viewerWorldPosition);\n    this._savedRig.decompose(rig.position, rig.quaternion, rig.scale);\n    rig.updateWorldMatrix(true, false);\n    this._basis.copy(rig.matrixWorld).invert();\n    this._matrix.premultiply(this._basis).decompose(camera.position, camera.quaternion, camera.scale);\n    camera.up.copy(this.anchor.up);\n    Object.assign(camera, this._savedProjection);\n    camera.updateProjectionMatrix();\n    camera.updateWorldMatrix(true, true);\n  }\n}\n","const HUD_CORNERS = ['top-left', 'top-right', 'bottom-left', 'bottom-right'];\n\nexport const HUD_GROUPS = [\n    { id: 'time', label: 'Time', bodyClass: '' },\n    { id: 'nav', label: 'Nav', bodyClass: '' },\n    { id: 'orbit', label: 'Orbital attitude', bodyClass: '' },\n    { id: 'terrain', label: 'Terrain', bodyClass: '' },\n    { id: 'link', label: 'Link', bodyClass: '' },\n    { id: 'target', label: 'Target', bodyClass: '' },\n    { id: 'viewshed', label: 'Viewshed', bodyClass: '' },\n    { id: 'device', label: 'Device', bodyClass: '' },\n    { id: 'tile', label: 'Tile Info', bodyClass: 'hud-grid' },\n    { id: 'system', label: 'System', bodyClass: '' },\n    { id: 'lod', label: 'Surface LOD', bodyClass: 'hud-grid' }\n];\n\nexport const HUD_ITEMS = [\n    ...['earthAngle','lookYaw','lookPitch','roll','lat','lon','altitudeM','rangeM','heading','pitch'].map((key,index)=>({key:'orbit.'+key,label:['Earth offset','Look yaw','Look tilt','Roll / north','Latitude','Longitude','WGS84 altitude','Earth range','Heading','Pitch'][index],group:'orbit',defaultCorner:null})),\n    { key: 'time.mode', label: 'Mode', group: 'time', defaultCorner: 'top-left' },\n    { key: 'time.utc', label: 'UTC', group: 'time', defaultCorner: null },\n    { key: 'time.utcDate', label: 'UTC Date', group: 'time', defaultCorner: null },\n    { key: 'time.local', label: 'Local', group: 'time', defaultCorner: null },\n    { key: 'time.localDate', label: 'Local Date', group: 'time', defaultCorner: null },\n\n    { key: 'nav.lat', label: 'Lat', group: 'nav', defaultCorner: 'top-left' },\n    { key: 'nav.lon', label: 'Lon', group: 'nav', defaultCorner: 'top-left' },\n    { key: 'nav.country', label: 'Country', group: 'nav', defaultCorner: 'bottom-left' },\n    { key: 'nav.admin', label: 'Admin', group: 'nav', defaultCorner: 'bottom-left' },\n    { key: 'nav.building', label: 'Building', group: 'nav', defaultCorner: null },\n    { key: 'nav.buildingAddr', label: 'Address', group: 'nav', defaultCorner: null },\n    { key: 'nav.buildingHeight', label: 'Bldg Height', group: 'nav', defaultCorner: null },\n    { key: 'nav.buildingLevels', label: 'Bldg Levels', group: 'nav', defaultCorner: null },\n    { key: 'nav.road', label: 'Road / Path', group: 'nav', defaultCorner: 'top-left' },\n    { key: 'nav.roadClass', label: 'Road Class', group: 'nav', defaultCorner: null },\n    { key: 'nav.roadDistance', label: 'Road Offset', group: 'nav', defaultCorner: null },\n    { key: 'nav.heading', label: 'Hdg', group: 'nav', defaultCorner: null },\n    { key: 'nav.pitch', label: 'Pitch', group: 'nav', defaultCorner: null },\n    { key: 'nav.speed', label: 'Spd', group: 'nav', defaultCorner: null },\n    { key: 'nav.weatherCond', label: 'Cond', group: 'nav', defaultCorner: 'bottom-right' },\n    { key: 'nav.weatherTemp', label: 'Temp', group: 'nav', defaultCorner: 'bottom-right' },\n    { key: 'nav.weatherClouds', label: 'Clouds', group: 'nav', defaultCorner: 'bottom-right' },\n    { key: 'nav.weatherHumidity', label: 'Humidity', group: 'nav', defaultCorner: 'bottom-right' },\n    { key: 'nav.weatherWind', label: 'Wind', group: 'nav', defaultCorner: 'bottom-right' },\n    { key: 'nav.weatherPrecip', label: 'Precip', group: 'nav', defaultCorner: null },\n    { key: 'nav.weatherUpdated', label: 'Updated', group: 'nav', defaultCorner: null },\n\n    { key: 'terrain.agl', label: 'AGL', group: 'terrain', defaultCorner: null },\n    { key: 'terrain.msl', label: 'Sea', group: 'terrain', defaultCorner: 'top-right' },\n    { key: 'terrain.ground', label: 'Gnd', group: 'terrain', defaultCorner: null },\n    { key: 'terrain.vspeed', label: 'Vspd', group: 'terrain', defaultCorner: null },\n    { key: 'terrain.lod', label: 'LOD', group: 'terrain', defaultCorner: null },\n    { key: 'terrain.tiles', label: 'Tiles', group: 'terrain', defaultCorner: null },\n    { key: 'terrain.stage', label: 'Elev', group: 'terrain', defaultCorner: null },\n\n    { key: 'link.reqs', label: 'Req', group: 'link', defaultCorner: null },\n    { key: 'link.resps', label: 'Resp', group: 'link', defaultCorner: null },\n    { key: 'link.kbIn', label: 'KB In', group: 'link', defaultCorner: null },\n    { key: 'link.kbOut', label: 'KB Out', group: 'link', defaultCorner: null },\n    { key: 'link.ratio', label: 'Ratio', group: 'link', defaultCorner: null },\n\n    { key: 'target.lat', label: 'Lat', group: 'target', defaultCorner: null },\n    { key: 'target.lon', label: 'Lon', group: 'target', defaultCorner: null },\n    { key: 'target.elev', label: 'Elev', group: 'target', defaultCorner: null },\n    { key: 'target.agl', label: 'AGL', group: 'target', defaultCorner: null },\n    { key: 'target.radius', label: 'Radius', group: 'target', defaultCorner: null },\n    { key: 'target.country', label: 'Country', group: 'target', defaultCorner: null },\n    { key: 'target.admin', label: 'Admin', group: 'target', defaultCorner: null },\n    { key: 'target.building', label: 'Building', group: 'target', defaultCorner: null },\n    { key: 'target.buildingAddr', label: 'Address', group: 'target', defaultCorner: null },\n    { key: 'target.buildingHeight', label: 'Bldg Height', group: 'target', defaultCorner: null },\n    { key: 'target.buildingLevels', label: 'Bldg Levels', group: 'target', defaultCorner: null },\n    { key: 'target.aircraftModel', label: 'Aircraft', group: 'target', defaultCorner: null },\n    { key: 'target.aircraftCallsign', label: 'Callsign', group: 'target', defaultCorner: null },\n    { key: 'target.aircraftId', label: 'ICAO', group: 'target', defaultCorner: null },\n    { key: 'target.aircraftAlt', label: 'AC Alt', group: 'target', defaultCorner: null },\n    { key: 'target.aircraftSpeed', label: 'AC Spd', group: 'target', defaultCorner: null },\n    { key: 'target.aircraftHeading', label: 'AC Hdg', group: 'target', defaultCorner: null },\n    { key: 'target.aircraftLat', label: 'AC Lat', group: 'target', defaultCorner: null },\n    { key: 'target.aircraftLon', label: 'AC Lon', group: 'target', defaultCorner: null },\n    { key: 'target.aircraftSource', label: 'AC Src', group: 'target', defaultCorner: null },\n    { key: 'target.satelliteName', label: 'Satellite', group: 'target', defaultCorner: null },\n    { key: 'target.satelliteId', label: 'NORAD', group: 'target', defaultCorner: null },\n    { key: 'target.satelliteType', label: 'Sat Type', group: 'target', defaultCorner: null },\n    { key: 'target.satelliteAlt', label: 'Sat Alt', group: 'target', defaultCorner: null },\n    { key: 'target.satelliteLat', label: 'Sat Lat', group: 'target', defaultCorner: null },\n    { key: 'target.satelliteLon', label: 'Sat Lon', group: 'target', defaultCorner: null },\n    { key: 'target.satelliteSource', label: 'Sat Src', group: 'target', defaultCorner: null },\n    { key: 'target.vesselName', label: 'Vessel', group: 'target', defaultCorner: null },\n    { key: 'target.vesselMmsi', label: 'MMSI', group: 'target', defaultCorner: null },\n    { key: 'target.vesselSpeed', label: 'Vessel Spd', group: 'target', defaultCorner: null },\n    { key: 'target.vesselHeading', label: 'Vessel Hdg', group: 'target', defaultCorner: null },\n    { key: 'target.vesselLat', label: 'Vessel Lat', group: 'target', defaultCorner: null },\n    { key: 'target.vesselLon', label: 'Vessel Lon', group: 'target', defaultCorner: null },\n    { key: 'target.vesselStatus', label: 'Vessel Status', group: 'target', defaultCorner: null },\n    { key: 'target.vesselSource', label: 'Vessel Src', group: 'target', defaultCorner: null },\n    { key: 'target.sunElev', label: 'Sun El', group: 'target', defaultCorner: null },\n    { key: 'target.sunAz', label: 'Sun Az', group: 'target', defaultCorner: null },\n    { key: 'target.sunInc', label: 'Sun Inc', group: 'target', defaultCorner: null },\n    { key: 'target.solarTime', label: 'Solar', group: 'target', defaultCorner: null },\n    { key: 'target.moonElev', label: 'Moon El', group: 'target', defaultCorner: null },\n    { key: 'target.moonAz', label: 'Moon Az', group: 'target', defaultCorner: null },\n    { key: 'target.weatherCond', label: 'Cond', group: 'target', defaultCorner: null },\n    { key: 'target.weatherTemp', label: 'Temp', group: 'target', defaultCorner: null },\n    { key: 'target.weatherClouds', label: 'Clouds', group: 'target', defaultCorner: null },\n    { key: 'target.weatherHumidity', label: 'Humidity', group: 'target', defaultCorner: null },\n    { key: 'target.weatherWind', label: 'Wind', group: 'target', defaultCorner: null },\n    { key: 'target.weatherPrecip', label: 'Precip', group: 'target', defaultCorner: null },\n    { key: 'target.weatherUpdated', label: 'Updated', group: 'target', defaultCorner: null },\n\n    { key: 'viewshed.aircraft', label: 'Aircraft', group: 'viewshed', defaultCorner: null, type: 'list' },\n    { key: 'viewshed.satellites', label: 'Satellites', group: 'viewshed', defaultCorner: null, type: 'list' },\n    { key: 'viewshed.maritime', label: 'Maritime', group: 'viewshed', defaultCorner: null, type: 'list' },\n    { key: 'viewshed.buildings', label: 'Building Addresses', group: 'viewshed', defaultCorner: 'bottom-left', type: 'list' },\n    { key: 'viewshed.businesses', label: 'Businesses', group: 'viewshed', defaultCorner: 'bottom-left', type: 'list' },\n    { key: 'viewshed.natural', label: 'Natural Features', group: 'viewshed', defaultCorner: 'bottom-left', type: 'list' },\n    { key: 'viewshed.infrastructure', label: 'Infrastructure', group: 'viewshed', defaultCorner: 'bottom-left', type: 'list' },\n    { key: 'viewshed.incidents', label: 'Incidents', group: 'viewshed', defaultCorner: 'bottom-left', type: 'list' },\n\n    { key: 'device.status', label: 'Status', group: 'device', defaultCorner: null },\n    { key: 'device.heading', label: 'Heading', group: 'device', defaultCorner: null },\n    { key: 'device.headingSrc', label: 'Hdg Src', group: 'device', defaultCorner: null },\n    { key: 'device.yaw', label: 'Yaw', group: 'device', defaultCorner: null },\n    { key: 'device.pitch', label: 'Pitch', group: 'device', defaultCorner: null },\n    { key: 'device.roll', label: 'Roll', group: 'device', defaultCorner: null },\n    { key: 'device.alpha', label: 'Alpha', group: 'device', defaultCorner: null },\n    { key: 'device.beta', label: 'Beta', group: 'device', defaultCorner: null },\n    { key: 'device.gamma', label: 'Gamma', group: 'device', defaultCorner: null },\n    { key: 'device.calibrated', label: 'Calibrated', group: 'device', defaultCorner: null },\n\n    { key: 'tile.highlight', label: 'Highlight', group: 'tile', defaultCorner: null, pinable: false, showInInfo: false },\n    { key: 'tile.id', label: 'Tile ID', group: 'tile', defaultCorner: null },\n    { key: 'tile.lod', label: 'LOD', group: 'tile', defaultCorner: null },\n    { key: 'tile.path', label: 'Path', group: 'tile', defaultCorner: null },\n    { key: 'tile.imgZoom', label: 'Img Zoom', group: 'tile', defaultCorner: null },\n    { key: 'tile.imgSize', label: 'Img Tiles', group: 'tile', defaultCorner: null },\n    { key: 'tile.imgBytes', label: 'Img Bytes', group: 'tile', defaultCorner: null },\n    { key: 'tile.elevReady', label: 'Elev Fetch', group: 'tile', defaultCorner: null },\n    { key: 'tile.elevActive', label: 'Elev Active', group: 'tile', defaultCorner: null },\n\n    { key: 'system.fps', label: 'FPS', group: 'system', defaultCorner: 'top-left' },\n    { key: 'system.tiles', label: 'Tiles', group: 'system', defaultCorner: null },\n    { key: 'system.stage', label: 'Stage', group: 'system', defaultCorner: null },\n    { key: 'system.visible', label: 'Visible', group: 'system', defaultCorner: null },\n    { key: 'system.maxLod', label: 'Max LOD', group: 'system', defaultCorner: null },\n    { key: 'system.elevActive', label: 'Elev Active', group: 'system', defaultCorner: null },\n    { key: 'system.elevForce', label: 'Elev Forced', group: 'system', defaultCorner: null },\n\n    { key: 'lod.ringMeters', label: 'Rings', group: 'lod', defaultCorner: null },\n    { key: 'lod.ringCaps', label: 'LOD Caps', group: 'lod', defaultCorner: null },\n    { key: 'lod.ringImg', label: 'Img Caps', group: 'lod', defaultCorner: null },\n    { key: 'lod.stageProgress', label: 'Stage', group: 'lod', defaultCorner: null },\n    { key: 'lod.underImagery', label: 'Underfoot Img', group: 'lod', defaultCorner: null },\n    { key: 'lod.underElev', label: 'Underfoot Elev', group: 'lod', defaultCorner: null },\n    { key: 'lod.elevNear', label: 'Elev Near', group: 'lod', defaultCorner: null },\n    { key: 'lod.elevMid', label: 'Elev Mid', group: 'lod', defaultCorner: null },\n    { key: 'lod.elevFar', label: 'Elev Far', group: 'lod', defaultCorner: null }\n];\n\nexport const HUD_ITEM_MAP = new Map(HUD_ITEMS.map((item) => [item.key, item]));\nexport const HUD_DEFAULT_PINS = HUD_ITEMS.reduce((acc, item) => {\n    acc[item.key] = item.defaultCorner;\n    return acc;\n}, {});\n\nexport function normalizeHudPins(pins = {}) {\n    if (!pins || typeof pins !== 'object') return {};\n    const out = {};\n    Object.entries(pins).forEach(([key, corner]) => {\n        const item = HUD_ITEM_MAP.get(key);\n        if (!item) return;\n        if (corner === null || corner === 'none' || corner === false) {\n            out[key] = null;\n            return;\n        }\n        if (!HUD_CORNERS.includes(corner)) return;\n        out[key] = corner;\n    });\n    return out;\n}\n\nclass HudInfoStore {\n    constructor({ root = document } = {}) {\n        this.root = root;\n        this._elements = new Map();\n        this._listElements = new Map();\n        this._values = new Map();\n        this._lists = new Map();\n        this._data = new Map();\n        this._listHighlights = new Map();\n        this._dirty = new Set();\n        this._dirtyLists = new Set();\n        this._flushScheduled = false;\n        this._flushHandle = null;\n        this._cancelFlush = null;\n        this._presentationSuspended = false;\n    }\n\n    setPresentationSuspended(suspended) {\n        const next = suspended === true;\n        if (this._presentationSuspended === next) return;\n        this._presentationSuspended = next;\n        if (next && this._flushScheduled) {\n            this._cancelFlush?.(this._flushHandle);\n            this._flushHandle = null; this._cancelFlush = null; this._flushScheduled = false;\n        }\n        if (!next) {\n            this._applyAll();\n            this._dirty.clear(); this._dirtyLists.clear();\n        }\n    }\n\n    refresh(root = this.root) {\n        if (root) this.root = root;\n        this._elements.clear();\n        this._listElements.clear();\n        if (!this.root || !this.root.querySelectorAll) return;\n\n        this.root.querySelectorAll('[data-hud-key]').forEach((el) => {\n            const key = el.getAttribute('data-hud-key');\n            if (!key) return;\n            const set = this._elements.get(key) || new Set();\n            set.add(el);\n            this._elements.set(key, set);\n        });\n\n        this.root.querySelectorAll('[data-hud-list]').forEach((el) => {\n            const key = el.getAttribute('data-hud-list');\n            if (!key) return;\n            const set = this._listElements.get(key) || new Set();\n            set.add(el);\n            this._listElements.set(key, set);\n        });\n\n        this._applyAll();\n    }\n\n    setValue(key, value) {\n        if (!key) return;\n        const formatted = this._formatValue(value);\n        if (this._values.get(key) === formatted) return;\n        this._values.set(key, formatted);\n        this._dirty.add(key);\n        this._scheduleFlush();\n    }\n\n    setData(key, value) {\n        if (!key) return;\n        this._data.set(key, value);\n        if (this._listElements.has(key) || this._lists.has(key)) {\n            this._dirtyLists.add(key);\n            this._scheduleFlush();\n        }\n    }\n\n    getData(key) {\n        if (!key) return null;\n        return this._data.has(key) ? this._data.get(key) : null;\n    }\n\n    getValue(key) {\n        if (!key) return null;\n        return this._values.get(key) || null;\n    }\n\n    setList(key, items) {\n        if (!key) return;\n        const list = Array.isArray(items)\n            ? items.filter((item) => item !== null && item !== undefined).map((item) => String(item))\n            : (items ? [String(items)] : []);\n        const prev = this._lists.get(key) || [];\n        if (prev.length === list.length && prev.every((item, idx) => item === list[idx])) return;\n        this._lists.set(key, list);\n        this._dirtyLists.add(key);\n        this._scheduleFlush();\n    }\n\n    setListHighlight(key, highlight) {\n        if (!key) return;\n        const next = highlight && (highlight.id !== undefined || highlight.index !== undefined)\n            ? {\n                id: highlight.id !== undefined && highlight.id !== null ? String(highlight.id) : null,\n                index: Number.isFinite(highlight.index) ? highlight.index : null\n            }\n            : null;\n        const prev = this._listHighlights.get(key) || null;\n        if (prev?.id === next?.id && prev?.index === next?.index) return;\n        if (next) {\n            this._listHighlights.set(key, next);\n        } else {\n            this._listHighlights.delete(key);\n        }\n        if (this._presentationSuspended) return;\n        const containers = this._listElements.get(key);\n        if (!containers) return;\n        containers.forEach((el) => this._applyListHighlight(el, next));\n    }\n\n    _applyAll() {\n        if (this._presentationSuspended) return;\n        this._values.forEach((value, key) => {\n            const elements = this._elements.get(key);\n            if (!elements) return;\n            elements.forEach((el) => {\n                if (el.textContent !== value) el.textContent = value;\n            });\n        });\n        this._lists.forEach((items, key) => {\n            const containers = this._listElements.get(key);\n            if (!containers) return;\n            containers.forEach((el) => this._renderList(el, items));\n        });\n    }\n\n    _scheduleFlush() {\n        if (this._presentationSuspended) return;\n        if (this._flushScheduled) return;\n        this._flushScheduled = true;\n        const flush = () => this._flush();\n        if (typeof requestAnimationFrame === 'function') {\n            this._cancelFlush = handle => globalThis.cancelAnimationFrame?.(handle);\n            this._flushHandle = requestAnimationFrame(flush);\n        } else {\n            this._cancelFlush = handle => clearTimeout(handle);\n            this._flushHandle = setTimeout(flush, 0);\n        }\n    }\n\n    _flush() {\n        this._flushScheduled = false;\n        this._flushHandle = null; this._cancelFlush = null;\n        if (this._presentationSuspended) return;\n        if (this._dirty.size) {\n            this._dirty.forEach((key) => {\n                const elements = this._elements.get(key);\n                if (!elements) return;\n                const value = this._values.get(key);\n                if (value === undefined) return;\n                elements.forEach((el) => {\n                    if (el.textContent !== value) el.textContent = value;\n                });\n            });\n            this._dirty.clear();\n        }\n        if (this._dirtyLists.size) {\n            this._dirtyLists.forEach((key) => {\n                const containers = this._listElements.get(key);\n                if (!containers) return;\n                const items = this._lists.get(key) || [];\n                containers.forEach((el) => this._renderList(el, items));\n            });\n            this._dirtyLists.clear();\n        }\n    }\n\n    _renderList(container, items) {\n        while (container.firstChild) {\n            container.removeChild(container.firstChild);\n        }\n        const key = container.getAttribute('data-hud-list');\n        const meta = key ? this._data.get(key) : null;\n        const highlight = key ? this._listHighlights.get(key) : null;\n        const list = items.length ? items : ['--'];\n        const frag = document.createDocumentFragment();\n        list.forEach((line, index) => {\n            const item = document.createElement('div');\n            item.className = 'hud-list-item';\n            item.textContent = line;\n            if (key) {\n                item.dataset.hudList = key;\n                item.dataset.hudItemIndex = String(index);\n            }\n            const metaEntry = Array.isArray(meta) ? meta[index] : null;\n            if (metaEntry) {\n                if (metaEntry.id !== undefined && metaEntry.id !== null) {\n                    item.dataset.hudItemId = String(metaEntry.id);\n                }\n                if (metaEntry.type) {\n                    item.dataset.hudItemType = String(metaEntry.type);\n                }\n                const color = this._formatColor(metaEntry.colorHex ?? metaEntry.hex ?? metaEntry.color);\n                if (color) {\n                    item.dataset.hudColor = 'true';\n                    item.style.setProperty('--hud-list-accent', color);\n                }\n            }\n            if (highlight) {\n                const matchById = highlight.id && item.dataset.hudItemId === highlight.id;\n                const matchByIndex = highlight.index !== null && Number(item.dataset.hudItemIndex) === highlight.index;\n                item.classList.toggle('hud-list-item-highlight', !!(matchById || matchByIndex));\n            }\n            frag.appendChild(item);\n        });\n        container.appendChild(frag);\n    }\n\n    _applyListHighlight(container, highlight) {\n        if (!container) return;\n        const items = container.querySelectorAll('.hud-list-item');\n        items.forEach((item) => {\n            if (!highlight) {\n                item.classList.remove('hud-list-item-highlight');\n                return;\n            }\n            const matchById = highlight.id && item.dataset.hudItemId === highlight.id;\n            const matchByIndex = highlight.index !== null && Number(item.dataset.hudItemIndex) === highlight.index;\n            item.classList.toggle('hud-list-item-highlight', !!(matchById || matchByIndex));\n        });\n    }\n\n    _formatColor(value) {\n        if (Number.isFinite(value)) {\n            return `#${(value >>> 0).toString(16).padStart(6, '0')}`;\n        }\n        if (typeof value === 'string') {\n            const clean = value.trim();\n            if (/^#[0-9a-f]{3,8}$/i.test(clean)) return clean;\n            if (/^rgba?\\(/i.test(clean) || /^hsla?\\(/i.test(clean)) return clean;\n        }\n        return '';\n    }\n\n    _formatValue(value) {\n        if (value === null || value === undefined || value === '') return '--';\n        return String(value);\n    }\n}\n\nlet hudInfoStoreInstance = null;\n\nexport function getHudInfoStore(options = {}) {\n    if (!hudInfoStoreInstance) {\n        hudInfoStoreInstance = new HudInfoStore(options);\n    } else if (options.root && options.root !== hudInfoStoreInstance.root) {\n        hudInfoStoreInstance.refresh(options.root);\n    }\n    return hudInfoStoreInstance;\n}\n","/**\n * Sun Position Calculator\n *\n * Calculates astronomical sun position based on date, time, and Earth's axial tilt.\n * Formulas based on NOAA Solar Calculator and suncalc library.\n *\n * References:\n * - https://github.com/mourner/suncalc\n * - https://gml.noaa.gov/grad/solcalc/\n */\n\nimport * as THREE from 'three';\nimport { Equator, Horizon, Observer } from 'astronomy-engine';\nimport { EARTH_PRIME_MERIDIAN_OFFSET_RAD } from './constants.js';\n\n// Constants\nconst RAD = Math.PI / 180;\nconst DEG = 180 / Math.PI;\nconst EARTH_OBLIQUITY = 23.4397 * RAD; // Earth's axial tilt in radians\nconst J1970 = 2440588;\nconst J2000 = 2451545;\n\n/**\n * Convert date to Julian day number\n */\nfunction toJulian(date) {\n  return date.valueOf() / 86400000 - 0.5 + J1970;\n}\n\n/**\n * Convert Julian day to number of days since J2000\n */\nfunction toDays(date) {\n  return toJulian(date) - J2000;\n}\n\n/**\n * Calculate solar mean anomaly\n */\nfunction solarMeanAnomaly(days) {\n  return (357.5291 + 0.98560028 * days) * RAD;\n}\n\n/**\n * Calculate equation of center\n */\nfunction equationOfCenter(M) {\n  return (1.9148 * Math.sin(M) +\n          0.0200 * Math.sin(2 * M) +\n          0.0003 * Math.sin(3 * M)) * RAD;\n}\n\n/**\n * Calculate ecliptic longitude\n */\nfunction eclipticLongitude(M) {\n  const C = equationOfCenter(M);\n  const P = (102.9372) * RAD; // perihelion\n  return M + C + P + Math.PI;\n}\n\n/**\n * Calculate solar declination (sun's angle relative to Earth's equator)\n * This accounts for Earth's 23.44° axial tilt\n */\nfunction solarDeclination(days) {\n  const L = eclipticLongitude(solarMeanAnomaly(days));\n  return Math.asin(Math.sin(L) * Math.sin(EARTH_OBLIQUITY));\n}\n\n/**\n * Calculate right ascension\n */\nfunction rightAscension(days) {\n  const L = eclipticLongitude(solarMeanAnomaly(days));\n  return Math.atan2(\n    Math.sin(L) * Math.cos(EARTH_OBLIQUITY),\n    Math.cos(L)\n  );\n}\n\n/**\n * Calculate sidereal time (rotation of Earth)\n */\nfunction siderealTime(days, lng) {\n  return (280.16 + 360.9856235 * days) * RAD - lng;\n}\n\n/**\n * Calculate sun position (altitude and azimuth)\n *\n * @param {Date} date - The date/time for calculation\n * @param {number} lat - Latitude in degrees (-90 to 90)\n * @param {number} lng - Longitude in degrees (-180 to 180)\n * @returns {Object} { altitude, azimuth, declination } in radians\n */\nexport function calculateSunPosition(date, lat = 0, lng = 0) {\n  // HUD/local ENU adapter: same apparent astronomy model as the scene bodies.\n  // No refraction is added to geometric scene coordinates. Compass azimuth\n  // is clockwise from north (the old approximation accidentally used south).\n  const observer = new Observer(lat, lng, 0);\n  const equator = Equator('Sun', date, observer, true, true);\n  const horizon = Horizon(date, observer, equator.ra, equator.dec);\n  return {\n    altitude: horizon.altitude * RAD,\n    azimuth: horizon.azimuth * RAD,\n    declination: equator.dec * RAD,\n  };\n}\n\n/**\n * Get sun direction as a THREE.Vector3\n * This returns a normalized direction vector pointing FROM the Earth TO the Sun\n *\n * @param {Date} date - The date/time for calculation\n * @param {number} lat - Latitude in degrees (default 0 = equator)\n * @param {number} lng - Longitude in degrees (default 0 = prime meridian)\n * @returns {THREE.Vector3} Normalized direction vector\n */\nexport function getSunDirectionVector(date, lat = 0, lng = 0) {\n  const pos = calculateSunPosition(date, lat, lng);\n\n  // Convert spherical coordinates (altitude, azimuth) to Cartesian\n  // Azimuth: 0 = North, π/2 = East, π = South, -π/2 = West\n  // Altitude: 0 = horizon, π/2 = zenith, -π/2 = nadir\n\n  const x = Math.cos(pos.altitude) * Math.sin(pos.azimuth);\n  const y = Math.sin(pos.altitude);\n  const z = Math.cos(pos.altitude) * Math.cos(pos.azimuth);\n\n  // This is the direction from Earth to Sun\n  return new THREE.Vector3(x, y, z).normalize();\n}\n\n/**\n * Get geocentric sun direction (Earth-centered inertial, projected to Earth-fixed frame)\n * This is independent of observer location and suitable for global lighting.\n * Returns a normalized direction vector pointing FROM the Earth TO the Sun.\n *\n * @param {Date} date\n * @returns {THREE.Vector3}\n */\nexport function getSunDirectionGeocentric(date) {\n  const days = toDays(date);\n  const dec = solarDeclination(days);\n  const ra = rightAscension(days);\n  // Greenwich hour angle: H = GMST - RA\n  const gmst = siderealTime(days, 0);\n  const H = gmst - ra;\n  // Subsolar longitude λ = -H, latitude = declination\n  const lon = -H;\n  const lat = dec;\n  const x = Math.cos(lat) * Math.sin(lon);\n  const y = Math.sin(lat);\n  const z = Math.cos(lat) * Math.cos(lon);\n  return new THREE.Vector3(x, y, z).normalize();\n}\n\n/**\n * Get simplified sun direction based on time of day only (no geo coordinates)\n * Useful for visualization and simplified day/night cycles\n *\n * This calculates the sun direction as if viewing from longitude 0° (Prime Meridian)\n * at the equator, with proper seasonal declination.\n *\n * @param {Date} date - The date/time\n * @returns {THREE.Vector3} Normalized direction vector\n */\nexport function getSimplifiedSunDirection(date) {\n  const days = toDays(date);\n  const dec = solarDeclination(days);\n\n  // Calculate hour angle based on UTC time\n  // At UTC noon (12:00), sun should be at longitude 0° (Prime Meridian)\n  const hours = date.getUTCHours() + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600;\n  // Hour angle: 0 at 12:00 UTC, positive to the east (sunrise in +X)\n  const hourAngle = ((12 - hours) / 24) * Math.PI * 2; // -π..π range over the day\n\n  // Create direction with declination (seasonal tilt) and hour angle (daily rotation)\n  const x = Math.cos(dec) * Math.sin(hourAngle);\n  const y = Math.sin(dec);\n  const z = Math.cos(dec) * Math.cos(hourAngle);\n\n  return new THREE.Vector3(x, y, z).normalize();\n}\n\n/**\n * Get sun direction in ecliptic frame (no declination, for tilted Earth group)\n * Returns direction from Earth to Sun in the orbital plane (ecliptic).\n * Use this when your Earth model has axial tilt applied as a group rotation.\n *\n * This uses ONLY Earth's orbital position (seasonal), not daily rotation.\n * Daily rotation should be applied by rotating the Earth group.\n *\n * @param {Date} date - The date/time\n * @returns {THREE.Vector3} Normalized direction vector in ecliptic plane (y≈0)\n */\nexport function getSunDirectionEcliptic(date) {\n  const days = toDays(date);\n  const L = eclipticLongitude(solarMeanAnomaly(days));\n\n  // Sun direction in ecliptic plane (y=0, no declination)\n  const x = Math.sin(L);\n  const y = 0; // Ecliptic plane, no tilt\n  const z = Math.cos(L);\n\n  return new THREE.Vector3(x, y, z).normalize();\n}\n\n/**\n * Calculate Earth's rotation angle for the current time (DEPRECATED - use getEarthRotationAngleUTC)\n * Returns the rotation needed to align Earth's texture with real-time orientation\n *\n * @param {Date} date - Current date/time\n * @returns {number} Rotation angle in radians (around Y axis)\n * @deprecated Use getEarthRotationAngleUTC instead\n */\nexport function getEarthRotationAngle(date) {\n  return getEarthRotationAngleUTC(date);\n}\n\n/**\n * Calculate Earth's rotation angle based on UTC time (GMST approximation)\n * This is the proper way to rotate Earth without circular dependency on sun direction.\n *\n * Assumes:\n * - Texture prime meridian is at +Z when rotation.y = 0\n * - At UTC noon (12:00), Prime Meridian should face +Z\n * - Earth rotates counter-clockwise (eastward) when viewed from north pole\n *\n * @param {Date} date - Current date/time\n * @returns {number} Rotation angle in radians (around Y axis)\n */\nexport function getEarthRotationAngleUTC(date) {\n  const days = toDays(date);\n  const gmst = siderealTime(days, 0);\n  const twoPi = Math.PI * 2;\n  let angle = gmst + EARTH_PRIME_MERIDIAN_OFFSET_RAD;\n  angle = ((angle % twoPi) + twoPi) % twoPi;\n  return angle;\n}\n\n/**\n * Get day of year (1-365/366)\n */\nexport function getDayOfYear(date) {\n  const start = new Date(date.getFullYear(), 0, 0);\n  const diff = date - start;\n  const oneDay = 1000 * 60 * 60 * 24;\n  return Math.floor(diff / oneDay);\n}\n\n/**\n * Calculate solar noon (when sun is highest in sky) for a location\n */\nexport function getSolarNoon(date, lng = 0) {\n  const days = toDays(date);\n  const lngRad = -lng * RAD;\n  const ra = rightAscension(days);\n  const lmst = siderealTime(days, lngRad);\n\n  // When hour angle H = 0, sun is at solar noon\n  const noonOffset = (ra - lmst) / (2 * Math.PI);\n\n  const noon = new Date(date);\n  noon.setUTCHours(12, 0, 0, 0);\n  noon.setTime(noon.getTime() + noonOffset * 24 * 60 * 60 * 1000);\n\n  return noon;\n}\n","import * as THREE from 'three';\nimport { Rotation_EQJ_EQD, SiderealTime } from 'astronomy-engine';\nimport { AXIAL_TILT_RAD } from './constants.js';\nimport { getEarthRotationAngleUTC } from './sun-calculator.js';\n\n// Planet-local: +X east, +Y north, +Z Greenwich. This is also the terrain,\n// camera and URL frame. Centralize the ORDER, not just the rotation angles.\nexport function setPlanetFrameEuler(result, angle = 0) {\n  return result.set(0, angle, -AXIAL_TILT_RAD, 'ZYX');\n}\n\nexport class CelestialFrame {\n  constructor() {\n    this.euler = new THREE.Euler();\n    this.earthFixedToWorld = new THREE.Matrix4();\n    this.eqjToEarthFixed = new THREE.Matrix4();\n    this.eqjToWorld = new THREE.Matrix4();\n    this._precession = new THREE.Matrix4();\n    this.timeMs = NaN;\n  }\n\n  update(date) {\n    const timeMs = date.getTime();\n    if (!Number.isFinite(timeMs) || timeMs === this.timeMs) return this;\n    setPlanetFrameEuler(this.euler, getEarthRotationAngleUTC(date));\n    this.earthFixedToWorld.makeRotationFromEuler(this.euler);\n    // Astronomy Engine rotation arrays are column-major (rot[input][output]).\n    const r = Rotation_EQJ_EQD(date).rot;\n    this._precession.set(\n      r[0][0], r[1][0], r[2][0], 0,\n      r[0][1], r[1][1], r[2][1], 0,\n      r[0][2], r[1][2], r[2][2], 0,\n      0, 0, 0, 1,\n    );\n    const theta = SiderealTime(date) * Math.PI / 12;\n    const c = Math.cos(theta), s = Math.sin(theta);\n    this.eqjToEarthFixed.set(-s, c, 0, 0, 0, 0, 1, 0, c, s, 0, 0, 0, 0, 0, 1)\n      .multiply(this._precession);\n    this.eqjToWorld.multiplyMatrices(this.earthFixedToWorld, this.eqjToEarthFixed);\n    this.timeMs = timeMs;\n    return this;\n  }\n}\n\n/** Astronomy Engine EQJ axes: +X RA 0, +Y RA 6h, +Z celestial north. */\nexport function equatorialDirection(raDegrees, decDegrees, result = new THREE.Vector3()) {\n  const ra = raDegrees * Math.PI / 180, dec = decDegrees * Math.PI / 180;\n  return result.set(Math.cos(dec) * Math.cos(ra), Math.cos(dec) * Math.sin(ra), Math.sin(dec));\n}\n\n/** NASA SVS 4851 J2000 plate-carree: RA=0 at centre, RA increases left. */\nexport function celestialTextureUv(raDegrees, decDegrees, result = new THREE.Vector2()) {\n  return result.set(((0.5 - raDegrees / 360) % 1 + 1) % 1, 0.5 + decDegrees / 180);\n}\n\nexport function properMotionVector(raDegrees, decDegrees, muRa, muDec, result = new THREE.Vector3()) {\n  const ra = raDegrees * Math.PI / 180, dec = decDegrees * Math.PI / 180;\n  const scale = Math.PI / (180 * 3600);\n  return result.set(-muRa*Math.sin(ra) - muDec*Math.sin(dec)*Math.cos(ra),\n    muRa*Math.cos(ra) - muDec*Math.sin(dec)*Math.sin(ra), muDec*Math.cos(dec)).multiplyScalar(scale);\n}\n\nexport const julianYearsSinceJ2000 = ms => (ms - 946728000000) / 31557600000;\n","/**\n * frameClock — per-frame timing publisher for the AsyncHarness.\n *\n * Single source of truth for \"what frame are we on\" and \"how much budget did the\n * last frame burn\". Consumers (HoverDispatcher, BudgetScheduler, dev-mode debug\n * panels) subscribe to frame events and read frameClock.state synchronously.\n *\n * Ticked from animation-loop.js in two places:\n *   - beforeRender(now, dt)  — after camera update, before renderer.render()\n *                              (consumers like HoverDispatcher need fresh camera)\n *   - afterRender(now, dt)   — after render + budget governor tick\n *                              (frame cost is now known and published)\n *\n * This module has no dependencies and is safe to import anywhere.\n */\n\nconst _beforeRenderSubs = new Set();\nconst _afterRenderSubs = new Set();\n\nconst _state = {\n  frameIndex: 0,\n  now: 0,\n  dt: 0,\n  lastFrameBudgetMs: 0,\n  lastRenderAt: 0,\n};\n\n/**\n * Subscribe to before-render tick. Fired after camera update but before\n * renderer.render(). Use this for anything that needs fresh camera state\n * (hover raycasts, label layout against current view).\n *\n * @param {(state: typeof _state) => void} cb\n * @returns {() => void} unsubscribe\n */\nexport function onBeforeRender(cb) {\n  if (typeof cb !== 'function') return () => {};\n  _beforeRenderSubs.add(cb);\n  return () => _beforeRenderSubs.delete(cb);\n}\n\n/**\n * Subscribe to after-render tick. Fired after renderer.render() and\n * budget governor. Use this for metrics, telemetry, deferred cleanup.\n *\n * @param {(state: typeof _state) => void} cb\n * @returns {() => void} unsubscribe\n */\nexport function onAfterRender(cb) {\n  if (typeof cb !== 'function') return () => {};\n  _afterRenderSubs.add(cb);\n  return () => _afterRenderSubs.delete(cb);\n}\n\n/**\n * Ticked by animation-loop.js BEFORE renderer.render().\n * Do not call from user code.\n *\n * @param {number} now   performance.now() of current frame\n * @param {number} dt    delta seconds\n */\nexport function tickBeforeRender(now, dt) {\n  _state.frameIndex = (_state.frameIndex + 1) | 0;\n  _state.now = now;\n  _state.dt = dt;\n  for (const cb of _beforeRenderSubs) {\n    try {\n      cb(_state);\n    } catch (e) {\n      if (typeof console !== 'undefined') {\n        console.warn('[frameClock] beforeRender subscriber threw', e);\n      }\n    }\n  }\n}\n\n/**\n * Ticked by animation-loop.js AFTER renderer.render() and budget governor.\n * Do not call from user code.\n *\n * @param {number} now             performance.now() at frame end\n * @param {number} frameBudgetMs   total ms spent in the frame (including render)\n */\nexport function tickAfterRender(now, frameBudgetMs) {\n  _state.lastFrameBudgetMs = Number.isFinite(frameBudgetMs) ? frameBudgetMs : 0;\n  _state.lastRenderAt = now;\n  for (const cb of _afterRenderSubs) {\n    try {\n      cb(_state);\n    } catch (e) {\n      if (typeof console !== 'undefined') {\n        console.warn('[frameClock] afterRender subscriber threw', e);\n      }\n    }\n  }\n}\n\n/**\n * Read-only snapshot of current frame state. Safe to call from anywhere.\n *\n * @returns {Readonly<{frameIndex:number, now:number, dt:number, lastFrameBudgetMs:number, lastRenderAt:number}>}\n */\nexport function getFrameState() {\n  return _state;\n}\n\n/**\n * Dev-mode stats for window.__noclipAsync.debug().\n */\nexport function getFrameClockStats() {\n  return {\n    frameIndex: _state.frameIndex,\n    now: _state.now,\n    dt: _state.dt,\n    lastFrameBudgetMs: _state.lastFrameBudgetMs,\n    subscribers: {\n      beforeRender: _beforeRenderSubs.size,\n      afterRender: _afterRenderSubs.size,\n    },\n  };\n}\n","/**\n * BudgetScheduler — frame-aware scheduling primitives for the AsyncHarness.\n *\n * Provides four main tools for keeping CPU work off the render-critical path:\n *\n *   1. rafCoalesce(key, fn)\n *        Merge rapid events (mousemove, resize) into a single call at next frame.\n *        Dispatches INSIDE animation-loop's frame (via frameClock.onBeforeRender)\n *        so consumers see fresh camera state. Repeated calls with the same key\n *        overwrite the pending callback — the latest one wins.\n *\n *   2. runChunked(iterable, processFn, {budgetMs, signal})\n *        Consume an iterable across multiple frames, yielding when a per-frame\n *        budget is exceeded. Used for bulk mesh creation, label layout, etc.\n *\n *   3. yieldIfOverBudget(frameStartMs, budgetMs)\n *        Inline helper for existing sync loops. Awaits a macrotask yield if the\n *        current batch has burned past its budget.\n *\n *   4. deferUntilIdle(fn, timeoutMs)\n *        Run work when the browser is idle. Prefers requestIdleCallback,\n *        falls back to setTimeout(fn, 0) with a deadline approximation.\n *\n * All methods are safe to call before animation-loop starts ticking — pending\n * rafCoalesce callbacks drain on the first frame.\n */\n\nimport { onBeforeRender } from '../frameClock.js';\n\n// ── rafCoalesce ──────────────────────────────────────────────────────────\n// Keyed map of pending callbacks. On each beforeRender tick, all pending\n// callbacks drain in insertion order. The frameClock subscription is lazy —\n// we only subscribe once the first call is made.\nconst _pending = new Map();\nlet _subscribed = false;\n\nfunction _ensureSubscribed() {\n  if (_subscribed) return;\n  _subscribed = true;\n  onBeforeRender(() => {\n    if (_pending.size === 0) return;\n    // Snapshot so handlers that re-enqueue don't re-drain this frame.\n    const drain = Array.from(_pending.entries());\n    _pending.clear();\n    for (const [, fn] of drain) {\n      try {\n        fn();\n      } catch (e) {\n        if (typeof console !== 'undefined') {\n          console.warn('[BudgetScheduler] rafCoalesce handler threw', e);\n        }\n      }\n    }\n  });\n}\n\n/**\n * Coalesce rapid events to at-most-once per frame, dispatched inside the\n * animation-loop's frame phase (after camera update, before render).\n *\n * @param {string}   key  stable identifier — repeated calls overwrite\n * @param {Function} fn   callback to invoke at the next frame tick\n */\nexport function rafCoalesce(key, fn) {\n  if (!key || typeof fn !== 'function') return;\n  _ensureSubscribed();\n  _pending.set(key, fn);\n}\n\n/**\n * Cancel a pending rafCoalesce callback by key. No-op if nothing pending.\n * @param {string} key\n */\nexport function cancelRafCoalesce(key) {\n  if (!key) return;\n  _pending.delete(key);\n}\n\n// ── yield helpers ────────────────────────────────────────────────────────\nconst _schedulerPostTask = (typeof globalThis !== 'undefined'\n  && typeof globalThis.scheduler === 'object'\n  && globalThis.scheduler\n  && typeof globalThis.scheduler.postTask === 'function')\n  ? (fn, priority) => globalThis.scheduler.postTask(fn, { priority })\n  : null;\n\n/**\n * Yield control to the event loop. Prefers scheduler.postTask, falls back to\n * setTimeout(0). Returns a promise that resolves on the next microtask/macrotask.\n * @param {'user-blocking'|'user-visible'|'background'} [priority]\n * @returns {Promise<void>}\n */\nexport function yieldToEventLoop(priority = 'user-visible') {\n  return new Promise((resolve) => {\n    if (_schedulerPostTask) {\n      _schedulerPostTask(resolve, priority);\n    } else {\n      setTimeout(resolve, 0);\n    }\n  });\n}\n\n/**\n * If the current batch has burned past budget, yield. Intended for inline\n * use inside existing sync loops being migrated to chunked execution:\n *\n *   const start = performance.now();\n *   for (const item of items) {\n *     process(item);\n *     if (await yieldIfOverBudget(start, 4)) start = performance.now();\n *   }\n *\n * @param {number} frameStartMs\n * @param {number} budgetMs\n * @returns {Promise<boolean>} true if we yielded\n */\nexport async function yieldIfOverBudget(frameStartMs, budgetMs) {\n  const elapsed = performance.now() - frameStartMs;\n  if (elapsed < budgetMs) return false;\n  await yieldToEventLoop();\n  return true;\n}\n\n/**\n * Chunk a heavy iterable across frames. Calls processFn(item) for each entry,\n * yielding when the per-chunk budget is exceeded. Returns a promise that\n * resolves when the iteration completes (or rejects if signal aborts).\n *\n * @template T\n * @param {Iterable<T>|T[]} iterable\n * @param {(item: T, index: number) => void|Promise<void>} processFn\n * @param {{ budgetMs?: number, signal?: AbortSignal }} [opts]\n */\nexport async function runChunked(iterable, processFn, opts = {}) {\n  const budgetMs = Number.isFinite(opts.budgetMs) ? opts.budgetMs : 4;\n  const signal = opts.signal || null;\n  let index = 0;\n  let chunkStart = performance.now();\n  for (const item of iterable) {\n    if (signal?.aborted) {\n      throw new DOMException('runChunked aborted', 'AbortError');\n    }\n    await processFn(item, index++);\n    if ((performance.now() - chunkStart) >= budgetMs) {\n      await yieldToEventLoop();\n      chunkStart = performance.now();\n    }\n  }\n}\n\n// ── idle deferral ────────────────────────────────────────────────────────\nconst _requestIdle = (typeof globalThis !== 'undefined'\n  && typeof globalThis.requestIdleCallback === 'function')\n  ? globalThis.requestIdleCallback.bind(globalThis)\n  : null;\n\n/**\n * Run fn during browser idle time. Prefers requestIdleCallback with a\n * fallback to setTimeout. Useful for warming workers, prefetching, metrics.\n *\n * @param {Function} fn\n * @param {number} [timeoutMs]  max wait before forcing execution\n * @returns {() => void}        cancel token\n */\nexport function deferUntilIdle(fn, timeoutMs = 2000) {\n  if (typeof fn !== 'function') return () => {};\n  if (_requestIdle) {\n    const handle = _requestIdle(() => {\n      try { fn(); } catch (e) { console.warn('[BudgetScheduler] idle fn threw', e); }\n    }, { timeout: timeoutMs });\n    return () => {\n      if (typeof globalThis.cancelIdleCallback === 'function') {\n        globalThis.cancelIdleCallback(handle);\n      }\n    };\n  }\n  const timer = setTimeout(() => {\n    try { fn(); } catch (e) { console.warn('[BudgetScheduler] idle fn threw', e); }\n  }, Math.min(timeoutMs, 100));\n  return () => clearTimeout(timer);\n}\n\n/**\n * Await the next rAF. Returns the DOMHighResTimeStamp of that frame.\n * Falls back to setTimeout(16) in non-browser environments.\n *\n * @returns {Promise<number>}\n */\nexport function nextFrame() {\n  if (typeof requestAnimationFrame === 'function') {\n    return new Promise((resolve) => requestAnimationFrame(resolve));\n  }\n  return new Promise((resolve) => setTimeout(() => resolve(performance.now()), 16));\n}\n\n// ── dev-mode stats ───────────────────────────────────────────────────────\nexport function getBudgetSchedulerStats() {\n  return {\n    pendingCoalesced: _pending.size,\n    pendingKeys: Array.from(_pending.keys()),\n    schedulerPostTaskAvailable: !!_schedulerPostTask,\n    requestIdleCallbackAvailable: !!_requestIdle,\n    subscribed: _subscribed,\n  };\n}\n","import * as THREE from 'three';\n\nexport const CANONICAL_EDGES = ['v0v1', 'v1v2', 'v2v0'];\nexport const EDGE_INDEX_REVERSED = Object.freeze({\n    v0v1: true,\n    v1v2: true,\n    v2v0: false\n});\n\nconst PARENT_EDGE_TO_CHILD = Object.freeze({\n    v0v1: {\n        start: { slot: 1, edge: 'v0v1' },\n        end: { slot: 2, edge: 'v2v0' }\n    },\n    v1v2: {\n        start: { slot: 2, edge: 'v0v1' },\n        end: { slot: 3, edge: 'v2v0' }\n    },\n    v2v0: {\n        start: { slot: 3, edge: 'v0v1' },\n        end: { slot: 1, edge: 'v2v0' }\n    }\n});\n\nconst CHILD_EDGE_TO_PARENT = Object.freeze({\n    1: {\n        v0v1: { parentEdge: 'v0v1', half: 'start' },\n        v2v0: { parentEdge: 'v2v0', half: 'end' }\n    },\n    2: {\n        v0v1: { parentEdge: 'v1v2', half: 'start' },\n        v2v0: { parentEdge: 'v0v1', half: 'end' }\n    },\n    3: {\n        v0v1: { parentEdge: 'v2v0', half: 'start' },\n        v2v0: { parentEdge: 'v1v2', half: 'end' }\n    }\n});\n\nconst INTERNAL_SIBLING = Object.freeze({\n    0: {\n        v0v1: { slot: 2, edge: 'v1v2', reverse: true },\n        v1v2: { slot: 3, edge: 'v1v2', reverse: true },\n        v2v0: { slot: 1, edge: 'v1v2', reverse: true }\n    },\n    1: {\n        v1v2: { slot: 0, edge: 'v2v0', reverse: true }\n    },\n    2: {\n        v1v2: { slot: 0, edge: 'v0v1', reverse: true }\n    },\n    3: {\n        v1v2: { slot: 0, edge: 'v1v2', reverse: true }\n    }\n});\n\nconst EDGE_NAME_ALIASES = Object.freeze({\n    v2v1: 'v1v2'\n});\n\nconst clamp01 = (value) => Math.min(1, Math.max(0, value));\n\nconst splitRange = (t0, t1, half) => {\n    const mid = (t0 + t1) * 0.5;\n    if (half === 'start') return { t0, t1: mid };\n    if (half === 'end') return { t0: mid, t1 };\n    return { t0, t1 };\n};\n\nconst formatRootIndex = (index) => String(index).padStart(2, '0');\n\nexport const normalizeEdgeName = (edgeName) => {\n    if (!edgeName) return null;\n    return EDGE_NAME_ALIASES[edgeName] || edgeName;\n};\n\nexport const toTileEdgeName = (edgeName) => {\n    if (!edgeName) return null;\n    return edgeName === 'v1v2' ? 'v2v1' : edgeName;\n};\n\nexport const getEdgeIndexReversed = (edgeName) => {\n    const canonical = normalizeEdgeName(edgeName);\n    return !!EDGE_INDEX_REVERSED[canonical];\n};\n\nexport const getParentEdgeForChildEdge = (childSlot, edgeName) => {\n    const canonical = normalizeEdgeName(edgeName);\n    if (canonical === null || canonical === undefined) return null;\n    const mapping = CHILD_EDGE_TO_PARENT[childSlot]?.[canonical];\n    return mapping ? mapping.parentEdge : null;\n};\n\nexport const getEdgeEndpoints = (tile, edgeName) => {\n    const canonical = normalizeEdgeName(edgeName);\n    if (!tile || !canonical) return null;\n    if (canonical === 'v0v1') return { v0: tile.v0, v1: tile.v1 };\n    if (canonical === 'v1v2') return { v0: tile.v1, v1: tile.v2 };\n    if (canonical === 'v2v0') return { v0: tile.v2, v1: tile.v0 };\n    return null;\n};\n\nexport const getChildSlot = (tile) => {\n    if (!tile || !tile.parent) return null;\n    return tile.index - tile.parent.index * 4;\n};\n\nexport const getChildPath = (tile) => {\n    const path = [];\n    let current = tile;\n    while (current && current.parent) {\n        const slot = getChildSlot(current);\n        if (slot === null || slot < 0 || slot > 3) break;\n        path.unshift(slot);\n        current = current.parent;\n    }\n    return path;\n};\n\nexport const getRootIndex = (tile) => {\n    let current = tile;\n    while (current && current.parent) {\n        current = current.parent;\n    }\n    return current ? current.index : null;\n};\n\nexport const formatTileKey = (rootIndex, path) => {\n    const level = Array.isArray(path) ? path.length : 0;\n    const pathStr = Array.isArray(path) ? path.join('') : '';\n    return `R${formatRootIndex(rootIndex)}-L${level}-${pathStr}`;\n};\n\nconst edgeReverseFlag = (a0, a1, b0, b1) => {\n    const costAligned = a0.distanceTo(b0) + a1.distanceTo(b1);\n    const costReverse = a0.distanceTo(b1) + a1.distanceTo(b0);\n    return costReverse < costAligned;\n};\n\nconst pointOnArc = (p, v0, v1, tolerance) => {\n    const pN = p.clone().normalize();\n    const v0N = v0.clone().normalize();\n    const v1N = v1.clone().normalize();\n\n    const normal = new THREE.Vector3().crossVectors(v0N, v1N);\n    if (normal.lengthSq() < tolerance * tolerance) {\n        return pN.distanceTo(v0N) < tolerance || pN.distanceTo(v1N) < tolerance;\n    }\n    normal.normalize();\n\n    const distToPlane = Math.abs(normal.dot(pN));\n    if (distToPlane > tolerance) return false;\n\n    if (pN.distanceTo(v0N) < tolerance || pN.distanceTo(v1N) < tolerance) {\n        return true;\n    }\n\n    const angle_v0_v1 = Math.acos(Math.max(-1, Math.min(1, v0N.dot(v1N))));\n    const angle_v0_p = Math.acos(Math.max(-1, Math.min(1, v0N.dot(pN))));\n    const angle_p_v1 = Math.acos(Math.max(-1, Math.min(1, pN.dot(v1N))));\n\n    const angleDiff = Math.abs((angle_v0_p + angle_p_v1) - angle_v0_v1);\n    return angleDiff < tolerance;\n};\n\nexport const defaultEdgesOverlap = (v0A, v1A, v0B, v1B) => {\n    const tolerance = 1e-4;\n    const normalA = new THREE.Vector3().crossVectors(v0A, v1A).normalize();\n    const normalB = new THREE.Vector3().crossVectors(v0B, v1B).normalize();\n    const dotNormals = Math.abs(normalA.dot(normalB));\n    if (dotNormals < 1 - tolerance) return false;\n\n    const v0B_on_A = pointOnArc(v0B, v0A, v1A, tolerance);\n    const v1B_on_A = pointOnArc(v1B, v0A, v1A, tolerance);\n    const v0A_on_B = pointOnArc(v0A, v0B, v1B, tolerance);\n    const v1A_on_B = pointOnArc(v1A, v0B, v1B, tolerance);\n\n    const bPointsOnA = (v0B_on_A ? 1 : 0) + (v1B_on_A ? 1 : 0);\n    const aPointsOnB = (v0A_on_B ? 1 : 0) + (v1A_on_B ? 1 : 0);\n\n    if (bPointsOnA === 2 || aPointsOnB === 2) return true;\n    if ((bPointsOnA === 2 && aPointsOnB >= 1) || (aPointsOnB === 2 && bPointsOnA >= 1)) {\n        return true;\n    }\n    return false;\n};\n\nexport class EdgeStitchTopology {\n    constructor(options = {}) {\n        this._edgesOverlap = typeof options.edgesOverlap === 'function'\n            ? options.edgesOverlap\n            : defaultEdgesOverlap;\n        this._rootEdgeMap = new Map();\n    }\n\n    buildRootAdjacency(rootTiles) {\n        if (!Array.isArray(rootTiles) || rootTiles.length === 0) {\n            this._rootEdgeMap.clear();\n            return this._rootEdgeMap;\n        }\n\n        this._rootEdgeMap.clear();\n        const tiles = rootTiles.filter(tile => tile && tile.level === 0);\n        for (const tile of tiles) {\n            this._rootEdgeMap.set(tile.index, {});\n        }\n\n        for (const tileA of tiles) {\n            for (const edgeNameA of CANONICAL_EDGES) {\n                const entry = this._rootEdgeMap.get(tileA.index);\n                if (entry && entry[edgeNameA]) continue;\n\n                const edgeA = getEdgeEndpoints(tileA, edgeNameA);\n                if (!edgeA) continue;\n                let found = false;\n\n                for (const tileB of tiles) {\n                    if (tileA === tileB) continue;\n                    for (const edgeNameB of CANONICAL_EDGES) {\n                        const edgeB = getEdgeEndpoints(tileB, edgeNameB);\n                        if (!edgeB) continue;\n                        if (!this._edgesOverlap(edgeA.v0, edgeA.v1, edgeB.v0, edgeB.v1)) continue;\n\n                        const reverse = edgeReverseFlag(edgeA.v0, edgeA.v1, edgeB.v0, edgeB.v1);\n\n                        const mapA = this._rootEdgeMap.get(tileA.index);\n                        const mapB = this._rootEdgeMap.get(tileB.index);\n                        if (mapA && !mapA[edgeNameA]) {\n                            mapA[edgeNameA] = {\n                                rootIndex: tileB.index,\n                                edgeName: edgeNameB,\n                                reverse\n                            };\n                        }\n                        if (mapB && !mapB[edgeNameB]) {\n                            mapB[edgeNameB] = {\n                                rootIndex: tileA.index,\n                                edgeName: edgeNameA,\n                                reverse\n                            };\n                        }\n                        found = true;\n                        break;\n                    }\n                    if (found) break;\n                }\n            }\n        }\n\n        return this._rootEdgeMap;\n    }\n\n    getRootEdgeMap() {\n        return this._rootEdgeMap;\n    }\n\n    resolveNeighborDescriptor(tile, edgeName) {\n        if (!tile) return null;\n        const canonicalEdge = normalizeEdgeName(edgeName);\n        if (!canonicalEdge) return null;\n\n        const path = getChildPath(tile);\n        const rootIndex = getRootIndex(tile);\n        let currentEdge = canonicalEdge;\n        let t0 = 0;\n        let t1 = 1;\n        let flip = false;\n        const halfPath = [];\n\n        let cursor = tile;\n        while (cursor && cursor.parent) {\n            const slot = getChildSlot(cursor);\n            if (slot === null) break;\n\n            const internal = INTERNAL_SIBLING[slot]?.[currentEdge];\n            if (internal) {\n                const neighborPath = path.slice();\n                neighborPath[neighborPath.length - 1] = internal.slot;\n                flip = flip ^ internal.reverse;\n                return this._buildDescriptor(rootIndex, neighborPath, internal.edge, { t0, t1 }, flip, 'sibling');\n            }\n\n            const external = CHILD_EDGE_TO_PARENT[slot]?.[currentEdge];\n            if (!external) return null;\n\n            const range = splitRange(t0, t1, external.half);\n            t0 = range.t0;\n            t1 = range.t1;\n            halfPath.unshift(external.half);\n\n            currentEdge = external.parentEdge;\n            cursor = cursor.parent;\n        }\n\n        if (!cursor) return null;\n        const rootMap = this._rootEdgeMap.get(rootIndex);\n        const rootNeighbor = rootMap ? rootMap[currentEdge] : null;\n        if (!rootNeighbor) return null;\n\n        flip = flip ^ rootNeighbor.reverse;\n\n        let neighborEdge = rootNeighbor.edgeName;\n        const neighborPath = [];\n        let descendEdge = neighborEdge;\n\n        for (const half of halfPath) {\n            const effectiveHalf = flip ? (half === 'start' ? 'end' : 'start') : half;\n            const childInfo = PARENT_EDGE_TO_CHILD[descendEdge]?.[effectiveHalf];\n            if (!childInfo) return null;\n            neighborPath.push(childInfo.slot);\n            descendEdge = childInfo.edge;\n        }\n\n        neighborEdge = descendEdge;\n        return this._buildDescriptor(rootNeighbor.rootIndex, neighborPath, neighborEdge, { t0, t1 }, flip, 'root');\n    }\n\n    _buildDescriptor(rootIndex, path, edgeName, originRange, flip, reason) {\n        const t0 = clamp01(originRange.t0);\n        const t1 = clamp01(originRange.t1);\n        const neighborRange = flip\n            ? { t0: 1 - t1, t1: 1 - t0 }\n            : { t0, t1 };\n        const indexReversed = getEdgeIndexReversed(edgeName);\n        return {\n            rootIndex,\n            path,\n            edgeName,\n            originRange: { t0, t1 },\n            neighborRange,\n            reverseForIndices: indexReversed,\n            flip,\n            reason,\n            key: formatTileKey(rootIndex, path)\n        };\n    }\n}\n","/**\n * Triangular tile for spherical tritree LOD system\n */\n\nimport * as THREE from 'three';\nimport {\n    PLANET_RADIUS,\n    ELEVATION_EXAGGERATION,\n    EARTH_RADIUS_M,\n    WGS84_SEMI_MAJOR_AXIS,\n    WGS84_SEMI_MINOR_AXIS\n} from './constants.js';\nimport { dirToLatLonLocal, lonLatToTileCoords, updateAttributeInPlace } from './geometry-utils.js';\nimport { getEdgeIndexReversed } from './edge-stitch-topology.js';\n\n// Global set for tiles pending normal recomputation (referenced from index.html)\n// This will be managed by the main application\nlet tilesPendingNormalsRef = null;\nconst imageryAvgSampler = { canvas: null, ctx: null };\nconst TWO_PI = Math.PI * 2;\nconst WIREFRAME_EVEREST_M = 8848;\nconst WIREFRAME_MIN_DEPTH_M = -11000;\nconst WIREFRAME_BELOW_MIN_OPACITY = 0.1;\nconst WIREFRAME_LINE_OPACITY = 0.04;\nconst wireframeMaterials = { fill: null, line: null };\nconst wireframeStyleState = {\n    // Match the photoreal-tile wireframe palette: satin-black fill,\n    // white wires. The terrain plates read as a translucent matte-\n    // black surface with the triangulation drawn over top in 50%-white.\n    fillMinColor: new THREE.Color(0x070707),\n    fillMaxColor: new THREE.Color(0x1a1a1a),\n    lineColor: new THREE.Color(0xffffff),\n    lineOverlayEnabled: false, // Default disabled for performance\n    fillMode: 0, // 0 = gradient, 1 = topo, 2 = halftone\n    topoEnabled: false,\n    topoInterval: 500, // meters between major contour bands\n    topoMinorDivisions: 5, // number of minor bands per major interval\n    topoLineWidth: 0.04, // line thickness as fraction of band (very thin)\n    halftoneScale: 0.0007,\n    halftoneStrength: 0.6,\n    halftoneSoftness: 0.08,\n    halftoneAngle: 30\n};\nconst DEBUG_LOGS = false;\n\n// ── Geometry pool: recycle BufferGeometry objects by resolution level ──\n// All TriTree tiles at the same level share identical vertex topology (only\n// positions differ). Reusing geometry avoids allocation churn during rapid\n// zoom in/out, reducing GC pressure.\nconst _geometryPool = new Map(); // resolution → BufferGeometry[]\nconst _GEOMETRY_POOL_MAX_PER_RES = 32;\n\nfunction acquirePooledGeometry(resolution) {\n    const pool = _geometryPool.get(resolution);\n    if (pool && pool.length > 0) {\n        return pool.pop();\n    }\n    return null;\n}\n\nexport function releasePooledGeometry(geom, resolution) {\n    if (!geom || !Number.isFinite(resolution) || resolution < 1) return;\n    let pool = _geometryPool.get(resolution);\n    if (!pool) {\n        pool = [];\n        _geometryPool.set(resolution, pool);\n    }\n    if (pool.length < _GEOMETRY_POOL_MAX_PER_RES) {\n        // Clear dynamic attributes but keep the typed array allocations\n        const posAttr = geom.getAttribute('position');\n        if (posAttr) posAttr.needsUpdate = false;\n        geom.deleteAttribute('uv');\n        geom.deleteAttribute('uv2');\n        geom.deleteAttribute('normal');\n        geom.deleteAttribute('aWaterMask');\n        pool.push(geom);\n    } else {\n        geom.dispose();\n    }\n}\n\n/** Dispose every inactive geometry retained for fast LOD resurrection. */\nexport function clearPooledGeometries() {\n    let disposed = 0;\n    for (const pool of _geometryPool.values()) {\n        for (const geometry of pool) {\n            geometry?.dispose?.();\n            disposed += 1;\n        }\n    }\n    _geometryPool.clear();\n    return disposed;\n}\n\nconst WGS84_A2 = WGS84_SEMI_MAJOR_AXIS * WGS84_SEMI_MAJOR_AXIS;\nconst WGS84_B2 = WGS84_SEMI_MINOR_AXIS * WGS84_SEMI_MINOR_AXIS;\n\nfunction ellipsoidRadiusForDir(x, y, z) {\n    const xx = x * x + z * z;\n    const yy = y * y;\n    const denom = (xx / WGS84_A2) + (yy / WGS84_B2);\n    if (!Number.isFinite(denom) || denom <= 0) return PLANET_RADIUS;\n    return 1 / Math.sqrt(denom);\n}\n\nfunction radiusFromElevation(baseRadius, elevMeters) {\n    const elev = Number.isFinite(elevMeters) ? elevMeters : 0;\n    return baseRadius + (elev * ELEVATION_EXAGGERATION);\n}\n\nfunction elevationFromRadius(radius, baseRadius) {\n    if (!Number.isFinite(radius) || !Number.isFinite(baseRadius)) return 0;\n    return (radius - baseRadius) / Math.max(ELEVATION_EXAGGERATION, 1e-6);\n}\n\nconst wireframeVertexShader = `\n    #include <common>\n    #include <logdepthbuf_pars_vertex>\n\n    uniform float uPlanetRadius;\n    uniform float uEarthRadius;\n    uniform float uExaggeration;\n\n    varying float vElevationMeters;\n    varying vec3 vWorldPos;\n\n    void main() {\n        // Position is in local coordinates (relative to tile center)\n        // Model matrix position contains tile center in world space\n        // Compute world position, then calculate radius\n        vec4 worldPos = modelMatrix * vec4(position, 1.0);\n        float radius = length(worldPos.xyz);\n        float denom = max(uExaggeration, 0.0001);\n        float elev = (radius - uPlanetRadius) * (uEarthRadius / (uPlanetRadius * denom));\n        vElevationMeters = elev;\n        vWorldPos = worldPos.xyz;\n\n        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n        #include <logdepthbuf_vertex>\n    }\n`;\n\nconst wireframeFillFragmentShader = `\n    #include <common>\n    #include <logdepthbuf_pars_fragment>\n\n    uniform float uEverestHeight;\n    uniform vec3 uMinColor;\n    uniform vec3 uMaxColor;\n    uniform float uTopoEnabled;\n    uniform float uTopoInterval;\n    uniform float uTopoMinorDivisions;\n    uniform float uTopoLineWidth;\n    uniform float uFillMode;\n    uniform float uHalftoneScale;\n    uniform float uHalftoneStrength;\n    uniform float uHalftoneSoftness;\n    uniform float uHalftoneAngle;\n\n    varying float vElevationMeters;\n    varying vec3 vWorldPos;\n\n    void main() {\n        #include <logdepthbuf_fragment>\n        float denom = max(uEverestHeight, 1.0);\n\n        vec3 color;\n        float fillMode = uFillMode;\n\n        if (fillMode > 1.5) {\n            float t = clamp(vElevationMeters / denom, 0.0, 1.0);\n            vec3 baseColor = mix(uMinColor, uMaxColor, t);\n\n            float ang = radians(uHalftoneAngle);\n            mat2 rot = mat2(cos(ang), -sin(ang), sin(ang), cos(ang));\n            vec2 grid = rot * (vWorldPos.xz * max(uHalftoneScale, 0.000001));\n            vec2 cell = fract(grid) - 0.5;\n            float dist = length(cell);\n            float radius = mix(0.12, 0.48, t);\n            float dot = 1.0 - smoothstep(radius, radius + max(uHalftoneSoftness, 0.0001), dist);\n            float shade = mix(1.0 - clamp(uHalftoneStrength, 0.0, 1.0), 1.0, dot);\n            color = baseColor * shade;\n        } else if (uTopoEnabled > 0.5 || (fillMode > 0.5 && fillMode < 1.5)) {\n            // Topographic contour mode\n            float elevation = vElevationMeters;\n            float interval = max(uTopoInterval, 1.0);\n            float minorInterval = interval / max(uTopoMinorDivisions, 1.0);\n\n            // Calculate which major and minor band we're in\n            float majorBand = floor(elevation / interval);\n            float minorBand = floor(elevation / minorInterval);\n\n            // Contour line detection - very thin lines at band boundaries\n            float lineWidth = uTopoLineWidth;\n            float majorLineWidth = lineWidth * 1.8; // Major lines slightly thicker\n\n            // Check if we're on a major contour line\n            float distToMajor = abs(fract(elevation / interval));\n            distToMajor = min(distToMajor, 1.0 - distToMajor);\n            float onMajorLine = 1.0 - smoothstep(0.0, majorLineWidth, distToMajor);\n\n            // Check if we're on a minor contour line\n            float distToMinor = abs(fract(elevation / minorInterval));\n            distToMinor = min(distToMinor, 1.0 - distToMinor);\n            float onMinorLine = 1.0 - smoothstep(0.0, lineWidth, distToMinor);\n\n            // Calculate base color from elevation - smooth gradient as base\n            float t = clamp(elevation / denom, 0.0, 1.0);\n\n            // Very subtle band brightness variation (barely noticeable)\n            float bandBrightness = mod(minorBand, 2.0) < 1.0 ? 0.97 : 1.0;\n\n            // Very subtle major band distinction\n            float majorBandEffect = mod(majorBand, 2.0) < 1.0 ? 0.0 : 0.015;\n\n            vec3 baseColor = mix(uMinColor, uMaxColor, t);\n            baseColor *= bandBrightness;\n            baseColor += vec3(majorBandEffect);\n\n            // Subtle contour lines - just slightly brighter than base\n            vec3 lineColor = mix(baseColor, uMaxColor, 0.15);\n            vec3 majorLineColor = mix(baseColor, uMaxColor, 0.25);\n\n            color = baseColor;\n            color = mix(color, lineColor, onMinorLine * 0.5);\n            color = mix(color, majorLineColor, onMajorLine * 0.7);\n        } else {\n            // Standard gradient mode\n            float t = clamp(vElevationMeters / denom, 0.0, 1.0);\n            color = mix(uMinColor, uMaxColor, t);\n        }\n\n        // FULLY OPAQUE to hide any imagery underneath\n        gl_FragColor = vec4(color, 1.0);\n    }\n`;\n\nconst wireframeLineFragmentShader = `\n    #include <common>\n    #include <logdepthbuf_pars_fragment>\n\n    uniform float uEverestHeight;\n    uniform float uMinDepth;\n    uniform float uBelowMinOpacity;\n    uniform float uLineOpacity;\n    uniform vec3 uLineColor;\n\n    varying float vElevationMeters;\n\n    void main() {\n        #include <logdepthbuf_fragment>\n        float depthSpan = max(1.0, -uMinDepth);\n        float belowT = clamp((vElevationMeters - uMinDepth) / depthSpan, 0.0, 1.0);\n        float belowAlpha = mix(uBelowMinOpacity, 1.0, belowT);\n\n        float aboveSpan = max(uEverestHeight, 1.0);\n        float aboveT = clamp(vElevationMeters / aboveSpan, 0.0, 1.0);\n        float aboveAlpha = 1.0 - aboveT;\n\n        float alpha = vElevationMeters < 0.0 ? belowAlpha : aboveAlpha;\n        alpha *= uLineOpacity;\n        gl_FragColor = vec4(uLineColor, alpha);\n    }\n`;\n\nfunction getWireframeFillMaterial() {\n    if (!wireframeMaterials.fill) {\n        wireframeMaterials.fill = new THREE.ShaderMaterial({\n            uniforms: {\n                uPlanetRadius: { value: PLANET_RADIUS },\n                uEarthRadius: { value: EARTH_RADIUS_M },\n                uExaggeration: { value: Math.max(ELEVATION_EXAGGERATION, 0.0001) },\n                uEverestHeight: { value: WIREFRAME_EVEREST_M },\n                uMinColor: { value: wireframeStyleState.fillMinColor.clone() },\n                uMaxColor: { value: wireframeStyleState.fillMaxColor.clone() },\n                uTopoEnabled: { value: wireframeStyleState.topoEnabled ? 1.0 : 0.0 },\n                uTopoInterval: { value: wireframeStyleState.topoInterval },\n                uTopoMinorDivisions: { value: wireframeStyleState.topoMinorDivisions },\n                uTopoLineWidth: { value: wireframeStyleState.topoLineWidth },\n                uFillMode: { value: wireframeStyleState.fillMode },\n                uHalftoneScale: { value: wireframeStyleState.halftoneScale },\n                uHalftoneStrength: { value: wireframeStyleState.halftoneStrength },\n                uHalftoneSoftness: { value: wireframeStyleState.halftoneSoftness },\n                uHalftoneAngle: { value: wireframeStyleState.halftoneAngle }\n            },\n            vertexShader: wireframeVertexShader,\n            fragmentShader: wireframeFillFragmentShader,\n            side: THREE.DoubleSide,\n            transparent: false, // Opaque to hide imagery\n            depthWrite: true    // Write to depth buffer\n        });\n        wireframeMaterials.fill.userData.shared = true;\n    }\n    return wireframeMaterials.fill;\n}\n\nfunction getWireframeLineMaterial() {\n    if (!wireframeMaterials.line) {\n        wireframeMaterials.line = new THREE.ShaderMaterial({\n            uniforms: {\n                uPlanetRadius: { value: PLANET_RADIUS },\n                uEarthRadius: { value: EARTH_RADIUS_M },\n                uExaggeration: { value: Math.max(ELEVATION_EXAGGERATION, 0.0001) },\n                uEverestHeight: { value: WIREFRAME_EVEREST_M },\n                uMinDepth: { value: WIREFRAME_MIN_DEPTH_M },\n                uBelowMinOpacity: { value: WIREFRAME_BELOW_MIN_OPACITY },\n                uLineOpacity: { value: WIREFRAME_LINE_OPACITY },\n                uLineColor: { value: wireframeStyleState.lineColor.clone() }\n            },\n            vertexShader: wireframeVertexShader,\n            fragmentShader: wireframeLineFragmentShader,\n            side: THREE.DoubleSide,\n            transparent: true,\n            wireframe: true,\n            depthWrite: false,\n            polygonOffset: true,\n            polygonOffsetFactor: -1,\n            polygonOffsetUnits: -1\n        });\n        wireframeMaterials.line.userData.shared = true;\n    }\n    return wireframeMaterials.line;\n}\n\nfunction getImageryAvgSampler(size) {\n    if (typeof document === 'undefined') return null;\n    if (!imageryAvgSampler.canvas) {\n        imageryAvgSampler.canvas = document.createElement('canvas');\n        imageryAvgSampler.ctx = imageryAvgSampler.canvas.getContext('2d', {\n            alpha: false,\n            willReadFrequently: true\n        });\n    }\n    const canvas = imageryAvgSampler.canvas;\n    const ctx = imageryAvgSampler.ctx;\n    if (!ctx) return null;\n    if (canvas.width !== size) canvas.width = size;\n    if (canvas.height !== size) canvas.height = size;\n    return { canvas, ctx };\n}\n\nexport function setTilesPendingNormals(set) {\n    tilesPendingNormalsRef = set;\n}\n\nexport function setWireframeStyle(style = {}) {\n    if (!style || typeof style !== 'object') return;\n    if (style.fillMinColor) wireframeStyleState.fillMinColor.set(style.fillMinColor);\n    if (style.fillMaxColor) wireframeStyleState.fillMaxColor.set(style.fillMaxColor);\n    if (style.lineColor) wireframeStyleState.lineColor.set(style.lineColor);\n    if (typeof style.lineOverlayEnabled === 'boolean') {\n        wireframeStyleState.lineOverlayEnabled = style.lineOverlayEnabled;\n    }\n    if (style.fillMode !== undefined) {\n        const raw = typeof style.fillMode === 'string' ? style.fillMode.toLowerCase() : style.fillMode;\n        if (raw === 'topo' || raw === 1) {\n            wireframeStyleState.fillMode = 1;\n        } else if (raw === 'halftone' || raw === 2) {\n            wireframeStyleState.fillMode = 2;\n        } else {\n            wireframeStyleState.fillMode = 0;\n        }\n    }\n    if (typeof style.topoEnabled === 'boolean') {\n        wireframeStyleState.topoEnabled = style.topoEnabled;\n    }\n    if (Number.isFinite(style.topoInterval)) {\n        wireframeStyleState.topoInterval = Math.max(10, style.topoInterval);\n    }\n    if (Number.isFinite(style.topoMinorDivisions)) {\n        wireframeStyleState.topoMinorDivisions = Math.max(1, Math.min(10, style.topoMinorDivisions));\n    }\n    if (Number.isFinite(style.topoLineWidth)) {\n        wireframeStyleState.topoLineWidth = Math.max(0.01, Math.min(0.5, style.topoLineWidth));\n    }\n    if (Number.isFinite(style.halftoneScale)) {\n        wireframeStyleState.halftoneScale = Math.max(0.00005, Math.min(0.02, style.halftoneScale));\n    }\n    if (Number.isFinite(style.halftoneStrength)) {\n        wireframeStyleState.halftoneStrength = Math.max(0.0, Math.min(1.0, style.halftoneStrength));\n    }\n    if (Number.isFinite(style.halftoneSoftness)) {\n        wireframeStyleState.halftoneSoftness = Math.max(0.001, Math.min(0.5, style.halftoneSoftness));\n    }\n    if (Number.isFinite(style.halftoneAngle)) {\n        wireframeStyleState.halftoneAngle = style.halftoneAngle;\n    }\n\n    if (wireframeMaterials.fill?.uniforms) {\n        const uniforms = wireframeMaterials.fill.uniforms;\n        if (uniforms.uMinColor) uniforms.uMinColor.value.copy(wireframeStyleState.fillMinColor);\n        if (uniforms.uMaxColor) uniforms.uMaxColor.value.copy(wireframeStyleState.fillMaxColor);\n        if (uniforms.uTopoEnabled) uniforms.uTopoEnabled.value = wireframeStyleState.topoEnabled ? 1.0 : 0.0;\n        if (uniforms.uTopoInterval) uniforms.uTopoInterval.value = wireframeStyleState.topoInterval;\n        if (uniforms.uTopoMinorDivisions) uniforms.uTopoMinorDivisions.value = wireframeStyleState.topoMinorDivisions;\n        if (uniforms.uTopoLineWidth) uniforms.uTopoLineWidth.value = wireframeStyleState.topoLineWidth;\n        if (uniforms.uFillMode) uniforms.uFillMode.value = wireframeStyleState.fillMode;\n        if (uniforms.uHalftoneScale) uniforms.uHalftoneScale.value = wireframeStyleState.halftoneScale;\n        if (uniforms.uHalftoneStrength) uniforms.uHalftoneStrength.value = wireframeStyleState.halftoneStrength;\n        if (uniforms.uHalftoneSoftness) uniforms.uHalftoneSoftness.value = wireframeStyleState.halftoneSoftness;\n        if (uniforms.uHalftoneAngle) uniforms.uHalftoneAngle.value = wireframeStyleState.halftoneAngle;\n    }\n    if (wireframeMaterials.line?.uniforms?.uLineColor) {\n        wireframeMaterials.line.uniforms.uLineColor.value.copy(wireframeStyleState.lineColor);\n    }\n}\n\nexport function isWireframeLineOverlayEnabled() {\n    return wireframeStyleState.lineOverlayEnabled;\n}\n\nconst fadeInActiveTiles = new Set();\nconst crossfadeActiveTiles = new Set();\n\nexport function registerFadeInTile(tile) {\n    if (tile) fadeInActiveTiles.add(tile);\n}\n\nfunction registerCrossfadeTile(tile) {\n    if (tile) crossfadeActiveTiles.add(tile);\n}\n\n/**\n * Update fade-in animations for all tiles in a tree\n * Call this every frame to animate tile loading transitions\n * @param {TriTile} rootTile - Root tile to traverse from\n */\nexport function updateTileFadeIns(rootTile) {\n    if (!rootTile || fadeInActiveTiles.size === 0) return;\n    // Only touch tiles actively fading in to avoid full-tree traversal.\n    const toRemove = [];\n    for (const tile of fadeInActiveTiles) {\n        if (!tile.updateFadeIn()) {\n            toRemove.push(tile);\n        }\n    }\n    for (const tile of toRemove) {\n        fadeInActiveTiles.delete(tile);\n    }\n}\n\n/**\n * Update crossfade animations for imagery resolution transitions\n * Call this every frame to animate smooth texture blending\n * @param {TriTile} rootTile - Root tile to traverse from\n */\nexport function updateTileCrossfades(rootTile) {\n    if (!rootTile || crossfadeActiveTiles.size === 0) return;\n    const toRemove = [];\n    for (const tile of crossfadeActiveTiles) {\n        if (!tile.updateCrossfade()) {\n            toRemove.push(tile);\n        }\n    }\n    for (const tile of toRemove) {\n        crossfadeActiveTiles.delete(tile);\n    }\n}\n\n// ============================================================================\n// Building Footprint Baking Helpers\n// ============================================================================\n\n/**\n * Test if a 2D point is inside a polygon using ray casting\n * @param {number} px - Point X\n * @param {number} py - Point Y\n * @param {Array<{x:number, y:number}>} polygon - Array of 2D points\n * @returns {boolean}\n */\nfunction pointInPolygon2D(px, py, polygon) {\n    let inside = false;\n    const n = polygon.length;\n    for (let i = 0, j = n - 1; i < n; j = i++) {\n        const xi = polygon[i].x, yi = polygon[i].y;\n        const xj = polygon[j].x, yj = polygon[j].y;\n        if (((yi > py) !== (yj > py)) &&\n            (px < (xj - xi) * (py - yi) / (yj - yi) + xi)) {\n            inside = !inside;\n        }\n    }\n    return inside;\n}\n\n/**\n * Compute signed area of a polygon (positive = CCW)\n */\nfunction polygonSignedArea2D(points) {\n    let area = 0;\n    for (let i = 0, j = points.length - 1; i < points.length; j = i++) {\n        area += (points[j].x * points[i].y) - (points[i].x * points[j].y);\n    }\n    return area * 0.5;\n}\n\n/**\n * Compute signed area of a 2D triangle (positive = CCW)\n */\nfunction triangleArea2D(ax, ay, bx, by, cx, cy) {\n    return 0.5 * ((bx - ax) * (cy - ay) - (cx - ax) * (by - ay));\n}\n\n/**\n * Test if point P is inside triangle ABC using barycentric coordinates\n */\nfunction pointInTriangle2D(px, py, ax, ay, bx, by, cx, cy) {\n    const area = triangleArea2D(ax, ay, bx, by, cx, cy);\n    if (Math.abs(area) < 1e-12) return false;\n    const s = (ax * (cy - ay) + (py - ay) * (cx - ax) - px * (cy - ay)) / (2 * area);\n    const t = (ax * (by - ay) + (py - ay) * (bx - ax) - px * (by - ay)) / (-2 * area);\n    return s >= 0 && t >= 0 && (s + t) <= 1;\n}\n\n/**\n * Line segment intersection test (returns t parameter for segment AB if intersection exists)\n */\nfunction segmentIntersection2D(ax, ay, bx, by, cx, cy, dx, dy) {\n    const denom = (dx - cx) * (ay - by) - (ax - bx) * (dy - cy);\n    if (Math.abs(denom) < 1e-12) return null;\n    const t = ((cx - ax) * (ay - by) - (ax - bx) * (cy - ay)) / denom;\n    const s = ((dx - cx) * (cy - ay) - (cx - ax) * (dy - cy)) / denom;\n    if (t >= 0 && t <= 1 && s >= 0 && s <= 1) {\n        return { t, s, x: ax + s * (bx - ax), y: ay + s * (by - ay) };\n    }\n    return null;\n}\n\n/**\n * Distance from point to line segment\n */\nfunction pointToSegmentDistance2D(px, py, ax, ay, bx, by) {\n    const dx = bx - ax;\n    const dy = by - ay;\n    const lenSq = dx * dx + dy * dy;\n    if (lenSq < 1e-12) {\n        return Math.sqrt((px - ax) * (px - ax) + (py - ay) * (py - ay));\n    }\n    let t = ((px - ax) * dx + (py - ay) * dy) / lenSq;\n    t = Math.max(0, Math.min(1, t));\n    const nearX = ax + t * dx;\n    const nearY = ay + t * dy;\n    return Math.sqrt((px - nearX) * (px - nearX) + (py - nearY) * (py - nearY));\n}\n\n/**\n * Check if a triangle intersects or is contained by a polygon\n */\nfunction triangleIntersectsPolygon2D(tri, polygon) {\n    // Check if any triangle vertex is inside polygon\n    for (const v of tri) {\n        if (pointInPolygon2D(v.x, v.y, polygon)) return true;\n    }\n    // Check if any polygon vertex is inside triangle\n    for (const v of polygon) {\n        if (pointInTriangle2D(v.x, v.y, tri[0].x, tri[0].y, tri[1].x, tri[1].y, tri[2].x, tri[2].y)) {\n            return true;\n        }\n    }\n    // Check edge intersections\n    const triEdges = [[0, 1], [1, 2], [2, 0]];\n    for (let i = 0; i < polygon.length; i++) {\n        const j = (i + 1) % polygon.length;\n        for (const [a, b] of triEdges) {\n            if (segmentIntersection2D(\n                tri[a].x, tri[a].y, tri[b].x, tri[b].y,\n                polygon[i].x, polygon[i].y, polygon[j].x, polygon[j].y\n            )) {\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\n/**\n * Reusable vectors for building extrusion calculations\n */\nconst _buildingTmpVec3A = new THREE.Vector3();\nconst _buildingTmpVec3B = new THREE.Vector3();\nconst _buildingTmpVec3C = new THREE.Vector3();\nconst _buildingTmpVec3D = new THREE.Vector3();\nconst _buildingTmpVec2A = { x: 0, y: 0 };\nconst _buildingTmpVec2B = { x: 0, y: 0 };\nconst _buildingTmpVec2C = { x: 0, y: 0 };\n\nexport class TriTile {\n    constructor(v0, v1, v2, level = 0, index = 0, parent = null,\n        radius = PLANET_RADIUS, elevationClient = null) {\n\n        this.v0 = v0.clone().normalize();\n        this.v1 = v1.clone().normalize();\n        this.v2 = v2.clone().normalize();\n        this.level = level;\n        this.index = index;\n        this.parent = parent;\n        this.radius = radius;\n        this.elevationClient = elevationClient;\n\n        this.children = null;\n        this.geometry = null;\n        this.mesh = null;\n        this.baseDirs = null;\n        this.baseRadii = null;\n        this.positionAttr = null;\n        this.resolution = 0;\n        this.vertexCount = 0;\n        this.baseVertexCount = 0;\n        this.baseIndexArray = null;\n        this.baseIndexCount = 0;\n        this._buildingExtrusions = null;\n        this._buildingFootprints = null;\n        this._buildingFootprintOptions = null;\n        this._buildingVertexCount = 0;\n        this._buildingModified = false;\n        this.elevationExpected = 0;\n        this.elevationDone = 0;\n        this.elevationState = null; // 0 = unregistered, 1 = registered, 2 = done\n        this.elevationVersion = 0;\n        this.elevationSeeded = null; // 1 = seeded or fetched\n        this.elevationSeededCount = 0;\n        this.elevationFillMask = null; // 1 = filled/interpolated (not fetched)\n        this.elevationComplete = false;\n        this.elevationHasData = false;\n        this.elevationRetryIndex = 0;\n        this.forceFullFetch = false;\n        this.elevationCache = null;\n        this.childrenPrepared = false;\n        this._childrenImageryPrepared = false;\n        this.elevationMorphEnabled = true;\n        this.elevationMorphSpeed = 8;\n        this.elevationMorphEpsilon = 0.05;\n        this.elevationMorphCurrent = null;\n        this.elevationMorphTarget = null;\n        this.elevationMorphPending = null;\n        this.elevationFillEnabled = true;\n        this.elevationForceCompleteEnabled = true;\n        this.elevationFillMaxPerFrame = 64;\n        this.elevationFillIntervalMs = 30;\n        this.elevationFillCursor = 0;\n        this.elevationFillLastTime = 0;\n        this._elevationFillLastDone = -1;\n        this.elevationFillComplete = false;\n        this._elevationFillCompleteDone = -1;\n        this._elevationFillCompleteSeeded = -1;\n        this._elevationFillAverage = null;\n        this._elevationFillAverageDone = -1;\n        this._elevationFillAverageDoneOnly = null;\n        this._elevationFillAverageDoneOnlyDone = -1;\n        this._boundsDirty = false;\n        this._normalsDirty = false;\n        this._pendingElevationUpdate = false;\n        this._pendingGeometryFinalize = false;\n        this.elevationHoldUntilComplete = false;\n        this.elevationHoldPending = null;\n        this._elevationLastProgressMs = 0;\n        this._elevationLastProgressDone = -1;\n        this._elevationStallSinceMs = 0;\n        this._surfaceForceFullFetch = false;\n        this._elevForceFetch = false;\n\n        // Stitching cache: the only supported seam path (through applyEdgeElevations/updateVertex).\n        this.edgeElevationCache = new Map(); // index -> { originalElevMeters, isVirtual, originalRadius }\n        this.stitchedEdges = new Map(); // edgeName -> { neighborTile, neighborLevel }\n        this.baseElevations = null; // Float32Array snapshot of ground-truth elevations before stitching\n        this.edgeVertexMask = null; // Uint8Array mask of edge membership per vertex\n        this.deferredEdgeElevations = new Map(); // index -> deferred elevation meters\n\n        // Neighbor tracking for LOD constraint enforcement\n        this.neighbors = new Map(); // edgeName -> neighbor tile reference\n        this.pendingLODConstraints = new Set(); // Tiles that need to subdivide due to neighbor constraint\n\n        this.centerDir = new THREE.Vector3()\n            .add(this.v0)\n            .add(this.v1)\n            .add(this.v2)\n            .normalize();\n        this.centerRadius = ellipsoidRadiusForDir(this.centerDir.x, this.centerDir.y, this.centerDir.z);\n        if (!Number.isFinite(this.centerRadius) || this.centerRadius <= 0) {\n            this.centerRadius = this.radius;\n        }\n        this.center = this.centerDir.clone().multiplyScalar(this.centerRadius);\n\n        const a0 = Math.acos(THREE.MathUtils.clamp(this.centerDir.dot(this.v0), -1, 1));\n        const a1 = Math.acos(THREE.MathUtils.clamp(this.centerDir.dot(this.v1), -1, 1));\n        const a2 = Math.acos(THREE.MathUtils.clamp(this.centerDir.dot(this.v2), -1, 1));\n        this.angularRadius = Math.max(a0, a1, a2);\n        this.geometricError = this.angularRadius * this.radius * ELEVATION_EXAGGERATION;\n\n        // imagery state\n        this.imageryVersion = null;\n        this.imageryZoom = null;\n        this.imageryTargetZoom = null;\n        this.imageryTileX = null;\n        this.imageryTileY = null;\n        this.imageryReady = false;\n        this.imageryAtlasKey = null;\n        this.imageryPendingKey = null;\n        this.imageryRequestedKey = null;\n        this.imageryRequestedZoom = null;\n        this.imageryPendingSince = null;\n        this.imageryPendingAttempts = 0;\n        this.imageryManager = null;\n        this.imageryTexture = null;\n        this.imageryAtlasMinX = null;\n        this.imageryAtlasMinY = null;\n        this.imageryAtlasW = null;\n        this.imageryAtlasH = null;\n        this.imageryAtlasZoom = null;\n        this.imageryPendingUv = null;\n        // FALLBACK SYSTEMS REMOVED - WMTS ONLY\n        this._imageryCoordCache = null; // { zoom, coords, minCx, maxCx, minCy, maxCy, n }\n        this._imageryUvCache = null; // { atlasKey, uvArray }\n        this._imageryVertexCount = 0;\n        this._imageryTmpDir = new THREE.Vector3();\n        this._pendingInheritedImagery = null; // imagery snapshot for immediate fallback\n        this._pendingInheritedManager = null;\n        this._pendingInheritedAtlasKey = null;\n        this.imageryLoading = false;\n        this.imageryLoadingStart = null;\n\n        // Photogrammetry state\n        this.photogramOffsets = null; // Float32Array per vertex (meters)\n        this.photogramKey = null;\n        this.photogramResOverride = null;\n        this.photogramPending = false;\n\n        // Track base elevation values (without photogram offsets)\n        this.elevationValues = null;\n\n        // Inherited imagery tracking (for merge-out only, not for children)\n        this.imageryInherited = false; // True if displaying adopted child imagery after merge\n        this.imageryInheritedZoom = null; // Zoom level of inherited imagery\n        this.inheritedAtlasKey = null; // Adopted atlas key (for cleanup)\n        this.inheritedTexture = null; // Adopted texture reference\n        // REMOVED: imagerySnapshotForInheritance - children load their own WMTS\n\n        // PHASE 2: Deferred removal tracking\n        this.deferredRemoval = false;\n        this.subdivisionTimestamp = null;\n\n        // Material management (no pooling - each tile has unique material)\n        this.treeManager = null; // Reference to TriTreeManager\n\n        this.materialDefault = null;\n        this.materialWireframeFill = null;\n        this.wireframeOverlay = null;\n        this.wireframeEnabled = false;\n        this.waterMaskAttr = null;\n\n        // Crack-sealing skirt. The skirt is a small, non-raycast child mesh so\n        // terrain sampling and physics continue to see only the authoritative\n        // triangle surface. Its top and bottom rows share each edge vertex's\n        // imagery UV, producing a straight downward continuation of the edge\n        // texel instead of a black or unrelated seam filler.\n        this.skirtMesh = null;\n        this.skirtGeometry = null;\n        this.skirtDepthMeters = null;\n        this._skirtSourceIndices = null;\n        this._skirtDirty = false;\n\n        // Fade-in animation for tile loading\n        this.fadeInEnabled = true;\n        this.fadeInDuration = 300; // ms\n        this.fadeInStart = null;\n        this.fadeInCurrent = 0; // 0 to 1\n        this.fadeInComplete = false;\n\n        // Crossfade animation for imagery transitions (upgrade/downgrade)\n        // DISABLED: Crossfade causes GPU churn due to shader texture sampling overhead\n        this.crossfadeEnabled = false;\n        this.crossfadeDuration = 400; // ms - slightly longer for smoother resolution blending\n        this.crossfadeStart = null;\n        this.crossfadeBlend = 1.0; // 0 = show prev, 1 = show current\n        this.crossfadeComplete = true;\n        this.crossfadePrevTexture = null; // Previous texture for blending\n        this.crossfadePrevAtlasKey = null; // Key for ref-counting\n        // UV transform from current UVs to previous texture's UVs\n        this.crossfadePrevUvOffset = null; // THREE.Vector2\n        this.crossfadePrevUvScale = null;  // THREE.Vector2\n    }\n\n    _applyLoadingUniforms(material) {\n        if (!material) return;\n        const uniforms = material.userData?.uniforms || material.uniforms;\n        if (!uniforms) return;\n        if (uniforms.loadingCenterDir?.value) {\n            uniforms.loadingCenterDir.value.copy(this.centerDir);\n        }\n        if (uniforms.loadingAngularRadius) {\n            uniforms.loadingAngularRadius.value = Number.isFinite(this.angularRadius) ? this.angularRadius : 0;\n        }\n        if (uniforms.loadingEnabled) {\n            uniforms.loadingEnabled.value = this.imageryLoading ? 1.0 : 0.0;\n        }\n        if (uniforms.loadingStartTime) {\n            uniforms.loadingStartTime.value = Number.isFinite(this.imageryLoadingStart)\n                ? this.imageryLoadingStart\n                : 0.0;\n        }\n    }\n\n    _syncLoadingUniforms() {\n        if (this.materialDefault) {\n            this._applyLoadingUniforms(this.materialDefault);\n        }\n        if (this.mesh?.material && this.mesh.material !== this.materialDefault) {\n            this._applyLoadingUniforms(this.mesh.material);\n        }\n    }\n\n    _setImageryLoading(enabled, startTime = null) {\n        const next = !!enabled;\n        if (next && !this.imageryLoading && Number.isFinite(startTime)) {\n            this.imageryLoadingStart = startTime;\n        } else if (!next) {\n            this.imageryLoadingStart = null;\n        }\n        if (this.imageryLoading === next) {\n            this._syncLoadingUniforms();\n            return;\n        }\n        this.imageryLoading = next;\n        this._syncLoadingUniforms();\n    }\n\n    subdivide() {\n        if (this.children) return this.children;\n\n        // PHASE 2: Record subdivision timestamp for priority boosting\n        this.subdivisionTimestamp = (typeof performance !== 'undefined' && performance.now)\n            ? performance.now()\n            : Date.now();\n\n        // REMOVED: Imagery snapshot for inheritance - children load their own WMTS imagery\n\n        const mid01 = new THREE.Vector3().addVectors(this.v0, this.v1).normalize();\n        const mid12 = new THREE.Vector3().addVectors(this.v1, this.v2).normalize();\n        const mid20 = new THREE.Vector3().addVectors(this.v2, this.v0).normalize();\n\n        const childLevel = this.level + 1;\n        this.children = [\n            new TriTile(mid01, mid12, mid20, childLevel, this.index * 4, this, this.radius, this.elevationClient),\n            new TriTile(this.v0, mid01, mid20, childLevel, this.index * 4 + 1, this, this.radius, this.elevationClient),\n            new TriTile(this.v1, mid12, mid01, childLevel, this.index * 4 + 2, this, this.radius, this.elevationClient),\n            new TriTile(this.v2, mid20, mid12, childLevel, this.index * 4 + 3, this, this.radius, this.elevationClient),\n        ];\n        return this.children;\n    }\n\n    buildGeometry() {\n        if (this.geometry) return this.geometry;\n\n        const baseRes = 3;\n        const resPerLevel = 2;\n        const override = Number.isFinite(this.photogramResOverride)\n            ? Math.max(2, Math.floor(this.photogramResOverride))\n            : null;\n        const res = override !== null\n            ? override\n            : Math.min(baseRes + this.level * resPerLevel, 19);\n        const vertexCount = ((res + 1) * (res + 2)) / 2;\n\n        const vertices = new Float32Array(vertexCount * 3);\n        const dirs = new Float32Array(vertexCount * 3);\n        const baseRadii = new Float32Array(vertexCount);\n        // A triangular grid with resolution N always contains N^2 triangles.\n        // Allocate its final index storage once instead of growing a JS array\n        // for every child created during a synchronous LOD split.\n        const indexArray = new Uint32Array(res * res * 3);\n\n        const v0 = this.v0;\n        const v1 = this.v1;\n        const v2 = this.v2;\n\n        // Tile-local coordinates: store positions relative to tile center for Float32 precision\n        // The mesh.position will be set to this.center when the mesh is created\n        const cx = this.center.x;\n        const cy = this.center.y;\n        const cz = this.center.z;\n\n        let idx = 0;\n        let maxLocalRadiusSq = 0;\n        for (let i = 0; i <= res; i++) {\n            for (let j = 0; j <= res - i; j++) {\n                const k = res - i - j;\n                const w0 = i / res;\n                const w1 = j / res;\n                const w2 = k / res;\n\n                let px = w0 * v0.x + w1 * v1.x + w2 * v2.x;\n                let py = w0 * v0.y + w1 * v1.y + w2 * v2.y;\n                let pz = w0 * v0.z + w1 * v1.z + w2 * v2.z;\n\n                const len = Math.sqrt(px * px + py * py + pz * pz) || 1;\n                px /= len; py /= len; pz /= len;\n\n                // Keep the split path allocation-free per vertex. Creating a\n                // Vector3 here used to generate hundreds of short-lived\n                // objects for every one of four children and cause visible GC\n                // stalls while walking through surface LODs.\n                const r = ellipsoidRadiusForDir(px, py, pz);\n                const v3 = idx * 3;\n                // Store position relative to tile center (local coordinates)\n                const localX = px * r - cx;\n                const localY = py * r - cy;\n                const localZ = pz * r - cz;\n                vertices[v3 + 0] = localX;\n                vertices[v3 + 1] = localY;\n                vertices[v3 + 2] = localZ;\n                dirs[v3 + 0] = px;\n                dirs[v3 + 1] = py;\n                dirs[v3 + 2] = pz;\n                baseRadii[idx] = r;\n                maxLocalRadiusSq = Math.max(\n                    maxLocalRadiusSq,\n                    localX * localX + localY * localY + localZ * localZ\n                );\n\n                idx++;\n            }\n        }\n\n        let vIdx = 0;\n        let indexOffset = 0;\n        for (let i = 0; i < res; i++) {\n            const rowStart = vIdx;\n            const rowLen = res - i + 1;\n            const nextRowStart = vIdx + rowLen;\n\n            for (let j = 0; j < res - i; j++) {\n                const a = rowStart + j;\n                const b = rowStart + j + 1;\n                const c = nextRowStart + j;\n\n                indexArray[indexOffset++] = a;\n                indexArray[indexOffset++] = b;\n                indexArray[indexOffset++] = c;\n\n                if (j < res - i - 1) {\n                    const d = nextRowStart + j + 1;\n                    indexArray[indexOffset++] = b;\n                    indexArray[indexOffset++] = d;\n                    indexArray[indexOffset++] = c;\n                }\n            }\n\n            vIdx = nextRowStart;\n        }\n\n        const positionArray = vertices;\n        const baseDirArray = dirs;\n\n        // Try to reuse a pooled geometry (same resolution = same topology)\n        let geom = acquirePooledGeometry(res);\n        if (geom) {\n            // Reuse: overwrite position data and index, keep allocation\n            const posAttr = geom.getAttribute('position');\n            if (posAttr && posAttr.array.length === positionArray.length) {\n                posAttr.array.set(positionArray);\n                posAttr.needsUpdate = true;\n            } else {\n                geom.setAttribute('position', new THREE.BufferAttribute(positionArray, 3));\n            }\n            geom.setIndex(new THREE.BufferAttribute(indexArray, 1));\n            geom.attributes.position.setUsage(THREE.DynamicDrawUsage);\n        } else {\n            geom = new THREE.BufferGeometry();\n            geom.setAttribute('position', new THREE.BufferAttribute(positionArray, 3));\n            geom.setIndex(new THREE.BufferAttribute(indexArray, 1));\n            geom.attributes.position.setUsage(THREE.DynamicDrawUsage);\n        }\n        // TriTree's physical light uses the stable ellipsoid/radial normal,\n        // matching photoreal deferred lighting. Seed that exact normal without\n        // a full indexed-face accumulation during every split. Elevation edits\n        // can still enqueue the existing bounded normal refresh later.\n        // Keep CPU-owned base directions independent: later bounded normal\n        // refreshes overwrite the normal attribute in place.\n        geom.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(baseDirArray), 3));\n        // The local origin is the tile's surface center. We already visited\n        // every vertex above, so install a conservative initial bound without\n        // another synchronous geometry scan. Streaming elevation marks bounds\n        // dirty and the bounded finalize queue refreshes it when needed.\n        geom.boundingSphere = new THREE.Sphere(\n            new THREE.Vector3(0, 0, 0),\n            Math.sqrt(maxLocalRadiusSq) + 1\n        );\n\n        this.geometry = geom;\n        this.baseDirs = baseDirArray;\n        this.baseRadii = baseRadii;\n        this.positionAttr = geom.getAttribute('position');\n        this.resolution = res;\n        this.vertexCount = vertexCount;\n        this.baseVertexCount = vertexCount;\n        this.baseIndexArray = indexArray;\n        this.baseIndexCount = indexArray.length;\n        this._buildEdgeVertexMask();\n        this.elevationValues = new Float32Array(vertexCount);\n        this.elevationValues.fill(Number.NaN);\n        this.elevationState = new Uint8Array(vertexCount);\n        this.elevationSeeded = new Uint8Array(vertexCount);\n        this.elevationSeededCount = 0;\n        this.elevationFillMask = new Uint8Array(vertexCount);\n        this.elevationExpected = 0;\n        this.elevationDone = 0;\n        this.elevationComplete = false;\n        this.elevationRetryIndex = 0;\n        const now = (typeof performance !== 'undefined' && performance.now)\n            ? performance.now()\n            : Date.now();\n        this._elevationLastProgressMs = now;\n        this._elevationLastProgressDone = this.elevationDone;\n        this._elevationStallSinceMs = 0;\n\n        this._seedHeightsFromCache();\n        this._seedHeightsFromParent();\n        this._initElevationMorphBuffers();\n        this._ensureBaseUVs();\n        if (this._buildingFootprints?.length) {\n            this.applyBuildingFootprints(this._buildingFootprints, this._buildingFootprintOptions || {});\n        } else if (this._buildingExtrusions?.positions?.length) {\n            this._applyBuildingExtrusions();\n        }\n        this._ensureWaterMask();\n\n        if (this.elevationClient) {\n            const tmpDir = new THREE.Vector3();\n            const resolveOcean = (typeof this.elevationClient.resolveOcean === 'function')\n                ? this.elevationClient.resolveOcean.bind(this.elevationClient)\n                : null;\n            const expectAll = typeof this.elevationClient.isFullFetchTile === 'function'\n                ? this.elevationClient.isFullFetchTile(this)\n                : (typeof this.elevationClient.isFullFetchLevel === 'function'\n                    ? this.elevationClient.isFullFetchLevel(this.level)\n                    : false);\n\n            // Keep lightweight temporary fill enabled so unfetched vertices don't remain\n            // at oblate/sea-level while real elevations stream in. Real fetches overwrite\n            // these placeholders via updateVertex() and clear fill masks (no double-apply).\n            this.elevationFillEnabled = true;\n            this.elevationFillComplete = false;\n\n            this.elevationExpected = expectAll ? vertexCount : 0;\n            let registeredCount = 0;\n            let intendedCount = 0; // Track how many SHOULD be registered (for accurate %)\n\n            for (let i = 0; i < vertexCount; i++) {\n                const i3 = i * 3;\n                tmpDir.set(baseDirArray[i3 + 0], baseDirArray[i3 + 1], baseDirArray[i3 + 2]);\n                const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n\n                if (resolveOcean) {\n                    const ocean = resolveOcean(latDeg, lonDeg, tmpDir, this, i);\n                    if (ocean && ocean.isOcean) {\n                        const mask = Number.isFinite(ocean.waterMask) ? ocean.waterMask : 1;\n                        this.setWaterMask(i, mask);\n                        // Water is a separate sea-level surface. Retain DEM\n                        // requests so ocean terrain can contain bathymetry.\n                    } else if (ocean && Number.isFinite(ocean.waterMask)) {\n                        this.setWaterMask(i, ocean.waterMask);\n                    }\n                }\n\n                if (!expectAll && !this.elevationClient.shouldRegisterVertex(this, i, res)) continue;\n\n                // This vertex SHOULD be registered - count it as intended regardless of success\n                intendedCount++;\n\n                const alreadyDone = this.elevationState[i] === 2;\n                const ok = this.elevationClient.registerVertex(latDeg, lonDeg, tmpDir, this, i);\n                if (ok) {\n                    if (!alreadyDone && this.elevationState[i] !== 2) {\n                        this.elevationState[i] = 1;\n                    }\n                    registeredCount++;\n                } else if (alreadyDone || this.elevationState[i] === 2) {\n                    registeredCount++;\n                }\n                // Note: if ok is false and not alreadyDone, vertex stays at state 0 for retry\n            }\n\n            if (!expectAll) {\n                // Use intended count for accurate percentage display\n                this.elevationExpected = intendedCount;\n            }\n            this._updateElevationComplete();\n            // Surface mode must stream elevation progressively; holding all updates until full\n            // completion can leave tiles visually flat/stale during startup.\n            const inSurfaceMode = !!this.treeManager?._inSurfaceMode;\n            this.elevationHoldUntilComplete = !inSurfaceMode && this.elevationExpected > 0 && !this.elevationComplete;\n        }\n\n        return geom;\n    }\n\n    setBuildingExtrusions(extrusions) {\n        let payload = null;\n        if (extrusions && extrusions.positions) {\n            let positions = extrusions.positions;\n            if (Array.isArray(positions)) {\n                positions = new Float32Array(positions);\n            } else if (ArrayBuffer.isView(positions) && !(positions instanceof Float32Array)) {\n                positions = new Float32Array(positions);\n            }\n            if (positions && positions.length) {\n                const floatCount = positions.length - (positions.length % 3);\n                if (floatCount > 0) {\n                    if (floatCount !== positions.length) {\n                        positions = positions.slice(0, floatCount);\n                    }\n                    payload = { positions };\n                }\n            }\n        }\n\n        this._buildingExtrusions = payload;\n        this._buildingVertexCount = payload ? payload.positions.length / 3 : 0;\n        if (!this.geometry || !this.positionAttr) return;\n        this._applyBuildingExtrusions();\n    }\n\n    _applyBuildingExtrusions() {\n        if (!this.geometry || !this.positionAttr) return;\n        const baseCount = this.vertexCount || (this.baseDirs ? this.baseDirs.length / 3 : 0);\n        if (!baseCount) return;\n\n        const extraPositions = this._buildingExtrusions?.positions || null;\n        const extraFloatCount = extraPositions\n            ? (extraPositions.length - (extraPositions.length % 3))\n            : 0;\n        const extraVertexCount = extraFloatCount / 3;\n\n        const baseFloatCount = baseCount * 3;\n        const basePositions = this.positionAttr.array;\n        const nextPositions = new Float32Array(baseFloatCount + extraFloatCount);\n        nextPositions.set(basePositions.subarray(0, baseFloatCount), 0);\n        if (extraFloatCount) {\n            nextPositions.set(extraPositions.subarray(0, extraFloatCount), baseFloatCount);\n        }\n\n        const positionAttr = new THREE.BufferAttribute(nextPositions, 3);\n        positionAttr.setUsage(THREE.DynamicDrawUsage);\n        this.geometry.setAttribute('position', positionAttr);\n        this.positionAttr = positionAttr;\n\n        const baseIndexArray = this.baseIndexArray || this.geometry.getIndex()?.array;\n        const baseIndexCount = this.baseIndexCount || (baseIndexArray ? baseIndexArray.length : 0);\n        if (baseIndexArray) {\n            let indexArray = baseIndexArray;\n            if (extraVertexCount > 0) {\n                const nextIndex = new Uint32Array(baseIndexCount + extraVertexCount);\n                nextIndex.set(baseIndexArray, 0);\n                for (let i = 0; i < extraVertexCount; i++) {\n                    nextIndex[baseIndexCount + i] = baseCount + i;\n                }\n                indexArray = nextIndex;\n            }\n            this.geometry.setIndex(new THREE.BufferAttribute(indexArray, 1));\n        }\n\n        this.geometry.deleteAttribute('normal');\n        this._buildingVertexCount = extraVertexCount;\n        this._imageryUvCache = null;\n        this._imageryVertexCount = 0;\n        this.imageryPendingUv = null;\n        if (this.imageryPendingKey) {\n            this.imageryPendingKey = null;\n            this.imageryRequestedKey = null;\n            this.imageryRequestedZoom = null;\n            this.imageryPendingSince = null;\n            this.imageryPendingAttempts = 0;\n        }\n        this._ensureBaseUVs();\n        this._ensureWaterMask();\n        this._markGeometryDirty();\n    }\n\n    /**\n     * Apply building footprints by extruding tile vertices within footprints.\n     * This modifies the tile mesh directly rather than adding separate geometry.\n     *\n     * @param {Array} buildings - Array of building objects with:\n     *   - footprint: Array<{x, y}> - 2D footprint in local tangent plane (meters)\n     *   - height: number - Building height in meters\n     *   - center: {lat, lon} - Center coordinates\n     *   - quaternion: THREE.Quaternion - Rotation from local to world\n     *   - basePosition: THREE.Vector3 - World position of building base\n     *   - embed: number - Depth to embed below terrain (meters)\n     * @param {Object} options - Options\n     *   - lodFactor: number (0-1) - Complexity multiplier based on distance\n     *   - maxSubdivisions: number - Max subdivisions per footprint edge\n     */\n    applyBuildingFootprints(buildings, options = {}) {\n        const buildingCount = Array.isArray(buildings) ? buildings.length : 0;\n        const debugLogs = options?.debugLogs === true;\n        if (debugLogs) {\n            console.log(`[TriTile] applyBuildingFootprints called: ${buildingCount} buildings, level=${this.level}, lodFactor=${options?.lodFactor}`);\n        }\n\n        if (!buildingCount) {\n            this._buildingFootprints = null;\n            this._buildingFootprintOptions = null;\n            if (this._buildingModified) {\n                this._restoreBaseGeometry();\n            }\n            this._buildingModified = false;\n            this._buildingVertexCount = 0;\n            return;\n        }\n\n        this._buildingFootprints = buildings;\n        this._buildingFootprintOptions = options;\n\n        if (!this.geometry || !this.positionAttr) {\n            this._buildingModified = false;\n            this._buildingVertexCount = 0;\n            return;\n        }\n\n        const cx = this.center.x;\n        const cy = this.center.y;\n        const cz = this.center.z;\n        const baseCount = this.baseVertexCount || this.vertexCount;\n        const baseDirs = this.baseDirs;\n        const baseIndexArray = this.baseIndexArray || this.geometry.getIndex()?.array;\n\n        if (!baseDirs || !baseIndexArray || baseCount <= 0) {\n            if (debugLogs) {\n                console.warn(`[TriTile] No baseDirs available`);\n            }\n            return;\n        }\n\n        const materialSide = this.mesh?.material?.side ??\n            this.materialDefault?.side ??\n            this.treeManager?.material?.side;\n        const backSide = materialSide === THREE.BackSide;\n\n        const basePosArray = this.positionAttr.array;\n        if (!basePosArray || basePosArray.length < baseCount * 3) {\n            if (debugLogs) {\n                console.warn('[TriTile] Missing base positions for building footprints');\n            }\n            return;\n        }\n\n        const baseRadii = new Float32Array(baseCount);\n        for (let i = 0; i < baseCount; i++) {\n            const i3 = i * 3;\n            const px = basePosArray[i3 + 0] + cx;\n            const py = basePosArray[i3 + 1] + cy;\n            const pz = basePosArray[i3 + 2] + cz;\n            const r = Math.sqrt(px * px + py * py + pz * pz);\n            baseRadii[i] = Number.isFinite(r) ? r : this.radius;\n        }\n\n        const sampleTileRadiusForDir = (dirX, dirY, dirZ) => {\n            let bestDot = -Infinity;\n            let bestRadius = null;\n            for (let i = 0; i < baseCount; i++) {\n                const i3 = i * 3;\n                const dot = baseDirs[i3 + 0] * dirX + baseDirs[i3 + 1] * dirY + baseDirs[i3 + 2] * dirZ;\n                if (dot > bestDot) {\n                    bestDot = dot;\n                    const r = baseRadii[i];\n                    bestRadius = Number.isFinite(r) ? r : null;\n                }\n            }\n            return bestRadius;\n        };\n\n        // New geometry buffers (start with base geometry)\n        const newPositions = new Array(baseCount * 3);\n        for (let i = 0; i < baseCount * 3; i++) {\n            newPositions[i] = basePosArray[i];\n        }\n        const newIndices = Array.from(baseIndexArray);\n\n        let wallTriangleCount = 0;\n        let roofTriangleCount = 0;\n\n        // Process each building\n        for (const building of buildings) {\n            if (!building.footprint || building.footprint.length < 3) continue;\n            const height = Number.isFinite(building.height) ? building.height : 10;\n            if (!Number.isFinite(height) || height <= 0) continue;\n\n            let footprint = building.footprint;\n            const quat = building.quaternion;\n            const basePos = building.basePosition;\n            const embed = building.embed || 0;\n\n            if (!basePos || !Number.isFinite(basePos.x) || !Number.isFinite(basePos.y) || !Number.isFinite(basePos.z)) {\n                continue;\n            }\n\n            const baseRadius = basePos.length();\n            if (!Number.isFinite(baseRadius) || baseRadius <= 0) continue;\n\n            if (polygonSignedArea2D(footprint) < 0) {\n                footprint = [...footprint].reverse();\n            }\n\n            const footprintCount = footprint.length;\n            const dirSamples = new Array(footprintCount * 3);\n            const groundVerts = new Array(footprintCount * 3);\n            const topVerts = new Array(footprintCount * 3);\n            let invalid = false;\n            let tileMinR = Infinity;\n            let tileMaxR = -Infinity;\n\n            for (let i = 0; i < footprintCount; i++) {\n                const pt = footprint[i];\n                _buildingTmpVec3D.set(pt.x, pt.y, 0);\n                if (quat) _buildingTmpVec3D.applyQuaternion(quat);\n                const wx = basePos.x + _buildingTmpVec3D.x;\n                const wy = basePos.y + _buildingTmpVec3D.y;\n                const wz = basePos.z + _buildingTmpVec3D.z;\n                if (!Number.isFinite(wx) || !Number.isFinite(wy) || !Number.isFinite(wz)) {\n                    invalid = true;\n                    break;\n                }\n                const wLen = Math.sqrt(wx * wx + wy * wy + wz * wz) || 1;\n                const dirX = wx / wLen;\n                const dirY = wy / wLen;\n                const dirZ = wz / wLen;\n                if (!Number.isFinite(dirX) || !Number.isFinite(dirY) || !Number.isFinite(dirZ)) {\n                    invalid = true;\n                    break;\n                }\n                const dIdx = i * 3;\n                dirSamples[dIdx] = dirX;\n                dirSamples[dIdx + 1] = dirY;\n                dirSamples[dIdx + 2] = dirZ;\n\n                const sampleR = sampleTileRadiusForDir(dirX, dirY, dirZ);\n                if (Number.isFinite(sampleR)) {\n                    if (sampleR < tileMinR) tileMinR = sampleR;\n                    if (sampleR > tileMaxR) tileMaxR = sampleR;\n                }\n            }\n            if (invalid) continue;\n\n            const hasTileSample = Number.isFinite(tileMinR) && Number.isFinite(tileMaxR) && tileMinR <= tileMaxR;\n            const tileMaxRadius = hasTileSample ? tileMaxR : baseRadius;\n            const tileMinRadius = hasTileSample ? tileMinR : tileMaxRadius;\n            const surfaceOffset = Number.isFinite(baseRadius)\n                ? (hasTileSample ? Math.min(0, baseRadius - tileMaxRadius) : (baseRadius - tileMaxRadius))\n                : 0;\n            const embedFloor = Math.max(0.5, height * 0.15);\n            const embedFromTile = Math.max(tileMaxRadius - tileMinRadius + 0.5, embedFloor);\n            const effectiveEmbed = Math.max(Number.isFinite(embed) ? embed : 0, embedFromTile);\n            const groundR = Math.max(0, tileMaxRadius + surfaceOffset - effectiveEmbed);\n            const topR = tileMaxRadius + surfaceOffset + height;\n            if (!Number.isFinite(groundR) || !Number.isFinite(topR)) continue;\n\n            for (let i = 0; i < footprintCount; i++) {\n                const gIdx = i * 3;\n                const dirX = dirSamples[gIdx];\n                const dirY = dirSamples[gIdx + 1];\n                const dirZ = dirSamples[gIdx + 2];\n                if (!Number.isFinite(dirX) || !Number.isFinite(dirY) || !Number.isFinite(dirZ)) {\n                    invalid = true;\n                    break;\n                }\n                groundVerts[gIdx] = dirX * groundR - cx;\n                groundVerts[gIdx + 1] = dirY * groundR - cy;\n                groundVerts[gIdx + 2] = dirZ * groundR - cz;\n\n                topVerts[gIdx] = dirX * topR - cx;\n                topVerts[gIdx + 1] = dirY * topR - cy;\n                topVerts[gIdx + 2] = dirZ * topR - cz;\n            }\n            if (invalid) continue;\n\n            const baseLen = Math.sqrt(basePos.x * basePos.x + basePos.y * basePos.y + basePos.z * basePos.z) || 1;\n            const baseRx = basePos.x / baseLen;\n            const baseRy = basePos.y / baseLen;\n            const baseRz = basePos.z / baseLen;\n\n            const groundStart = newPositions.length / 3;\n            for (let i = 0; i < groundVerts.length; i++) {\n                newPositions.push(groundVerts[i]);\n            }\n            const topStart = newPositions.length / 3;\n            for (let i = 0; i < topVerts.length; i++) {\n                newPositions.push(topVerts[i]);\n            }\n\n            for (let i = 0; i < footprintCount; i++) {\n                const j = (i + 1) % footprintCount;\n                const g0x = groundVerts[i * 3];\n                const g0y = groundVerts[i * 3 + 1];\n                const g0z = groundVerts[i * 3 + 2];\n                const g1x = groundVerts[j * 3];\n                const g1y = groundVerts[j * 3 + 1];\n                const g1z = groundVerts[j * 3 + 2];\n                const t1x = topVerts[j * 3];\n                const t1y = topVerts[j * 3 + 1];\n                const t1z = topVerts[j * 3 + 2];\n                const t0x = topVerts[i * 3];\n                const t0y = topVerts[i * 3 + 1];\n                const t0z = topVerts[i * 3 + 2];\n\n                const ax = g1x - g0x;\n                const ay = g1y - g0y;\n                const az = g1z - g0z;\n                const bx = t1x - g0x;\n                const by = t1y - g0y;\n                const bz = t1z - g0z;\n                const nx = ay * bz - az * by;\n                const ny = az * bx - ax * bz;\n                const nz = ax * by - ay * bx;\n\n                const edgeLen = Math.sqrt(ax * ax + ay * ay + az * az) || 1;\n                const ex = ax / edgeLen;\n                const ey = ay / edgeLen;\n                const ez = az / edgeLen;\n\n                const midWx = (g0x + g1x) * 0.5 + cx;\n                const midWy = (g0y + g1y) * 0.5 + cy;\n                const midWz = (g0z + g1z) * 0.5 + cz;\n                const midLen = Math.sqrt(midWx * midWx + midWy * midWy + midWz * midWz) || 1;\n                const rx = midWx / midLen;\n                const ry = midWy / midLen;\n                const rz = midWz / midLen;\n\n                const ox = ey * rz - ez * ry;\n                const oy = ez * rx - ex * rz;\n                const oz = ex * ry - ey * rx;\n                const dot = (nx * ox + ny * oy + nz * oz);\n                const flip = backSide ? dot > 0 : dot < 0;\n\n                if (flip) {\n                    newIndices.push(groundStart + i, topStart + j, groundStart + j);\n                    newIndices.push(groundStart + i, topStart + i, topStart + j);\n                } else {\n                    newIndices.push(groundStart + i, groundStart + j, topStart + j);\n                    newIndices.push(groundStart + i, topStart + j, topStart + i);\n                }\n                wallTriangleCount += 2;\n            }\n\n            const roofShape = new Array(footprintCount);\n            for (let i = 0; i < footprintCount; i++) {\n                const pt = footprint[i];\n                roofShape[i] = new THREE.Vector2(pt.x, pt.y);\n            }\n            const roofTris = THREE.ShapeUtils.triangulateShape(roofShape, []);\n            for (const tri of roofTris) {\n                const ax = topVerts[tri[0] * 3];\n                const ay = topVerts[tri[0] * 3 + 1];\n                const az = topVerts[tri[0] * 3 + 2];\n                const bx = topVerts[tri[1] * 3];\n                const by = topVerts[tri[1] * 3 + 1];\n                const bz = topVerts[tri[1] * 3 + 2];\n                const cxp = topVerts[tri[2] * 3];\n                const cyp = topVerts[tri[2] * 3 + 1];\n                const czp = topVerts[tri[2] * 3 + 2];\n\n                const abx = bx - ax;\n                const aby = by - ay;\n                const abz = bz - az;\n                const acx = cxp - ax;\n                const acy = cyp - ay;\n                const acz = czp - az;\n                const nx = aby * acz - abz * acy;\n                const ny = abz * acx - abx * acz;\n                const nz = abx * acy - aby * acx;\n                const dot = (nx * baseRx + ny * baseRy + nz * baseRz);\n                const flip = backSide ? dot > 0 : dot < 0;\n                if (flip) {\n                    newIndices.push(topStart + tri[0], topStart + tri[2], topStart + tri[1]);\n                } else {\n                    newIndices.push(topStart + tri[0], topStart + tri[1], topStart + tri[2]);\n                }\n                roofTriangleCount += 1;\n            }\n        }\n\n        const addedVertexCount = (newPositions.length / 3) - baseCount;\n        if (addedVertexCount <= 0) {\n            if (this._buildingModified) {\n                this._restoreBaseGeometry();\n            }\n            return;\n        }\n\n        // Update geometry buffers\n        const posArray = new Float32Array(newPositions);\n        const idxArray = new Uint32Array(newIndices);\n\n        const posAttr = new THREE.BufferAttribute(posArray, 3);\n        posAttr.setUsage(THREE.DynamicDrawUsage);\n        this.geometry.setAttribute('position', posAttr);\n        this.positionAttr = posAttr;\n\n        this.geometry.setIndex(new THREE.BufferAttribute(idxArray, 1));\n        this.geometry.deleteAttribute('normal');\n\n        this._buildingModified = true;\n        this._buildingVertexCount = addedVertexCount;\n\n        if (debugLogs) {\n            console.log(`[TriTile] Building footprints applied: ${this._buildingVertexCount} vertices added, walls=${wallTriangleCount} tris, roofs=${roofTriangleCount} tris, total indices=${newIndices.length}`);\n        }\n\n        // Reset UV cache\n        this._imageryUvCache = null;\n        this._imageryVertexCount = 0;\n\n        this._ensureBaseUVs();\n        this._ensureWaterMask();\n        this._markGeometryDirty();\n    }\n\n    /**\n     * Restore the tile to its original geometry (remove building modifications)\n     */\n    _restoreBaseGeometry() {\n        if (!this._buildingModified || !this.baseDirs || !this.baseIndexArray) return;\n\n        const baseCount = this.baseVertexCount || this.vertexCount;\n        const cx = this.center.x;\n        const cy = this.center.y;\n        const cz = this.center.z;\n\n        // Restore base positions\n        const posArray = new Float32Array(baseCount * 3);\n        const currentPos = this.positionAttr?.array;\n        if (currentPos && currentPos.length >= baseCount * 3) {\n            posArray.set(currentPos.subarray(0, baseCount * 3));\n        } else {\n            for (let i = 0; i < baseCount; i++) {\n                const i3 = i * 3;\n                const baseRadius = this._getBaseRadiusAtIndex(i);\n                posArray[i3] = this.baseDirs[i3] * baseRadius - cx;\n                posArray[i3 + 1] = this.baseDirs[i3 + 1] * baseRadius - cy;\n                posArray[i3 + 2] = this.baseDirs[i3 + 2] * baseRadius - cz;\n            }\n        }\n\n        const posAttr = new THREE.BufferAttribute(posArray, 3);\n        posAttr.setUsage(THREE.DynamicDrawUsage);\n        this.geometry.setAttribute('position', posAttr);\n        this.positionAttr = posAttr;\n\n        // Restore base indices\n        this.geometry.setIndex(new THREE.BufferAttribute(this.baseIndexArray.slice(), 1));\n        this.geometry.deleteAttribute('normal');\n\n        this._buildingModified = false;\n        this._buildingVertexCount = 0;\n        this._extendedDirs = null;\n\n        this._imageryUvCache = null;\n        this._imageryVertexCount = 0;\n\n        this._ensureBaseUVs();\n        this._ensureWaterMask();\n        this._markGeometryDirty();\n    }\n\n    _ensureBaseUVs() {\n        if (!this.geometry || !this.baseDirs || !this.vertexCount) return;\n\n        const baseCount = this.vertexCount;\n        const totalCount = this.positionAttr?.count || baseCount;\n        const existing = this.geometry.getAttribute('uv');\n        const existingUv2 = this.geometry.getAttribute('uv2');\n        if (existing && existing.count === totalCount) {\n            if (!existingUv2 || existingUv2.count !== totalCount) {\n                const uv2Array = new Float32Array(existing.array.length);\n                uv2Array.set(existing.array);\n                const uv2Attr = new THREE.BufferAttribute(uv2Array, 2);\n                this.geometry.setAttribute('uv2', uv2Attr);\n                uv2Attr.needsUpdate = true;\n            }\n            return;\n        }\n\n        const uvArray = new Float32Array(totalCount * 2);\n        const tmpDir = new THREE.Vector3();\n        let sumSin = 0;\n        let sumCos = 0;\n\n        for (let i = 0; i < baseCount; i++) {\n            const i3 = i * 3;\n            tmpDir.set(this.baseDirs[i3 + 0], this.baseDirs[i3 + 1], this.baseDirs[i3 + 2]);\n            const { lonDeg } = dirToLatLonLocal(tmpDir);\n            const lonRad = THREE.MathUtils.degToRad(lonDeg);\n            sumSin += Math.sin(lonRad);\n            sumCos += Math.cos(lonRad);\n        }\n\n        const refLonRad = Math.atan2(sumSin, sumCos);\n        const refLonDeg = THREE.MathUtils.radToDeg(refLonRad);\n\n        for (let i = 0; i < baseCount; i++) {\n            const i3 = i * 3;\n            tmpDir.set(this.baseDirs[i3 + 0], this.baseDirs[i3 + 1], this.baseDirs[i3 + 2]);\n            const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n            let lon = lonDeg;\n            const delta = lon - refLonDeg;\n            if (delta > 180) lon -= 360;\n            else if (delta < -180) lon += 360;\n\n            const u = (lon + 180) / 360;\n            const v = 1 - (latDeg + 90) / 180;\n            uvArray[i * 2 + 0] = THREE.MathUtils.clamp(u, 0, 1);\n            uvArray[i * 2 + 1] = THREE.MathUtils.clamp(v, 0, 1);\n        }\n\n        if (totalCount > baseCount && this.positionAttr) {\n            const pos = this.positionAttr.array;\n            const cx = this.center.x;\n            const cy = this.center.y;\n            const cz = this.center.z;\n            for (let i = baseCount; i < totalCount; i++) {\n                const i3 = i * 3;\n                const x = pos[i3 + 0] + cx;\n                const y = pos[i3 + 1] + cy;\n                const z = pos[i3 + 2] + cz;\n                tmpDir.set(x, y, z).normalize();\n                const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n                let lon = lonDeg;\n                const delta = lon - refLonDeg;\n                if (delta > 180) lon -= 360;\n                else if (delta < -180) lon += 360;\n\n                const u = (lon + 180) / 360;\n                const v = 1 - (latDeg + 90) / 180;\n                uvArray[i * 2 + 0] = THREE.MathUtils.clamp(u, 0, 1);\n                uvArray[i * 2 + 1] = THREE.MathUtils.clamp(v, 0, 1);\n            }\n        }\n\n        const uvAttr = new THREE.BufferAttribute(uvArray, 2);\n        this.geometry.setAttribute('uv', uvAttr);\n        uvAttr.needsUpdate = true;\n\n        const uv2Array = new Float32Array(uvArray.length);\n        uv2Array.set(uvArray);\n        const uv2Attr = new THREE.BufferAttribute(uv2Array, 2);\n        this.geometry.setAttribute('uv2', uv2Attr);\n        uv2Attr.needsUpdate = true;\n    }\n\n    _ensureWaterMask() {\n        if (!this.geometry) return;\n        const baseCount = this.vertexCount || (this.baseDirs ? this.baseDirs.length / 3 : 0);\n        const totalCount = this.positionAttr?.count || baseCount;\n        if (!totalCount) return;\n\n        const existing = this.geometry.getAttribute('aWaterMask');\n        if (existing && existing.count === totalCount) {\n            this.waterMaskAttr = existing;\n            return;\n        }\n\n        const maskArray = new Float32Array(totalCount);\n        if (existing && existing.array) {\n            const len = Math.min(existing.array.length, maskArray.length);\n            if (len > 0) {\n                maskArray.set(existing.array.subarray(0, len), 0);\n            }\n        }\n\n        const maskAttr = new THREE.BufferAttribute(maskArray, 1);\n        maskAttr.setUsage(THREE.DynamicDrawUsage);\n        this.geometry.setAttribute('aWaterMask', maskAttr);\n        this.waterMaskAttr = maskAttr;\n        maskAttr.needsUpdate = true;\n    }\n\n    setWaterMask(index, value) {\n        if (!Number.isFinite(index) || index < 0) return;\n        if (!this.waterMaskAttr) {\n            this._ensureWaterMask();\n        }\n        if (!this.waterMaskAttr) return;\n        if (index >= this.waterMaskAttr.count) return;\n        const v = Number.isFinite(value) ? THREE.MathUtils.clamp(value, 0, 1) : 0;\n        this.waterMaskAttr.setX(index, v);\n        this.waterMaskAttr.needsUpdate = true;\n        if (this.edgeVertexMask?.[index]) {\n            this._markSkirtDirty();\n        }\n    }\n\n    _resolveSkirtDepthMeters() {\n        if (Number.isFinite(this.skirtDepthMeters) && this.skirtDepthMeters > 0) {\n            return this.skirtDepthMeters;\n        }\n        const spanMeters = Math.max(1, (this.angularRadius || 0) * this.radius * 2);\n        // Fine surface tiles still receive a useful seal, while coarse orbit\n        // tiles avoid planet-scale curtains. This is geometry depth, so apply\n        // the same exaggeration used by terrain elevations.\n        return THREE.MathUtils.clamp(spanMeters * 0.1, 30, 4000) *\n            Math.max(1, ELEVATION_EXAGGERATION);\n    }\n\n    _markSkirtDirty() {\n        if (!this.skirtMesh) return;\n        this._skirtDirty = true;\n        this._queueGeometryFinalize();\n    }\n\n    _ensureSkirtMesh() {\n        if (!this.mesh || !this.geometry || !this.positionAttr || !this.materialDefault) return null;\n        if (this.skirtMesh) {\n            this.skirtMesh.material = this.mesh.material || this.materialDefault;\n            return this.skirtMesh;\n        }\n\n        this.skirtGeometry = new THREE.BufferGeometry();\n        this.skirtMesh = new THREE.Mesh(this.skirtGeometry, this.mesh.material || this.materialDefault);\n        this.skirtMesh.userData.firstDrawGuard = false;\n        this.skirtMesh.name = `tritree-skirt-l${this.level}`;\n        this.skirtMesh.castShadow = false;\n        this.skirtMesh.receiveShadow = true;\n        this.skirtMesh.frustumCulled = true;\n        this.skirtMesh.userData.isTriTreeSkirt = true;\n        // Skirts are a visual seal only. They must never become a camera floor,\n        // placement target, or physics surface.\n        this.skirtMesh.raycast = () => {};\n        this.mesh.add(this.skirtMesh);\n        this._syncSkirtGeometry(true);\n        return this.skirtMesh;\n    }\n\n    _syncSkirtMaterial() {\n        if (this.skirtMesh && this.mesh?.material) {\n            this.skirtMesh.material = this.mesh.material;\n        }\n    }\n\n    _syncSkirtGeometry(forceRebuild = false) {\n        if (!this.skirtGeometry || !this.positionAttr || !this.vertexCount) return false;\n\n        const edgeNames = ['v2v0', 'v0v1', 'v1v2'];\n        const edgeIndices = edgeNames.map((edgeName) => this._edgeVertexIndices(edgeName));\n        const sourceCount = edgeIndices.reduce((sum, edge) => sum + edge.length, 0);\n        const skirtVertexCount = sourceCount * 2;\n        const expectedIndexCount = this.resolution * edgeNames.length * 6;\n        let positionAttr = this.skirtGeometry.getAttribute('position');\n        const rebuild = forceRebuild || !positionAttr || positionAttr.count !== skirtVertexCount;\n\n        if (rebuild) {\n            positionAttr = new THREE.BufferAttribute(new Float32Array(skirtVertexCount * 3), 3);\n            positionAttr.setUsage(THREE.DynamicDrawUsage);\n            this.skirtGeometry.setAttribute('position', positionAttr);\n            this.skirtGeometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(skirtVertexCount * 2), 2));\n            this.skirtGeometry.setAttribute('uv2', new THREE.BufferAttribute(new Float32Array(skirtVertexCount * 2), 2));\n            const waterAttr = new THREE.BufferAttribute(new Float32Array(skirtVertexCount), 1);\n            waterAttr.setUsage(THREE.DynamicDrawUsage);\n            this.skirtGeometry.setAttribute('aWaterMask', waterAttr);\n\n            const indices = new Uint32Array(expectedIndexCount);\n            const sources = new Uint32Array(skirtVertexCount);\n            let vertexOffset = 0;\n            let indexOffset = 0;\n            for (const edge of edgeIndices) {\n                const edgeLength = edge.length;\n                for (let i = 0; i < edgeLength; i++) {\n                    sources[vertexOffset + i] = edge[i];\n                    sources[vertexOffset + edgeLength + i] = edge[i];\n                }\n                for (let i = 0; i < edgeLength - 1; i++) {\n                    const top0 = vertexOffset + i;\n                    const top1 = top0 + 1;\n                    const bottom0 = vertexOffset + edgeLength + i;\n                    const bottom1 = bottom0 + 1;\n                    indices[indexOffset++] = top0;\n                    indices[indexOffset++] = bottom0;\n                    indices[indexOffset++] = top1;\n                    indices[indexOffset++] = top1;\n                    indices[indexOffset++] = bottom0;\n                    indices[indexOffset++] = bottom1;\n                }\n                vertexOffset += edgeLength * 2;\n            }\n            this._skirtSourceIndices = sources;\n            this.skirtGeometry.setIndex(new THREE.BufferAttribute(indices, 1));\n        }\n\n        const sources = this._skirtSourceIndices;\n        if (!sources || sources.length !== skirtVertexCount) return false;\n        const surfacePositions = this.positionAttr.array;\n        const skirtPositions = positionAttr.array;\n        const surfaceUv = this.geometry.getAttribute('uv');\n        const surfaceUv2 = this.geometry.getAttribute('uv2') || surfaceUv;\n        const skirtUv = this.skirtGeometry.getAttribute('uv');\n        const skirtUv2 = this.skirtGeometry.getAttribute('uv2');\n        const surfaceWater = this.geometry.getAttribute('aWaterMask');\n        const skirtWater = this.skirtGeometry.getAttribute('aWaterMask');\n        const depth = this._resolveSkirtDepthMeters();\n        const cx = this.center.x;\n        const cy = this.center.y;\n        const cz = this.center.z;\n\n        for (let i = 0; i < sources.length; i++) {\n            const sourceIndex = sources[i];\n            const source3 = sourceIndex * 3;\n            const target3 = i * 3;\n            const edgeLength = this.resolution + 1;\n            const rowOffset = i % (edgeLength * 2);\n            const isBottom = rowOffset >= edgeLength;\n            const localX = surfacePositions[source3];\n            const localY = surfacePositions[source3 + 1];\n            const localZ = surfacePositions[source3 + 2];\n\n            if (isBottom) {\n                const worldX = localX + cx;\n                const worldY = localY + cy;\n                const worldZ = localZ + cz;\n                const radius = Math.sqrt(worldX * worldX + worldY * worldY + worldZ * worldZ) || 1;\n                const bottomRadius = Math.max(1, radius - depth);\n                const scale = bottomRadius / radius;\n                skirtPositions[target3] = worldX * scale - cx;\n                skirtPositions[target3 + 1] = worldY * scale - cy;\n                skirtPositions[target3 + 2] = worldZ * scale - cz;\n            } else {\n                skirtPositions[target3] = localX;\n                skirtPositions[target3 + 1] = localY;\n                skirtPositions[target3 + 2] = localZ;\n            }\n\n            // Top and bottom use the exact same edge sample. The ribbon thus\n            // continues the edge color vertically with no atlas-color bleed.\n            if (surfaceUv && skirtUv) {\n                skirtUv.setXY(i, surfaceUv.getX(sourceIndex), surfaceUv.getY(sourceIndex));\n            }\n            if (surfaceUv2 && skirtUv2) {\n                skirtUv2.setXY(i, surfaceUv2.getX(sourceIndex), surfaceUv2.getY(sourceIndex));\n            }\n            if (skirtWater) {\n                skirtWater.setX(i, surfaceWater ? surfaceWater.getX(sourceIndex) : 0);\n            }\n        }\n\n        positionAttr.needsUpdate = true;\n        if (skirtUv) skirtUv.needsUpdate = true;\n        if (skirtUv2) skirtUv2.needsUpdate = true;\n        if (skirtWater) skirtWater.needsUpdate = true;\n        this.skirtGeometry.computeVertexNormals();\n        this.skirtGeometry.computeBoundingSphere();\n        this._skirtDirty = false;\n        return true;\n    }\n\n    _disposeSkirtMesh() {\n        if (this.skirtMesh?.parent) {\n            this.skirtMesh.parent.remove(this.skirtMesh);\n        }\n        if (this.skirtGeometry) {\n            this.skirtGeometry.dispose();\n        }\n        // The skirt shares the terrain material; never dispose it here.\n        this.skirtMesh = null;\n        this.skirtGeometry = null;\n        this._skirtSourceIndices = null;\n        this._skirtDirty = false;\n    }\n\n    _updateElevationComplete() {\n        if (!this.vertexCount || this.vertexCount <= 0) {\n            this.elevationComplete = false;\n            return;\n        }\n        const needsFullFetch = this._requiresFullElevationFetch();\n        if (needsFullFetch && this.elevationExpected !== this.vertexCount) {\n            this.elevationExpected = this.vertexCount;\n        }\n        const hasDeferred = this.deferredEdgeElevations && this.deferredEdgeElevations.size > 0;\n        const hasMissing = this._hasMissingElevationVertices();\n        this.elevationComplete = !hasDeferred && !hasMissing;\n    }\n\n    disableElevationHold({ flushPending = true } = {}) {\n        this.elevationHoldUntilComplete = false;\n        if (!flushPending || !this.elevationHoldPending || this.elevationHoldPending.size === 0) {\n            return 0;\n        }\n\n        const allowMorph = this.elevationMorphEnabled && this._ensureElevationMorphBuffers();\n        let directUpdated = 0;\n        for (const [idx, elevMeters] of this.elevationHoldPending.entries()) {\n            if (allowMorph) {\n                this.elevationMorphTarget[idx] = elevMeters;\n                if (!this.elevationMorphPending) this.elevationMorphPending = new Set();\n                this.elevationMorphPending.add(idx);\n            } else {\n                this._applyElevationAtIndex(idx, elevMeters, true);\n                directUpdated += 1;\n            }\n        }\n        const flushed = this.elevationHoldPending.size;\n        this.elevationHoldPending = null;\n\n        if (allowMorph) {\n            this._queueElevationUpdate();\n        } else if (directUpdated > 0) {\n            this._markGeometryDirty();\n        }\n        return flushed;\n    }\n\n    _noteElevationProgress(now = null) {\n        const t = Number.isFinite(now)\n            ? now\n            : ((typeof performance !== 'undefined' && performance.now)\n                ? performance.now()\n                : Date.now());\n        this._elevationLastProgressMs = t;\n        this._elevationLastProgressDone = this.elevationDone;\n        this._elevationStallSinceMs = 0;\n    }\n\n    getElevationReadyRatio() {\n        const count = Number.isFinite(this.vertexCount) ? this.vertexCount : 0;\n        const done = Number.isFinite(this.elevationDone) ? this.elevationDone : 0;\n        const seeded = Number.isFinite(this.elevationSeededCount) ? this.elevationSeededCount : 0;\n        if (this.elevationExpected > 0 && count > 0 && this.elevationExpected >= count) {\n            return done / this.elevationExpected;\n        }\n        if (count > 0) {\n            return Math.min(1, Math.max(done / count, seeded / count));\n        }\n        if (this.elevationExpected > 0) {\n            return done / this.elevationExpected;\n        }\n        if (!this.elevationHasData && seeded === 0) return 0.0;\n        return this.elevationHasData ? 1.0 : 0.0;\n    }\n\n    getElevationFetchStats() {\n        const vertexCount = Number.isFinite(this.vertexCount) ? this.vertexCount : 0;\n        const expected = Number.isFinite(this.elevationExpected) && this.elevationExpected > 0\n            ? this.elevationExpected\n            : vertexCount;\n        const doneRaw = Number.isFinite(this.elevationDone) ? this.elevationDone : 0;\n        const expectedSafe = expected > 0 ? expected : 0;\n        const done = expectedSafe > 0 ? Math.min(doneRaw, expectedSafe) : doneRaw;\n        const ratio = expectedSafe > 0\n            ? done / expectedSafe\n            : (vertexCount > 0 ? Math.min(1, doneRaw / vertexCount) : 0);\n        return {\n            done,\n            expected: expectedSafe,\n            ratio\n        };\n    }\n\n    getElevationVisualStats() {\n        const vertexCount = Number.isFinite(this.vertexCount) ? this.vertexCount : 0;\n        if (vertexCount <= 0) {\n            return { done: 0, total: 0, ratio: 0, seededOnly: 0 };\n        }\n        let seededOnly = 0;\n        if (this.elevationSeeded && this.elevationState) {\n            for (let i = 0; i < vertexCount; i++) {\n                if (this.elevationSeeded[i] === 1 && this.elevationState[i] !== 2) {\n                    seededOnly++;\n                }\n            }\n        } else if (Number.isFinite(this.elevationSeededCount)) {\n            seededOnly = Math.max(0, Math.floor(this.elevationSeededCount));\n        }\n        const done = Number.isFinite(this.elevationDone) ? this.elevationDone : 0;\n        const visualDone = Math.min(vertexCount, done + seededOnly);\n        return {\n            done: visualDone,\n            total: vertexCount,\n            ratio: visualDone / vertexCount,\n            seededOnly\n        };\n    }\n\n    markElevationDone(index) {\n        if (!this.elevationState) return;\n        if (this.elevationState[index] === 2) return;\n        this.elevationState[index] = 2;\n        this.elevationDone += 1;\n        this._updateElevationComplete();\n        this._noteElevationProgress();\n\n        if (this.elevationHoldUntilComplete && this.elevationComplete) {\n            this.disableElevationHold({ flushPending: true });\n            this._queueElevationUpdate();\n        }\n\n        // Trigger automatic stitching callback if set\n        if (typeof this.onElevationUpdate === 'function') {\n            this.onElevationUpdate(this, index);\n        }\n    }\n\n    isElevationComplete() {\n        return !!this.elevationComplete;\n    }\n\n    hasMissingElevation() {\n        if (!this.vertexCount || this.vertexCount <= 0) return false;\n        const hasDeferred = this.deferredEdgeElevations && this.deferredEdgeElevations.size > 0;\n        return hasDeferred || this._hasMissingElevationVertices();\n    }\n\n    _hasMissingElevationVertices() {\n        if (!this.vertexCount || this.vertexCount <= 0) return false;\n        const count = this.vertexCount;\n        const state = this.elevationState;\n        const seeded = this.elevationSeeded;\n        const fillMask = this.elevationFillMask;\n        const edgeCache = this.edgeElevationCache;\n        const deferredEdges = this.deferredEdgeElevations;\n        const needsFullFetch = this._requiresFullElevationFetch();\n\n        for (let i = 0; i < count; i += 1) {\n            if (state && state[i] === 2) continue;\n            if (!needsFullFetch) {\n                if (seeded && seeded[i] === 1) continue;\n                if (fillMask && fillMask[i] === 1) continue;\n                if (edgeCache && edgeCache.has(i)) continue;\n                if (deferredEdges && deferredEdges.has(i)) continue;\n            }\n            return true;\n        }\n        return false;\n    }\n\n    _requiresFullElevationFetch() {\n        if (this.forceFullFetch || this._surfaceForceFullFetch || this._elevForceFetch) return true;\n        if (this.elevationClient && typeof this.elevationClient.isFullFetchTile === 'function') {\n            return this.elevationClient.isFullFetchTile(this);\n        }\n        return false;\n    }\n\n    getCornerPosition(label) {\n        if (!this.positionAttr) return null;\n        const res = this.resolution;\n        if (!Number.isFinite(res) || res < 0) return null;\n        const baseCount = this.vertexCount || (this.baseDirs ? this.baseDirs.length / 3 : 0);\n        // v2 = index 0, v1 = index res, v0 = last\n        let idx = null;\n        if (label === 'v0') {\n            idx = baseCount ? baseCount - 1 : null;\n        } else if (label === 'v1') {\n            idx = res;\n        } else if (label === 'v2') {\n            idx = 0;\n        }\n        if (idx === null || idx < 0) return null;\n        // Positions are stored in local coordinates - add tile center to get world position\n        const x = this.positionAttr.getX(idx) + this.center.x;\n        const y = this.positionAttr.getY(idx) + this.center.y;\n        const z = this.positionAttr.getZ(idx) + this.center.z;\n        return new THREE.Vector3(x, y, z);\n    }\n\n    _getBaseRadiusAtIndex(index) {\n        if (this.baseRadii && index < this.baseRadii.length) {\n            const r = this.baseRadii[index];\n            if (Number.isFinite(r) && r > 0) return r;\n        }\n        if (this.baseDirs && index * 3 + 2 < this.baseDirs.length) {\n            const i3 = index * 3;\n            return ellipsoidRadiusForDir(\n                this.baseDirs[i3 + 0],\n                this.baseDirs[i3 + 1],\n                this.baseDirs[i3 + 2]\n            );\n        }\n        return this.radius;\n    }\n\n    _getBaseRadiusFromWorldPos(x, y, z) {\n        const len = Math.sqrt(x * x + y * y + z * z) || 0;\n        if (!len) return this.radius;\n        return ellipsoidRadiusForDir(x / len, y / len, z / len);\n    }\n\n    _getPhotogramOffsetAtIndex(index) {\n        if (!this.photogramOffsets || !Number.isFinite(index) || index < 0) return 0;\n        const offset = this.photogramOffsets[index];\n        return Number.isFinite(offset) ? offset : 0;\n    }\n\n    _extractElevationFromRadius(index, radius, includePhotogramOffset = false) {\n        if (!Number.isFinite(radius) || radius <= 0) return null;\n        const baseRadius = this._getBaseRadiusAtIndex(index);\n        let elevMeters = elevationFromRadius(radius, baseRadius);\n        if (!includePhotogramOffset) {\n            elevMeters -= this._getPhotogramOffsetAtIndex(index);\n        }\n        return elevMeters;\n    }\n\n    /**\n     * Extract elevation in meters from a vertex position\n     * @param {number} index - Vertex index\n     * @returns {number|null} Elevation in meters, or null if unavailable\n     */\n    getVertexElevationMeters(index, options = null) {\n        if (!this.positionAttr || !Number.isFinite(index) || index < 0) return null;\n        const includePhotogramOffset = !!(options && options.includePhotogramOffset === true);\n        // Positions are stored in local coordinates - add tile center to get world position\n        const x = this.positionAttr.getX(index) + this.center.x;\n        const y = this.positionAttr.getY(index) + this.center.y;\n        const z = this.positionAttr.getZ(index) + this.center.z;\n        const r = Math.sqrt(x * x + y * y + z * z);\n        return this._extractElevationFromRadius(index, r, includePhotogramOffset);\n    }\n\n    _sampleElevationRange(values, t0, t1) {\n        if (!Array.isArray(values) || values.length < 2) return values || [];\n        const start = Math.min(t0, t1);\n        const end = Math.max(t0, t1);\n        const clampedStart = Math.max(0, Math.min(1, start));\n        const clampedEnd = Math.max(0, Math.min(1, end));\n        const span = Math.max(0, clampedEnd - clampedStart);\n        if (span <= 0) return [values[0], values[values.length - 1]];\n        const rawCount = (values.length - 1) * span;\n        const count = Math.max(2, Math.round(rawCount) + 1);\n        const out = new Array(count);\n        for (let i = 0; i < count; i++) {\n            const t = count === 1 ? 0 : (i / (count - 1));\n            const pos = (clampedStart + span * t) * (values.length - 1);\n            const i0 = Math.floor(pos);\n            const i1 = Math.min(i0 + 1, values.length - 1);\n            const tt = pos - i0;\n            out[i] = values[i0] * (1 - tt) + values[i1] * tt;\n        }\n        return out;\n    }\n\n    /**\n     * Reset elevation-aware edge cache, restoring original authentic elevations\n     */\n    resetEdgeElevationCache() {\n        if (!this.edgeElevationCache || this.edgeElevationCache.size === 0) return;\n        if (!this.positionAttr) return;\n\n        for (const [idx, cache] of this.edgeElevationCache.entries()) {\n            if (!cache.isVirtual) continue; // Only restore virtual positions\n\n            // Restore original position directly\n            this.positionAttr.setXYZ(idx, cache.originalX, cache.originalY, cache.originalZ);\n        }\n\n        this.positionAttr.needsUpdate = true;\n        if (this.geometry) {\n            this.geometry.computeVertexNormals();\n            this.geometry.computeBoundingSphere();\n        }\n\n        this.edgeElevationCache.clear();\n        this.stitchedEdges.clear();\n    }\n\n    clearSeamEdgeCache(activeMask = 0) {\n        if (!this.edgeElevationCache || this.edgeElevationCache.size === 0) return 0;\n        if (!this.positionAttr) return 0;\n\n        const maskArr = this.edgeVertexMask;\n        let cleared = 0;\n\n        for (const [idx, cache] of this.edgeElevationCache.entries()) {\n            if (!cache || cache.reason !== 'seam-cross-lod') continue;\n            const mask = maskArr && idx < maskArr.length ? maskArr[idx] : 0;\n            if (mask && (mask & activeMask)) continue;\n\n            if (Number.isFinite(cache.originalX) &&\n                Number.isFinite(cache.originalY) &&\n                Number.isFinite(cache.originalZ)) {\n                this.positionAttr.setXYZ(idx, cache.originalX, cache.originalY, cache.originalZ);\n            } else if (Number.isFinite(cache.originalElevMeters) && this.baseDirs) {\n                const i3 = idx * 3;\n                const bx = this.baseDirs[i3 + 0];\n                const by = this.baseDirs[i3 + 1];\n                const bz = this.baseDirs[i3 + 2];\n                const baseRadius = this._getBaseRadiusAtIndex(idx);\n                const r = radiusFromElevation(baseRadius, cache.originalElevMeters);\n                // Store in local coordinates (relative to tile center)\n                this.positionAttr.setXYZ(idx, bx * r - this.center.x, by * r - this.center.y, bz * r - this.center.z);\n            }\n\n            this.edgeElevationCache.delete(idx);\n            cleared++;\n        }\n\n        if (cleared > 0) {\n            this._markGeometryDirty();\n        }\n\n        return cleared;\n    }\n\n    clearSameLodSeamCache(activeMask = 0) {\n        if (!this.edgeElevationCache || this.edgeElevationCache.size === 0) return 0;\n        if (!this.positionAttr) return 0;\n\n        const maskArr = this.edgeVertexMask;\n        let cleared = 0;\n        for (const [idx, cache] of this.edgeElevationCache.entries()) {\n            if (!cache || cache.reason !== 'seam-same-lod') continue;\n            const mask = maskArr && idx < maskArr.length ? maskArr[idx] : 0;\n            if (mask && (mask & activeMask)) continue;\n\n            if (Number.isFinite(cache.originalX) &&\n                Number.isFinite(cache.originalY) &&\n                Number.isFinite(cache.originalZ)) {\n                this.positionAttr.setXYZ(idx, cache.originalX, cache.originalY, cache.originalZ);\n            } else if (Number.isFinite(cache.originalElevMeters) && this.baseDirs) {\n                const i3 = idx * 3;\n                const bx = this.baseDirs[i3 + 0];\n                const by = this.baseDirs[i3 + 1];\n                const bz = this.baseDirs[i3 + 2];\n                const baseRadius = this._getBaseRadiusAtIndex(idx);\n                const r = radiusFromElevation(baseRadius, cache.originalElevMeters);\n                // Store in local coordinates (relative to tile center)\n                this.positionAttr.setXYZ(idx, bx * r - this.center.x, by * r - this.center.y, bz * r - this.center.z);\n            }\n\n            this.edgeElevationCache.delete(idx);\n            cleared++;\n        }\n\n        if (cleared > 0) {\n            this._markGeometryDirty();\n        }\n\n        return cleared;\n    }\n\n    /**\n     * Create a snapshot of current ground-truth elevations before stitching.\n     * This preserves authentic elevation data so that coarse edges can be read\n     * without getting already-stitched virtual elevations.\n     *\n     * @returns {boolean} True if snapshot was created successfully\n     */\n    createBaseElevationSnapshot() {\n        if (!this.positionAttr) {\n            if (DEBUG_LOGS) {\n                console.warn('[TriTile] Cannot create base elevation snapshot - no geometry built');\n            }\n            return false;\n        }\n\n        const count = this.vertexCount || (this.baseDirs ? this.baseDirs.length / 3 : 0);\n        if (!count || count === 0) {\n            if (DEBUG_LOGS) {\n                console.warn('[TriTile] Cannot create base elevation snapshot - no vertices');\n            }\n            return false;\n        }\n\n        // Allocate or reuse array\n        if (!this.baseElevations || this.baseElevations.length !== count) {\n            this.baseElevations = new Float32Array(count);\n        }\n\n        // Snapshot current elevations\n        for (let i = 0; i < count; i++) {\n            const cache = this.edgeElevationCache ? this.edgeElevationCache.get(i) : null;\n            const useOriginal = cache && cache.lockMode !== 'hard' && Number.isFinite(cache.originalElevMeters);\n            const elev = useOriginal ? cache.originalElevMeters : this.getVertexElevationMeters(i);\n            this.baseElevations[i] = (elev !== null && Number.isFinite(elev)) ? elev : 0;\n        }\n\n        if (DEBUG_LOGS) {\n            console.log(`[TriTile] Created base elevation snapshot for ${count} vertices (tile level ${this.level})`);\n        }\n        return true;\n    }\n\n    _edgeVertexIndices(edgeName) {\n        const res = this.resolution;\n        if (!Number.isFinite(res) || res <= 0) return [];\n        const getIndex = (i, j) => {\n            let idx = 0;\n            for (let ii = 0; ii < i; ii++) idx += (res - ii + 1);\n            return idx + j;\n        };\n        const indices = [];\n        if (edgeName === 'v2v0') {\n            for (let i = 0; i <= res; i++) indices.push(getIndex(i, 0));\n        } else if (edgeName === 'v0v1') {\n            for (let i = 0; i <= res; i++) {\n                const j = res - i;\n                indices.push(getIndex(i, j));\n            }\n        } else if (edgeName === 'v2v1' || edgeName === 'v1v2') {\n            for (let j = 0; j <= res; j++) indices.push(getIndex(0, j));\n        }\n        return indices;\n    }\n\n    _buildEdgeVertexMask() {\n        const count = this.vertexCount || 0;\n        if (!count) {\n            this.edgeVertexMask = null;\n            return;\n        }\n        const mask = new Uint8Array(count);\n        const edges = [\n            ['v2v0', 1],\n            ['v0v1', 2],\n            ['v1v2', 4]\n        ];\n        for (const [edgeName, bit] of edges) {\n            const indices = this._edgeVertexIndices(edgeName);\n            for (const idx of indices) {\n                mask[idx] |= bit;\n            }\n        }\n        this.edgeVertexMask = mask;\n    }\n\n    _edgeMaskHasLowerNeighbor(mask) {\n        if (!mask) return false;\n        if (!this.treeManager || !this.treeManager._inSurfaceMode) return false;\n\n        const checkEdge = (edgeName) => {\n            const tm = this.treeManager;\n            if (tm && typeof tm.getEdgeNeighborInfos === 'function') {\n                const infos = tm.getEdgeNeighborInfos(this, edgeName);\n                if (infos && infos.length) {\n                    for (const info of infos) {\n                        const neighbor = info && info.tile;\n                        if (neighbor && typeof neighbor.level === 'number' && neighbor.level < this.level) {\n                            return true;\n                        }\n                    }\n                    return false;\n                }\n            }\n            const neighbor = this.neighbors ? this.neighbors.get(edgeName) : null;\n            return !!(neighbor && typeof neighbor.level === 'number' && neighbor.level < this.level);\n        };\n\n        if ((mask & 1) && checkEdge('v2v0')) return true;\n        if ((mask & 2) && checkEdge('v0v1')) return true;\n        if ((mask & 4) && checkEdge('v1v2')) return true;\n        return false;\n    }\n\n    _shouldDeferEdgeUpdate(index) {\n        // Edge deferral disabled: apply raw tile elevation immediately.\n        return false;\n    }\n\n    /**\n     * Get normalized corner IDs for an edge (for orientation matching).\n     * Returns corner IDs in the native order that _edgeVertexIndices returns.\n     *\n     * @param {string} edgeName - Edge name (v2v0, v0v1, v2v1)\n     * @returns {[string, string]} Array of [startCornerId, endCornerId]\n     */\n    _getEdgeCornerIds(edgeName) {\n        // Hash a corner vector to a consistent string ID\n        const hashCorner = (v) => {\n            const nx = Math.round(v.x * 1000) / 1000;\n            const ny = Math.round(v.y * 1000) / 1000;\n            const nz = Math.round(v.z * 1000) / 1000;\n            return `${nx},${ny},${nz}`;\n        };\n\n        // Return corner IDs in the order that _edgeVertexIndices traverses\n        if (edgeName === 'v2v0') {\n            return [hashCorner(this.v2), hashCorner(this.v0)]; // v2 -> v0\n        } else if (edgeName === 'v0v1') {\n            return [hashCorner(this.v0), hashCorner(this.v1)]; // v0 -> v1 (Note: indices go v1->v0 but we use geometric order)\n        } else if (edgeName === 'v2v1' || edgeName === 'v1v2') {\n            return [hashCorner(this.v2), hashCorner(this.v1)]; // v2 -> v1\n        }\n\n        return [null, null];\n    }\n\n    /**\n     * Check if this tile violates the 1-LOD constraint with any neighbor.\n     * Returns true if any neighbor is more than 1 level different.\n     */\n    violatesLODConstraint() {\n        for (const neighbor of this.neighbors.values()) {\n            if (!neighbor || typeof neighbor.level !== 'number') continue;\n            const levelDiff = Math.abs(this.level - neighbor.level);\n            if (levelDiff > 1) return true;\n        }\n        return false;\n    }\n\n    /**\n     * Get the maximum neighbor level across all edges.\n     * Used to determine if this tile needs to subdivide to maintain constraints.\n     */\n    getMaxNeighborLevel() {\n        let maxLevel = -1;\n        for (const neighbor of this.neighbors.values()) {\n            if (!neighbor || typeof neighbor.level !== 'number') continue;\n            maxLevel = Math.max(maxLevel, neighbor.level);\n        }\n        return maxLevel;\n    }\n\n    /**\n     * Check if this tile should be forced to subdivide due to neighbor constraints.\n     * A tile must subdivide if any neighbor is 2+ levels higher.\n     */\n    needsConstraintSubdivision() {\n        const maxNeighborLevel = this.getMaxNeighborLevel();\n        if (maxNeighborLevel < 0) return false;\n        return (maxNeighborLevel - this.level) >= 2;\n    }\n\n    /**\n     * Calculate elevation data completeness for a specific edge\n     * Returns percentage of edge vertices that have real elevation data (elevationState === 2)\n     * @param {string} edgeName - Edge name ('AB', 'BC', 'CA')\n     * @returns {number} Completeness ratio 0.0 to 1.0 (1.0 = all vertices have real data)\n     */\n    getEdgeElevationCompleteness(edgeName) {\n        if (!this.elevationState) return 0.0;\n\n        const indices = this._edgeVertexIndices(edgeName);\n        if (!indices || indices.length === 0) return 0.0;\n\n        let fetchedCount = 0;\n        for (const idx of indices) {\n            // elevationState[idx] === 2 means elevation data received from server\n            if (this.elevationState[idx] === 2) {\n                fetchedCount++;\n            }\n        }\n\n        return fetchedCount / indices.length;\n    }\n\n    /**\n     * Get overall tile elevation completeness (all vertices)\n     * @returns {number} Completeness ratio 0.0 to 1.0\n     */\n    getTileElevationCompleteness() {\n        if (!this.elevationState || !this.vertexCount) return 0.0;\n\n        let fetchedCount = 0;\n        for (let i = 0; i < this.vertexCount; i++) {\n            if (this.elevationState[i] === 2) {\n                fetchedCount++;\n            }\n        }\n\n        return fetchedCount / this.vertexCount;\n    }\n\n    /**\n     * Extract elevation data (in meters) from edge vertex positions\n     * This is the CORRECT way to get elevation for stitching - extract from authority tile\n     * and send through updateVertex() on subordinate tile\n     *\n     * @param {string} edgeName - 'v0v1' | 'v1v2' | 'v2v0'\n     * @returns {Array<number>} Array of elevation values in meters for each edge vertex\n     */\n    getEdgeElevations(edgeName, options = {}) {\n        if (!this.positionAttr || !this.baseDirs) return [];\n\n        const indices = this._edgeVertexIndices(edgeName);\n        if (!indices || indices.length === 0) return [];\n\n        const elevations = [];\n        const pos = this.positionAttr.array;\n        const hasState = !!this.elevationState;\n        // Positions are stored in local coordinates - add tile center\n        const cx = this.center.x;\n        const cy = this.center.y;\n        const cz = this.center.z;\n\n        for (const idx of indices) {\n            const cache = this.edgeElevationCache ? this.edgeElevationCache.get(idx) : null;\n            if (cache && cache.lockMode !== 'hard' && Number.isFinite(cache.originalElevMeters)) {\n                elevations.push(cache.originalElevMeters);\n                continue;\n            }\n\n            if (hasState && this.elevationState[idx] === 2) {\n                const i3 = idx * 3;\n                const x = pos[i3 + 0] + cx;\n                const y = pos[i3 + 1] + cy;\n                const z = pos[i3 + 2] + cz;\n\n                // Calculate radius from position\n                const r = Math.sqrt(x * x + y * y + z * z) || this.radius;\n\n                // Convert radius to elevation in meters\n                // This reverses the calculation in updateVertex()\n                const elevMeters = this._extractElevationFromRadius(idx, r, false);\n                elevations.push(Number.isFinite(elevMeters) ? elevMeters : 0);\n                continue;\n            }\n\n            const fallback = this.getVertexElevationMeters(idx);\n            elevations.push(Number.isFinite(fallback) ? fallback : 0);\n        }\n\n        const canonical = options && options.canonical;\n        const range = options && options.range;\n        let output = elevations;\n        if (canonical && getEdgeIndexReversed(edgeName)) {\n            output = elevations.slice().reverse();\n        }\n        if (range && Number.isFinite(range.t0) && Number.isFinite(range.t1)) {\n            output = this._sampleElevationRange(output, range.t0, range.t1);\n        }\n        return output;\n    }\n\n    /**\n     * Apply edge elevations from authority tile through proper elevation data system\n     * This is the CORRECT stitching approach - inject mock/proxy elevation data\n     * instead of directly manipulating vertex positions\n     *\n     * @param {string} edgeName - 'v0v1' | 'v1v2' | 'v2v0'\n     * @param {Array<number>} authorityElevations - Elevation values in meters from authority tile\n     * @param {object} neighborInfo - Info about the neighbor tile (for tracking)\n     * @returns {number} Number of vertices updated\n     */\n    applyEdgeElevations(edgeName, authorityElevations, neighborInfo = null) {\n        if (!this.positionAttr || !authorityElevations || authorityElevations.length === 0) return 0;\n\n        const indices = this._edgeVertexIndices(edgeName);\n        if (!indices || indices.length === 0) return 0;\n\n        const nFine = indices.length;\n        const nAuthority = authorityElevations.length;\n\n        if (nAuthority < 2 || nFine < 2) return 0;\n\n        const lockMode = neighborInfo && neighborInfo.lockMode ? neighborInfo.lockMode : 'soft';\n        const stitchReason = neighborInfo && neighborInfo.reason ? neighborInfo.reason : null;\n        const blendAlpha = neighborInfo && Number.isFinite(neighborInfo.blendAlpha)\n            ? Math.min(1, Math.max(0, neighborInfo.blendAlpha))\n            : 1;\n        const hasState = !!this.elevationState;\n\n        // Track stitched edge for reference\n        if (neighborInfo) {\n            this.stitchedEdges.set(edgeName, neighborInfo);\n        }\n\n        let updatedCount = 0;\n\n        // For each vertex on this tile's edge, interpolate elevation from authority data\n        for (let n = 0; n < nFine; n++) {\n            const idx = indices[n];\n            if (lockMode !== 'hard' && hasState && this.elevationState[idx] === 2) {\n                continue;\n            }\n\n            // Parameter along edge (0 to 1)\n            const t = n / (nFine - 1);\n\n            // Find which authority segment we're in\n            const pos_t = t * (nAuthority - 1);\n            const i0 = Math.floor(pos_t);\n            const i1 = Math.min(i0 + 1, nAuthority - 1);\n            const tt = pos_t - i0;\n\n            // Interpolate elevation from authority tile\n            let elevMeters;\n            if (n === 0) {\n                elevMeters = authorityElevations[0];\n            } else if (n === nFine - 1) {\n                elevMeters = authorityElevations[nAuthority - 1];\n            } else {\n                // Linear interpolation between consecutive authority elevations\n                elevMeters = authorityElevations[i0] * (1 - tt) + authorityElevations[i1] * tt;\n            }\n\n            if (blendAlpha < 1) {\n                if (!this.baseElevations) {\n                    this.createBaseElevationSnapshot();\n                }\n                let baseElev = Number.isFinite(this.baseElevations?.[idx])\n                    ? this.baseElevations[idx]\n                    : this.getVertexElevationMeters(idx);\n                if (!Number.isFinite(baseElev)) baseElev = 0;\n                elevMeters = baseElev * (1 - blendAlpha) + elevMeters * blendAlpha;\n            }\n\n            if (!this.edgeElevationCache) this.edgeElevationCache = new Map();\n            let cache = this.edgeElevationCache.get(idx);\n            if (!cache) {\n                const ox = this.positionAttr.getX(idx);\n                const oy = this.positionAttr.getY(idx);\n                const oz = this.positionAttr.getZ(idx);\n                const originalElev = this.getVertexElevationMeters(idx);\n                cache = {\n                    originalX: ox,\n                    originalY: oy,\n                    originalZ: oz,\n                    originalElevMeters: Number.isFinite(originalElev) ? originalElev : null,\n                    isVirtual: false,\n                    lockMode,\n                    reason: stitchReason\n                };\n                this.edgeElevationCache.set(idx, cache);\n            } else {\n                cache.lockMode = lockMode;\n                if (stitchReason && !cache.reason) {\n                    cache.reason = stitchReason;\n                }\n                if (!Number.isFinite(cache.originalElevMeters)) {\n                    const originalElev = this.getVertexElevationMeters(idx);\n                    if (Number.isFinite(originalElev)) {\n                        cache.originalElevMeters = originalElev;\n                    }\n                }\n            }\n\n            // CRITICAL: Apply elevation through updateVertex(), NOT direct position manipulation\n            // This ensures elevation goes through the proper elevation data system\n            this.updateVertex(idx, elevMeters, false); // false = don't mark as done (it's proxy data)\n            cache.isVirtual = true;\n\n            updatedCount++;\n        }\n\n        // updateVertex() already marks this geometry dirty. Normals, bounds,\n        // and the visual skirt are finalized by TriTreeManager's bounded\n        // geometry queue; never make an edge stitch a synchronous frame stall.\n        if (updatedCount > 0) this._markGeometryDirty();\n\n        if (DEBUG_LOGS) {\n            console.log(`[TriTile] Edge ${edgeName} stitched with elevation data: ${updatedCount} vertices updated (${nFine} fine, ${nAuthority} authority)`);\n        }\n        return updatedCount;\n    }\n\n    applySeamSnap(index, elevMeters, reason = 'seam-same-lod') {\n        if (!this.positionAttr || !this.baseDirs) return false;\n        if (!Number.isFinite(index) || index < 0) return false;\n        if (!Number.isFinite(elevMeters)) return false;\n\n        if (!this.edgeElevationCache) this.edgeElevationCache = new Map();\n        let cache = this.edgeElevationCache.get(index);\n        if (!cache) {\n            const ox = this.positionAttr.getX(index);\n            const oy = this.positionAttr.getY(index);\n            const oz = this.positionAttr.getZ(index);\n            const originalElev = this.getVertexElevationMeters(index);\n            cache = {\n                originalX: ox,\n                originalY: oy,\n                originalZ: oz,\n                originalElevMeters: Number.isFinite(originalElev) ? originalElev : null,\n                isVirtual: true,\n                lockMode: 'soft',\n                reason\n            };\n            this.edgeElevationCache.set(index, cache);\n        } else {\n            cache.lockMode = cache.lockMode || 'soft';\n            if (reason && !cache.reason) {\n                cache.reason = reason;\n            }\n            if (!Number.isFinite(cache.originalElevMeters)) {\n                const originalElev = this.getVertexElevationMeters(index);\n                if (Number.isFinite(originalElev)) {\n                    cache.originalElevMeters = originalElev;\n                }\n            }\n        }\n\n        this._applyElevationAtIndex(index, elevMeters, true);\n        return true;\n    }\n\n    retryRegisterMissingVertices(maxPerCall = 64) {\n        if (!this.elevationClient || !this.baseDirs || !this.elevationState) return 0;\n\n        const fullFetch = typeof this.elevationClient.isFullFetchTile === 'function' &&\n            this.elevationClient.isFullFetchTile(this);\n        const res = this.resolution;\n        const count = this.vertexCount;\n        if (!count) return 0;\n\n        const tmpDir = new THREE.Vector3();\n        let registered = 0;\n        let checked = 0;\n        let idx = this.elevationRetryIndex || 0;\n\n        // For full-fetch tiles, ensure expected count is set to total vertices\n        if (fullFetch && this.elevationExpected !== count) {\n            this.elevationExpected = count;\n            this._updateElevationComplete();\n        }\n\n        while (checked < count && registered < maxPerCall) {\n            const state = this.elevationState[idx];\n            // Retry vertices in unregistered state (0) OR registered state (1)\n            // that lost their backing record due memory pressure/rebuild.\n            if (state === 0 || state === 1) {\n                const i3 = idx * 3;\n                tmpDir.set(this.baseDirs[i3 + 0], this.baseDirs[i3 + 1], this.baseDirs[i3 + 2]);\n                const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n                const hasRecord = (state === 1 &&\n                    typeof this.elevationClient.hasVertexRecord === 'function')\n                    ? this.elevationClient.hasVertexRecord(latDeg, lonDeg)\n                    : false;\n                const needsRegistration = (state === 0) || (state === 1 && !hasRecord);\n                if (needsRegistration) {\n                    // For non-full-fetch, only retry vertices that should be registered.\n                    if (fullFetch || this.elevationClient.shouldRegisterVertex(this, idx, res)) {\n                        const ok = this.elevationClient.registerVertex(latDeg, lonDeg, tmpDir, this, idx);\n                        if (ok) {\n                            if (this.elevationState[idx] !== 2) {\n                                this.elevationState[idx] = 1;\n                            }\n                            registered++;\n                        } else if (this.elevationState[idx] === 2) {\n                            registered++;\n                        }\n                    }\n                }\n            }\n            idx = (idx + 1) % count;\n            checked++;\n        }\n\n        this.elevationRetryIndex = idx;\n        if (registered > 0 && this.elevationExpected === 0) {\n            // Recalculate expected count based on what should be registered\n            let intendedCount = 0;\n            for (let i = 0; i < count; i++) {\n                if (fullFetch || this.elevationClient.shouldRegisterVertex(this, i, res)) {\n                    intendedCount++;\n                }\n            }\n            this.elevationExpected = intendedCount;\n            this._updateElevationComplete();\n        }\n        return registered;\n    }\n\n    _seedHeightsFromParent() {\n        if (!this.parent) return;\n        if (!this.positionAttr || !this.baseDirs) return;\n\n        const parent = this.parent;\n        const parentRes = parent.elevationCache?.res || parent.resolution;\n        if (!parentRes) return;\n        if (!parent.positionAttr && !parent.elevationCache) return;\n\n        const childSlot = this._getChildSlot();\n        if (childSlot < 0 || childSlot > 3) return;\n\n        const res = this.resolution;\n        const count = this.vertexCount;\n        if (!count) return;\n\n        let idx = 0;\n        for (let i = 0; i <= res; i++) {\n            for (let j = 0; j <= res - i; j++) {\n                if (this.elevationSeeded && this.elevationSeeded[idx] === 1) {\n                    idx++;\n                    continue;\n                }\n                const k = res - i - j;\n                const w0 = i / res;\n                const w1 = j / res;\n                const w2 = k / res;\n\n                const mapped = this._mapChildWeightsToParent(childSlot, w0, w1, w2);\n                if (!mapped) {\n                    idx++;\n                    continue;\n                }\n\n                const elev = this._sampleParentElevation(parent, mapped.p0, mapped.p1, mapped.p2, parentRes);\n                if (Number.isFinite(elev)) {\n                    // Seeding is visual only; never mark as fetched.\n                    this._seedVertexHeight(idx, elev, { markDone: false });\n                }\n                idx++;\n            }\n        }\n    }\n\n    _seedHeightsFromCache() {\n        if (!this.positionAttr || !this.baseDirs) return;\n        const cache = this.elevationCache;\n        if (!cache || !cache.heights || !cache.heights.length) return;\n        if (Number.isFinite(cache.res) && cache.res !== this.resolution) return;\n\n        const heights = cache.heights;\n        const valid = cache.valid;\n        const done = cache.done;\n        const count = Math.min(this.vertexCount || 0, heights.length);\n        if (!count) return;\n        if (valid && valid.length >= count) {\n            let validCount = 0;\n            for (let i = 0; i < count; i++) {\n                if (valid[i] === 1) validCount++;\n            }\n            if (validCount !== count) {\n                return;\n            }\n        } else {\n            return;\n        }\n\n        for (let i = 0; i < count; i++) {\n            if (valid && valid[i] !== 1) continue;\n            if (this.elevationSeeded && this.elevationSeeded[i] === 1) continue;\n            const elev = heights[i];\n            if (!Number.isFinite(elev)) continue;\n            const markDone = done ? done[i] === 1 : false;\n            this._seedVertexHeight(i, elev, { markDone });\n        }\n    }\n\n    primeElevationFromClientCache({ markDone = true, maxSamples = null } = {}) {\n        if (!this.elevationClient || typeof this.elevationClient.getCachedElevationMeters !== 'function') {\n            return 0;\n        }\n        if (!this.positionAttr || !this.baseDirs || !this.elevationState) return 0;\n        const count = this.vertexCount || 0;\n        if (!count) return 0;\n\n        const limit = Number.isFinite(maxSamples)\n            ? Math.max(0, Math.floor(maxSamples))\n            : Infinity;\n        if (limit <= 0) return 0;\n\n        const fullFetch = this._requiresFullElevationFetch();\n        const res = this.resolution;\n        const tmpDir = this._primeElevTmpDir || (this._primeElevTmpDir = new THREE.Vector3());\n        let applied = 0;\n\n        for (let i = 0; i < count; i += 1) {\n            if (applied >= limit) break;\n            if (this.elevationState[i] === 2) continue;\n            if (!fullFetch &&\n                this.elevationClient?.shouldRegisterVertex &&\n                !this.elevationClient.shouldRegisterVertex(this, i, res)) {\n                continue;\n            }\n\n            const i3 = i * 3;\n            tmpDir.set(this.baseDirs[i3 + 0], this.baseDirs[i3 + 1], this.baseDirs[i3 + 2]);\n            const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n            const elev = this.elevationClient.getCachedElevationMeters(latDeg, lonDeg);\n            if (!Number.isFinite(elev)) continue;\n\n            this._seedVertexHeight(i, elev, { markDone: !!markDone });\n            applied += 1;\n        }\n\n        if (applied > 0) {\n            this._updateElevationComplete();\n            this._noteElevationProgress();\n            const inSurfaceMode = !!this.treeManager?._inSurfaceMode;\n            if (inSurfaceMode && this.elevationHoldUntilComplete && typeof this.disableElevationHold === 'function') {\n                this.disableElevationHold({ flushPending: true });\n            }\n        }\n\n        return applied;\n    }\n\n    _initElevationMorphBuffers() {\n        if (!this.elevationMorphEnabled) return;\n        if (!this.positionAttr || !this.baseDirs) return;\n        const count = this.vertexCount || 0;\n        if (!count) return;\n        if (!this.elevationMorphCurrent || this.elevationMorphCurrent.length !== count) {\n            this.elevationMorphCurrent = new Float32Array(count);\n        }\n        if (!this.elevationMorphTarget || this.elevationMorphTarget.length !== count) {\n            this.elevationMorphTarget = new Float32Array(count);\n        }\n\n        const pos = this.positionAttr.array;\n        // Positions are stored in local coordinates - add tile center to compute radius\n        const cx = this.center.x;\n        const cy = this.center.y;\n        const cz = this.center.z;\n        for (let i = 0; i < count; i++) {\n            const x = pos[i * 3 + 0] + cx;\n            const y = pos[i * 3 + 1] + cy;\n            const z = pos[i * 3 + 2] + cz;\n            const r = Math.sqrt(x * x + y * y + z * z) || this.radius;\n            const elev = this._extractElevationFromRadius(i, r, false);\n            const safeElev = Number.isFinite(elev) ? elev : 0;\n            this.elevationMorphCurrent[i] = safeElev;\n            this.elevationMorphTarget[i] = safeElev;\n        }\n        this.elevationMorphPending = null;\n    }\n\n    _ensureElevationMorphBuffers() {\n        if (!this.elevationMorphEnabled) return false;\n        const count = this.vertexCount || 0;\n        if (!count || !this.positionAttr || !this.baseDirs) return false;\n        if (!this.elevationMorphCurrent || this.elevationMorphCurrent.length !== count ||\n            !this.elevationMorphTarget || this.elevationMorphTarget.length !== count) {\n            this._initElevationMorphBuffers();\n        }\n        return !!(this.elevationMorphCurrent && this.elevationMorphTarget);\n    }\n\n    _getChildSlot() {\n        if (!this.parent) return -1;\n        return this.index - this.parent.index * 4;\n    }\n\n    _mapChildWeightsToParent(childSlot, w0, w1, w2) {\n        if (childSlot === 0) {\n            return {\n                p0: 0.5 * w0 + 0.5 * w2,\n                p1: 0.5 * w0 + 0.5 * w1,\n                p2: 0.5 * w1 + 0.5 * w2\n            };\n        }\n        if (childSlot === 1) {\n            return {\n                p0: w0 + 0.5 * w1 + 0.5 * w2,\n                p1: 0.5 * w1,\n                p2: 0.5 * w2\n            };\n        }\n        if (childSlot === 2) {\n            return {\n                p0: 0.5 * w2,\n                p1: w0 + 0.5 * w1 + 0.5 * w2,\n                p2: 0.5 * w1\n            };\n        }\n        if (childSlot === 3) {\n            return {\n                p0: 0.5 * w1,\n                p1: 0.5 * w2,\n                p2: w0 + 0.5 * w1 + 0.5 * w2\n            };\n        }\n        return null;\n    }\n\n    _mapParentWeightsToChild(childSlot, p0, p1, p2) {\n        if (childSlot === 0) {\n            return {\n                c0: p0 + p1 - p2,\n                c1: -p0 + p1 + p2,\n                c2: p0 - p1 + p2\n            };\n        }\n        if (childSlot === 1) {\n            return {\n                c0: 1 - 2 * (p1 + p2),\n                c1: 2 * p1,\n                c2: 2 * p2\n            };\n        }\n        if (childSlot === 2) {\n            return {\n                c0: 1 - 2 * (p0 + p2),\n                c1: 2 * p2,\n                c2: 2 * p0\n            };\n        }\n        if (childSlot === 3) {\n            return {\n                c0: 1 - 2 * (p0 + p1),\n                c1: 2 * p0,\n                c2: 2 * p1\n            };\n        }\n        return null;\n    }\n\n    _sampleParentElevation(parent, p0, p1, p2, parentRes) {\n        const i = p0 * parentRes;\n        const j = p1 * parentRes;\n        let i0 = Math.floor(i);\n        let j0 = Math.floor(j);\n        if (i0 < 0 || j0 < 0) return null;\n        if (i0 + j0 > parentRes) {\n            const overflow = i0 + j0 - parentRes;\n            j0 = Math.max(0, j0 - overflow);\n        }\n\n        const fi = i - i0;\n        const fj = j - j0;\n        const maxI = parentRes - 1;\n        const maxJ = parentRes - 1;\n\n        const idxA = this._indexFromIJ(i0, j0, parentRes);\n        if (idxA === null) return null;\n\n        if (fi + fj <= 1) {\n            const idxB = (i0 + 1 <= maxI) ? this._indexFromIJ(i0 + 1, j0, parentRes) : null;\n            const idxC = (j0 + 1 <= maxJ) ? this._indexFromIJ(i0, j0 + 1, parentRes) : null;\n            const wA = 1 - fi - fj;\n            const wB = fi;\n            const wC = fj;\n            return this._sampleParentTriangle(parent, [\n                { idx: idxA, w: wA },\n                { idx: idxB, w: wB },\n                { idx: idxC, w: wC }\n            ]);\n        }\n\n        const idxB = (i0 + 1 <= maxI) ? this._indexFromIJ(i0 + 1, j0, parentRes) : null;\n        const idxC = (j0 + 1 <= maxJ) ? this._indexFromIJ(i0, j0 + 1, parentRes) : null;\n        const idxD = (i0 + 1 <= maxI && j0 + 1 <= maxJ)\n            ? this._indexFromIJ(i0 + 1, j0 + 1, parentRes)\n            : null;\n        const wB = 1 - fj;\n        const wC = 1 - fi;\n        const wD = fi + fj - 1;\n        return this._sampleParentTriangle(parent, [\n            { idx: idxB, w: wB },\n            { idx: idxC, w: wC },\n            { idx: idxD, w: wD }\n        ]);\n    }\n\n    _indexFromIJ(i, j, res) {\n        if (i < 0 || j < 0 || i + j > res) return null;\n        const rowStart = Math.floor(i * (2 * res - i + 3) / 2);\n        return rowStart + j;\n    }\n\n    _gridIndexFromWeights(p0, p1, res) {\n        if (!Number.isFinite(p0) || !Number.isFinite(p1) || !Number.isFinite(res)) return null;\n        const i = p0 * res;\n        const j = p1 * res;\n        const iRound = Math.round(i);\n        const jRound = Math.round(j);\n        const eps = 1e-5;\n        if (Math.abs(i - iRound) > eps || Math.abs(j - jRound) > eps) return null;\n        if (iRound < 0 || jRound < 0 || iRound + jRound > res) return null;\n        return this._indexFromIJ(iRound, jRound, res);\n    }\n\n    _ijFromIndex(index, res) {\n        if (!Number.isFinite(index) || index < 0) return null;\n        if (!Number.isFinite(res) || res <= 0) return null;\n        let rowStart = 0;\n        for (let i = 0; i <= res; i++) {\n            const rowLen = res - i + 1;\n            if (index < rowStart + rowLen) {\n                return { i, j: index - rowStart };\n            }\n            rowStart += rowLen;\n        }\n        return null;\n    }\n\n    _isTileElevationDone(tile, idx) {\n        if (!tile || idx === null || idx === undefined) return false;\n        if (tile.elevationCache && tile.elevationCache.done) {\n            return tile.elevationCache.done[idx] === 1;\n        }\n        if (tile.elevationState) {\n            return tile.elevationState[idx] === 2;\n        }\n        return false;\n    }\n\n    _isElevationDone(index) {\n        return !!(this.elevationState && this.elevationState[index] === 2);\n    }\n\n    _isElevationValidForFill(index) {\n        if (this._isElevationDone(index)) return true;\n        if (this.elevationSeeded && this.elevationSeeded[index] === 1) return true;\n        return false;\n    }\n\n    _getElevationValueForFill(index) {\n        if (this.elevationValues && Number.isFinite(this.elevationValues[index])) {\n            return this.elevationValues[index];\n        }\n        if (this.elevationMorphTarget && Number.isFinite(this.elevationMorphTarget[index])) {\n            return this.elevationMorphTarget[index];\n        }\n        if (this.elevationMorphCurrent && Number.isFinite(this.elevationMorphCurrent[index])) {\n            return this.elevationMorphCurrent[index];\n        }\n        return this.getVertexElevationMeters(index);\n    }\n\n    _computeFillAverageElevation(doneOnly = false) {\n        if (doneOnly) {\n            if (this._elevationFillAverageDoneOnlyDone === this.elevationDone &&\n                Number.isFinite(this._elevationFillAverageDoneOnly)) {\n                return this._elevationFillAverageDoneOnly;\n            }\n        } else if (this._elevationFillAverageDone === this.elevationDone &&\n            Number.isFinite(this._elevationFillAverage)) {\n            return this._elevationFillAverage;\n        }\n        if (!this.vertexCount) return null;\n        let sum = 0;\n        let count = 0;\n        for (let i = 0; i < this.vertexCount; i++) {\n            const valid = doneOnly ? this._isElevationDone(i) : this._isElevationValidForFill(i);\n            if (!valid) continue;\n            const value = this._getElevationValueForFill(i);\n            if (!Number.isFinite(value)) continue;\n            sum += value;\n            count += 1;\n        }\n        const avg = count > 0 ? (sum / count) : null;\n        if (doneOnly) {\n            this._elevationFillAverageDoneOnly = avg;\n            this._elevationFillAverageDoneOnlyDone = this.elevationDone;\n        } else {\n            this._elevationFillAverage = avg;\n            this._elevationFillAverageDone = this.elevationDone;\n        }\n        return avg;\n    }\n\n    _estimateParentElevationForVertex(index) {\n        if (!this.parent) return null;\n        if (!Number.isFinite(index) || index < 0) return null;\n        const res = this.resolution;\n        if (!Number.isFinite(res) || res <= 0) return null;\n        const parentRes = this.parent.elevationCache?.res || this.parent.resolution;\n        if (!Number.isFinite(parentRes) || parentRes <= 0) return null;\n        const childSlot = this._getChildSlot();\n        if (childSlot < 0 || childSlot > 3) return null;\n\n        const ij = this._ijFromIndex(index, res);\n        if (!ij) return null;\n        const k = res - ij.i - ij.j;\n        if (k < 0) return null;\n        const w0 = ij.i / res;\n        const w1 = ij.j / res;\n        const w2 = k / res;\n        const mapped = this._mapChildWeightsToParent(childSlot, w0, w1, w2);\n        if (!mapped) return null;\n        return this._sampleParentElevation(this.parent, mapped.p0, mapped.p1, mapped.p2, parentRes);\n    }\n\n    fillMissingElevations(maxUpdates = null) {\n        if (!this.elevationFillEnabled) return 0;\n        if (this.elevationFillComplete &&\n            this._elevationFillCompleteDone === this.elevationDone &&\n            this._elevationFillCompleteSeeded === this.elevationSeededCount) {\n            return 0;\n        }\n        const needsFullFetch = this._requiresFullElevationFetch();\n        if (this.elevationExpected > 0 &&\n            this.elevationDone === 0 &&\n            this.elevationSeededCount === 0 &&\n            !needsFullFetch) {\n            return 0;\n        }\n        if (!this.positionAttr || !this.baseDirs) return 0;\n        if (!this.vertexCount || !this.elevationState && !this.elevationSeeded) return 0;\n        const res = this.resolution;\n        if (!Number.isFinite(res) || res <= 0) return 0;\n\n        const now = (typeof performance !== 'undefined' && performance.now)\n            ? performance.now()\n            : Date.now();\n        if (this._elevationFillLastDone === this.elevationDone &&\n            Number.isFinite(this.elevationFillIntervalMs) &&\n            this.elevationFillIntervalMs > 0 &&\n            now - this.elevationFillLastTime < this.elevationFillIntervalMs) {\n            return 0;\n        }\n\n        this.elevationFillLastTime = now;\n        this._elevationFillLastDone = this.elevationDone;\n\n        const limit = Number.isFinite(maxUpdates) ? Math.max(0, Math.floor(maxUpdates)) : this.elevationFillMaxPerFrame;\n        if (limit <= 0) return 0;\n\n        let idx = Number.isFinite(this.elevationFillCursor) ? this.elevationFillCursor : 0;\n        let checked = 0;\n        let updated = 0;\n        const count = this.vertexCount;\n        const minNeighbors = 1;\n        const epsilon = 0.25;\n        const hasRealData = !!this.elevationState && this.elevationDone > 0;\n        const allowSeededFill = false;\n        const useDoneNeighbors = false;\n        let missing = 0;\n\n        while (checked < count && updated < limit) {\n            const isDone = this._isElevationDone(idx);\n            const isSeeded = !!(this.elevationSeeded && this.elevationSeeded[idx] === 1);\n            if (!isDone && (!isSeeded || allowSeededFill)) {\n                if (this._shouldDeferEdgeUpdate(idx)) {\n                    idx = (idx + 1) % count;\n                    checked++;\n                    continue;\n                }\n                // Keep authoritative hard-locked seam vertices untouched.\n                const edgeCache = this.edgeElevationCache ? this.edgeElevationCache.get(idx) : null;\n                if (edgeCache && edgeCache.lockMode === 'hard') {\n                    idx = (idx + 1) % count;\n                    checked++;\n                    continue;\n                }\n                const isEdgeVertex = !!(this.edgeVertexMask && this.edgeVertexMask[idx]);\n                missing++;\n                const cache = this.edgeElevationCache ? this.edgeElevationCache.get(idx) : null;\n                if (!cache) {\n                    const ij = this._ijFromIndex(idx, res);\n                    if (ij) {\n                        const neighbors = [];\n                        const addNeighbor = (ii, jj) => {\n                            if (ii < 0 || jj < 0 || ii + jj > res) return;\n                            const nIdx = this._indexFromIJ(ii, jj, res);\n                            if (Number.isFinite(nIdx)) neighbors.push(nIdx);\n                        };\n\n                        addNeighbor(ij.i - 1, ij.j);\n                        addNeighbor(ij.i - 1, ij.j + 1);\n                        addNeighbor(ij.i, ij.j - 1);\n                        addNeighbor(ij.i, ij.j + 1);\n                        addNeighbor(ij.i + 1, ij.j);\n                        addNeighbor(ij.i + 1, ij.j - 1);\n\n                        let sum = 0;\n                        let hits = 0;\n                        for (const nIdx of neighbors) {\n                            const validNeighbor = useDoneNeighbors\n                                ? this._isElevationDone(nIdx)\n                                : this._isElevationValidForFill(nIdx);\n                            if (!validNeighbor) continue;\n                            const value = this._getElevationValueForFill(nIdx);\n                            if (!Number.isFinite(value)) continue;\n                            sum += value;\n                            hits += 1;\n                        }\n\n                        let fill = null;\n                        if (hits >= minNeighbors) {\n                            fill = sum / hits;\n                        } else {\n                            const avg = this._computeFillAverageElevation(useDoneNeighbors);\n                            if (Number.isFinite(avg)) fill = avg;\n                            if (!Number.isFinite(fill)) {\n                                const parentFill = this._estimateParentElevationForVertex(idx);\n                                if (Number.isFinite(parentFill)) fill = parentFill;\n                            }\n                        }\n\n                        if (Number.isFinite(fill)) {\n                            const current = this._getElevationValueForFill(idx);\n                            if (!Number.isFinite(current) || Math.abs(fill - current) > epsilon) {\n                                const allowMorph = this.elevationMorphEnabled && this._ensureElevationMorphBuffers();\n                                this._applyElevationAtIndex(idx, fill, allowMorph);\n                                // Edge placeholders are visual-only; keep them \"missing\"\n                                // so authoritative fetch continues and eventually replaces them.\n                                if (this.elevationFillMask && !isEdgeVertex) {\n                                    this.elevationFillMask[idx] = 1;\n                                }\n                                updated++;\n                            }\n                        }\n                    }\n                }\n            }\n\n            idx = (idx + 1) % count;\n            checked++;\n        }\n\n        this.elevationFillCursor = idx;\n\n        const hasAnyData = this.elevationDone > 0 || this.elevationSeededCount > 0;\n        if (hasAnyData && checked >= count && updated === 0 && missing === 0) {\n            this.elevationFillComplete = true;\n            this._elevationFillCompleteDone = this.elevationDone;\n            this._elevationFillCompleteSeeded = this.elevationSeededCount;\n        } else {\n            this.elevationFillComplete = false;\n        }\n\n        if (updated > 0) {\n            this.elevationFillComplete = false;\n            this._queueElevationUpdate();\n            this._markGeometryDirty();\n        }\n\n        return updated;\n    }\n\n    /**\n     * Force-complete missing elevation samples with fallback values.\n     */\n    forceCompleteMissingElevations({ allowEdges = true, maxUpdates = null } = {}) {\n        if (this.elevationForceCompleteEnabled === false) return 0;\n        if (!this.positionAttr || !this.baseDirs) return 0;\n        if (!this.vertexCount || !this.elevationState) return 0;\n        const res = this.resolution;\n        if (!Number.isFinite(res) || res <= 0) return 0;\n        const updateLimit = Number.isFinite(maxUpdates)\n            ? Math.max(0, Math.floor(maxUpdates))\n            : Infinity;\n        if (updateLimit <= 0) return 0;\n\n        let expected = Number.isFinite(this.elevationExpected) ? this.elevationExpected : 0;\n        const count = this.vertexCount;\n        const shouldForceFullFetch = !!this.forceFullFetch ||\n            (this.elevationClient &&\n                typeof this.elevationClient.isFullFetchTile === 'function' &&\n                this.elevationClient.isFullFetchTile(this));\n        if (shouldForceFullFetch && count > 0 && expected < count) {\n            this.elevationExpected = count;\n            expected = count;\n            this._updateElevationComplete();\n        }\n        if (expected <= 0) return 0;\n        if (this.elevationDone >= expected) return 0;\n        const fullFetch = expected >= count && count > 0;\n        const hasRealData = this.elevationDone > 0;\n        const useDoneNeighbors = hasRealData;\n        const minNeighbors = 1;\n        const epsilon = 0.05;\n        const avgDone = this._computeFillAverageElevation(true);\n        const avgAny = this._computeFillAverageElevation(false);\n        const fallbackAvg = Number.isFinite(avgDone)\n            ? avgDone\n            : (Number.isFinite(avgAny) ? avgAny : 0);\n\n        let updated = 0;\n\n        for (let idx = 0; idx < count && updated < updateLimit; idx++) {\n            const state = this.elevationState[idx];\n            if (state === 2) continue;\n            if (!fullFetch && state !== 1) continue;\n            if (this.elevationFillMask && this.elevationFillMask[idx] === 1) continue;\n\n            if (!allowEdges) {\n                const edgeMask = this.edgeVertexMask ? this.edgeVertexMask[idx] : 0;\n                if (edgeMask) continue;\n            }\n\n            if (this._shouldDeferEdgeUpdate(idx)) continue;\n\n            let fill = null;\n            const isSeeded = !!(this.elevationSeeded && this.elevationSeeded[idx] === 1);\n            if (isSeeded) {\n                const current = this._getElevationValueForFill(idx);\n                if (Number.isFinite(current)) {\n                    fill = current;\n                }\n            }\n\n            if (!Number.isFinite(fill)) {\n                const ij = this._ijFromIndex(idx, res);\n                if (ij) {\n                    const neighbors = [];\n                    const addNeighbor = (ii, jj) => {\n                        if (ii < 0 || jj < 0 || ii + jj > res) return;\n                        const nIdx = this._indexFromIJ(ii, jj, res);\n                        if (Number.isFinite(nIdx)) neighbors.push(nIdx);\n                    };\n\n                    addNeighbor(ij.i - 1, ij.j);\n                    addNeighbor(ij.i - 1, ij.j + 1);\n                    addNeighbor(ij.i, ij.j - 1);\n                    addNeighbor(ij.i, ij.j + 1);\n                    addNeighbor(ij.i + 1, ij.j);\n                    addNeighbor(ij.i + 1, ij.j - 1);\n\n                    let sum = 0;\n                    let hits = 0;\n                    for (const nIdx of neighbors) {\n                        const validNeighbor = useDoneNeighbors\n                            ? this._isElevationDone(nIdx)\n                            : this._isElevationValidForFill(nIdx);\n                        if (!validNeighbor) continue;\n                        const value = this._getElevationValueForFill(nIdx);\n                        if (!Number.isFinite(value)) continue;\n                        sum += value;\n                        hits += 1;\n                    }\n\n                    if (hits >= minNeighbors) {\n                        fill = sum / hits;\n                    }\n                }\n            }\n\n            if (!Number.isFinite(fill)) {\n                fill = fallbackAvg;\n            }\n            if (!Number.isFinite(fill)) {\n                fill = 0;\n            }\n\n            const current = this._getElevationValueForFill(idx);\n            if (!Number.isFinite(current) || Math.abs(fill - current) > epsilon) {\n                const allowMorph = this.elevationMorphEnabled && this._ensureElevationMorphBuffers();\n                this._applyElevationAtIndex(idx, fill, allowMorph);\n            }\n            if (this.elevationFillMask) {\n                this.elevationFillMask[idx] = 1;\n            }\n            this.elevationFillComplete = false;\n            updated++;\n        }\n\n        if (updated > 0) {\n            this._queueElevationUpdate();\n            this._markGeometryDirty();\n        }\n\n        return updated;\n    }\n\n    /**\n     * Force completion when elevation progress stalls for a while.\n     */\n    forceCompleteMissingElevationsIfStalled(now, { stallMs, allowEdges = true, maxUpdates = null } = {}) {\n        if (this.elevationForceCompleteEnabled === false) return 0;\n        let expected = Number.isFinite(this.elevationExpected) ? this.elevationExpected : 0;\n        const count = this.vertexCount || 0;\n        const shouldForceFullFetch = !!this.forceFullFetch ||\n            (this.elevationClient &&\n                typeof this.elevationClient.isFullFetchTile === 'function' &&\n                this.elevationClient.isFullFetchTile(this));\n        if (shouldForceFullFetch && count > 0 && expected < count) {\n            this.elevationExpected = count;\n            expected = count;\n            this._updateElevationComplete();\n        }\n        if (expected <= 0 || this.elevationDone >= expected) {\n            this._elevationStallSinceMs = 0;\n            return 0;\n        }\n        const maxWait = Number.isFinite(stallMs) ? stallMs : 0;\n        if (maxWait <= 0) return 0;\n\n        const currentNow = Number.isFinite(now)\n            ? now\n            : ((typeof performance !== 'undefined' && performance.now)\n                ? performance.now()\n                : Date.now());\n        const last = Number.isFinite(this._elevationLastProgressMs) ? this._elevationLastProgressMs : 0;\n        if (!last) {\n            this._elevationLastProgressMs = currentNow;\n            this._elevationLastProgressDone = this.elevationDone;\n            return 0;\n        }\n        if (Number.isFinite(this._elevationLastProgressDone) &&\n            this._elevationLastProgressDone !== this.elevationDone) {\n            this._noteElevationProgress(currentNow);\n            return 0;\n        }\n        if (currentNow - last < maxWait) return 0;\n\n        if (!this._elevationStallSinceMs) {\n            this._elevationStallSinceMs = currentNow;\n        }\n\n        return this.forceCompleteMissingElevations({ allowEdges, maxUpdates });\n    }\n\n    _getElevationAtIndex(parent, idx) {\n        if (parent.elevationCache && parent.elevationCache.heights) {\n            return parent.elevationCache.heights[idx] ?? 0;\n        }\n        if (!parent.positionAttr) return 0;\n        const pos = parent.positionAttr.array;\n        // Positions are stored in local coordinates - add parent tile center\n        const x = pos[idx * 3 + 0] + parent.center.x;\n        const y = pos[idx * 3 + 1] + parent.center.y;\n        const z = pos[idx * 3 + 2] + parent.center.z;\n        const r = Math.sqrt(x * x + y * y + z * z) || parent.radius;\n        if (typeof parent._extractElevationFromRadius === 'function') {\n            const sampled = parent._extractElevationFromRadius(idx, r, false);\n            return Number.isFinite(sampled) ? sampled : 0;\n        }\n        const baseRadius = (typeof parent._getBaseRadiusAtIndex === 'function')\n            ? parent._getBaseRadiusAtIndex(idx)\n            : parent.radius;\n        let elevMeters = elevationFromRadius(r, baseRadius);\n        if (parent.photogramOffsets && Number.isFinite(parent.photogramOffsets[idx])) {\n            elevMeters -= parent.photogramOffsets[idx];\n        }\n        return elevMeters;\n    }\n\n    _isParentElevationValid(parent, idx) {\n        if (parent.elevationCache && parent.elevationCache.valid) {\n            return parent.elevationCache.valid[idx] === 1;\n        }\n        if (parent.elevationSeeded) {\n            return parent.elevationSeeded[idx] === 1 ||\n                (parent.elevationState ? parent.elevationState[idx] === 2 : false);\n        }\n        if (parent.elevationState) {\n            return parent.elevationState[idx] === 2;\n        }\n        return true;\n    }\n\n    _sampleParentTriangle(parent, samples) {\n        let weighted = 0;\n        let total = 0;\n        for (const sample of samples) {\n            if (sample.idx === null) continue;\n            if (!this._isParentElevationValid(parent, sample.idx)) continue;\n            weighted += this._getElevationAtIndex(parent, sample.idx) * sample.w;\n            total += sample.w;\n        }\n        if (total <= 0) return null;\n        return weighted / total;\n    }\n\n    _seedVertexHeight(index, elevMeters, { markDone = false } = {}) {\n        if (!this.positionAttr || !this.baseDirs) return;\n        const base = this.baseDirs;\n        const pos = this.positionAttr.array;\n\n        // Check if this vertex is part of a stitched edge\n        const isStitchedVertex = this.edgeElevationCache && this.edgeElevationCache.has(index);\n\n        if (isStitchedVertex) {\n            // Don't overwrite stitched positions with seeded elevation\n            // The stitched position takes priority\n            return;\n        }\n\n        if (this.elevationFillMask && this.elevationFillMask[index] === 1) {\n            this.elevationFillMask[index] = 0;\n        }\n\n        const bx = base[index * 3 + 0];\n        const by = base[index * 3 + 1];\n        const bz = base[index * 3 + 2];\n\n        const baseRadius = this._getBaseRadiusAtIndex(index);\n        const r = radiusFromElevation(baseRadius, elevMeters);\n\n        // Store position relative to tile center (local coordinates)\n        pos[index * 3 + 0] = bx * r - this.center.x;\n        pos[index * 3 + 1] = by * r - this.center.y;\n        pos[index * 3 + 2] = bz * r - this.center.z;\n        if (Number.isFinite(elevMeters)) {\n            this.elevationHasData = true;\n        }\n        if (this.elevationMorphCurrent && this.elevationMorphTarget) {\n            this.elevationMorphCurrent[index] = elevMeters;\n            this.elevationMorphTarget[index] = elevMeters;\n        }\n        if (this.elevationSeeded) {\n            if (this.elevationSeeded[index] !== 1) {\n                this.elevationSeededCount += 1;\n            }\n            this.elevationSeeded[index] = 1;\n        }\n        if (markDone && this.elevationState) {\n            if (this.elevationState[index] !== 2) {\n                this.elevationState[index] = 2;\n                this.elevationDone += 1;\n                this._noteElevationProgress();\n            }\n        }\n        this.elevationFillComplete = false;\n        if (markDone) {\n            this._updateElevationComplete();\n        }\n        this._queueElevationUpdate();\n        this._markGeometryDirty();\n    }\n\n    cacheElevationSamples() {\n        if (!this.positionAttr || !this.baseDirs) return;\n        const count = this.vertexCount || 0;\n        if (!count) return;\n\n        const heights = new Float32Array(count);\n        const valid = new Uint8Array(count);\n        const doneMask = new Uint8Array(count);\n        const pos = this.positionAttr.array;\n        const hasState = !!this.elevationState;\n        const hasSeeded = !!this.elevationSeeded;\n        // Positions are stored in local coordinates - add tile center to compute radius\n        const cx = this.center.x;\n        const cy = this.center.y;\n        const cz = this.center.z;\n\n        for (let i = 0; i < count; i++) {\n            const x = pos[i * 3 + 0] + cx;\n            const y = pos[i * 3 + 1] + cy;\n            const z = pos[i * 3 + 2] + cz;\n            const r = Math.sqrt(x * x + y * y + z * z) || this.radius;\n            let elev = this._getElevationValueForFill(i);\n            if (!Number.isFinite(elev)) {\n                elev = this._extractElevationFromRadius(i, r, false);\n            }\n            heights[i] = Number.isFinite(elev) ? elev : 0;\n            const seeded = hasSeeded ? (this.elevationSeeded[i] === 1) : false;\n            const done = hasState ? (this.elevationState[i] === 2) : false;\n            const edgeCache = this.edgeElevationCache ? this.edgeElevationCache.get(i) : null;\n            const hasAuthoritativeEdgeData = !!(edgeCache &&\n                edgeCache.isVirtual !== true &&\n                Number.isFinite(edgeCache.originalElevMeters));\n            valid[i] = (seeded || done || hasAuthoritativeEdgeData) ? 1 : 0;\n            doneMask[i] = done ? 1 : 0;\n        }\n\n        this.elevationCache = {\n            res: this.resolution,\n            heights,\n            valid,\n            done: doneMask\n        };\n    }\n\n    cacheElevationFromChildren() {\n        if (!this.children || !this.children.length) return;\n\n        const baseRes = 3;\n        const resPerLevel = 2;\n        const res = this.resolution || Math.min(baseRes + this.level * resPerLevel, 19);\n        if (!Number.isFinite(res) || res <= 0) return;\n        const count = ((res + 1) * (res + 2)) / 2;\n\n        const heights = new Float32Array(count);\n        const valid = new Uint8Array(count);\n        const doneMask = new Uint8Array(count);\n        const prev = this.elevationCache;\n        if (prev && prev.res === res && prev.heights) {\n            heights.set(prev.heights);\n            if (prev.valid) valid.set(prev.valid);\n            if (prev.done) doneMask.set(prev.done);\n        }\n\n        const childInfo = this.children.map((child) => {\n            if (!child) {\n                return { tile: null, res: null, hasData: false };\n            }\n            const childRes = child.elevationCache?.res || child.resolution;\n            let hasData = (child.elevationDone || 0) > 0 ||\n                (child.elevationSeededCount || 0) > 0 ||\n                !!child.elevationHasData ||\n                !!(child.edgeElevationCache && child.edgeElevationCache.size) ||\n                !!(child.deferredEdgeElevations && child.deferredEdgeElevations.size);\n            if (!hasData && child.elevationCache?.valid) {\n                hasData = child.elevationCache.valid.some((value) => value === 1);\n            }\n            return { tile: child, res: childRes, hasData };\n        });\n\n        let idx = 0;\n        for (let i = 0; i <= res; i++) {\n            for (let j = 0; j <= res - i; j++) {\n                const k = res - i - j;\n                const w0 = i / res;\n                const w1 = j / res;\n                const w2 = k / res;\n\n                let childSlot = 0;\n                if (w0 >= 0.5) childSlot = 1;\n                else if (w1 >= 0.5) childSlot = 2;\n                else if (w2 >= 0.5) childSlot = 3;\n\n                const info = childInfo[childSlot];\n                if (!info || !info.tile || !info.res || !info.hasData) {\n                    idx++;\n                    continue;\n                }\n                const mapped = this._mapParentWeightsToChild(childSlot, w0, w1, w2);\n                if (!mapped) {\n                    idx++;\n                    continue;\n                }\n                const elev = this._sampleParentElevation(info.tile, mapped.c0, mapped.c1, mapped.c2, info.res);\n                if (Number.isFinite(elev)) {\n                    const childIdx = this._gridIndexFromWeights(mapped.c0, mapped.c1, info.res);\n                    const markDone = childIdx !== null && this._isTileElevationDone(info.tile, childIdx);\n                    heights[idx] = elev;\n                    valid[idx] = 1;\n                    doneMask[idx] = markDone ? 1 : 0;\n                }\n                idx++;\n            }\n        }\n\n        this.elevationCache = {\n            res,\n            heights,\n            valid,\n            done: doneMask\n        };\n    }\n\n    applyElevationCacheToMesh() {\n        if (!this.positionAttr || !this.baseDirs) return 0;\n        const cache = this.elevationCache;\n        if (!cache || !cache.heights || !cache.valid) return 0;\n        if (Number.isFinite(cache.res) && Number.isFinite(this.resolution) &&\n            cache.res !== this.resolution) {\n            return 0;\n        }\n        const count = Math.min(this.vertexCount || 0, cache.heights.length);\n        if (!count) return 0;\n        let updated = 0;\n        for (let i = 0; i < count; i++) {\n            if (cache.valid[i] !== 1) continue;\n            const elev = cache.heights[i];\n            if (!Number.isFinite(elev)) continue;\n            const markDone = cache.done ? cache.done[i] === 1 : false;\n            this._seedVertexHeight(i, elev, { markDone });\n            updated++;\n        }\n        return updated;\n    }\n\n    prepareChildrenForSplit() {\n        if (!this.children) return;\n        if (!this.childrenPrepared) {\n            this.childrenPrepared = true;\n            this.cacheElevationSamples();\n        }\n        if (this.treeManager?.imageryInheritanceEnabled !== true) {\n            for (const child of this.children) {\n                child?._clearPendingInheritedImagery?.();\n            }\n            this._childrenImageryPrepared = false;\n            return;\n        }\n        // Seamless imagery handoff: allow children to inherit parent imagery until their own WMTS loads.\n        // This prevents black tiles during split while keeping upgrades incremental.\n        if (this._childrenImageryPrepared) return;\n        // Allow inheritance even if imageryReady is false (e.g., parent is upgrading imagery).\n        // As long as we have a valid atlas+texture, children can safely sample it as fallback.\n        if (!this.imageryTexture || !this.imageryAtlasKey || !this.imageryManager) {\n            return;\n        }\n\n        const atlasZoom = Number.isFinite(this.imageryAtlasZoom) ? this.imageryAtlasZoom : this.imageryZoom;\n        if (!Number.isFinite(atlasZoom) ||\n            !Number.isFinite(this.imageryAtlasMinX) || !Number.isFinite(this.imageryAtlasMinY) ||\n            !Number.isFinite(this.imageryAtlasW) || !Number.isFinite(this.imageryAtlasH)) {\n            return;\n        }\n\n        const inherited = {\n            texture: this.imageryTexture,\n            atlasKey: this.imageryAtlasKey,\n            atlasZoom,\n            minX: this.imageryAtlasMinX,\n            minY: this.imageryAtlasMinY,\n            wTiles: this.imageryAtlasW,\n            hTiles: this.imageryAtlasH,\n            versionId: this.imageryVersion\n        };\n\n        for (const child of this.children) {\n            if (!child) continue;\n            if (child.imageryReady && !child.imageryInherited) continue;\n            if (child.mesh && child.geometry && child.baseDirs) {\n                if (typeof child._clearPendingInheritedImagery === 'function') {\n                    child._clearPendingInheritedImagery();\n                }\n                child._applyInheritedImagery(inherited, this.imageryManager);\n            } else {\n                child._setPendingInheritedImagery(inherited, this.imageryManager);\n            }\n        }\n        this._childrenImageryPrepared = true;\n    }\n\n    // REMOVED: _inheritImageryFallbackToChildren - no fallbacks, WMTS only\n\n    // REMOVED: All fallback/inheritance methods - WMTS only, no parent-child imagery sharing\n\n    _setPendingInheritedImagery(inherited, imageryManager) {\n        if (!inherited || !inherited.atlasKey || !imageryManager) {\n            this._clearPendingInheritedImagery();\n            return;\n        }\n\n        // Acquire before releasing an identical pending identity: its cache\n        // owner may already have been evicted.\n        imageryManager.retainAtlas(inherited.atlasKey, inherited.texture);\n        this._clearPendingInheritedImagery();\n        this._pendingInheritedImagery = inherited;\n        this._pendingInheritedManager = imageryManager;\n        this._pendingInheritedAtlasKey = inherited.atlasKey;\n    }\n\n    _clearPendingInheritedImagery() {\n        if (this._pendingInheritedAtlasKey && this._pendingInheritedManager) {\n            this._pendingInheritedManager.releaseAtlas(this._pendingInheritedAtlasKey, this._pendingInheritedImagery?.texture);\n        }\n        this._pendingInheritedImagery = null;\n        this._pendingInheritedManager = null;\n        this._pendingInheritedAtlasKey = null;\n    }\n\n    _hasRenderableImageryMap() {\n        const map = this.mesh?.material?.map || this.materialDefault?.map || this.imageryTexture || this.inheritedTexture;\n        const image = map?.image || map?.source?.data || map?.source?.image;\n        if (!image) return false;\n        const width = Number(\n            image.videoWidth ??\n            image.naturalWidth ??\n            image.width ??\n            image.clientWidth ??\n            0\n        );\n        const height = Number(\n            image.videoHeight ??\n            image.naturalHeight ??\n            image.height ??\n            image.clientHeight ??\n            0\n        );\n        return width > 1 && height > 1;\n    }\n\n    _hasValidImageryAtlasBinding({ allowInherited = true } = {}) {\n        const atlasZoom = Number.isFinite(this.imageryAtlasZoom) ? this.imageryAtlasZoom : this.imageryZoom;\n        const hasOwnAtlas = !!(\n            this.imageryTexture &&\n            this.imageryAtlasKey &&\n            Number.isFinite(atlasZoom) &&\n            Number.isFinite(this.imageryAtlasMinX) &&\n            Number.isFinite(this.imageryAtlasMinY) &&\n            Number.isFinite(this.imageryAtlasW) &&\n            this.imageryAtlasW > 0 &&\n            Number.isFinite(this.imageryAtlasH) &&\n            this.imageryAtlasH > 0\n        );\n        if (hasOwnAtlas) return true;\n        if (!allowInherited) return false;\n\n        const inheritedZoom = Number.isFinite(this.imageryInheritedZoom)\n            ? this.imageryInheritedZoom\n            : atlasZoom;\n        return !!(\n            this.imageryInherited &&\n            this.inheritedTexture &&\n            this.inheritedAtlasKey &&\n            Number.isFinite(inheritedZoom)\n        );\n    }\n\n    hasImageryCoverage() {\n        const hasMap = this._hasRenderableImageryMap();\n        const hasBinding = this._hasValidImageryAtlasBinding({ allowInherited: true });\n        if (this.imageryReady || this.imageryInherited) {\n            return hasMap && hasBinding;\n        }\n        if (!hasMap) return false;\n        return hasBinding;\n    }\n\n    hasCoverage() {\n        const fallbackLevel = Number.isFinite(this.treeManager?.initialSubdivLevel)\n            ? Math.max(0, Math.floor(this.treeManager.initialSubdivLevel))\n            : 2;\n        const lowLodFallback = !!this.mesh && this.level <= fallbackLevel;\n        return !!(\n            this.hasImageryCoverage() ||\n            lowLodFallback // keep coarse globe visible while higher-LOD imagery converges\n        );\n    }\n\n    /**\n     * Convert a lat/lon point to atlas UV coordinates for this tile's imagery.\n     * Returns null if imagery metadata is missing.\n     */\n    getAtlasUvForLatLon(latDeg, lonDeg, out = { u: 0, v: 0 }) {\n        const atlasZoom = Number.isFinite(this.imageryAtlasZoom) ? this.imageryAtlasZoom : this.imageryZoom;\n        const minX = this.imageryAtlasMinX;\n        const minY = this.imageryAtlasMinY;\n        const wTiles = this.imageryAtlasW;\n        const hTiles = this.imageryAtlasH;\n        const texture = this.imageryTexture;\n        if (!texture || !Number.isFinite(atlasZoom) ||\n            !Number.isFinite(minX) || !Number.isFinite(minY) ||\n            !Number.isFinite(wTiles) || !Number.isFinite(hTiles)) {\n            return null;\n        }\n\n        const imageryManager = this.imageryManager;\n        const tileSize = imageryManager?.tileSize || 256;\n        const atlasWidth = wTiles * tileSize;\n        const atlasHeight = hTiles * tileSize;\n        if (!atlasWidth || !atlasHeight) return null;\n\n        const coords = lonLatToTileCoords(lonDeg, latDeg, atlasZoom);\n        const alignedMinX = this._alignAtlasMinXToTileFrame(\n            minX,\n            wTiles,\n            coords.n,\n            coords.cx\n        );\n        const halfPixelU = 0.5 / atlasWidth;\n        const halfPixelV = 0.5 / atlasHeight;\n        const u = ((coords.cx - alignedMinX) * tileSize + 0.5) / atlasWidth;\n        const v = ((coords.cy - minY) * tileSize + 0.5) / atlasHeight;\n        out.u = THREE.MathUtils.clamp(u, halfPixelU, 1 - halfPixelU);\n        out.v = THREE.MathUtils.clamp(v, halfPixelV, 1 - halfPixelV);\n        return out;\n    }\n\n    // REMOVED: _applyImageryFallback and _clearImageryFallback - no fallbacks, WMTS only\n\n    _alignAtlasMinXToTileFrame(minX, wTiles, n, refCx, minCx = null, maxCx = null) {\n        if (!Number.isFinite(minX)) return minX;\n        if (!Number.isFinite(n) || n <= 0) return minX;\n\n        const atlasWidth = Number.isFinite(wTiles)\n            ? Math.max(1, Number(wTiles))\n            : 1;\n        let alignedMinX = Number(minX);\n        const atlasCenter = alignedMinX + (atlasWidth * 0.5);\n        if (Number.isFinite(refCx)) {\n            const wrapShift = Math.round((refCx - atlasCenter) / n);\n            alignedMinX += wrapShift * n;\n        }\n\n        if (!Number.isFinite(minCx) || !Number.isFinite(maxCx)) {\n            return alignedMinX;\n        }\n\n        const tileMin = Math.min(minCx, maxCx);\n        const tileMax = Math.max(minCx, maxCx);\n        let bestMinX = alignedMinX;\n        let bestOverlap = -Infinity;\n        let bestCenterDist = Infinity;\n\n        for (let shift = -2; shift <= 2; shift += 1) {\n            const candidateMinX = alignedMinX + (shift * n);\n            const candidateMaxX = candidateMinX + atlasWidth;\n            const overlap = Math.max(0, Math.min(tileMax, candidateMaxX) - Math.max(tileMin, candidateMinX));\n            const candidateCenter = candidateMinX + (atlasWidth * 0.5);\n            const centerRef = Number.isFinite(refCx) ? refCx : ((tileMin + tileMax) * 0.5);\n            const centerDist = Math.abs(candidateCenter - centerRef);\n            if (overlap > bestOverlap || (overlap === bestOverlap && centerDist < bestCenterDist)) {\n                bestOverlap = overlap;\n                bestCenterDist = centerDist;\n                bestMinX = candidateMinX;\n            }\n        }\n\n        return bestMinX;\n    }\n\n    _computeImageryAverageColor() {\n        if (!this.imageryTexture || !this.geometry) return null;\n        const image = this.imageryTexture.image;\n        if (!image || !image.width || !image.height) return null;\n        const uvAttr = this.geometry.getAttribute('uv2') || this.geometry.getAttribute('uv');\n        if (!uvAttr || uvAttr.count === 0) return null;\n\n        let minU = 1, maxU = 0, minV = 1, maxV = 0;\n        for (let i = 0; i < uvAttr.count; i++) {\n            const u = uvAttr.getX(i);\n            const v = uvAttr.getY(i);\n            if (u < minU) minU = u;\n            if (u > maxU) maxU = u;\n            if (v < minV) minV = v;\n            if (v > maxV) maxV = v;\n        }\n\n        minU = THREE.MathUtils.clamp(minU, 0, 1);\n        maxU = THREE.MathUtils.clamp(maxU, 0, 1);\n        minV = THREE.MathUtils.clamp(minV, 0, 1);\n        maxV = THREE.MathUtils.clamp(maxV, 0, 1);\n\n        const width = image.width;\n        const height = image.height;\n        const sx = Math.max(0, Math.min(width - 1, Math.floor(minU * width)));\n        const sw = Math.max(1, Math.min(width - sx, Math.ceil((maxU - minU) * width)));\n        const sy = Math.max(0, Math.min(height - 1, Math.floor((1 - maxV) * height)));\n        const sh = Math.max(1, Math.min(height - sy, Math.ceil((maxV - minV) * height)));\n\n        const sampleSize = 8;\n        const sampler = getImageryAvgSampler(sampleSize);\n        if (!sampler) return null;\n        const { ctx } = sampler;\n\n        try {\n            ctx.clearRect(0, 0, sampleSize, sampleSize);\n            ctx.drawImage(image, sx, sy, sw, sh, 0, 0, sampleSize, sampleSize);\n            const data = ctx.getImageData(0, 0, sampleSize, sampleSize).data;\n            let r = 0;\n            let g = 0;\n            let b = 0;\n            const count = data.length / 4;\n            for (let i = 0; i < data.length; i += 4) {\n                r += data[i];\n                g += data[i + 1];\n                b += data[i + 2];\n            }\n            if (!count) return null;\n            return {\n                r: r / count,\n                g: g / count,\n                b: b / count\n            };\n        } catch (err) {\n            return null;\n        }\n    }\n\n    _applyInheritedImagery(inherited, imageryManager) {\n        if (!inherited || !imageryManager) return false;\n        if (!this.mesh || !this.geometry || !this.baseDirs) return false;\n        if (!inherited.texture || !inherited.atlasKey) return false;\n\n        // Keep any pending hold until the bound tile has acquired ownership.\n\n        const atlasZoom = inherited.atlasZoom;\n        const minX = inherited.minX;\n        const minY = inherited.minY;\n        const wTiles = inherited.wTiles;\n        const hTiles = inherited.hTiles;\n        if (!Number.isFinite(atlasZoom) ||\n            !Number.isFinite(minX) || !Number.isFinite(minY) ||\n            !Number.isFinite(wTiles) || !Number.isFinite(hTiles)) {\n            return false;\n        }\n\n        const baseCount = this.vertexCount || (this.baseDirs ? this.baseDirs.length / 3 : 0);\n        const totalCount = this.positionAttr?.count || baseCount;\n        const tmpDir = this._imageryTmpDir || (this._imageryTmpDir = new THREE.Vector3());\n        let sumSin = 0;\n        let sumCos = 0;\n        let n = 0;\n        let minCx = +Infinity;\n        let maxCx = -Infinity;\n        // Inherited imagery is a temporary split handoff, not the child's\n        // authoritative atlas. Project only the three child corners, then\n        // barycentrically interpolate their parent-atlas coordinates. The old\n        // path repeated atan/asin/Mercator conversion for every vertex of all\n        // four children inside one synchronous split.\n        const corners = [this.v0, this.v1, this.v2];\n        const cornerCoords = corners.map((corner) => {\n            const { latDeg, lonDeg } = dirToLatLonLocal(corner);\n            const c = lonLatToTileCoords(lonDeg, latDeg, atlasZoom);\n            n = c.n;\n            const angle = (c.cx / n) * TWO_PI;\n            sumSin += Math.sin(angle);\n            sumCos += Math.cos(angle);\n            return { cx: c.cx, cy: c.cy, n };\n        });\n\n        const meanAngle = Math.atan2(sumSin, sumCos);\n        const refCx = THREE.MathUtils.euclideanModulo((meanAngle / TWO_PI) * n, n);\n        for (let i = 0; i < cornerCoords.length; i++) {\n            let cx = cornerCoords[i].cx;\n            if (cx - refCx > n * 0.5) cx -= n;\n            else if (refCx - cx > n * 0.5) cx += n;\n            cornerCoords[i].cx = cx;\n            if (cx < minCx) minCx = cx;\n            if (cx > maxCx) maxCx = cx;\n        }\n        const atlasMinXUv = this._alignAtlasMinXToTileFrame(minX, wTiles, n, refCx, minCx, maxCx);\n        const atlasMinXStored = Number.isFinite(n)\n            ? THREE.MathUtils.euclideanModulo(minX, n)\n            : minX;\n\n        const atlasWidth = wTiles * imageryManager.tileSize;\n        const atlasHeight = hTiles * imageryManager.tileSize;\n        const halfPixelU = 0.5 / atlasWidth;\n        const halfPixelV = 0.5 / atlasHeight;\n        const uvArray = new Float32Array(totalCount * 2);\n\n        const expectedBaseCount = Number.isFinite(this.resolution)\n            ? ((this.resolution + 1) * (this.resolution + 2)) / 2\n            : 0;\n        if (expectedBaseCount === baseCount && this.resolution > 0 && this.level >= 10) {\n            let vertexIndex = 0;\n            const resolution = this.resolution;\n            for (let i = 0; i <= resolution; i++) {\n                for (let j = 0; j <= resolution - i; j++) {\n                    const k = resolution - i - j;\n                    const w0 = i / resolution;\n                    const w1 = j / resolution;\n                    const w2 = k / resolution;\n                    const cellX = cornerCoords[0].cx * w0 +\n                        cornerCoords[1].cx * w1 +\n                        cornerCoords[2].cx * w2;\n                    const cellY = cornerCoords[0].cy * w0 +\n                        cornerCoords[1].cy * w1 +\n                        cornerCoords[2].cy * w2;\n                    const u = ((cellX - atlasMinXUv) * imageryManager.tileSize + 0.5) / atlasWidth;\n                    const v = ((cellY - minY) * imageryManager.tileSize + 0.5) / atlasHeight;\n                    uvArray[vertexIndex * 2 + 0] = THREE.MathUtils.clamp(u, halfPixelU, 1 - halfPixelU);\n                    uvArray[vertexIndex * 2 + 1] = THREE.MathUtils.clamp(v, halfPixelV, 1 - halfPixelV);\n                    vertexIndex++;\n                }\n            }\n        } else {\n            // Non-triangular compatibility geometry keeps the exact mapping.\n            for (let i = 0; i < baseCount; i++) {\n                const i3 = i * 3;\n                tmpDir.set(\n                    this.baseDirs[i3 + 0],\n                    this.baseDirs[i3 + 1],\n                    this.baseDirs[i3 + 2]\n                );\n                const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n                const c = lonLatToTileCoords(lonDeg, latDeg, atlasZoom);\n                let cellX = c.cx;\n                if (cellX - refCx > n * 0.5) cellX -= n;\n                else if (refCx - cellX > n * 0.5) cellX += n;\n                const u = ((cellX - atlasMinXUv) * imageryManager.tileSize + 0.5) / atlasWidth;\n                const v = ((c.cy - minY) * imageryManager.tileSize + 0.5) / atlasHeight;\n                uvArray[i * 2 + 0] = THREE.MathUtils.clamp(u, halfPixelU, 1 - halfPixelU);\n                uvArray[i * 2 + 1] = THREE.MathUtils.clamp(v, halfPixelV, 1 - halfPixelV);\n            }\n        }\n\n        if (totalCount > baseCount && this.positionAttr) {\n            const pos = this.positionAttr.array;\n            const cx = this.center.x;\n            const cy = this.center.y;\n            const cz = this.center.z;\n            for (let i = baseCount; i < totalCount; i++) {\n                const i3 = i * 3;\n                const x = pos[i3 + 0] + cx;\n                const y = pos[i3 + 1] + cy;\n                const z = pos[i3 + 2] + cz;\n                tmpDir.set(x, y, z).normalize();\n                const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n                const c = lonLatToTileCoords(lonDeg, latDeg, atlasZoom);\n                let cellX = c.cx;\n                if (cellX - refCx > n * 0.5) cellX -= n;\n                else if (refCx - cellX > n * 0.5) cellX += n;\n                const u = ((cellX - atlasMinXUv) * imageryManager.tileSize + 0.5) / atlasWidth;\n                const v = ((c.cy - minY) * imageryManager.tileSize + 0.5) / atlasHeight;\n                uvArray[i * 2 + 0] = THREE.MathUtils.clamp(u, halfPixelU, 1 - halfPixelU);\n                uvArray[i * 2 + 1] = THREE.MathUtils.clamp(v, halfPixelV, 1 - halfPixelV);\n            }\n        }\n\n        // Check if we had previous imagery - use crossfade for smooth transition\n        const targetMaterial = (this.wireframeEnabled && this.materialDefault)\n            ? this.materialDefault\n            : this.mesh.material;\n        const hadPreviousImagery = !!targetMaterial.map;\n\n        // Store previous atlas key for release after crossfade\n        const prevAtlasKey = this.imageryAtlasKey;\n        const prevInheritedKey = this.inheritedAtlasKey;\n        const prevTexture = this.imageryTexture || targetMaterial.map;\n        const prevInheritedTexture = this.inheritedTexture;\n        const prevManager = this.imageryManager || imageryManager;\n\n        updateAttributeInPlace(this.geometry, 'uv2', uvArray, 2);\n        this._imageryVertexCount = totalCount;\n        this._markSkirtDirty();\n\n        // Retain the old identity before replacing its key/manager metadata.\n        if (hadPreviousImagery && this.crossfadeEnabled) {\n            this._startCrossfade(inherited.texture, new THREE.Vector2(0, 0), new THREE.Vector2(1, 1));\n        }\n        this.imageryManager = imageryManager;\n        this.imageryReady = true;\n        this.imageryInherited = true;\n        this.imageryInheritedZoom = atlasZoom;\n        this.imageryVersion = inherited.versionId;\n        this.imageryZoom = atlasZoom;\n        this.imageryTargetZoom = atlasZoom;\n        this.imageryAtlasKey = inherited.atlasKey;\n        this.imageryAtlasMinX = atlasMinXStored;\n        this.imageryAtlasMinY = minY;\n        this.imageryAtlasW = wTiles;\n        this.imageryAtlasH = hTiles;\n        this.imageryAtlasZoom = atlasZoom;\n        this.imageryTexture = inherited.texture;\n        this.inheritedAtlasKey = inherited.atlasKey;\n        this.inheritedTexture = inherited.texture;\n        const alreadyRetainingNewAtlas = prevAtlasKey === inherited.atlasKey &&\n            prevTexture === inherited.texture && prevManager === imageryManager;\n        if (!alreadyRetainingNewAtlas) {\n            imageryManager.retainAtlas(inherited.atlasKey, inherited.texture);\n        }\n        this._clearPendingInheritedImagery();\n\n        targetMaterial.map = inherited.texture;\n        targetMaterial.needsUpdate = true;\n\n        // Release old refs only after the new map is bound (or crossfade has retained old ref).\n        if (prevAtlasKey && !alreadyRetainingNewAtlas) {\n            prevManager.releaseAtlas(prevAtlasKey, prevTexture);\n        }\n        if (prevInheritedKey && prevInheritedKey !== prevAtlasKey) {\n            prevManager.releaseAtlas(prevInheritedKey, prevInheritedTexture);\n        }\n        this._setImageryLoading(false);\n\n        if (this.treeManager && typeof this.treeManager.onTileImageryReady === 'function') {\n            this.treeManager.onTileImageryReady(this);\n        }\n\n        this.fadeInStart = null;\n        this.fadeInCurrent = 1;\n        this.fadeInComplete = true;\n\n        return true;\n    }\n\n    // REMOVED: _applyInheritedImagery - no inherited imagery fallback, WMTS only\n\n    ensureMesh(parent, baseMaterial, treeManager = null) {\n        if (!this.mesh) {\n            this.buildGeometry();\n\n            // PHASE 3: Use material pooling if manager is available\n            // Tiles without imagery or with fallback colors share the base material\n            // SIMPLIFIED: Each tile gets its own cloned material (no pooling/sharing)\n            this.treeManager = treeManager;\n            if (this._pendingElevationUpdate) {\n                this._queueElevationUpdate();\n            }\n            if (this._pendingGeometryFinalize) {\n                this._queueGeometryFinalize();\n            }\n            let mat;\n            if (treeManager && typeof treeManager.getSharedMaterial === 'function') {\n                // Get unique cloned material for this tile\n                mat = treeManager.getSharedMaterial(baseMaterial);\n            } else {\n                // Fallback: clone directly if no manager\n                mat = baseMaterial.clone();\n            }\n\n            this.mesh = new THREE.Mesh(this.geometry, mat);\n            this.mesh.userData.firstDrawGuard = false; // terrain tiles swap seamlessly\n            this.mesh.castShadow = false;\n            this.mesh.receiveShadow = true;\n            // Visibility is managed by TriTreeManager; start hidden to avoid LOD overlap\n            this.mesh.visible = false;\n            this.mesh.userData.tile = this; // Store tile reference for surface sampling\n            if (!this.mesh.userData._lensFlareRaycastPatched && this.mesh.raycast) {\n                const baseRaycast = this.mesh.raycast.bind(this.mesh);\n                this.mesh.raycast = function (raycaster, intersects) {\n                    const material = this.material;\n                    let restore = null;\n                    if (Array.isArray(material)) {\n                        restore = material.map((matEntry) => {\n                            if (!matEntry) return null;\n                            const prev = matEntry.side;\n                            matEntry.side = THREE.DoubleSide;\n                            return prev;\n                        });\n                    } else if (material) {\n                        restore = material.side;\n                        material.side = THREE.DoubleSide;\n                    }\n                    try {\n                        baseRaycast(raycaster, intersects);\n                    } finally {\n                        if (Array.isArray(material) && Array.isArray(restore)) {\n                            material.forEach((matEntry, idx) => {\n                                if (!matEntry) return;\n                                const prev = restore[idx];\n                                if (prev !== null && prev !== undefined) {\n                                    matEntry.side = prev;\n                                }\n                            });\n                        } else if (material && restore !== null && restore !== undefined) {\n                            material.side = restore;\n                        }\n                    }\n                };\n                this.mesh.userData._lensFlareRaycastPatched = true;\n            }\n            // Position mesh at tile center - vertices are stored in local coordinates\n            this.mesh.position.copy(this.center);\n            parent.add(this.mesh);\n            this.materialDefault = mat;\n            this._ensureSkirtMesh();\n\n            // Initialize per-tile loading uniforms (center, radius, state)\n            this._syncLoadingUniforms();\n\n            if (this._pendingInheritedImagery) {\n                const pendingInherited = this._pendingInheritedImagery;\n                const pendingManager = this._pendingInheritedManager || treeManager?.imageryManager;\n                const pendingHoldManager = this._pendingInheritedManager;\n                const pendingHoldKey = this._pendingInheritedAtlasKey;\n\n                this._pendingInheritedImagery = null;\n                this._pendingInheritedManager = null;\n                this._pendingInheritedAtlasKey = null;\n\n                if (pendingInherited && pendingManager) {\n                    this._applyInheritedImagery(pendingInherited, pendingManager);\n                }\n                if (pendingHoldKey && pendingHoldManager) {\n                    pendingHoldManager.releaseAtlas(pendingHoldKey, pendingInherited.texture);\n                }\n            }\n\n            // WMTS imagery will be applied when loaded.\n        }\n    }\n\n    setVisible(visible) {\n        if (this.mesh) this.mesh.visible = visible;\n    }\n\n    /**\n     * Update fade-in animation for smooth tile loading transitions\n     * Call this every frame for tiles that are fading in\n     */\n    updateFadeIn() {\n        if (this.fadeInComplete || !this.fadeInEnabled || !this.fadeInStart) return false;\n        if (!this.mesh || !this.mesh.material) return false;\n\n        const now = performance.now();\n        const elapsed = now - this.fadeInStart;\n        const progress = Math.min(elapsed / this.fadeInDuration, 1.0);\n\n        // Ease-out cubic for smooth fade\n        const eased = 1 - Math.pow(1 - progress, 3);\n        this.fadeInCurrent = eased;\n\n        const targetMaterial = (this.wireframeEnabled && this.materialDefault)\n            ? this.materialDefault\n            : this.mesh.material;\n\n        if (targetMaterial) {\n            targetMaterial.opacity = eased;\n        }\n\n        if (progress >= 1.0) {\n            this.fadeInComplete = true;\n            this.fadeInStart = null;\n            if (targetMaterial) {\n                targetMaterial.opacity = 1;\n                if (targetMaterial.transparent) {\n                    targetMaterial.transparent = false;\n                    targetMaterial.needsUpdate = true;\n                }\n            }\n            return false; // Done fading\n        }\n\n        return true; // Still fading\n    }\n\n    /**\n     * Update crossfade animation for smooth imagery resolution transitions\n     * Blends between previous and current textures using shader uniform\n     * @returns {boolean} true if still animating, false if complete\n     */\n    updateCrossfade() {\n        if (this.crossfadeComplete || !this.crossfadeEnabled || !this.crossfadeStart) return false;\n        if (!this.mesh || !this.mesh.material) return false;\n\n        const now = performance.now();\n        const elapsed = now - this.crossfadeStart;\n        const progress = Math.min(elapsed / this.crossfadeDuration, 1.0);\n\n        // Ease-out cubic for smooth blend\n        const eased = 1 - Math.pow(1 - progress, 3);\n        this.crossfadeBlend = eased;\n\n        const targetMaterial = (this.wireframeEnabled && this.materialDefault)\n            ? this.materialDefault\n            : this.mesh.material;\n\n        // Update shader uniform for crossfade blend\n        if (targetMaterial?.userData?.uniforms?.imageryBlend) {\n            targetMaterial.userData.uniforms.imageryBlend.value = eased;\n        }\n\n        if (progress >= 1.0) {\n            this.crossfadeComplete = true;\n            this.crossfadeStart = null;\n            this.crossfadeBlend = 1.0;\n\n            // Release the previous texture reference now that crossfade is complete\n            this._releaseCrossfadePrevTexture();\n\n            // Reset uniforms to fully show current texture (if uniforms exist)\n            if (targetMaterial?.userData?.uniforms) {\n                const uniforms = targetMaterial.userData.uniforms;\n                if (uniforms.imageryBlend) uniforms.imageryBlend.value = 1.0;\n                if (uniforms.imageryTexturePrev) uniforms.imageryTexturePrev.value = null;\n            }\n\n            return false; // Done crossfading\n        }\n\n        return true; // Still crossfading\n    }\n\n    /**\n     * Start a crossfade transition from current imagery to new imagery\n     * @param {THREE.Texture} newTexture - The new texture to fade to\n     * @param {THREE.Vector2} prevUvOffset - UV offset for previous texture\n     * @param {THREE.Vector2} prevUvScale - UV scale for previous texture\n     */\n    _startCrossfade(newTexture, prevUvOffset, prevUvScale) {\n        if (!this.crossfadeEnabled || !this.mesh?.material) {\n            return;\n        }\n\n        const targetMaterial = (this.wireframeEnabled && this.materialDefault)\n            ? this.materialDefault\n            : this.mesh.material;\n\n        // Store current texture as previous for blending\n        const currentTex = targetMaterial.map;\n        if (!currentTex) {\n            // No previous texture, just set new one directly\n            return;\n        }\n\n        if (currentTex === newTexture) return;\n        this._releaseCrossfadePrevTexture();\n        // Retain reference to previous atlas\n        if (this.imageryAtlasKey && this.imageryManager) {\n            this.crossfadePrevAtlasKey = this.imageryAtlasKey;\n            this.crossfadePrevManager = this.imageryManager;\n            this.crossfadePrevManager.retainAtlas(this.crossfadePrevAtlasKey, currentTex);\n        }\n\n        this.crossfadePrevTexture = currentTex;\n        this.crossfadePrevUvOffset = prevUvOffset || new THREE.Vector2(0, 0);\n        this.crossfadePrevUvScale = prevUvScale || new THREE.Vector2(1, 1);\n\n        // Set up shader uniforms for crossfade (if uniforms exist - crossfade may be disabled)\n        if (targetMaterial?.userData?.uniforms) {\n            const uniforms = targetMaterial.userData.uniforms;\n            if (uniforms.imageryTexturePrev) uniforms.imageryTexturePrev.value = currentTex;\n            if (uniforms.imageryBlend) uniforms.imageryBlend.value = 0;\n            if (uniforms.imageryPrevUvOffset) {\n                uniforms.imageryPrevUvOffset.value.copy(this.crossfadePrevUvOffset);\n            }\n            if (uniforms.imageryPrevUvScale) {\n                uniforms.imageryPrevUvScale.value.copy(this.crossfadePrevUvScale);\n            }\n        }\n\n        // Start crossfade animation\n        this.crossfadeStart = performance.now();\n        this.crossfadeBlend = 0;\n        this.crossfadeComplete = false;\n        registerCrossfadeTile(this);\n    }\n\n    /**\n     * Release the previous texture reference after crossfade completes\n     */\n    _releaseCrossfadePrevTexture() {\n        const manager = this.crossfadePrevManager || this.imageryManager;\n        if (this.crossfadePrevAtlasKey && manager) {\n            manager.releaseAtlas(this.crossfadePrevAtlasKey, this.crossfadePrevTexture);\n        }\n        this.crossfadePrevManager = null;\n        this.crossfadePrevAtlasKey = null;\n        this.crossfadePrevTexture = null;\n        this.crossfadePrevUvOffset = null;\n        this.crossfadePrevUvScale = null;\n    }\n\n    /**\n     * Adopt imagery from best child during merge (zoom out)\n     * Finds the child with highest resolution imagery and inherits it\n     */\n    _adoptChildImagery({ minCoverageRatio = 1 } = {}) {\n        if (!this.children || !this.mesh || !this.geometry || !this.baseDirs) return false;\n\n        // Find best child imagery (highest zoom level, with actual imagery)\n        let bestChild = null;\n        let bestZoom = -1;\n        for (const child of this.children) {\n            if (!child) continue;\n            if (child.hasImageryCoverage?.() && child.imageryTexture && child.imageryAtlasKey) {\n                const zoom = Number.isFinite(child.imageryZoom) ? child.imageryZoom : 0;\n                if (zoom > bestZoom) {\n                    bestZoom = zoom;\n                    bestChild = child;\n                }\n            }\n        }\n\n        if (!bestChild || !bestChild.imageryManager) return false;\n\n        // Build inherited imagery data from best child\n        const inherited = {\n            texture: bestChild.imageryTexture,\n            atlasKey: bestChild.imageryAtlasKey,\n            atlasZoom: Number.isFinite(bestChild.imageryAtlasZoom) ? bestChild.imageryAtlasZoom : bestChild.imageryZoom,\n            minX: bestChild.imageryAtlasMinX,\n            minY: bestChild.imageryAtlasMinY,\n            wTiles: bestChild.imageryAtlasW,\n            hTiles: bestChild.imageryAtlasH,\n            versionId: bestChild.imageryVersion\n        };\n\n        const coverageRatio = this._computeInheritedCoverageRatio(inherited, bestChild.imageryManager);\n        const clampedMinCoverage = THREE.MathUtils.clamp(\n            Number.isFinite(minCoverageRatio) ? minCoverageRatio : 1,\n            0,\n            1\n        );\n        if (!Number.isFinite(coverageRatio) || coverageRatio < clampedMinCoverage) {\n            return false;\n        }\n\n        // Store reference to imageryManager before applying\n        this.imageryManager = bestChild.imageryManager;\n\n        // Apply inherited imagery - this recalculates UVs for parent tile\n        return this._applyInheritedImagery(inherited, bestChild.imageryManager);\n    }\n\n    _computeAtlasBoundsForZoom(targetZoom, { padTiles = 0, useAutoCoverage = true, maxSpan = null } = {}) {\n        if (!Number.isFinite(targetZoom)) return null;\n        const baseCount = this.vertexCount || (this.baseDirs ? this.baseDirs.length / 3 : 0);\n        if (!baseCount || !this.baseDirs) return null;\n        const totalCount = this.positionAttr?.count || baseCount;\n        const tmpDir = new THREE.Vector3();\n        let minCx = +Infinity, maxCx = -Infinity;\n        let minCy = +Infinity, maxCy = -Infinity;\n        let sumSin = 0;\n        let sumCos = 0;\n        let n = 0;\n\n        for (let i = 0; i < baseCount; i++) {\n            const bx = this.baseDirs[i * 3 + 0];\n            const by = this.baseDirs[i * 3 + 1];\n            const bz = this.baseDirs[i * 3 + 2];\n            tmpDir.set(bx, by, bz);\n            const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n            const c = lonLatToTileCoords(lonDeg, latDeg, targetZoom);\n            n = c.n;\n            const angle = (c.cx / n) * TWO_PI;\n            sumSin += Math.sin(angle);\n            sumCos += Math.cos(angle);\n            if (c.cy < minCy) minCy = c.cy;\n            if (c.cy > maxCy) maxCy = c.cy;\n        }\n\n        if (useAutoCoverage && totalCount > baseCount && this.positionAttr) {\n            const pos = this.positionAttr.array;\n            const cx = this.center.x;\n            const cy = this.center.y;\n            const cz = this.center.z;\n            for (let i = baseCount; i < totalCount; i++) {\n                const i3 = i * 3;\n                const x = pos[i3 + 0] + cx;\n                const y = pos[i3 + 1] + cy;\n                const z = pos[i3 + 2] + cz;\n                tmpDir.set(x, y, z).normalize();\n                const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n                const c = lonLatToTileCoords(lonDeg, latDeg, targetZoom);\n                n = c.n;\n                const angle = (c.cx / n) * TWO_PI;\n                sumSin += Math.sin(angle);\n                sumCos += Math.cos(angle);\n                if (c.cy < minCy) minCy = c.cy;\n                if (c.cy > maxCy) maxCy = c.cy;\n            }\n        }\n\n        if (!Number.isFinite(n) || n <= 0) return null;\n        const meanAngle = Math.atan2(sumSin, sumCos);\n        const refCx = THREE.MathUtils.euclideanModulo((meanAngle / TWO_PI) * n, n);\n\n        for (let i = 0; i < baseCount; i++) {\n            const bx = this.baseDirs[i * 3 + 0];\n            const by = this.baseDirs[i * 3 + 1];\n            const bz = this.baseDirs[i * 3 + 2];\n            tmpDir.set(bx, by, bz);\n            const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n            const c = lonLatToTileCoords(lonDeg, latDeg, targetZoom);\n            let cxTile = c.cx;\n            if (cxTile - refCx > n * 0.5) cxTile -= n;\n            else if (refCx - cxTile > n * 0.5) cxTile += n;\n            if (cxTile < minCx) minCx = cxTile;\n            if (cxTile > maxCx) maxCx = cxTile;\n        }\n\n        if (useAutoCoverage && totalCount > baseCount && this.positionAttr) {\n            const pos = this.positionAttr.array;\n            const cx = this.center.x;\n            const cy = this.center.y;\n            const cz = this.center.z;\n            for (let i = baseCount; i < totalCount; i++) {\n                const i3 = i * 3;\n                const x = pos[i3 + 0] + cx;\n                const y = pos[i3 + 1] + cy;\n                const z = pos[i3 + 2] + cz;\n                tmpDir.set(x, y, z).normalize();\n                const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n                const c = lonLatToTileCoords(lonDeg, latDeg, targetZoom);\n                let cxTile = c.cx;\n                if (cxTile - refCx > n * 0.5) cxTile -= n;\n                else if (refCx - cxTile > n * 0.5) cxTile += n;\n                if (cxTile < minCx) minCx = cxTile;\n                if (cxTile > maxCx) maxCx = cxTile;\n            }\n        }\n\n        let minX = Math.floor(minCx) - padTiles;\n        let maxX = Math.floor(maxCx) + padTiles;\n        let minY = Math.floor(minCy) - padTiles;\n        let maxY = Math.floor(maxCy) + padTiles;\n\n        minY = Math.max(0, minY);\n        maxY = Math.min(n - 1, maxY);\n        const spanX = Math.max(1, maxX - minX + 1);\n        const spanY = Math.max(1, maxY - minY + 1);\n        const maxAllowed = Number.isFinite(maxSpan) ? Math.max(1, Math.floor(maxSpan)) : null;\n        if (maxAllowed && (spanX > maxAllowed || spanY > maxAllowed)) {\n            return null;\n        }\n\n        return {\n            minX,\n            maxX,\n            minY,\n            maxY,\n            wTiles: spanX,\n            hTiles: spanY,\n            zoom: targetZoom,\n            n,\n            refCx\n        };\n    }\n\n    _computeInheritedCoverageRatio(inherited, imageryManager) {\n        if (!inherited || !imageryManager) return 0;\n        const atlasZoom = inherited.atlasZoom;\n        const minX = inherited.minX;\n        const minY = inherited.minY;\n        const wTiles = inherited.wTiles;\n        const hTiles = inherited.hTiles;\n        if (!Number.isFinite(atlasZoom) ||\n            !Number.isFinite(minX) || !Number.isFinite(minY) ||\n            !Number.isFinite(wTiles) || !Number.isFinite(hTiles)) {\n            return 0;\n        }\n\n        const required = this._computeAtlasBoundsForZoom(atlasZoom, {\n            padTiles: 0,\n            useAutoCoverage: true,\n            maxSpan: null\n        });\n        if (!required) return 0;\n\n        const reqW = Math.max(1, required.maxX - required.minX + 1);\n        const reqH = Math.max(1, required.maxY - required.minY + 1);\n        const reqArea = reqW * reqH;\n        if (!Number.isFinite(reqArea) || reqArea <= 0) return 0;\n\n        const atlasMinY = minY;\n        const atlasMaxY = minY + hTiles - 1;\n        const overlapY = Math.max(0, Math.min(required.maxY, atlasMaxY) - Math.max(required.minY, atlasMinY) + 1);\n        if (overlapY <= 0) return 0;\n\n        const atlasMinX = minX;\n        const atlasMaxX = minX + wTiles - 1;\n        const n = Number.isFinite(required.n) ? required.n : null;\n        const shiftCandidates = n ? [-n, 0, n] : [0];\n        let overlapX = 0;\n        for (const shift of shiftCandidates) {\n            const shiftedMin = atlasMinX + shift;\n            const shiftedMax = atlasMaxX + shift;\n            const candidate = Math.max(0, Math.min(required.maxX, shiftedMax) - Math.max(required.minX, shiftedMin) + 1);\n            if (candidate > overlapX) overlapX = candidate;\n        }\n        if (overlapX <= 0) return 0;\n\n        const overlapArea = overlapX * overlapY;\n        return THREE.MathUtils.clamp(overlapArea / reqArea, 0, 1);\n    }\n\n    _resolveMergeMosaicOptions(imageryManager) {\n        const tree = this.treeManager;\n        const defaultMaxAtlasTiles = Number.isFinite(imageryManager?.maxAtlasTiles)\n            ? Math.max(1, Math.floor(imageryManager.maxAtlasTiles))\n            : 8;\n        const maxAtlasTiles = Number.isFinite(tree?.mergeMosaicMaxAtlasTiles)\n            ? Math.max(1, Math.floor(tree.mergeMosaicMaxAtlasTiles))\n            : Math.max(defaultMaxAtlasTiles, Math.min(16, defaultMaxAtlasTiles + 2));\n        const padTiles = Number.isFinite(tree?.mergeMosaicPadTiles)\n            ? Math.max(0, Math.floor(tree.mergeMosaicPadTiles))\n            : 0;\n        const minZoom = Number.isFinite(tree?.mergeMosaicMinZoom)\n            ? Math.max(0, Math.floor(tree.mergeMosaicMinZoom))\n            : 0;\n        const priority = Number.isFinite(tree?.mergeMosaicPriority)\n            ? tree.mergeMosaicPriority\n            : 1000;\n        return {\n            maxAtlasTiles,\n            padTiles,\n            minZoom,\n            priority\n        };\n    }\n\n    _tryAdoptChildMosaicImagery() {\n        if (!this.children || !this.mesh || !this.geometry || !this.baseDirs) return false;\n        const candidates = this.children.filter((child) => {\n            if (!child || !child.hasImageryCoverage?.()) return false;\n            const hasZoom = Number.isFinite(child.imageryAtlasZoom) || Number.isFinite(child.imageryZoom);\n            const hasVersion = !!(child.imageryVersion || child.imageryManager?.versionId || this.imageryVersion);\n            return hasZoom && hasVersion;\n        });\n        if (!candidates.length) return false;\n\n        let baseChild = null;\n        let baseZoom = -1;\n        for (const child of candidates) {\n            const childZoom = Number.isFinite(child.imageryAtlasZoom)\n                ? child.imageryAtlasZoom\n                : child.imageryZoom;\n            if (!Number.isFinite(childZoom)) continue;\n            if (!baseChild || childZoom > baseZoom) {\n                baseChild = child;\n                baseZoom = childZoom;\n            }\n        }\n        if (!baseChild || !Number.isFinite(baseZoom)) return false;\n\n        const imageryManager = baseChild.imageryManager || this.imageryManager || this.treeManager?.imageryManager;\n        if (!imageryManager) return false;\n\n        const versionId = baseChild.imageryVersion || this.imageryVersion || imageryManager.versionId;\n        if (!versionId) return false;\n\n        const options = this._resolveMergeMosaicOptions(imageryManager);\n        const startZoom = Math.max(0, Math.floor(baseZoom));\n        const minZoom = Math.min(startZoom, options.minZoom);\n        let bounds = null;\n        for (let zoom = startZoom; zoom >= minZoom; zoom--) {\n            bounds = this._computeAtlasBoundsForZoom(zoom, {\n                padTiles: options.padTiles,\n                useAutoCoverage: true,\n                maxSpan: options.maxAtlasTiles\n            });\n            if (bounds) break;\n        }\n        if (!bounds) return false;\n\n        const seq = (this._mergeMosaicSeq = (this._mergeMosaicSeq || 0) + 1);\n        imageryManager.buildMosaicAtlasFromTiles({\n            versionId,\n            z: bounds.zoom,\n            minX: bounds.minX,\n            minY: bounds.minY,\n            wTiles: bounds.wTiles,\n            hTiles: bounds.hTiles,\n            priority: options.priority,\n            contextKey: 'merge-mosaic'\n        }).then((mosaic) => {\n            if (!mosaic || this._mergeMosaicSeq !== seq) return;\n            if (!this.mesh || !this.geometry || !this.baseDirs) return;\n            this.imageryManager = imageryManager;\n            this._applyInheritedImagery(mosaic, imageryManager);\n        }).catch(() => {});\n\n        return true;\n    }\n\n    applyRenderRules(rules = {}) {\n        if (!this.mesh || !this.mesh.material) return;\n        if (rules.wireframe !== undefined) {\n            if (rules.wireframe) {\n                // ALWAYS apply wireframe when rules say wireframe is on\n                // This ensures material is correct even if state got out of sync\n                const needsApply = !this.wireframeEnabled ||\n                    this.mesh.material !== this.materialWireframeFill;\n                if (needsApply) {\n                    this._enableWireframeMode();\n                }\n            } else if (this.wireframeEnabled) {\n                this._disableWireframeMode();\n            }\n        }\n    }\n\n    setBaseMaterial(materialInstance) {\n        if (!materialInstance) return;\n        materialInstance.wireframe = false;\n        if (this.materialDefault && this.materialDefault !== materialInstance &&\n            typeof this.materialDefault.dispose === 'function') {\n            this.materialDefault.dispose();\n        }\n        this.materialDefault = materialInstance;\n        if (this.mesh && !this.wireframeEnabled) {\n            this.mesh.material = materialInstance;\n            this.mesh.material.needsUpdate = true;\n        }\n        this._syncSkirtMaterial();\n        this._syncLoadingUniforms();\n    }\n\n    _enableWireframeMode() {\n        if (!this.mesh) return;\n\n        this.wireframeEnabled = true;\n        if (!this.materialWireframeFill) {\n            this.materialWireframeFill = getWireframeFillMaterial();\n        }\n        // CRITICAL: Always set material, even if already set\n        this.mesh.material = this.materialWireframeFill;\n        this.mesh.material.needsUpdate = true;\n        this._syncSkirtMaterial();\n\n        // Keep imagery textures resident while in wireframe so we can instantly recover.\n        if (this.materialDefault?.uniforms?.imageryBlend) {\n            this.materialDefault.uniforms.imageryBlend.value = 1.0;\n        }\n        if (this.materialDefault?.userData?.uniforms?.imageryBlend) {\n            this.materialDefault.userData.uniforms.imageryBlend.value = 1.0;\n        }\n\n        // Release crossfade texture references\n        this._releaseCrossfadePrevTexture();\n        this.crossfadeComplete = true;\n        this.crossfadeStart = null;\n\n        this._ensureWireframeOverlay();\n    }\n\n    _disableWireframeMode() {\n        this.wireframeEnabled = false;\n        if (this.mesh && this.materialDefault) {\n            this.mesh.material = this.materialDefault;\n            this.mesh.material.needsUpdate = true;\n        }\n        this._syncSkirtMaterial();\n        if (this.wireframeOverlay) {\n            this.wireframeOverlay.visible = false;\n        }\n    }\n\n    _ensureWireframeOverlay() {\n        // Line overlay is controlled by global wireframe style setting\n        // Disabled by default for performance (doubles draw calls per tile)\n        if (!wireframeStyleState.lineOverlayEnabled) {\n            // If overlay exists but is now disabled, hide it\n            if (this.wireframeOverlay) {\n                this.wireframeOverlay.visible = false;\n            }\n            return;\n        }\n        if (!this.mesh || !this.geometry) return;\n        if (!this.wireframeOverlay) {\n            const wireMat = getWireframeLineMaterial();\n            const wireMesh = new THREE.Mesh(this.geometry, wireMat);\n            wireMesh.renderOrder = 2;\n            this.wireframeOverlay = wireMesh;\n            this.mesh.add(wireMesh);\n        }\n        this.wireframeOverlay.visible = true;\n    }\n\n    _disposeWireframeAssets() {\n        if (this.wireframeOverlay) {\n            if (this.wireframeOverlay.parent) {\n                this.wireframeOverlay.parent.remove(this.wireframeOverlay);\n            }\n            if (this.wireframeOverlay.material && !this.wireframeOverlay.material.userData?.shared) {\n                this.wireframeOverlay.material.dispose();\n            }\n            this.wireframeOverlay = null;\n        }\n        if (this.materialWireframeFill && !this.materialWireframeFill.userData?.shared) {\n            this.materialWireframeFill.dispose();\n        }\n        this.materialWireframeFill = null;\n        this.wireframeEnabled = false;\n    }\n\n    /**\n     * Remove mesh from scene (for parent tiles that have been subdivided)\n     */\n    removeMesh(group) {\n        const preserveLowLod = this.level <= 4;\n        if (this.mesh) {\n            this.prepareChildrenForSplit();\n            if (preserveLowLod) {\n                // Keep low LOD atlas/data resident for fast zoom-out reuse; just hide the mesh\n                this.mesh.visible = false;\n                this.deferredRemoval = false;\n                return;\n            }\n            // Clear imagery first to release atlas references\n            this.clearImagery();\n            this._disposeWireframeAssets();\n            this._disposeSkirtMesh();\n\n            group.remove(this.mesh);\n            if (this.mesh.geometry) this.mesh.geometry.dispose();\n            if (this.mesh.material) this.mesh.material.dispose();\n            this.mesh = null;\n        }\n        if (!preserveLowLod) {\n            this.geometry = null;\n            this.baseDirs = null;\n            this.baseRadii = null;\n            this.positionAttr = null;\n            this.resolution = 0;\n            this.vertexCount = 0;\n            this.elevationExpected = 0;\n            this.elevationDone = 0;\n            this.elevationState = null;\n            this.elevationSeeded = null;\n            this.elevationFillMask = null;\n            this.elevationComplete = false;\n            this.elevationHasData = false;\n            this.elevationRetryIndex = 0;\n            this.elevationMorphCurrent = null;\n            this.elevationMorphTarget = null;\n            this.elevationMorphPending = null;\n            this.elevationHoldPending = null;\n            this.elevationHoldUntilComplete = false;\n            this._elevationFillAverage = null;\n            this._elevationFillAverageDone = -1;\n            this._elevationFillAverageDoneOnly = null;\n            this._elevationFillAverageDoneOnlyDone = -1;\n            this._elevationLastProgressMs = 0;\n            this._elevationLastProgressDone = -1;\n            this._elevationStallSinceMs = 0;\n            this.waterMaskAttr = null;\n            // Inform elevation client to prune vertices tied to this tile\n            if (this.elevationClient && typeof this.elevationClient.pruneTile === 'function') {\n                this.elevationClient.pruneTile(this, { keepRecords: true });\n            }\n        }\n        this.deferredRemoval = false;\n    }\n\n    // REMOVED: Deferred removal system (removeMeshDeferred, notifyChildReady) - instant subdivision only\n\n    destroyChildren(group) {\n        if (!this.children) return 0;\n        this.cacheElevationFromChildren();\n        this.applyElevationCacheToMesh();\n\n        const canInheritImagery = this.treeManager?.imageryInheritanceEnabled === true;\n        if (canInheritImagery) {\n            // Prefer a merge-time mosaic from child tiles (no UV stretching).\n            const adoptedMosaic = this._tryAdoptChildMosaicImagery();\n            const minCoverageRatio = Number.isFinite(this.treeManager?.mergeChildAdoptMinCoverage)\n                ? this.treeManager.mergeChildAdoptMinCoverage\n                : 0.995;\n            // Only fall back to single-child inheritance when it fully covers the parent tile.\n            const adoptedChild = adoptedMosaic\n                ? false\n                : this._adoptChildImagery({ minCoverageRatio });\n            if (!adoptedChild && !adoptedMosaic && this.imageryInherited) {\n                this.clearImagery();\n            }\n        } else if (this.imageryInherited) {\n            this.clearImagery();\n        }\n\n        let count = 0;\n        const stack = [...this.children];\n        while (stack.length) {\n            const t = stack.pop();\n            if (t.children) stack.push(...t.children);\n\n            // Clear imagery first to release atlas references\n            t.clearImagery();\n            t._disposeWireframeAssets();\n            t._disposeSkirtMesh();\n\n            if (t.mesh) {\n                group.remove(t.mesh);\n                if (t.mesh.geometry) {\n                    // Return geometry to pool for reuse instead of disposing\n                    releasePooledGeometry(t.mesh.geometry, t.resolution);\n                }\n                if (t.mesh.material) t.mesh.material.dispose();\n                t.mesh.geometry = null;\n                t.mesh.material = null;\n                t.mesh = null;\n            }\n            t.geometry = null;\n            t.baseDirs = null;\n            t.baseRadii = null;\n            t.positionAttr = null;\n            t.resolution = 0;\n            t.vertexCount = 0;\n            t.elevationExpected = 0;\n            t.elevationDone = 0;\n            t.elevationState = null;\n            t.elevationSeeded = null;\n            t.elevationSeededCount = 0;\n            t.elevationFillMask = null;\n            t.elevationComplete = false;\n            t.elevationHasData = false;\n            t.elevationRetryIndex = 0;\n            t.elevationMorphCurrent = null;\n            t.elevationMorphTarget = null;\n            t.elevationMorphPending = null;\n            t.elevationHoldPending = null;\n            t.elevationHoldUntilComplete = false;\n            t.elevationFillComplete = false;\n            t._elevationFillCompleteDone = -1;\n            t._elevationFillCompleteSeeded = -1;\n            t._elevationFillAverage = null;\n            t._elevationFillAverageDone = -1;\n            t._elevationFillAverageDoneOnly = null;\n            t._elevationFillAverageDoneOnlyDone = -1;\n            t._elevationLastProgressMs = 0;\n            t._elevationLastProgressDone = -1;\n            t._elevationStallSinceMs = 0;\n            t.waterMaskAttr = null;\n            t.children = null;\n\n            // FIX #3: Clear neighbor tracking maps to prevent stale references\n            if (t.neighbors) t.neighbors.clear();\n            if (t.edgeElevationCache) t.edgeElevationCache.clear();\n            if (t.stitchedEdges) t.stitchedEdges.clear();\n            if (t.deferredEdgeElevations) t.deferredEdgeElevations.clear();\n            t.edgeVertexMask = null;\n\n            if (this.elevationClient && typeof this.elevationClient.pruneTile === 'function') {\n                this.elevationClient.pruneTile(t, { keepRecords: true });\n            }\n            count++;\n        }\n        this.children = null;\n        this.childrenPrepared = false;\n        return count;\n    }\n\n    _applyElevationAtIndex(index, elevMeters, syncMorph = true) {\n        if (!this.positionAttr || !this.baseDirs) return;\n        const base = this.baseDirs;\n        const pos = this.positionAttr.array;\n\n        const bx = base[index * 3 + 0];\n        const by = base[index * 3 + 1];\n        const bz = base[index * 3 + 2];\n\n        if (!this.elevationValues || this.elevationValues.length !== this.positionAttr.count) {\n            this.elevationValues = new Float32Array(this.positionAttr.count);\n            this.elevationValues.fill(Number.NaN);\n        }\n        if (Number.isFinite(elevMeters)) {\n            this.elevationValues[index] = elevMeters;\n        }\n\n        const baseRadius = this._getBaseRadiusAtIndex(index);\n        const baseElev = Number.isFinite(elevMeters) ? elevMeters : 0;\n        const offset = (this.photogramOffsets && Number.isFinite(this.photogramOffsets[index]))\n            ? this.photogramOffsets[index]\n            : 0;\n        const r = radiusFromElevation(baseRadius, baseElev + offset);\n\n        // Store position relative to tile center (local coordinates)\n        pos[index * 3 + 0] = bx * r - this.center.x;\n        pos[index * 3 + 1] = by * r - this.center.y;\n        pos[index * 3 + 2] = bz * r - this.center.z;\n        if (Number.isFinite(elevMeters)) {\n            this.elevationHasData = true;\n        }\n\n        if (syncMorph && this.elevationMorphCurrent && this.elevationMorphTarget) {\n            this.elevationMorphCurrent[index] = elevMeters;\n            this.elevationMorphTarget[index] = elevMeters;\n            if (this.elevationMorphPending) this.elevationMorphPending.delete(index);\n        }\n    }\n\n    _queueElevationUpdate() {\n        if (this.treeManager && typeof this.treeManager.queueElevationUpdate === 'function') {\n            this.treeManager.queueElevationUpdate(this);\n            this._pendingElevationUpdate = false;\n        } else {\n            this._pendingElevationUpdate = true;\n        }\n    }\n\n    _queueGeometryFinalize() {\n        if (this.treeManager && typeof this.treeManager.queueGeometryFinalize === 'function') {\n            this.treeManager.queueGeometryFinalize(this);\n            this._pendingGeometryFinalize = false;\n        } else {\n            this._pendingGeometryFinalize = true;\n        }\n    }\n\n    _markGeometryDirty() {\n        if (this.positionAttr) {\n            this.positionAttr.needsUpdate = true;\n        }\n        this._boundsDirty = true;\n        this._normalsDirty = true;\n        this._markSkirtDirty();\n        this._queueGeometryFinalize();\n    }\n\n    needsElevationUpdate() {\n        return !!(this.elevationMorphPending && this.elevationMorphPending.size > 0) ||\n            (this.elevationFillEnabled && !this.elevationFillComplete);\n    }\n\n    updateVertex(index, elevMeters, markDone = true) {\n        if (!this.positionAttr || !this.baseDirs) return;\n        if (Number.isFinite(elevMeters)) {\n            this.elevationHasData = true;\n        }\n        if (!this.elevationValues || this.elevationValues.length !== this.positionAttr.count) {\n            this.elevationValues = new Float32Array(this.positionAttr.count);\n            this.elevationValues.fill(Number.NaN);\n        }\n        if (Number.isFinite(elevMeters)) {\n            this.elevationValues[index] = elevMeters;\n        }\n\n        if (markDone && this._shouldDeferEdgeUpdate(index)) {\n            if (!this.deferredEdgeElevations) this.deferredEdgeElevations = new Map();\n            this.deferredEdgeElevations.set(index, elevMeters);\n\n            const cache = this.edgeElevationCache ? this.edgeElevationCache.get(index) : null;\n            if (cache) {\n                cache.originalElevMeters = elevMeters;\n            }\n            this.elevationFillComplete = false;\n            this._queueElevationUpdate();\n            return;\n        }\n\n        if (this.elevationFillMask && this.elevationFillMask[index] === 1) {\n            this.elevationFillMask[index] = 0;\n        }\n\n        if (this.deferredEdgeElevations && this.deferredEdgeElevations.has(index)) {\n            this.deferredEdgeElevations.delete(index);\n        }\n\n        const cache = this.edgeElevationCache ? this.edgeElevationCache.get(index) : null;\n        const isStitchedVertex = !!cache;\n        const lockMode = cache ? cache.lockMode : null;\n        const preserveStitch = isStitchedVertex && markDone && lockMode === 'hard';\n        const holdUpdate = markDone && this.elevationHoldUntilComplete && !this.elevationComplete;\n\n        if (isStitchedVertex && markDone) {\n            cache.originalElevMeters = elevMeters;\n            if (!preserveStitch) {\n                this.edgeElevationCache.delete(index);\n            }\n        }\n\n        let didMorph = false;\n        if (!preserveStitch) {\n            if (holdUpdate) {\n                if (!this.elevationHoldPending) this.elevationHoldPending = new Map();\n                this.elevationHoldPending.set(index, elevMeters);\n                didMorph = true;\n            } else {\n                const allowMorph = markDone && this.elevationMorphEnabled && this._ensureElevationMorphBuffers();\n                if (allowMorph) {\n                    this.elevationMorphTarget[index] = elevMeters;\n                    if (!this.elevationMorphPending) this.elevationMorphPending = new Set();\n                    this.elevationMorphPending.add(index);\n                    this._queueElevationUpdate();\n                    didMorph = true;\n                } else {\n                    // Normal vertex - apply elevation directly (including proxy data)\n                    this._applyElevationAtIndex(index, elevMeters, markDone);\n                }\n            }\n        }\n\n        if (this.elevationSeeded && markDone) {\n            if (this.elevationSeeded[index] !== 1) {\n                this.elevationSeededCount += 1;\n            }\n            this.elevationSeeded[index] = 1;\n        }\n        if (markDone) {\n            this.elevationFillComplete = false;\n            this._queueElevationUpdate();\n        }\n\n        if (markDone) {\n            this.markElevationDone(index);\n        }\n\n        if (!preserveStitch && !didMorph) {\n            this._markGeometryDirty();\n        }\n    }\n\n    flushDeferredEdgeElevations(maxApply = null) {\n        if (!this.deferredEdgeElevations || this.deferredEdgeElevations.size === 0) return 0;\n        if (!this.positionAttr || !this.baseDirs) return 0;\n\n        const limit = Number.isFinite(maxApply) ? Math.max(0, Math.floor(maxApply)) : Infinity;\n        if (limit <= 0) return 0;\n\n        const allowMorph = this.elevationMorphEnabled && this._ensureElevationMorphBuffers();\n        let applied = 0;\n        let directUpdated = 0;\n        const toRemove = [];\n\n        for (const [idx, elevMeters] of this.deferredEdgeElevations.entries()) {\n            if (applied >= limit) break;\n            if (this._shouldDeferEdgeUpdate(idx)) continue;\n\n            if (allowMorph) {\n                this.elevationMorphTarget[idx] = elevMeters;\n                if (!this.elevationMorphPending) this.elevationMorphPending = new Set();\n                this.elevationMorphPending.add(idx);\n            } else {\n                this._applyElevationAtIndex(idx, elevMeters, true);\n                directUpdated++;\n            }\n\n            if (this.edgeElevationCache) {\n                this.edgeElevationCache.delete(idx);\n            }\n\n            toRemove.push(idx);\n            applied++;\n        }\n\n        for (const idx of toRemove) {\n            this.deferredEdgeElevations.delete(idx);\n            this.markElevationDone(idx);\n        }\n\n        if (allowMorph && applied > 0) {\n            this._queueElevationUpdate();\n        }\n\n        if (directUpdated > 0) {\n            this._markGeometryDirty();\n        }\n\n        return applied;\n    }\n\n    applyElevationMorph(dt) {\n        if (this.elevationHoldUntilComplete && !this.elevationComplete) {\n            return 0;\n        }\n        let updated = 0;\n        if (this.elevationMorphEnabled &&\n            this.elevationMorphPending &&\n            this.elevationMorphPending.size > 0 &&\n            this.positionAttr &&\n            this.baseDirs) {\n            const speed = Number.isFinite(this.elevationMorphSpeed) ? this.elevationMorphSpeed : 4;\n            const epsilon = Number.isFinite(this.elevationMorphEpsilon) ? this.elevationMorphEpsilon : 0.05;\n            const step = 1 - Math.exp(-speed * Math.max(0, dt || 0));\n            if (Number.isFinite(step) && step > 0) {\n                const pending = this.elevationMorphPending;\n                const remove = [];\n\n                for (const idx of pending) {\n                    const cache = this.edgeElevationCache ? this.edgeElevationCache.get(idx) : null;\n                    if (cache && cache.lockMode === 'hard') {\n                        remove.push(idx);\n                        continue;\n                    }\n                    const target = this.elevationMorphTarget?.[idx];\n                    const current = this.elevationMorphCurrent?.[idx];\n                    if (!Number.isFinite(target) || !Number.isFinite(current)) {\n                        remove.push(idx);\n                        continue;\n                    }\n                    let next = current + (target - current) * step;\n                    if (Math.abs(target - next) <= epsilon) {\n                        next = target;\n                        remove.push(idx);\n                    }\n                    this.elevationMorphCurrent[idx] = next;\n                    this._applyElevationAtIndex(idx, next, false);\n                    updated++;\n                }\n\n                for (const idx of remove) pending.delete(idx);\n                if (pending.size === 0) this.elevationMorphPending = null;\n            }\n        }\n\n        const filled = this.fillMissingElevations(this.elevationFillMaxPerFrame);\n        updated += filled;\n\n        if (updated > 0) {\n            this._markGeometryDirty();\n        }\n\n        return updated;\n    }\n\n    clearImagery(options = {}) {\n        const preservePhotogram = options?.preservePhotogram === true;\n        this._clearPendingInheritedImagery();\n        // Release atlas reference before clearing\n        if (this.imageryManager && this.imageryAtlasKey) {\n            this.imageryManager.releaseAtlas(this.imageryAtlasKey, this.imageryTexture);\n        }\n        if (this.imageryManager && this.inheritedAtlasKey && this.inheritedAtlasKey !== this.imageryAtlasKey) {\n            this.imageryManager.releaseAtlas(this.inheritedAtlasKey, this.inheritedTexture);\n        }\n\n        // Clean up any in-progress crossfade\n        this._releaseCrossfadePrevTexture();\n        this.crossfadeStart = null;\n        this.crossfadeBlend = 1.0;\n        this.crossfadeComplete = true;\n\n        // PHASE 3: Release shared material if using pooling\n        if (this.treeManager && this.sharedMaterialKey) {\n            this.treeManager.releaseSharedMaterial(this.sharedMaterialKey);\n            this.sharedMaterialKey = null;\n        }\n\n        this.imageryVersion = null;\n        this.imageryZoom = null;\n        this.imageryTargetZoom = null;\n        this.imageryTileX = null;\n        this.imageryTileY = null;\n        this.imageryReady = false;\n        this.imageryAtlasKey = null;\n        this.imageryPendingKey = null;\n        this.imageryRequestedKey = null;\n        this.imageryRequestedZoom = null;\n        this.imageryPendingSince = null;\n        this.imageryPendingAttempts = 0;\n        this.imageryTexture = null;\n        this.imageryAtlasMinX = null;\n        this.imageryAtlasMinY = null;\n        this.imageryAtlasW = null;\n        this.imageryAtlasH = null;\n        this.imageryAtlasZoom = null;\n        this.imageryPendingUv = null;\n        // Fallback systems removed\n        this.imageryInherited = false;\n        this.imageryInheritedZoom = null;\n        this.inheritedAtlasKey = null;\n        this.inheritedTexture = null;\n        this._imageryCoordCache = null;\n        this._imageryUvCache = null;\n        this._imageryVertexCount = 0;\n        this._childrenImageryPrepared = false;\n        this._setImageryLoading(false);\n        if (this.mesh && this.mesh.material) {\n            this.mesh.material.map = null;\n            this.mesh.material.needsUpdate = true;\n        }\n        if (this.materialDefault && this.materialDefault !== this.mesh?.material) {\n            this.materialDefault.map = null;\n            this.materialDefault.needsUpdate = true;\n        }\n\n        if (this.photogramOffsets && !preservePhotogram) {\n            this.clearPhotogramOffsets();\n        }\n    }\n\n    setPhotogramOffsets(offsets, key = null) {\n        this.photogramOffsets = offsets || null;\n        this.photogramKey = key || null;\n    }\n\n    clearPhotogramOffsets() {\n        this.photogramOffsets = null;\n        this.photogramKey = null;\n        this.photogramPending = false;\n        this.applyPhotogramOffsets();\n    }\n\n    applyPhotogramOffsets() {\n        if (!this.positionAttr || !this.baseDirs) return 0;\n        const count = this.positionAttr.count || 0;\n        if (!count) return 0;\n        const pos = this.positionAttr.array;\n        const cx = this.center.x;\n        const cy = this.center.y;\n        const cz = this.center.z;\n        let updated = 0;\n        for (let i = 0; i < count; i += 1) {\n            let baseElev = null;\n            if (this.elevationValues && Number.isFinite(this.elevationValues[i])) {\n                baseElev = this.elevationValues[i];\n            }\n            if (!Number.isFinite(baseElev)) {\n                const i3 = i * 3;\n                const wx = pos[i3 + 0] + cx;\n                const wy = pos[i3 + 1] + cy;\n                const wz = pos[i3 + 2] + cz;\n                const r = Math.sqrt(wx * wx + wy * wy + wz * wz) || 0;\n                baseElev = this._extractElevationFromRadius(i, r, false);\n            }\n            this._applyElevationAtIndex(i, baseElev, true);\n            updated += 1;\n        }\n        if (updated > 0) {\n            this._markGeometryDirty();\n        }\n        return updated;\n    }\n\n    rebuildGeometryForPhotogram(resOverride, imageryConfig = null) {\n        if (!Number.isFinite(resOverride)) return false;\n        const next = Math.max(2, Math.floor(resOverride));\n        if (this.photogramResOverride === next && this.geometry) return false;\n        this.photogramResOverride = next;\n\n        if (this.elevationClient && typeof this.elevationClient.pruneTile === 'function') {\n            this.elevationClient.pruneTile(this, { keepRecords: true });\n        }\n\n        if (this.geometry) {\n            this.geometry.dispose();\n        }\n        this._disposeSkirtMesh();\n        this.geometry = null;\n        this.positionAttr = null;\n        this.baseDirs = null;\n        this.baseRadii = null;\n        this.baseIndexArray = null;\n        this.baseIndexCount = 0;\n        this.vertexCount = 0;\n        this.baseVertexCount = 0;\n        this._imageryCoordCache = null;\n        this._imageryUvCache = null;\n        this._imageryVertexCount = 0;\n        this.photogramOffsets = null;\n        this.photogramKey = null;\n\n        this.buildGeometry();\n\n        if (this.mesh) {\n            this.mesh.geometry = this.geometry;\n            this.mesh.geometry.computeBoundingSphere();\n            this._ensureSkirtMesh();\n        }\n\n        if (this.imageryReady || this.imageryPendingKey) {\n            this.clearImagery();\n        }\n\n        if (this.imageryManager && imageryConfig) {\n            this.ensureImagery(this.imageryManager, imageryConfig, this.treeManager?.group || null);\n        }\n\n        this._markGeometryDirty();\n        return true;\n    }\n\n    ensureImagery(imageryManager, config, group = null) {\n        if (!imageryManager || !config || !config.enabled) return;\n        if (!this.mesh || !this.baseDirs || !this.geometry) return;\n        // Retire through the original owner before readiness/identity checks:\n        // a later fallback can use the same source ID with a new manager.\n        if (this.imageryManager && this.imageryManager !== imageryManager) this.clearImagery();\n        if (this.treeManager?.imageryInheritanceEnabled !== true && this.imageryInherited) {\n            // Force convergence to authoritative WMTS atlas mapping when inheritance is disabled.\n            this.clearImagery();\n        }\n\n        const {\n            versionId,\n            zoom,\n            maxAtlasTiles = imageryManager.maxAtlasTiles,\n            padTiles = imageryManager.padTiles,\n            requestPriority,\n            requestContextKey,\n            requestRing,\n            autoCoverage,\n            snapshotAtlas\n        } = config;\n\n        const rootZoom = (this.level === 0 && Number.isFinite(config.rootZoom))\n            ? Math.max(0, config.rootZoom)\n            : null;\n        const minZoom = Number.isFinite(config.minZoom)\n            ? Math.max(0, Math.floor(config.minZoom))\n            : null;\n\n        let targetZoom = rootZoom !== null ? rootZoom : zoom;\n        if (imageryManager?.getEffectiveMaxZoom && Number.isFinite(targetZoom)) {\n            // Resolve fallback zoom to a stable level. Some regions can be unavailable across\n            // multiple adjacent zooms (e.g., z4 -> z3 -> z2). A single-step clamp causes retry\n            // loops that keep requesting the same unavailable atlas level.\n            let stableZoom = Math.max(0, Math.floor(targetZoom));\n            for (let i = 0; i < 8; i++) {\n                const { latDeg, lonDeg } = dirToLatLonLocal(this.centerDir);\n                const coords = lonLatToTileCoords(lonDeg, latDeg, stableZoom);\n                const effectiveZoom = imageryManager.getEffectiveMaxZoom(versionId, stableZoom, coords.x, coords.y);\n                if (!Number.isFinite(effectiveZoom)) break;\n                const nextZoom = Math.max(0, Math.floor(effectiveZoom));\n                if (nextZoom >= stableZoom) break;\n                stableZoom = nextZoom;\n            }\n            targetZoom = stableZoom;\n        }\n        const pendingStallMs = Number.isFinite(this.treeManager?.imageryPendingStallMs)\n            ? this.treeManager.imageryPendingStallMs\n            : 2500;\n        const nowMsStart = (typeof performance !== 'undefined' && performance.now)\n            ? performance.now()\n            : Date.now();\n        const pendingAgeAtStartMs = Number.isFinite(this.imageryPendingSince)\n            ? (nowMsStart - this.imageryPendingSince)\n            : Infinity;\n        const pendingRequestedZoom = Number.isFinite(this.imageryRequestedZoom)\n            ? this.imageryRequestedZoom\n            : this.imageryTargetZoom;\n        const pendingVersionMatches = !this.imageryVersion || this.imageryVersion === versionId;\n        if (this.imageryPendingKey &&\n            pendingVersionMatches &&\n            Number.isFinite(pendingRequestedZoom) &&\n            pendingRequestedZoom >= targetZoom &&\n            pendingAgeAtStartMs <= pendingStallMs) {\n            return;\n        }\n\n        const hasMap = !!(this.mesh && this.mesh.material && this.mesh.material.map);\n        if (!this.imageryReady && this.hasImageryCoverage()) {\n            // Recover from stale readiness state: if a valid map+atlas is bound, keep it live.\n            this.imageryReady = true;\n        }\n        const baseCount = this.vertexCount || (this.baseDirs ? this.baseDirs.length / 3 : 0);\n        const totalCount = this.positionAttr?.count || baseCount;\n        const uv2Attr = this.geometry && this.geometry.getAttribute('uv2');\n        const hasUVs = !!(uv2Attr && uv2Attr.count === totalCount &&\n            this._imageryVertexCount === totalCount);\n        // Skip if already have same or higher resolution imagery (never downgrade)\n        const currentZoom = this.imageryTargetZoom;\n        const alreadyHigherOrEqual = Number.isFinite(currentZoom)\n            && Number.isFinite(targetZoom)\n            && currentZoom >= targetZoom;\n        if (this.imageryReady &&\n            this.imageryVersion === versionId &&\n            alreadyHigherOrEqual &&\n            hasMap && hasUVs) {\n            return;\n        }\n\n        // Store imagery manager reference for cleanup\n        this.imageryManager = imageryManager;\n\n        const vxCount = baseCount;\n        const tmpDir = this._imageryTmpDir || (this._imageryTmpDir = new THREE.Vector3());\n        // CRITICAL: Don't do early-return check here - we need to calculate the ACTUAL atlas zoom first\n        // The requested zoom might drop to a lower zoom if the tile spans too many tiles\n        // So we can't know if we're loading the same atlas until after the calculation\n\n        this.imageryVersion = versionId;\n        this.imageryTargetZoom = targetZoom;\n        const useAutoCoverage = autoCoverage === true;\n\n        const prepareCoords = (targetZoom) => {\n            const cached = this._imageryCoordCache;\n            if (cached && cached.zoom === targetZoom && cached.vertexCount === vxCount &&\n                cached.totalCount === totalCount && cached.autoCoverage === useAutoCoverage) {\n                return cached;\n            }\n            const coordsLocal = new Array(vxCount);\n            let minCx = +Infinity, maxCx = -Infinity;\n            let minCy = +Infinity, maxCy = -Infinity;\n            let sumSin = 0;\n            let sumCos = 0;\n            let n = 0;\n\n            for (let i = 0; i < vxCount; i++) {\n                const bx = this.baseDirs[i * 3 + 0];\n                const by = this.baseDirs[i * 3 + 1];\n                const bz = this.baseDirs[i * 3 + 2];\n                tmpDir.set(bx, by, bz);\n\n                const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n                const c = lonLatToTileCoords(lonDeg, latDeg, targetZoom);\n                n = c.n;\n                coordsLocal[i] = { cx: c.cx, cy: c.cy, n };\n\n                const angle = (c.cx / n) * TWO_PI;\n                sumSin += Math.sin(angle);\n                sumCos += Math.cos(angle);\n\n                if (c.cy < minCy) minCy = c.cy;\n                if (c.cy > maxCy) maxCy = c.cy;\n            }\n\n            if (useAutoCoverage && totalCount > vxCount && this.positionAttr) {\n                const pos = this.positionAttr.array;\n                const cx = this.center.x;\n                const cy = this.center.y;\n                const cz = this.center.z;\n                for (let i = vxCount; i < totalCount; i++) {\n                    const i3 = i * 3;\n                    const x = pos[i3 + 0] + cx;\n                    const y = pos[i3 + 1] + cy;\n                    const z = pos[i3 + 2] + cz;\n                    tmpDir.set(x, y, z).normalize();\n                    const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n                    const c = lonLatToTileCoords(lonDeg, latDeg, targetZoom);\n                    n = c.n;\n                    const angle = (c.cx / n) * TWO_PI;\n                    sumSin += Math.sin(angle);\n                    sumCos += Math.cos(angle);\n                    if (c.cy < minCy) minCy = c.cy;\n                    if (c.cy > maxCy) maxCy = c.cy;\n                }\n            }\n\n            const meanAngle = Math.atan2(sumSin, sumCos);\n            const refCx = THREE.MathUtils.euclideanModulo((meanAngle / TWO_PI) * n, n);\n\n            for (let i = 0; i < vxCount; i++) {\n                let cx = coordsLocal[i].cx;\n                if (cx - refCx > n * 0.5) cx -= n;\n                else if (refCx - cx > n * 0.5) cx += n;\n                coordsLocal[i].cx = cx;\n\n                if (cx < minCx) minCx = cx;\n                if (cx > maxCx) maxCx = cx;\n            }\n\n            if (useAutoCoverage && totalCount > vxCount && this.positionAttr) {\n                const pos = this.positionAttr.array;\n                const cx = this.center.x;\n                const cy = this.center.y;\n                const cz = this.center.z;\n                for (let i = vxCount; i < totalCount; i++) {\n                    const i3 = i * 3;\n                    const x = pos[i3 + 0] + cx;\n                    const y = pos[i3 + 1] + cy;\n                    const z = pos[i3 + 2] + cz;\n                    tmpDir.set(x, y, z).normalize();\n                    const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n                    const c = lonLatToTileCoords(lonDeg, latDeg, targetZoom);\n                    let cxTile = c.cx;\n                    if (Number.isFinite(refCx) && Number.isFinite(c.n)) {\n                        if (cxTile - refCx > c.n * 0.5) cxTile -= c.n;\n                        else if (refCx - cxTile > c.n * 0.5) cxTile += c.n;\n                    }\n                    if (cxTile < minCx) minCx = cxTile;\n                    if (cxTile > maxCx) maxCx = cxTile;\n                }\n            }\n\n            const out = {\n                coords: coordsLocal,\n                minCx,\n                maxCx,\n                minCy,\n                maxCy,\n                n,\n                zoom: targetZoom,\n                refCx,\n                vertexCount: vxCount,\n                totalCount,\n                autoCoverage: useAutoCoverage\n            };\n            this._imageryCoordCache = out;\n            return out;\n        };\n\n        let atlasData = null;\n\n        const snapshotZoom = Number.isFinite(snapshotAtlas?.zoom)\n            ? Math.max(0, Math.floor(snapshotAtlas.zoom))\n            : null;\n        const snapshotMinX = Number.isFinite(snapshotAtlas?.minX)\n            ? Math.floor(snapshotAtlas.minX)\n            : null;\n        const snapshotMinY = Number.isFinite(snapshotAtlas?.minY)\n            ? Math.floor(snapshotAtlas.minY)\n            : null;\n        const snapshotW = Number.isFinite(snapshotAtlas?.w)\n            ? Math.max(1, Math.floor(snapshotAtlas.w))\n            : null;\n        const snapshotH = Number.isFinite(snapshotAtlas?.h)\n            ? Math.max(1, Math.floor(snapshotAtlas.h))\n            : null;\n        const hasSnapshotAtlas = Number.isFinite(snapshotZoom) &&\n            Number.isFinite(snapshotMinX) &&\n            Number.isFinite(snapshotMinY) &&\n            Number.isFinite(snapshotW) &&\n            Number.isFinite(snapshotH);\n        if (hasSnapshotAtlas) {\n            const { coords, minCx, maxCx, n, refCx } = prepareCoords(snapshotZoom);\n            const uvMinX = this._alignAtlasMinXToTileFrame(snapshotMinX, snapshotW, n, refCx, minCx, maxCx);\n            atlasData = {\n                coords,\n                minX: uvMinX,\n                maxX: uvMinX + snapshotW - 1,\n                requestMinX: snapshotMinX,\n                requestMaxX: snapshotMinX + snapshotW - 1,\n                minY: snapshotMinY,\n                maxY: snapshotMinY + snapshotH - 1,\n                wTiles: snapshotW,\n                hTiles: snapshotH,\n                zoom: snapshotZoom,\n                n,\n                refCx\n            };\n        }\n\n        while (!atlasData && targetZoom >= 0) {\n            const { coords: finalCoords, minCx, maxCx, minCy, maxCy, n, refCx } = prepareCoords(targetZoom);\n\n            let minX = Math.floor(minCx) - padTiles;\n            let maxX = Math.floor(maxCx) + padTiles;\n            let minY = Math.floor(minCy) - padTiles;\n            let maxY = Math.floor(maxCy) + padTiles;\n\n            const spanX = Math.max(1, maxX - minX + 1);\n            const spanY = Math.max(1, maxY - minY + 1);\n            const maxSpanAllowed = Math.min(maxAtlasTiles, n);\n\n            // If the triangle spans too many tiles at this zoom, drop to a lower zoom\n            if (spanX > maxSpanAllowed || spanY > maxSpanAllowed) {\n                // For root-level fallback (rootZoom set), clamp instead of aborting so we always have coverage\n                if (rootZoom !== null && targetZoom === rootZoom) {\n                    minX = Math.max(0, minX);\n                    maxX = Math.min(n - 1, maxX);\n                    minY = Math.max(0, minY);\n                    maxY = Math.min(n - 1, maxY);\n                } else if (minZoom !== null && targetZoom <= minZoom) {\n                    // Base preload may lock a minimum zoom; allow oversize atlas if needed.\n                } else {\n                    targetZoom -= 1;\n                    continue;\n                }\n            }\n\n            atlasData = {\n                coords: finalCoords,\n                minX,\n                maxX,\n                requestMinX: minX,\n                requestMaxX: maxX,\n                minY,\n                maxY,\n                wTiles: spanX,\n                hTiles: spanY,\n                zoom: targetZoom,\n                n,\n                refCx\n            };\n            break;\n        }\n\n        if (!atlasData) return;\n\n        const {\n            coords: finalCoords,\n            minX,\n            maxX,\n            requestMinX = minX,\n            requestMaxX = maxX,\n            minY,\n            maxY,\n            wTiles,\n            hTiles,\n            zoom: atlasZoom,\n            n,\n            refCx\n        } = atlasData;\n        const requestMinXCanonical = Number.isFinite(n) && Number.isFinite(requestMinX)\n            ? THREE.MathUtils.euclideanModulo(requestMinX, n)\n            : requestMinX;\n        const requestMaxXCanonical = Number.isFinite(requestMinXCanonical) && Number.isFinite(wTiles)\n            ? (requestMinXCanonical + wTiles - 1)\n            : requestMaxX;\n        // Calculate atlas key for ref-counting\n        const atlasKey = imageryManager.getAtlasKey(versionId, atlasZoom, requestMinXCanonical, minY, wTiles, hTiles);\n        const nowMs = (typeof performance !== 'undefined' && performance.now)\n            ? performance.now()\n            : Date.now();\n        const pendingAgeNowMs = Number.isFinite(this.imageryPendingSince)\n            ? (nowMs - this.imageryPendingSince)\n            : Infinity;\n        const clearPendingRequest = () => {\n            this.imageryPendingKey = null;\n            this.imageryRequestedZoom = null;\n            this.imageryPendingUv = null;\n            this.imageryPendingSince = null;\n        };\n\n        // Keep existing imagery state while upgrading so visible tiles do not flap to blank.\n        // Only mark not-ready when there is no currently renderable coverage.\n        const hadRenderableCoverage = this.hasImageryCoverage();\n        if (this.imageryAtlasKey !== atlasKey) {\n            this.imageryReady = !!hadRenderableCoverage;\n        }\n\n        // CRITICAL: Check if we're already loading this exact atlas\n        // Do this AFTER calculating the actual atlas bounds (which might have dropped zoom levels)\n        // but BEFORE setting UVs to avoid unnecessary work\n        if (this.imageryAtlasKey === atlasKey && !this.imageryReady && this.imageryPendingKey === atlasKey) {\n            // Already loading this exact atlas; treat long-pending requests as stalled and retry.\n            if (pendingAgeNowMs <= pendingStallMs) return;\n            clearPendingRequest();\n        }\n\n        // Also check if we're pending the same atlas\n        if (this.imageryPendingKey === atlasKey) {\n            // Retry stalled pending requests instead of waiting indefinitely.\n            if (pendingAgeNowMs <= pendingStallMs) return;\n            clearPendingRequest();\n        }\n\n        // Now calculate and set UVs (cache per atlasKey to avoid recompute)\n        let uvArray = null;\n        const cachedUv = this._imageryUvCache;\n        if (cachedUv && cachedUv.atlasKey === atlasKey &&\n            cachedUv.minX === minX &&\n            cachedUv.vertexCount === totalCount &&\n            cachedUv.uvArray?.length === totalCount * 2) {\n            uvArray = cachedUv.uvArray;\n        } else {\n            uvArray = new Float32Array(totalCount * 2);\n            const tileSize = imageryManager.tileSize;\n            const atlasWidth = wTiles * tileSize;\n            const atlasHeight = hTiles * tileSize;\n            const halfPixelU = 0.5 / atlasWidth;\n            const halfPixelV = 0.5 / atlasHeight;\n\n            for (let i = 0; i < vxCount; i++) {\n                const c = finalCoords[i];\n                const u = ((c.cx - minX) * tileSize + 0.5) / atlasWidth;\n                const v = ((c.cy - minY) * tileSize + 0.5) / atlasHeight;\n                uvArray[i * 2 + 0] = THREE.MathUtils.clamp(u, halfPixelU, 1 - halfPixelU);\n                uvArray[i * 2 + 1] = THREE.MathUtils.clamp(v, halfPixelV, 1 - halfPixelV);\n            }\n\n            if (totalCount > vxCount && this.positionAttr) {\n                const pos = this.positionAttr.array;\n                const cx = this.center.x;\n                const cy = this.center.y;\n                const cz = this.center.z;\n                const wrapN = Number.isFinite(n) ? n : null;\n                for (let i = vxCount; i < totalCount; i++) {\n                    const i3 = i * 3;\n                    const x = pos[i3 + 0] + cx;\n                    const y = pos[i3 + 1] + cy;\n                    const z = pos[i3 + 2] + cz;\n                    tmpDir.set(x, y, z).normalize();\n                    const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n                    const c = lonLatToTileCoords(lonDeg, latDeg, atlasZoom);\n                    let cellX = c.cx;\n                    const cellN = wrapN || c.n;\n                    if (Number.isFinite(refCx) && Number.isFinite(cellN)) {\n                        if (cellX - refCx > cellN * 0.5) cellX -= cellN;\n                        else if (refCx - cellX > cellN * 0.5) cellX += cellN;\n                    }\n                    const u = ((cellX - minX) * tileSize + 0.5) / atlasWidth;\n                    const v = ((c.cy - minY) * tileSize + 0.5) / atlasHeight;\n                    uvArray[i * 2 + 0] = THREE.MathUtils.clamp(u, halfPixelU, 1 - halfPixelU);\n                    uvArray[i * 2 + 1] = THREE.MathUtils.clamp(v, halfPixelV, 1 - halfPixelV);\n                }\n            }\n\n            this._imageryUvCache = { atlasKey, minX, uvArray, vertexCount: totalCount };\n        }\n\n        const hasLiveAtlas = this.imageryAtlasKey && this.imageryTexture;\n        const deferUvUpdate = (this.imageryInherited && this.inheritedTexture && this.inheritedAtlasKey) ||\n            (hasLiveAtlas && this.imageryAtlasKey !== atlasKey);\n        if (deferUvUpdate) {\n            // Keep current UVs until the new atlas arrives to avoid mismatched sampling.\n            this.imageryPendingUv = uvArray;\n            this._imageryVertexCount = 0;\n        } else {\n            updateAttributeInPlace(this.geometry, 'uv2', uvArray, 2);\n            this.imageryPendingUv = null;\n            this._imageryVertexCount = totalCount;\n            this._markSkirtDirty();\n        }\n\n        this.imageryRequestedZoom = atlasZoom;\n        this.imageryZoom = atlasZoom;\n        this.imageryPendingKey = atlasKey; // Store the ACTUAL atlas key, not preliminary\n        this.imageryPendingSince = (typeof performance !== 'undefined' && performance.now)\n            ? performance.now()\n            : Date.now();\n        this.imageryPendingAttempts = (this.imageryPendingAttempts || 0) + 1;\n        const shouldShowLoading = !hasMap && !this.imageryInherited;\n        this._setImageryLoading(shouldShowLoading, this.imageryPendingSince);\n\n        imageryManager.getAtlas(requestMinXCanonical, requestMaxXCanonical, minY, maxY, atlasZoom, {\n            priority: requestPriority,\n            contextKey: requestContextKey,\n            ring: requestRing,\n            versionId\n        })\n            .then(tex => {\n                if (!tex) {\n                    const pendingMatches = this.imageryPendingKey === atlasKey;\n                    if (!pendingMatches) return;\n\n                    this.imageryPendingKey = null;\n                    this.imageryRequestedZoom = null;\n                    this.imageryPendingUv = null;\n                    this.imageryPendingSince = null;\n                    this.imageryPendingAttempts = 0;\n\n                    let retryImmediately = false;\n                    let retryZoom = null;\n                    if (imageryManager?.getEffectiveMaxZoom && Number.isFinite(atlasZoom)) {\n                        const { latDeg, lonDeg } = dirToLatLonLocal(this.centerDir);\n                        const coords = lonLatToTileCoords(lonDeg, latDeg, atlasZoom);\n                        const effectiveZoom = imageryManager.getEffectiveMaxZoom(versionId, atlasZoom, coords.x, coords.y);\n                        retryImmediately = Number.isFinite(effectiveZoom) && effectiveZoom < atlasZoom;\n                        if (retryImmediately) {\n                            retryZoom = Math.max(0, Math.floor(effectiveZoom));\n                        }\n                    }\n\n                    if (retryImmediately) {\n                        const retryConfig = Number.isFinite(retryZoom)\n                            ? { ...config, zoom: retryZoom }\n                            : config;\n                        const retry = () => {\n                            if (!this.mesh || !this.geometry) return;\n                            if (this.imageryPendingKey) return;\n                            this.ensureImagery(imageryManager, retryConfig, group);\n                        };\n                        if (typeof queueMicrotask === 'function') {\n                            queueMicrotask(retry);\n                        } else {\n                            Promise.resolve().then(retry);\n                        }\n                    } else {\n                        this._setImageryLoading(false);\n                    }\n                    return;\n                }\n                if (!this.mesh || !this.mesh.material) return;\n\n                // CRITICAL FIX: Validate that this texture EXACTLY matches what we're expecting\n                // The pending key must match the atlas key we're receiving\n                if (this.imageryPendingKey !== atlasKey) {\n                    // console.log('[imagery] Discarding stale texture - pending key mismatch', {\n                    //     expected: this.imageryPendingKey,\n                    //     received: atlasKey\n                    // });\n                    return; // Discard stale texture\n                }\n\n                if (this.imageryPendingUv && this.geometry) {\n                    updateAttributeInPlace(this.geometry, 'uv2', this.imageryPendingUv, 2);\n                    this.imageryPendingUv = null;\n                    this._imageryVertexCount = totalCount;\n                    this._markSkirtDirty();\n                }\n\n                const prevAtlasKey = this.imageryAtlasKey;\n                const prevInheritedKey = this.inheritedAtlasKey;\n                const prevTexture = this.imageryTexture;\n                const prevInheritedTexture = this.inheritedTexture;\n                const targetMaterial = (this.wireframeEnabled && this.materialDefault)\n                    ? this.materialDefault\n                    : this.mesh.material;\n\n                // Check if we already have imagery - if so, use crossfade for smooth transition\n                const hadPreviousImagery = !!targetMaterial.map;\n\n                if (hadPreviousImagery && this.crossfadeEnabled) {\n                    // Start crossfade from previous texture to new texture\n                    // The UV transform is identity since we're using the same UV2 attribute\n                    // (the new UVs were already applied above via imageryPendingUv)\n                    this._startCrossfade(tex, new THREE.Vector2(0, 0), new THREE.Vector2(1, 1));\n                }\n\n                // SEAMLESS TRANSITION: Clear inherited imagery state when own imagery arrives\n                if (this.imageryInherited) {\n                    this.imageryInherited = false;\n                    this.imageryInheritedZoom = null;\n                    this.inheritedAtlasKey = null;\n                    this.inheritedTexture = null;\n                }\n\n                // Retain new atlas reference\n                this.imageryAtlasKey = atlasKey;\n                this.imageryPendingKey = null;\n                this.imageryPendingSince = null;\n                this.imageryPendingAttempts = 0;\n                imageryManager.retainAtlas(atlasKey, tex);\n\n                targetMaterial.map = tex;\n                targetMaterial.needsUpdate = true;\n                this.imageryReady = true;\n                this._setImageryLoading(false);\n\n                // Release old refs only after the new map is bound.\n                if (prevAtlasKey) {\n                    imageryManager.releaseAtlas(prevAtlasKey, prevTexture);\n                }\n                if (prevInheritedKey &&\n                    prevInheritedKey !== prevAtlasKey &&\n                    this.imageryManager) {\n                    this.imageryManager.releaseAtlas(prevInheritedKey, prevInheritedTexture);\n                }\n\n                // Start fade-in animation only for first-time imagery loads\n                if (!hadPreviousImagery && this.fadeInEnabled && this.level > 0) {  // Skip fade for base tiles\n                    this.fadeInStart = performance.now();\n                    this.fadeInCurrent = 0;\n                    this.fadeInComplete = false;\n                    registerFadeInTile(this);\n                    // Make material transparent for fade-in\n                    if (targetMaterial.transparent === undefined || !targetMaterial.transparent) {\n                        targetMaterial.transparent = true;\n                        targetMaterial.opacity = 0;\n                        targetMaterial.needsUpdate = true;\n                    }\n                } else if (!hadPreviousImagery) {\n                    this.fadeInComplete = true;\n                    this.fadeInCurrent = 1;\n                }\n\n                this.imageryTileX = requestMinXCanonical;\n                this.imageryTileY = minY;\n                this.imageryTexture = tex;\n                this.imageryAtlasMinX = requestMinXCanonical;\n                this.imageryAtlasMinY = minY;\n                this.imageryAtlasW = wTiles;\n                this.imageryAtlasH = hTiles;\n                this.imageryAtlasZoom = atlasZoom;\n\n                if (this.treeManager && typeof this.treeManager.onTileImageryReady === 'function') {\n                    this.treeManager.onTileImageryReady(this);\n                }\n\n                if (this.children && !this._childrenImageryPrepared) {\n                    this.prepareChildrenForSplit();\n                }\n\n                // REMOVED: notifyChildReady call - instant subdivision, no deferred removal\n            })\n            .catch(err => {\n                console.error('[imagery] apply atlas failed', err);\n                if (this.imageryPendingKey === atlasKey) {\n                    this.imageryPendingKey = null;\n                    this.imageryRequestedZoom = null;\n                    this.imageryPendingUv = null;\n                    this.imageryPendingSince = null;\n                    this.imageryPendingAttempts = 0;\n                    this._setImageryLoading(false);\n                }\n            });\n    }\n\n    /**\n     * Generate a geohash-like hierarchical tile identifier\n     * Format: R{root}-L{level}-{path}\n     * Example: R05-L3-0213 (root tile 5, level 3, child path 0→2→1→3)\n     */\n    getTileId() {\n        const rootIndex = this._getRootIndex();\n        const path = this._getChildPath();\n        return `R${String(rootIndex).padStart(2, '0')}-L${this.level}-${path}`;\n    }\n\n    /**\n     * Get the root tile index (0-19) by traversing up the hierarchy\n     */\n    _getRootIndex() {\n        let tile = this;\n        while (tile.parent !== null) {\n            tile = tile.parent;\n        }\n        return tile.index;\n    }\n\n    /**\n     * Get the child path from root to this tile\n     * Returns string like \"0213\" representing child slots traversed\n     */\n    _getChildPath() {\n        if (this.level === 0) return '';\n\n        const path = [];\n        let tile = this;\n        while (tile.parent !== null) {\n            const childSlot = tile.index - tile.parent.index * 4;\n            path.unshift(childSlot);\n            tile = tile.parent;\n        }\n        return path.join('');\n    }\n\n    /**\n     * Get full path address with edge identifier\n     * Format: \"R04-L6-100010:v2v0\" (tile path + edge)\n     * Format: \"R04-L6-100010@v0\" (tile path + corner)\n     */\n    getEdgeAddress(edgeName) {\n        return `${this.getTileId()}:${edgeName}`;\n    }\n\n    getCornerAddress(cornerName) {\n        return `${this.getTileId()}@${cornerName}`;\n    }\n\n    /**\n     * Get the centroid (center point) of this tile in world space\n     */\n    getCentroid() {\n        return new THREE.Vector3()\n            .add(this.v0)\n            .add(this.v1)\n            .add(this.v2)\n            .divideScalar(3);\n    }\n\n    /**\n     * Get the maximum edge length of this tile (for spatial filtering)\n     */\n    getMaxEdgeLength() {\n        const e0 = this.v0.distanceTo(this.v1);\n        const e1 = this.v1.distanceTo(this.v2);\n        const e2 = this.v2.distanceTo(this.v0);\n        return Math.max(e0, e1, e2);\n    }\n\n    /**\n     * Get lat/lon for this tile's centroid\n     */\n    getCentroidLatLon() {\n        const centroid = this.getCentroid().normalize();\n        const lat = Math.asin(centroid.y) * 180 / Math.PI;\n        const lon = Math.atan2(centroid.z, centroid.x) * 180 / Math.PI;\n        return { lat, lon };\n    }\n\n    /**\n     * Get vertex count along a specific edge\n     * Returns the number of vertices that lie on the given edge\n     */\n    getEdgeVertexCount(edgeName) {\n        const baseCount = this.vertexCount || (this.baseDirs ? this.baseDirs.length / 3 : 0);\n        if (!this.positionAttr || baseCount === 0) return 0;\n\n        // Get edge corner vertices\n        let v0, v1;\n        if (edgeName === 'v0v1') {\n            v0 = this.v0;\n            v1 = this.v1;\n        } else if (edgeName === 'v1v2') {\n            v0 = this.v1;\n            v1 = this.v2;\n        } else if (edgeName === 'v2v0') {\n            v0 = this.v2;\n            v1 = this.v0;\n        } else {\n            return 0;\n        }\n\n        // Count vertices on this edge\n        const positions = this.positionAttr.array;\n        const tolerance = 0.001;\n        let count = 0;\n        // Positions are stored in local coordinates - add tile center\n        const cx = this.center.x;\n        const cy = this.center.y;\n        const cz = this.center.z;\n\n        // Check each vertex to see if it lies on the edge\n        for (let i = 0; i < baseCount; i++) {\n            const vx = positions[i * 3] + cx;\n            const vy = positions[i * 3 + 1] + cy;\n            const vz = positions[i * 3 + 2] + cz;\n            const vertex = new THREE.Vector3(vx, vy, vz);\n\n            // Check if this vertex is on the edge (collinear with v0 and v1)\n            if (this._isVertexOnEdge(vertex, v0, v1, tolerance)) {\n                count++;\n            }\n        }\n\n        return count;\n    }\n\n    /**\n     * Helper: Check if a vertex lies on an edge\n     */\n    _isVertexOnEdge(vertex, edgeV0, edgeV1, tolerance) {\n        // Normalize all vectors (for spherical geometry)\n        const v = vertex.clone().normalize();\n        const v0 = edgeV0.clone().normalize();\n        const v1 = edgeV1.clone().normalize();\n\n        // Check if v is coplanar with v0 and v1 (on same great circle)\n        const normal = new THREE.Vector3().crossVectors(v0, v1);\n        if (normal.lengthSq() < tolerance * tolerance) {\n            // Degenerate case: v0 and v1 are very close\n            return v.distanceTo(v0) < tolerance || v.distanceTo(v1) < tolerance;\n        }\n        normal.normalize();\n\n        const distToPlane = Math.abs(normal.dot(v));\n        if (distToPlane > tolerance) return false; // Not on great circle\n\n        // Check if v is between v0 and v1 along the arc\n        const angle_v0_v1 = Math.acos(Math.max(-1, Math.min(1, v0.dot(v1))));\n        const angle_v0_v = Math.acos(Math.max(-1, Math.min(1, v0.dot(v))));\n        const angle_v_v1 = Math.acos(Math.max(-1, Math.min(1, v.dot(v1))));\n\n        // v is on arc if sum of angles equals total arc angle (within tolerance)\n        const angleDiff = Math.abs((angle_v0_v + angle_v_v1) - angle_v0_v1);\n        return angleDiff < tolerance;\n    }\n\n    /**\n     * Get neighbor tile IDs for display\n     * Returns object with edge names and their neighbor tile IDs\n     */\n    getNeighborIds() {\n        const neighborIds = {};\n        for (const [edgeName, neighbor] of this.neighbors.entries()) {\n            if (neighbor && typeof neighbor.getTileId === 'function') {\n                neighborIds[edgeName] = neighbor.getTileId();\n            }\n        }\n        return neighborIds;\n    }\n\n    /**\n     * Get imagery byte size estimate\n     * Returns approximate memory usage in bytes\n     */\n    getImageryByteSize() {\n        if (!this.imageryAtlasW || !this.imageryAtlasH) return 0;\n\n        // Each WMTS tile is 256x256 pixels, RGBA format (4 bytes per pixel)\n        const tileSize = 256;\n        const bytesPerPixel = 4;\n        const bytesPerTile = tileSize * tileSize * bytesPerPixel;\n\n        const numTiles = this.imageryAtlasW * this.imageryAtlasH;\n        return numTiles * bytesPerTile;\n    }\n}\n\n/**\n * Create 20 root tiles from icosahedron geometry\n * @param {number} radius - Planet radius\n * @param {object} elevationClient - Elevation client instance\n * @returns {Array<TriTile>} Array of 20 root tiles\n */\nexport function createIcosahedronTiles(radius, elevationClient) {\n    const t = (1 + Math.sqrt(5)) / 2;\n    const verts = [\n        new THREE.Vector3(-1, t, 0).normalize(),\n        new THREE.Vector3(1, t, 0).normalize(),\n        new THREE.Vector3(-1, -t, 0).normalize(),\n        new THREE.Vector3(1, -t, 0).normalize(),\n\n        new THREE.Vector3(0, -1, t).normalize(),\n        new THREE.Vector3(0, 1, t).normalize(),\n        new THREE.Vector3(0, -1, -t).normalize(),\n        new THREE.Vector3(0, 1, -t).normalize(),\n\n        new THREE.Vector3(t, 0, -1).normalize(),\n        new THREE.Vector3(t, 0, 1).normalize(),\n        new THREE.Vector3(-t, 0, -1).normalize(),\n        new THREE.Vector3(-t, 0, 1).normalize(),\n    ];\n\n    const faces = [\n        [0, 11, 5], [0, 5, 1], [0, 1, 7], [0, 7, 10], [0, 10, 11],\n        [1, 5, 9], [5, 11, 4], [11, 10, 2], [10, 7, 6], [7, 1, 8],\n        [3, 9, 4], [3, 4, 2], [3, 2, 6], [3, 6, 8], [3, 8, 9],\n        [4, 9, 5], [2, 4, 11], [6, 2, 10], [8, 6, 7], [9, 8, 1],\n    ];\n\n    const tiles = [];\n    for (let i = 0; i < faces.length; i++) {\n        const [i0, i1, i2] = faces[i];\n        tiles.push(\n            new TriTile(verts[i0], verts[i1], verts[i2], 0, i, null, radius, elevationClient)\n        );\n    }\n    return tiles;\n}\n","/**\n * Animation Loop Module\n *\n * Manages the main render loop and per-frame updates for:\n * - Lighting and sun position\n * - Camera controls and surface movement\n * - LOD terrain updates\n * - Elevation data fetching\n * - Normal computation\n * - Performance monitoring\n * - Metrics display\n */\n\nimport * as THREE from 'three';\nimport { photorealInteriorState } from '../refactor/render/PhotorealInterior.js';\nimport {\n    raySphereIntersection,\n    rayEllipsoidIntersection,\n    worldPosToLatLonLocal\n} from './geometry-utils.js';\nimport { PLANET_RADIUS, ELEVATION_EXAGGERATION, WGS84_SEMI_MAJOR_AXIS, WGS84_SEMI_MINOR_AXIS } from './constants.js';\nimport { updateTileFadeIns, updateTileCrossfades } from './tri-tile.js';\nimport { getHudInfoStore } from './hud-info-store.js';\nimport { tickBeforeRender as asyncTickBefore, tickAfterRender as asyncTickAfter } from '../refactor/async/frameClock.js';\n\nconst WGS84_A2 = WGS84_SEMI_MAJOR_AXIS * WGS84_SEMI_MAJOR_AXIS;\nconst WGS84_B2 = WGS84_SEMI_MINOR_AXIS * WGS84_SEMI_MINOR_AXIS;\n// Browser RAF timestamps jitter around exact refresh multiples. Without a\n// small allowance, a nominal 33.33 ms cadence on a 60 Hz display can miss the\n// second tick by microseconds and quantize down to 20 FPS; 83.33 ms similarly\n// falls from 12 FPS to 10 FPS.\nconst RENDER_CADENCE_JITTER_TOLERANCE_MS = 1;\n\n// Shared by the visual tape and the pointer gesture so one tick always maps\n// to the same physical altitude change.\nexport const ALTITUDE_TAPE_SCALE = Object.freeze({\n    unitsPerLine: 200,\n    lineSpacingPx: 16,\n});\n\n/** Sea-level datum for a signed height: ASL at or above mean sea level, BSL below. */\nexport function seaLevelDatum(msl) {\n    return Number.isFinite(msl) && msl < 0 ? 'BSL' : 'ASL';\n}\n\n// Heights are signed: below sea level reads negative and is labelled BSL.\n// Underwater, depth below the surface is primary and AGL is the height above\n// the seabed (null until measured bathymetry is resident).\nexport function resolveAltitudeHudPresentation({ inSurface, agl, msl, underwater = false } = {}) {\n    const finite = value => (Number.isFinite(value) ? value : null);\n    if (inSurface && underwater) {\n        return { title: 'ALT BSL', primary: finite(msl), secondaryLabel: 'AGL', secondary: finite(agl) };\n    }\n    if (inSurface) {\n        return { title: 'ALT AGL', primary: finite(agl), secondaryLabel: seaLevelDatum(msl), secondary: finite(msl) };\n    }\n    return { title: `ALT ${seaLevelDatum(msl)}`, primary: finite(msl), secondaryLabel: 'AGL', secondary: null };\n}\n\nfunction ellipsoidRadiusForDir(dir) {\n    if (!dir) return PLANET_RADIUS;\n    const x = dir.x || 0;\n    const y = dir.y || 0;\n    const z = dir.z || 0;\n    const xx = x * x + z * z;\n    const yy = y * y;\n    const denom = (xx / WGS84_A2) + (yy / WGS84_B2);\n    if (!Number.isFinite(denom) || denom <= 0) return PLANET_RADIUS;\n    return 1 / Math.sqrt(denom);\n}\n\nexport class AnimationLoop {\n    constructor(options) {\n        // Core components\n        this.renderer = options.renderer;\n        this.scene = options.scene;\n        this.camera = options.camera;\n        this.lightingSystem = options.lightingSystem;\n        this.moonSystem = options.moonSystem || null;\n        this.surfaceController = options.surfaceController;\n        this.vrManager = options.vrManager || null;\n        this.triTree = options.triTree;\n        this.elevationClient = options.elevationClient;\n        this.sceneInitializer = options.sceneInitializer;\n        this.setRenderScale = options.setRenderScale || null;\n        this.uiController = options.uiController || null;\n        // HudManager attaches its complication after scene initialization. The\n        // accepted scene clock remains the only owner of attitude sampling.\n        this.orbitTelemetry = null;\n        this.weatherSystem = options.weatherSystem || null;\n        this.presenceSystem = options.presenceSystem || null;\n        this.stereoRenderer = options.stereoRenderer || null;\n        this.motionTracker = options.motionTracker || null;\n        // WO-069: motion execution shares this loop's one accepted frame\n        // timestamp. MotionRuntime intentionally owns no RAF or timer.\n        this.motionRuntime = options.motionRuntime || null;\n        this.onBeforeFrame = typeof options.onBeforeFrame === 'function' ? options.onBeforeFrame : null;\n        this.onFrameComplete = typeof options.onFrameComplete === 'function' ? options.onFrameComplete : null;\n        // Audio and Physics systems\n        this.audioSystem = options.audioSystem || null;\n        this.physicsSystem = options.physicsSystem || null;\n        this.proximityTriggerManager = options.proximityTriggerManager || null;\n        this.clickTriggerManager = options.clickTriggerManager || null;\n\n        // Event bus for system communication\n        this.eventBus = options.eventBus || null;\n        this._navOverride = null;\n        this._navOverrideListener = null;\n        if (this.eventBus && typeof this.eventBus.on === 'function') {\n            this._navOverrideListener = (payload) => {\n                if (!payload || payload.active === false) {\n                    this._navOverride = null;\n                    return;\n                }\n                const lat = Number.isFinite(payload.lat) ? payload.lat : null;\n                const lon = Number.isFinite(payload.lon) ? payload.lon : null;\n                const modeLabel = typeof payload.mode === 'string' && payload.mode.trim()\n                    ? payload.mode.trim()\n                    : null;\n                this._navOverride = { lat, lon, modeLabel, active: true };\n            };\n            this.eventBus.on('hud:nav-override', this._navOverrideListener);\n        }\n\n        // Camera-relative rendering for floating-point precision\n        // By positioning triTree.group at negative camera position,\n        // all terrain vertices become camera-relative (small values = high precision)\n        this._floatingOriginEnabled = true;\n        this._lastOriginUpdatePos = new THREE.Vector3();\n        this._tmpCameraWorldPos = new THREE.Vector3();\n        this._gravityCenter = new THREE.Vector3();\n        this._metricViewDirection = new THREE.Vector3();\n        this._lodTargetDirection = new THREE.Vector3();\n\n        // Performance monitoring\n        this.perf = options.perf;\n        this.perfStart = options.perfStart;\n        this.perfEnd = options.perfEnd;\n        this.updateDebugPanel = options.updateDebugPanel;\n        this.onFrame = typeof options.onFrame === 'function' ? options.onFrame : null;\n        this.onAfterRender = typeof options.onAfterRender === 'function'\n            ? options.onAfterRender\n            : null;\n        this.budgetGovernor = options.budgetGovernor || null;\n\n        // Tiles pending normal computation\n        this.tilesPendingNormals = options.tilesPendingNormals;\n        // PHASE 4: Increased budget from 16 to 32 for faster normal computation\n        this.maxNormalsPerFrame = 32; // Budget for normal recomputation per frame\n        this.maxElevationMorphTilesPerFrame = Number.isFinite(options.maxElevationMorphTilesPerFrame)\n            ? Math.max(1, Math.floor(options.maxElevationMorphTilesPerFrame))\n            : 24;\n        this.maxGeometryFinalizeTilesPerFrame = Number.isFinite(options.maxGeometryFinalizeTilesPerFrame)\n            ? Math.max(1, Math.floor(options.maxGeometryFinalizeTilesPerFrame))\n            : 24;\n        this.maxElevationMorphMsPerFrame = Number.isFinite(options.maxElevationMorphMsPerFrame)\n            ? Math.max(0, options.maxElevationMorphMsPerFrame)\n            : 2.5;\n        this.maxGeometryFinalizeMsPerFrame = Number.isFinite(options.maxGeometryFinalizeMsPerFrame)\n            ? Math.max(0, options.maxGeometryFinalizeMsPerFrame)\n            : 2.0;\n        this.maxNormalsMsPerFrame = Number.isFinite(options.maxNormalsMsPerFrame)\n            ? Math.max(0, options.maxNormalsMsPerFrame)\n            : 1.25;\n        this._normalsQueue = [];\n        this._normalsQueueIndex = 0;\n\n        // Metrics DOM elements\n        this.metrics = {\n            tiles: options.metricTiles,\n            level: options.metricLevel,\n            hex: options.metricHex,\n            batches: options.metricBatches,\n            verts: options.metricVerts,\n            latlon: options.metricLatLon,\n            reqs: options.metricReqs,\n            resps: options.metricResps,\n            kbOut: options.metricKBOut,\n            kbIn: options.metricKBIn,\n            ptsOut: options.metricPtsOut,\n            ptsIn: options.metricPtsIn,\n            ratio: options.metricRatio,\n            currentTime: options.metricCurrentTime,\n            sunDir: options.metricSunDir\n        };\n\n        // HUD elements (optional overlay)\n        this.hud = this._initHud();\n        this.hudStore = getHudInfoStore();\n        this.hudStore.refresh();\n        this._hudPrevSurfaceDir = new THREE.Vector3();\n        this._hudHasPrevSurfaceDir = false;\n        this._hudSurfaceLocalDir = new THREE.Vector3();\n        this._hudSurfaceLocalQuat = new THREE.Quaternion();\n        this._hudPrevAltitude = null;\n        this._hudSpeed = 0;\n        this._hudVSpeed = 0;\n        this._cameraWorldPosition = new THREE.Vector3();\n        this._logicalCameraWorldPosition = new THREE.Vector3();\n        this._altimeterDragBound = false;\n        this._pitchDragBound = false;\n        this._compassDragBound = false;\n\n        // Animation state\n        this.lastTime = performance.now();\n        this.running = false;\n        this._rafId = null;\n        this._frameOwner = null;\n        this._lastRenderTime = null;\n        this._lastRenderIntervalMs = null;\n        this._lastHeavyFrameLog = 0;\n        // Throttling for expensive UI/metrics updates (not HUD - HUD updates every frame)\n        this.metricsThrottleMs = 300;\n        this._lastPerfUpdate = 0;\n        this._lastTerrainUpdate = 0;\n        this._lastNetworkUpdate = 0;\n        this._lastLightingUpdate = 0;\n        this._lastPositionUpdate = 0;\n        this._lastHudUpdate = 0;\n        this._lastLodOverlayUpdate = 0;\n        this._lastEarthRotation = null;\n        this._longTaskTotal = 0;\n        this._lastLongTaskTotal = 0;\n        this._lastLongTaskDelta = 0;\n        this._longTaskObserver = null;\n        this._initLongTaskObserver();\n        this._stallGuard = {\n            enabled: true,\n            thresholdMs: 200,\n            recoverMs: 80,\n            framesRequired: 3,\n            recoverFrames: 75,\n            badFrames: 0,\n            goodFrames: 0,\n            active: false,\n            prevAtmosphere: null,\n            prevSceneLowFps: null,\n            prevTerrainLowFps: null\n        };\n        this.lowFpsMode = {\n            enabled: true,\n            affectsTerrain: options.lowFpsAffectsTerrain === true,\n            fpsThreshold: 20,\n            recoverFpsThreshold: 28,\n            framesRequired: 6,\n            recoverFrames: 180,\n            minToggleIntervalMs: 5000,\n            belowCount: 0,\n            aboveCount: 0,\n            active: options.bootLowFpsMode !== false,\n            lastFps: 60,\n            lastToggleMs: Number.NEGATIVE_INFINITY\n        };\n        const cadenceMs = Number.isFinite(options.renderCadenceMs) ? options.renderCadenceMs : 0;\n        this.renderCadenceMs = Math.max(0, cadenceMs);\n        this._renderCadenceState = {\n            mode: this.renderCadenceMs > 0 ? 'fixed' : 'unlimited',\n            effectiveMs: this.renderCadenceMs,\n            targetFps: this.renderCadenceMs > 0 ? 1000 / this.renderCadenceMs : null,\n        };\n        const frameDiscard = options.frameDiscard || null;\n        const discardThreshold = Number.isFinite(frameDiscard?.waitThresholdMs)\n            ? frameDiscard.waitThresholdMs\n            : (Number.isFinite(options.frameDiscardThresholdMs) ? options.frameDiscardThresholdMs : 120);\n        this.frameDiscard = {\n            enabled: !!(frameDiscard?.enabled ?? options.frameDiscardEnabled),\n            waitThresholdMs: Math.max(0, discardThreshold)\n        };\n        this._cadencePrimed = false;\n        // Render resolution must remain fixed. Performance governors may shed\n        // optional work, but must not change pixel ratio/render scale.\n        this.autoRenderScale = {\n            enabled: false,\n            targetFps: 30,\n            lowFpsThreshold: 30,\n            stableFpsThreshold: 31,\n            lowFpsFramesRequired: 6,\n            stableFramesRequired: 120,\n            lowFpsFrames: 0,\n            stableFrames: 0,\n            emaFps: null,\n            emaAlpha: 0.1,\n            kp: 0.02,\n            ki: 0.0015,\n            kd: 0.01,\n            integral: 0,\n            integralLimit: 200,\n            prevError: 0,\n            lastUpdate: 0,\n            updateIntervalMs: 200,\n            minScale: 1,\n            maxScale: 1,\n            maxStepDown: 0.08,\n            maxStepUp: 0.02,\n            deadband: 0.25\n        };\n    }\n\n    /**\n     * Start the animation loop\n     */\n    start() {\n        if (this.running) return;\n        this.running = true;\n        this.lastTime = performance.now();\n        if (this.lowFpsMode?.active) {\n            this.lowFpsMode.lastToggleMs = this.lastTime;\n            this.sceneInitializer?.setLowFpsMode?.(true);\n            if (this.lowFpsMode.affectsTerrain) {\n                this.triTree?.setLowFpsMode?.(true);\n            }\n        }\n        if (!this._boundAnimate) {\n            this._boundAnimate = (time, frame) => this.animate(time, frame);\n        }\n        if (this.renderer && typeof this.renderer.setAnimationLoop === 'function') {\n            this._frameOwner = 'renderer';\n            this.renderer.setAnimationLoop(this._boundAnimate);\n        } else {\n            this._frameOwner = 'raf';\n            this._scheduleNextFrame();\n        }\n\n        // Visibility handler: when the tab regains focus after being\n        // backgrounded, the next animate() tick would otherwise see an\n        // elapsedMs spanning the full idle duration (seconds or minutes).\n        // That pushes dt into physics/surface-controller paths that\n        // assume 16-33 ms per frame, producing NaN positions, exploded\n        // velocities, and — visible to the user — a frozen scene.\n        // On visibilitychange -> visible we reset lastTime so the first\n        // resumed frame is a normal ~16 ms delta and state stays sane.\n        if (typeof document !== 'undefined' && !this._visibilityHandler) {\n            this._visibilityHandler = () => {\n                if (document.visibilityState === 'visible') {\n                    this.lastTime = performance.now();\n                    this._lastRenderTime = null;\n                    // DELIBERATELY do NOT reset _lastEarthRotation here.\n                    //\n                    // The lighting system follows the real-world clock\n                    // (currentDate = new Date() each tick), so while the tab\n                    // was hidden the simulated Earth rotation advanced\n                    // monotonically with wall time. On resume the planet's\n                    // absolute angle is set to the new time via\n                    // triTree.setEarthRotation(earthRotation) — rotating the\n                    // planet beneath the camera. surfaceController.applyEarthRotation\n                    // (delta) is what compensates by rotating the camera's\n                    // local \"up\" vector by the same delta, keeping the user\n                    // pinned to the same lat/lon on the surface.\n                    //\n                    // Resetting _lastEarthRotation to null here used to make\n                    // the first resumed frame skip that compensation (the\n                    // null-branch short-circuit in animate()), which was\n                    // exactly the regression where lat/lon drifted westward\n                    // by `tabDuration × earthAngularVelocity × cos(lat)` —\n                    // ~264m for a ~1s tab-away at lat 45°.\n                    //\n                    // Keeping the previous angle lets the first frame after\n                    // resume compute a normal delta = (newAngle - lastAngle)\n                    // and apply it as a single rotation step. The wrap logic\n                    // in animate() already keeps |delta| ≤ π so multi-hour\n                    // pauses don't blow up either.\n                    if (this._stallGuard) {\n                        this._stallGuard.badFrames = 0;\n                        this._stallGuard.goodFrames = 0;\n                    }\n                }\n            };\n            document.addEventListener('visibilitychange', this._visibilityHandler);\n        }\n    }\n\n    /**\n     * Stop the animation loop\n     */\n    stop() {\n        this.running = false;\n        if (this.renderer && typeof this.renderer.setAnimationLoop === 'function') {\n            this.renderer.setAnimationLoop(null);\n        }\n        if (this._rafId !== null) {\n            cancelAnimationFrame(this._rafId);\n            this._rafId = null;\n        }\n        this._frameOwner = null;\n        if (typeof document !== 'undefined' && this._visibilityHandler) {\n            document.removeEventListener('visibilitychange', this._visibilityHandler);\n            this._visibilityHandler = null;\n        }\n    }\n\n    _resolveRenderCadenceMs(_now = performance.now(), immersiveXR = false) {\n        const stereoPresenting = this.stereoRenderer?.isEnabled?.() === true;\n        if (immersiveXR || stereoPresenting) {\n            this._renderCadenceState = {\n                mode: immersiveXR ? 'xr' : 'stereo',\n                effectiveMs: 0,\n                targetFps: null,\n            };\n            return 0;\n        }\n        const fixedMs = Math.max(0, Number(this.renderCadenceMs) || 0);\n        this._renderCadenceState = {\n            mode: fixedMs > 0 ? 'fixed' : 'unlimited',\n            effectiveMs: fixedMs,\n            targetFps: fixedMs > 0 ? 1000 / fixedMs : null,\n        };\n        return fixedMs;\n    }\n\n    getRenderCadenceState() {\n        return { ...this._renderCadenceState };\n    }\n\n    _initHud() {\n        const hud = {\n            layout: document.getElementById('hud-layout'),\n            overlay: document.getElementById('hud-overlay'),\n            altimeter: document.getElementById('hud-altimeter'),\n            altTitle: document.getElementById('hud-alt-title'),\n            altLines: document.getElementById('hud-alt-lines'),\n            altReadout: document.getElementById('hud-alt-readout'),\n            altSubReadout: document.getElementById('hud-alt-subreadout'),\n            pitchLines: document.getElementById('hud-pitch-lines'),\n            pitchReadout: document.getElementById('hud-pitch-readout'),\n            pitchSubReadout: document.getElementById('hud-pitch-subreadout'),\n            compass: document.getElementById('hud-compass'),\n            compassLines: document.getElementById('hud-compass-lines'),\n            compassReadout: document.getElementById('hud-compass-readout'),\n            compassSubReadout: document.getElementById('hud-compass-subreadout'),\n            fov: document.getElementById('hud-fov'),\n            fovLines: document.getElementById('hud-fov-lines'),\n            fovReadout: document.getElementById('hud-fov-readout'),\n            fovSubReadout: document.getElementById('hud-fov-subreadout'),\n            mode: document.getElementById('hud-mode'),\n            lat: document.getElementById('hud-lat'),\n            lon: document.getElementById('hud-lon'),\n            heading: document.getElementById('hud-heading'),\n            pitch: document.getElementById('hud-pitch'),\n            speed: document.getElementById('hud-speed'),\n            vspeed: document.getElementById('hud-vspeed'),\n            agl: document.getElementById('hud-agl'),\n            msl: document.getElementById('hud-msl'),\n            ground: document.getElementById('hud-ground-elev'),\n            lod: document.getElementById('hud-lod'),\n            tiles: document.getElementById('hud-tiles'),\n            stage: document.getElementById('hud-stage'),\n            reqs: document.getElementById('hud-reqs'),\n            resps: document.getElementById('hud-resps'),\n            kbIn: document.getElementById('hud-kb-in'),\n            kbOut: document.getElementById('hud-kb-out'),\n            ratio: document.getElementById('hud-ratio'),\n            perfFps: document.getElementById('hud-perf-fps'),\n            perfTiles: document.getElementById('hud-perf-tiles'),\n            perfStageLabel: document.getElementById('hud-perf-stage-label'),\n            perfStageBar: document.getElementById('hud-perf-stage-bar'),\n            perfVisible: document.getElementById('hud-perf-visible'),\n            perfMaxLod: document.getElementById('hud-perf-max-lod')\n        };\n\n        // Anchoring zero at the lower edge exposes the full tape above it.\n        // Retain enough reusable lines to cover tall mobile viewports.\n        hud.altTicks = this._buildScaleLines(hud.altLines, 81);\n        hud.pitchTicks = this._buildScaleLines(hud.pitchLines, 41);\n        hud.compassTicks = this._buildCompassTicks(hud.compassLines, 51);\n        hud.fovTicks = hud.fovLines ? this._buildFovTicks(hud.fovLines, 41) : [];\n        hud.pitchLadder = document.getElementById('hud-pitch-ladder');\n        this._bindAltimeterDrag(hud.altimeter);\n        this._bindPitchDrag(hud.pitchLadder);\n        this._bindCompassDrag(hud.compass);\n        return hud;\n    }\n\n    _bindAltimeterDrag(altimeter) {\n        if (!altimeter || this._altimeterDragBound) return;\n        this._altimeterDragBound = true;\n\n        const state = {\n            active: false,\n            pointerId: null,\n            lastY: 0,\n            currentAlt: 0,\n            autoTarget: 0,\n            autoVelocity: 0,\n            autoRaf: null,\n            lastAutoTime: 0\n        };\n        const metersPerPixel = ALTITUDE_TAPE_SCALE.unitsPerLine\n            / ALTITUDE_TAPE_SCALE.lineSpacingPx;\n        const autoScrollZonePx = 28;\n        const maxAutoSpeed = metersPerPixel * 320;\n        const autoResponse = 10;\n        const altitudeBoostStartRatio = 0.65;\n        const altitudeBoostMax = 3.0;\n        const orbitExitEpsilon = 0.5;\n\n        const getAltitudeLiftScale = (altitude, maxAltitude, ascending) => {\n            if (!ascending) return 1;\n            if (!Number.isFinite(altitude) || !Number.isFinite(maxAltitude) || maxAltitude <= 0) return 1;\n            const ratio = THREE.MathUtils.clamp(altitude / maxAltitude, 0, 1);\n            const t = THREE.MathUtils.clamp(\n                (ratio - altitudeBoostStartRatio) / Math.max(1e-6, (1 - altitudeBoostStartRatio)),\n                0,\n                1\n            );\n            return 1 + ((altitudeBoostMax - 1) * t * t);\n        };\n\n        const maybeTransitionOrbitAtMax = (altitude, maxAltitude) => {\n            if (!Number.isFinite(altitude) || !Number.isFinite(maxAltitude)) return;\n            if (altitude < (maxAltitude - orbitExitEpsilon)) return;\n            const mode = this.surfaceController?.getCameraMode?.();\n            if (mode === 'surface' || this.surfaceController?.isInSurfaceMode?.()) {\n                this.surfaceController?.exitSurfaceMode?.();\n            }\n        };\n\n        const getOverflow = (clientY) => {\n            const rect = altimeter.getBoundingClientRect();\n            if (clientY < rect.top) {\n                return { dir: -1, overflow: rect.top - clientY };\n            }\n            if (clientY > rect.bottom) {\n                return { dir: 1, overflow: clientY - rect.bottom };\n            }\n            return { dir: 0, overflow: 0 };\n        };\n\n        const updateAutoTarget = (clientY) => {\n            const { dir, overflow } = getOverflow(clientY);\n            if (!dir || overflow <= 0) {\n                state.autoTarget = 0;\n                return;\n            }\n            const strength = THREE.MathUtils.clamp(overflow / autoScrollZonePx, 0, 1);\n            const currentAlt = Number.isFinite(state.currentAlt)\n                ? state.currentAlt\n                : (this.surfaceController?.getSurfaceAltitudeMeters?.() ?? 0);\n            const maxAlt = this.surfaceController?.getSurfaceAltitudeMax?.() ?? 100000;\n            const liftScale = getAltitudeLiftScale(currentAlt, maxAlt, dir > 0);\n            state.autoTarget = dir * maxAutoSpeed * strength * liftScale;\n            if (!state.autoRaf) {\n                state.lastAutoTime = performance.now();\n                state.autoRaf = requestAnimationFrame(stepAuto);\n            }\n        };\n\n        const stepAuto = (now) => {\n            if (!state.active) {\n                state.autoRaf = null;\n                return;\n            }\n            const dt = Math.max(0, (now - state.lastAutoTime) / 1000);\n            state.lastAutoTime = now;\n            const alpha = 1 - Math.exp(-autoResponse * dt);\n            state.autoVelocity += (state.autoTarget - state.autoVelocity) * alpha;\n\n            if (Math.abs(state.autoVelocity) > 0.01) {\n                const minAlt = this.surfaceController?.getSurfaceAltitudeMin?.() ?? 0;\n                const maxAlt = this.surfaceController?.getSurfaceAltitudeMax?.() ?? 100000;\n                const nextAlt = THREE.MathUtils.clamp(\n                    (Number.isFinite(state.currentAlt) ? state.currentAlt : 0) + state.autoVelocity * dt,\n                    minAlt,\n                    maxAlt\n                );\n                if (Number.isFinite(nextAlt)) {\n                    this.surfaceController.setSurfaceAltitudeMeters?.(nextAlt);\n                    this.surfaceController.applySurfaceCamera?.();\n                    state.currentAlt = nextAlt;\n                    maybeTransitionOrbitAtMax(nextAlt, maxAlt);\n                }\n            }\n\n            if (Math.abs(state.autoTarget) < 0.01 && Math.abs(state.autoVelocity) < 0.01) {\n                state.autoVelocity = 0;\n                state.autoRaf = null;\n                return;\n            }\n            state.autoRaf = requestAnimationFrame(stepAuto);\n        };\n\n        const stopDrag = (pointerId) => {\n            if (!state.active) return;\n            if (state.pointerId !== null && pointerId !== state.pointerId) return;\n            state.active = false;\n            state.pointerId = null;\n            altimeter.classList.remove('dragging');\n            state.autoTarget = 0;\n            state.autoVelocity = 0;\n            if (state.autoRaf) {\n                cancelAnimationFrame(state.autoRaf);\n                state.autoRaf = null;\n            }\n        };\n\n        altimeter.addEventListener('pointerdown', (event) => {\n            if (event.button !== undefined && event.button !== 0) return;\n            if (!this.surfaceController?.isInSurfaceMode?.()) return;\n\n            state.active = true;\n            state.pointerId = event.pointerId;\n            state.lastY = event.clientY;\n            state.currentAlt = this.surfaceController.getSurfaceAltitudeMeters?.() ?? 0;\n            state.autoTarget = 0;\n            state.autoVelocity = 0;\n            altimeter.classList.add('dragging');\n            if (typeof altimeter.setPointerCapture === 'function') {\n                altimeter.setPointerCapture(event.pointerId);\n            }\n            event.preventDefault();\n        });\n\n        altimeter.addEventListener('pointermove', (event) => {\n            if (!state.active) return;\n            if (state.pointerId !== null && event.pointerId !== state.pointerId) return;\n\n            const { dir, overflow } = getOverflow(event.clientY);\n            if (dir === 0 || overflow <= 0) {\n                const delta = event.clientY - state.lastY;\n                const minAlt = this.surfaceController?.getSurfaceAltitudeMin?.() ?? 0;\n                const maxAlt = this.surfaceController?.getSurfaceAltitudeMax?.() ?? 100000;\n                const currentAlt = Number.isFinite(state.currentAlt) ? state.currentAlt : 0;\n                const liftScale = getAltitudeLiftScale(currentAlt, maxAlt, delta > 0);\n                const nextAlt = THREE.MathUtils.clamp(\n                    currentAlt + (delta * metersPerPixel * liftScale),\n                    minAlt,\n                    maxAlt\n                );\n                if (Number.isFinite(nextAlt)) {\n                    // Use setter to update both altitude and MSL atomically\n                    this.surfaceController.setSurfaceAltitudeMeters?.(nextAlt);\n                    this.surfaceController.applySurfaceCamera?.();\n                    state.currentAlt = nextAlt;\n                    maybeTransitionOrbitAtMax(nextAlt, maxAlt);\n                }\n            } else {\n                updateAutoTarget(event.clientY);\n            }\n            state.lastY = event.clientY;\n            event.preventDefault();\n        });\n\n        altimeter.addEventListener('pointerup', (event) => {\n            stopDrag(event.pointerId);\n            if (typeof altimeter.releasePointerCapture === 'function') {\n                altimeter.releasePointerCapture(event.pointerId);\n            }\n            event.preventDefault();\n        });\n\n        altimeter.addEventListener('pointercancel', (event) => {\n            stopDrag(event.pointerId);\n        });\n\n        altimeter.addEventListener('lostpointercapture', (event) => {\n            stopDrag(event.pointerId);\n        });\n    }\n\n    _bindPitchDrag(pitchLadder) {\n        if (!pitchLadder || this._pitchDragBound) return;\n        this._pitchDragBound = true;\n\n        const state = {\n            active: false,\n            pointerId: null,\n            startY: 0,\n            startPitch: 0\n        };\n        // Degrees per pixel - 2 degrees per 16 pixels (matching the tape scale)\n        const degreesPerPixel = 2 / 16;\n\n        const stopDrag = (pointerId) => {\n            if (!state.active) return;\n            if (state.pointerId !== null && pointerId !== state.pointerId) return;\n            state.active = false;\n            state.pointerId = null;\n            pitchLadder.classList.remove('dragging');\n        };\n\n        pitchLadder.addEventListener('pointerdown', (event) => {\n            if (event.button !== undefined && event.button !== 0) return;\n            if (!this.surfaceController?.isInSurfaceMode?.()) return;\n\n            state.active = true;\n            state.pointerId = event.pointerId;\n            state.startY = event.clientY;\n            state.startPitch = this.surfaceController.surfaceState?.pitch ?? 0;\n            pitchLadder.classList.add('dragging');\n            if (typeof pitchLadder.setPointerCapture === 'function') {\n                pitchLadder.setPointerCapture(event.pointerId);\n            }\n            event.preventDefault();\n        });\n\n        pitchLadder.addEventListener('pointermove', (event) => {\n            if (!state.active) return;\n            if (state.pointerId !== null && event.pointerId !== state.pointerId) return;\n\n            const delta = event.clientY - state.startY;\n            // Finger-following drag: dragging DOWN on the tape should make\n            // the tape scroll DOWN under the finger (higher pitch ticks\n            // revealing from above). Incrementing pitch scrolls the tape\n            // down — see _updateScaleTape where higher `value` pushes\n            // lower-value ticks to positive y. Previously this used\n            // `startPitch - delta` which scrolled the tape opposite to\n            // the finger direction and felt backwards on touch.\n            const deltaDeg = delta * degreesPerPixel;\n            const DEG2RAD = Math.PI / 180;\n            const nextPitch = THREE.MathUtils.clamp(\n                state.startPitch + deltaDeg * DEG2RAD,\n                -1.45, // ~-83 degrees\n                1.45   // ~+83 degrees\n            );\n            if (Number.isFinite(nextPitch) && this.surfaceController.surfaceState) {\n                this.surfaceController.surfaceState.pitch = nextPitch;\n                this.surfaceController.applySurfaceCamera?.();\n            }\n            event.preventDefault();\n        });\n\n        pitchLadder.addEventListener('pointerup', (event) => {\n            stopDrag(event.pointerId);\n            if (typeof pitchLadder.releasePointerCapture === 'function') {\n                pitchLadder.releasePointerCapture(event.pointerId);\n            }\n            event.preventDefault();\n        });\n\n        pitchLadder.addEventListener('pointercancel', (event) => {\n            stopDrag(event.pointerId);\n        });\n\n        pitchLadder.addEventListener('lostpointercapture', (event) => {\n            stopDrag(event.pointerId);\n        });\n    }\n\n    _bindCompassDrag(compass) {\n        if (!compass || this._compassDragBound) return;\n        this._compassDragBound = true;\n\n        const state = {\n            active: false,\n            pointerId: null,\n            startX: 0,\n            startYaw: 0\n        };\n        // Degrees per pixel - based on compass tape scale\n        const degreesPerPixel = 5 / 16;\n\n        const stopDrag = (pointerId) => {\n            if (!state.active) return;\n            if (state.pointerId !== null && pointerId !== state.pointerId) return;\n            state.active = false;\n            state.pointerId = null;\n            compass.classList.remove('dragging');\n        };\n\n        compass.addEventListener('pointerdown', (event) => {\n            if (event.button !== undefined && event.button !== 0) return;\n            if (!this.surfaceController?.isInSurfaceMode?.()) return;\n\n            state.active = true;\n            state.pointerId = event.pointerId;\n            state.startX = event.clientX;\n            state.startYaw = this.surfaceController.surfaceState?.yaw ?? 0;\n            compass.classList.add('dragging');\n            if (typeof compass.setPointerCapture === 'function') {\n                compass.setPointerCapture(event.pointerId);\n            }\n            event.preventDefault();\n        });\n\n        compass.addEventListener('pointermove', (event) => {\n            if (!state.active) return;\n            if (state.pointerId !== null && event.pointerId !== state.pointerId) return;\n\n            const delta = event.clientX - state.startX;\n            // Dragging right (positive delta) should decrease heading (turn left visually, compass moves right)\n            const deltaDeg = delta * degreesPerPixel;\n            const DEG2RAD = Math.PI / 180;\n            const nextYaw = state.startYaw - deltaDeg * DEG2RAD;\n            if (Number.isFinite(nextYaw) && this.surfaceController.surfaceState) {\n                this.surfaceController.surfaceState.yaw = nextYaw;\n                this.surfaceController.applySurfaceCamera?.();\n            }\n            event.preventDefault();\n        });\n\n        compass.addEventListener('pointerup', (event) => {\n            stopDrag(event.pointerId);\n            if (typeof compass.releasePointerCapture === 'function') {\n                compass.releasePointerCapture(event.pointerId);\n            }\n            event.preventDefault();\n        });\n\n        compass.addEventListener('pointercancel', (event) => {\n            stopDrag(event.pointerId);\n        });\n\n        compass.addEventListener('lostpointercapture', (event) => {\n            stopDrag(event.pointerId);\n        });\n    }\n\n    _enqueueNormals(tile) {\n        if (!tile || !this.tilesPendingNormals) return;\n        if (!this.tilesPendingNormals.has(tile)) {\n            this.tilesPendingNormals.add(tile);\n            this._normalsQueue.push(tile);\n        }\n    }\n\n    _buildScaleLines(container, count) {\n        if (!container) return [];\n        const lines = [];\n        container.innerHTML = '';\n        for (let i = 0; i < count; i++) {\n            const line = document.createElement('div');\n            line.className = 'hud-tick minor';\n            const label = document.createElement('span');\n            label.className = 'hud-tick-label';\n            line.appendChild(label);\n            container.appendChild(line);\n            lines.push({ line, label });\n        }\n        return lines;\n    }\n\n    _buildCompassTicks(container, count) {\n        if (!container) return [];\n        const ticks = [];\n        container.innerHTML = '';\n        for (let i = 0; i < count; i++) {\n            const tick = document.createElement('div');\n            tick.className = 'hud-compass-tick minor';\n            const label = document.createElement('span');\n            label.className = 'hud-compass-label';\n            tick.appendChild(label);\n            container.appendChild(tick);\n            ticks.push({ line: tick, label });\n        }\n        return ticks;\n    }\n\n    _buildFovTicks(container, count) {\n        if (!container) return [];\n        const ticks = [];\n        container.innerHTML = '';\n        for (let i = 0; i < count; i++) {\n            const tick = document.createElement('div');\n            tick.className = 'hud-fov-tick minor';\n            const label = document.createElement('span');\n            label.className = 'hud-fov-label';\n            tick.appendChild(label);\n            container.appendChild(tick);\n            ticks.push({ line: tick, label });\n        }\n        return ticks;\n    }\n\n    _formatMeters(value) {\n        if (!Number.isFinite(value)) return '--';\n        const abs = Math.abs(value);\n        if (abs >= 1000) {\n            const km = value / 1000;\n            const decimals = Math.abs(km) >= 100 ? 0 : Math.abs(km) >= 10 ? 1 : 2;\n            return `${km.toFixed(decimals)} km`;\n        }\n        const decimals = abs < 10 ? 2 : abs < 100 ? 1 : 0;\n        return `${value.toFixed(decimals)} m`;\n    }\n\n    _formatMetersCompact(value) {\n        if (!Number.isFinite(value)) return '--';\n        const abs = Math.abs(value);\n        if (abs >= 1000) {\n            const km = value / 1000;\n            const decimals = Math.abs(km) >= 100 ? 0 : Math.abs(km) >= 10 ? 1 : 2;\n            return `${km.toFixed(decimals)}km`;\n        }\n        const decimals = abs < 10 ? 2 : abs < 100 ? 1 : 0;\n        return `${value.toFixed(decimals)}m`;\n    }\n\n    _formatMetersTick(value) {\n        if (!Number.isFinite(value)) return '';\n        const abs = Math.abs(value);\n        if (abs >= 10000) {\n            return `${(value / 1000).toFixed(0)}k`;\n        }\n        if (abs >= 1000) {\n            return `${(value / 1000).toFixed(1)}k`;\n        }\n        return `${Math.round(value)}`;\n    }\n\n    _formatSpeed(value) {\n        if (!Number.isFinite(value)) return '--';\n        if (value >= 1000) {\n            return `${(value / 1000).toFixed(2)} km/s`;\n        }\n        return `${value.toFixed(value < 10 ? 2 : value < 100 ? 1 : 0)} m/s`;\n    }\n\n    _formatAngle(value) {\n        if (!Number.isFinite(value)) return '--';\n        return `${value.toFixed(1)}°`;\n    }\n\n    _formatHeading(value) {\n        if (!Number.isFinite(value)) return '---';\n        const heading = (value % 360 + 360) % 360;\n        const dir = this._headingToCardinal(heading);\n        return `${heading.toFixed(0)}° ${dir}`;\n    }\n\n    _headingToCardinal(heading) {\n        const dirs = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'];\n        const idx = Math.round(heading / 45) % 8;\n        return dirs[idx];\n    }\n\n    _applyWeatherSummary(prefix, summary) {\n        const values = summary?.values || null;\n        const data = summary?.data || null;\n        const entries = [\n            ['weatherCond', 'condition'],\n            ['weatherTemp', 'temp'],\n            ['weatherClouds', 'clouds'],\n            ['weatherHumidity', 'humidity'],\n            ['weatherWind', 'wind'],\n            ['weatherPrecip', 'precip'],\n            ['weatherUpdated', 'updated']\n        ];\n\n        entries.forEach(([suffix, field]) => {\n            const key = `${prefix}.${suffix}`;\n            const hasValue = values && Object.prototype.hasOwnProperty.call(values, field);\n            this.hudStore.setValue(key, hasValue ? (values[field] ?? '--') : '--');\n            const hasData = data && Object.prototype.hasOwnProperty.call(data, field);\n            this.hudStore.setData(key, hasData ? (data[field] ?? null) : null);\n        });\n    }\n\n    _getCameraWorldPosition() {\n        if (!this.camera) return this._cameraWorldPosition;\n        this.camera.getWorldPosition(this._cameraWorldPosition);\n        if (this.camera.userData) {\n            // Keep the published logical position stable and distinct from\n            // the loop's scratch vector. Tile traversal, labels, and event\n            // picking retain this object between callbacks; aliasing it to a\n            // reused scratch value let a later consumer temporarily publish a\n            // camera pose which no longer matched camera.matrixWorld.\n            this._logicalCameraWorldPosition.copy(this._cameraWorldPosition);\n            this.camera.userData.worldPosition = this._logicalCameraWorldPosition;\n        }\n        return this._cameraWorldPosition;\n    }\n\n    /**\n     * Publish the physical camera transform after an out-of-band surface\n     * correction. PlanetScene calls this when a freshly streamed underfoot\n     * model repositions the camera inside its onFrame hook.\n     */\n    syncCameraWorldPosition() {\n        this.sceneInitializer?.syncXRCamera?.();\n        return this._getCameraWorldPosition();\n    }\n\n    /**\n     * Camera-relative rendering (floating origin) for terrain precision\n     *\n     * At planetary scale (6.4 million meters), 32-bit floats lose precision causing\n     * vertex jitter. By positioning triTree.group at negative camera position,\n     * terrain vertices become camera-relative and stay in high-precision range.\n     *\n     * The key insight: Instead of moving the camera around a huge world,\n     * we keep terrain positioned relative to camera, so rendered vertex\n     * positions are always small numbers with high precision.\n     *\n     * DISABLED: This approach conflicts with the existing scene hierarchy where\n     * triTree.group is used for Earth rotation. Need a different approach that\n     * doesn't conflict with the group's rotation transform.\n     */\n    _updateFloatingOrigin() {\n        // Disabled - the simple group offset approach doesn't work because:\n        // 1. triTree.group already has a rotation transform for Earth rotation\n        // 2. Camera is in a different coordinate space (worldRoot hierarchy)\n        // 3. Setting group.position breaks the terrain rendering\n        //\n        // Alternative approaches needed:\n        // - Shader-based camera-relative vertex transformation\n        // - Separate floating origin group that wraps triTree.group\n        // - Double-precision emulation in shaders\n        return;\n    }\n\n    /**\n     * Main animation loop\n     */\n    animate(time) {\n        if (!this.running) return;\n        if (this._frameOwner === 'raf') this._scheduleNextFrame();\n        // WebGL context lost (scene overload / GPU VRAM exhaustion): park the\n        // whole frame — no GL work against a dead context — until it's\n        // restored. RAF stays scheduled above so we auto-resume. This is what\n        // turns an overload from a hard tab crash into a recoverable stall.\n        if (this.sceneInitializer?.isContextLost?.() || this.sceneInitializer?.isRenderBlocked?.()) {\n            return;\n        }\n        const now = Number.isFinite(time) ? time : performance.now();\n        const elapsedMs = now - this.lastTime;\n        const immersiveXR = this.renderer?.xr?.isPresenting === true;\n        const cadenceMs = this._resolveRenderCadenceMs(now, immersiveXR);\n        if (!immersiveXR && cadenceMs > 0) {\n            if (!this._cadencePrimed) {\n                this._cadencePrimed = true;\n            } else if ((elapsedMs + RENDER_CADENCE_JITTER_TOLERANCE_MS) < cadenceMs) {\n                return;\n            }\n        }\n        if (!immersiveXR && this.frameDiscard?.enabled) {\n            const thresholdMs = Number.isFinite(this.frameDiscard.waitThresholdMs)\n                ? this.frameDiscard.waitThresholdMs\n                : 0;\n            const effectiveThreshold = cadenceMs > 0\n                ? Math.max(thresholdMs, cadenceMs * 2.25)\n                : thresholdMs;\n            if (effectiveThreshold > 0 && elapsedMs > effectiveThreshold) {\n                this.lastTime = now;\n                return;\n            }\n        }\n        // Clamp dt to a sane maximum. When the tab is backgrounded (or any\n        // long pause — GC, devtools open, breakpoint hit), the next frame\n        // reports a huge elapsedMs. Every physics/surface path downstream\n        // multiplies by dt, so an unclamped 10-second dt turns into a\n        // velocity integration of 10 seconds in one step — camera shoots\n        // off the ellipsoid, surface controller produces NaN, the renderer\n        // silently draws nothing, and the scene looks frozen even though\n        // the loop is still running. 100 ms is the max a single frame can\n        // legitimately represent at 10 fps; anything longer is treated as\n        // a pause and we take a single 100 ms step.\n        const dtRaw = elapsedMs / 1000;\n        const dt = (Number.isFinite(dtRaw) && dtRaw > 0) ? Math.min(dtRaw, 0.1) : 0.0167;\n        this.lastTime = now;\n        // Wrap the entire frame body in a try/catch. A thrown exception\n        // inside one subsystem (e.g. a NaN slipping into surface controller)\n        // would otherwise bubble up and, under renderer.setAnimationLoop,\n        // break the rAF scheduling chain entirely — permanent freeze. With\n        // the catch, the loop logs and continues on the next frame.\n        const frameCpuStarted = this.perf?.enabled ? performance.now() : null;\n        const completedBefore = this._completedRenderFrames || 0;\n        let frameFailed = false;\n        try {\n            this._animateFrameBody(now, dt);\n        } catch (error) {\n            frameFailed = true;\n            if (!this._lastFrameErrorAt || (now - this._lastFrameErrorAt) > 2000) {\n                console.warn('[AnimationLoop] frame body threw; continuing', error);\n                this._lastFrameErrorAt = now;\n                this._frameErrorCount = (this._frameErrorCount || 0) + 1;\n            }\n        } finally {\n            // One completed CPU sample per accepted frame, including HUD,\n            // governor and after-frame work. Metrics UI refresh cadence must\n            // not decide which frames or tails the live profiler can see.\n            if (frameCpuStarted !== null) this.perf.record('frame', performance.now() - frameCpuStarted);\n            try { this.onFrameComplete?.({ now: performance.now(),\n                submitted: (this._completedRenderFrames || 0) > completedBefore, failed: frameFailed }); }\n            catch { /* optional diagnostics never interrupt the scene clock */ }\n        }\n    }\n\n    _scheduleNextFrame() {\n        if (!this.running || this._frameOwner !== 'raf' || this._rafId !== null) return;\n        this._rafId = requestAnimationFrame((time) => {\n            this._rafId = null;\n            this.animate(time);\n        });\n    }\n\n    _animateFrameBody(now, dt) {\n\n        // Start performance tracking\n        if (this.perf.enabled) {\n            this.perf.frameStart = performance.now();\n        }\n\n        // Update lighting\n        this.perfStart('lighting');\n        this.lightingSystem.update(dt);\n        if (this.moonSystem) {\n            this.moonSystem.update(\n                this.lightingSystem.currentDate,\n                this.lightingSystem.getCelestialEphemeris?.(),\n            );\n        }\n        this.sceneInitializer.updateSunVisual(dt);\n        if (this.sceneInitializer && typeof this.sceneInitializer.updateWater === 'function') {\n            this.sceneInitializer.updateWater(dt);\n        }\n        if (this.sceneInitializer && typeof this.sceneInitializer.updateImageryLoading === 'function') {\n            this.sceneInitializer.updateImageryLoading(now);\n        }\n        const earthRotation = this.lightingSystem.getEarthRotationAngle();\n        // Treat transit mode like surface for rotation — prevents earth spinning under camera during descent\n        const cameraMode = this.surfaceController?.cameraMode;\n        const inSurfaceMode = cameraMode === 'surface' || cameraMode === 'transit' || cameraMode === 'toSurface';\n        // Keep the physical scattering floor depressed only after surface\n        // contact. Descent retains the clean zero-offset orbital limb, while\n        // ascent releases the surface offset on its first toOrbit frame.\n        this.sceneInitializer?.setAtmosphereSurfaceCameraModeActive?.(\n            cameraMode === 'surface'\n        );\n        this._applyEarthRotationFrame(earthRotation, inSurfaceMode);\n        this.perfEnd('lighting');\n\n        // Update physics with radial gravity\n        if (this.physicsSystem) {\n            this.perfStart('physics');\n            this.physicsSystem.update(dt, this._gravityCenter);\n            this.perfEnd('physics');\n        }\n\n        // Update proximity triggers\n        if (this.proximityTriggerManager) {\n            this.perfStart('proximity-triggers');\n            const observerPos = this._getCameraWorldPosition();\n            this.proximityTriggerManager.update(observerPos, dt);\n            this.perfEnd('proximity-triggers');\n        }\n\n        // Update click triggers\n        if (this.clickTriggerManager) {\n            this.perfStart('click-triggers');\n            const observerPos = this._getCameraWorldPosition();\n            this.clickTriggerManager.update(observerPos);\n            this.perfEnd('click-triggers');\n        }\n\n        // Update controls and camera\n        if (this.renderer?.xr?.isPresenting) {\n            this.syncCameraWorldPosition();\n            this.vrManager?.updateInput(dt);\n            // Analog turning changes the rig, not the native head. Re-publish\n            // before gaze-relative walking consumes this frame's direction.\n            this.syncCameraWorldPosition();\n        }\n        this.perfStart('controls.total');\n        try { this.onBeforeFrame?.(now, dt); }\n        catch { /* optional diagnostics never interrupt navigation/rendering */ }\n        this.perfStart('controls.update');\n        this.surfaceController.update();\n        this.perfEnd('controls.update');\n        this.perfStart('controls.move');\n        this.surfaceController.applySurfaceMovement(dt);\n        this.perfEnd('controls.move');\n        if (this.surfaceController?.isInSurfaceMode?.()) {\n            // Keep camera pose synchronized with same-frame movement state.\n            this.surfaceController.applySurfaceCamera?.();\n        }\n        this.perfEnd('controls.total');\n\n        // The controller has finished its writes and downstream camera\n        // publication/LOD/presence have not sampled the frame yet. This is the\n        // sole MotionRuntime scheduler in the application.\n        this.motionRuntime?.update?.(now, {\n            dt,\n            cameraMode: this.surfaceController?.cameraMode || null,\n            immersiveXR: this.renderer?.xr?.isPresenting === true,\n        });\n\n        // Camera-relative rendering: position terrain group at negative camera position\n        // This gives maximum floating-point precision for terrain vertices near the camera\n        this._updateFloatingOrigin();\n\n        this.syncCameraWorldPosition();\n\n        // Sky orientation, twilight and labels must sample the final same-frame\n        // observer pose, especially on the first frame after a time/location seek.\n        this.sceneInitializer.updateStarFieldRotation(earthRotation);\n\n        if (this.motionTracker) {\n            this.motionTracker.update({\n                camera: this.camera,\n                surfaceController: this.surfaceController,\n                now,\n                dt\n            });\n        }\n\n        if (this.presenceSystem) {\n            this.presenceSystem.update(dt, now);\n        }\n\n        // Save view state periodically (throttled)\n        if (this.uiController && this.uiController._throttledSaveViewState) {\n            this.uiController._throttledSaveViewState();\n        }\n        if (this.uiController && this.uiController._throttledUpdateUrlState) {\n            this.uiController._throttledUpdateUrlState();\n        }\n\n        // Update terrain LOD\n        this.perfStart('lod.total');\n        this.perfStart('cpu.lod.update');\n        const surfacePos = this.surfaceController.getSurfacePosition();\n        const frameIntervalHintMs = this._getRenderIntervalMs(dt);\n        this.triTree?.setFrameBudgetHint?.(frameIntervalHintMs);\n        this.triTree.update(this.camera, surfacePos);\n        this.perfEnd('cpu.lod.update');\n        this.perfEnd('lod.total');\n\n        // Update elevation data fetching\n        this.perfStart('elevation.total');\n        this.perfStart('elevation.camera');\n        this.elevationClient.updateCamera(this.camera, surfacePos);\n        this.perfEnd('elevation.camera');\n        this.perfStart('elevation.tick');\n        this.elevationClient.tick();\n        this.perfEnd('elevation.tick');\n        this.perfEnd('elevation.total');\n\n        // Smoothly morph elevation updates to avoid terrain popping\n        this.perfStart('elevation.morph');\n        const elevationQueue = this.triTree?._tilesNeedingElevationUpdate;\n        if (elevationQueue && elevationQueue.size > 0) {\n            const tileBudget = Math.max(1, Math.floor(this.maxElevationMorphTilesPerFrame || 1));\n            const msBudget = Math.max(0, this.maxElevationMorphMsPerFrame || 0);\n            const nowFn = (typeof performance !== 'undefined' && performance.now)\n                ? () => performance.now()\n                : () => Date.now();\n            const morphStart = nowFn();\n            let processed = 0;\n            for (const tile of elevationQueue) {\n                if (!tile || typeof tile.applyElevationMorph !== 'function') {\n                    elevationQueue.delete(tile);\n                    continue;\n                }\n                if (typeof tile.needsElevationUpdate === 'function' && !tile.needsElevationUpdate()) {\n                    elevationQueue.delete(tile);\n                    continue;\n                }\n                tile.applyElevationMorph(dt);\n                if (typeof tile.needsElevationUpdate === 'function' && !tile.needsElevationUpdate()) {\n                    elevationQueue.delete(tile);\n                }\n                processed++;\n                if (processed >= tileBudget) break;\n                if (msBudget > 0 && ((nowFn() - morphStart) >= msBudget)) break;\n            }\n        }\n        this.perfEnd('elevation.morph');\n\n        const geometryFinalizeQueue = this.triTree?._tilesNeedingGeometryFinalize;\n        if (geometryFinalizeQueue && geometryFinalizeQueue.size > 0) {\n            const tileBudget = Math.max(1, Math.floor(this.maxGeometryFinalizeTilesPerFrame || 1));\n            const msBudget = Math.max(0, this.maxGeometryFinalizeMsPerFrame || 0);\n            const nowFn = (typeof performance !== 'undefined' && performance.now)\n                ? () => performance.now()\n                : () => Date.now();\n            const finalizeStart = nowFn();\n            let processed = 0;\n            for (const tile of geometryFinalizeQueue) {\n                if (!tile || !tile.geometry) {\n                    geometryFinalizeQueue.delete(tile);\n                    continue;\n                }\n                if (tile._skirtDirty && typeof tile._syncSkirtGeometry === 'function') {\n                    tile._syncSkirtGeometry();\n                }\n                if (tile._boundsDirty) {\n                    tile.geometry.computeBoundingSphere();\n                    tile._boundsDirty = false;\n                }\n                if (tile._normalsDirty) {\n                    this._enqueueNormals(tile);\n                    tile._normalsDirty = false;\n                }\n                geometryFinalizeQueue.delete(tile);\n                processed++;\n                if (processed >= tileBudget) break;\n                if (msBudget > 0 && ((nowFn() - finalizeStart) >= msBudget)) break;\n            }\n        }\n\n        // Compute normals for pending tiles (bounded per frame)\n        this.perfStart('normals');\n        if (this.tilesPendingNormals.size > 0) {\n            if (this._normalsQueueIndex >= this._normalsQueue.length) {\n                this._normalsQueue = Array.from(this.tilesPendingNormals);\n                this._normalsQueueIndex = 0;\n            }\n\n            let normalsComputed = 0;\n            const normalsStart = performance.now();\n            const normalsMsBudget = Math.max(0, this.maxNormalsMsPerFrame || 0);\n            while (normalsComputed < this.maxNormalsPerFrame &&\n                this._normalsQueueIndex < this._normalsQueue.length) {\n                if (normalsComputed > 0 && normalsMsBudget > 0 &&\n                    (performance.now() - normalsStart) >= normalsMsBudget) {\n                    break;\n                }\n                const tile = this._normalsQueue[this._normalsQueueIndex++];\n                if (!this.tilesPendingNormals.has(tile)) {\n                    continue;\n                }\n                if (tile.geometry) {\n                    tile.geometry.computeVertexNormals();\n                }\n                this.tilesPendingNormals.delete(tile);\n                normalsComputed++;\n            }\n\n            if (this._normalsQueueIndex >= this._normalsQueue.length) {\n                this._normalsQueue.length = 0;\n                this._normalsQueueIndex = 0;\n            }\n        }\n        this.perfEnd('normals');\n\n        if (this.surfaceController?.isInSurfaceMode?.()) {\n            // Elevation morph can raise terrain after controls update; enforce floor before render.\n            this.surfaceController.enforceSurfaceFloor?.({ useSample: true });\n        }\n\n        // Floor enforcement can move the physical camera after the earlier\n        // logical-position publication. Photoreal traversal runs in onFrame\n        // below and must see this corrected pose in the same frame; otherwise\n        // its nadir focus, SSE, and horizon selection lag behind the renderer\n        // until a pointer drag happens to force another reconciliation.\n        this.syncCameraWorldPosition();\n\n        // Hex selector fade animation\n        if (this.sceneInitializer && typeof this.sceneInitializer.updateHexFade === 'function') {\n            this.sceneInitializer.updateHexFade(dt);\n        }\n\n        // Tile edge highlight fade animation\n        if (this.eventManager && typeof this.eventManager.updateTileEdgeFade === 'function') {\n            this.eventManager.updateTileEdgeFade(dt);\n        }\n\n        // Tile texture fade-in animations\n        if (this.triTree && this.triTree.rootTile) {\n            updateTileFadeIns(this.triTree.rootTile);\n            updateTileCrossfades(this.triTree.rootTile);\n        }\n\n        // AsyncHarness frame tick — BEFORE render, AFTER camera update.\n        // Fires HoverDispatcher / rafCoalesce consumers with fresh camera state.\n        // See refactor/async/frameClock.js and refactor/async/README.md.\n        asyncTickBefore(now, dt);\n\n        // Optional per-frame hook (non-critical work)\n        if (this.onFrame) {\n            try {\n                this.onFrame(dt, now);\n            } catch (error) {\n                console.warn('AnimationLoop onFrame error', error);\n            }\n        }\n\n        // Update tile material uniforms with camera position (for high-precision water shading)\n        const camWorldPos = this._getCameraWorldPosition();\n        this.triTree?.setCameraWorldPosition?.(camWorldPos);\n        if (this.sceneInitializer) {\n            this.sceneInitializer.photorealInterior = photorealInteriorState(this.surfaceController, camWorldPos);\n            this.sceneInitializer.photorealUnderwater = this.surfaceController?._oceanState?.underwater === true;\n        }\n\n        // A source version can change during onFrame. Recheck before stereo,\n        // atmosphere, or direct GL work can read a cold decoded image.\n        if (this.sceneInitializer?.isRenderBlocked?.()) return;\n\n        // Render scene\n        this.perfStart('render.scene');\n        this.perfStart('render.total');\n        this.perfStart('atmosphere.total');\n        const stereoActive = !this.renderer?.xr?.isPresenting\n            && this.stereoRenderer?.isEnabled?.() && this.stereoRenderer?.render;\n        const stereoRendered = stereoActive ? this.stereoRenderer.render(dt) : false;\n        if (stereoRendered) {\n            this.sceneInitializer?.recordExternalFrameOwner?.('stereo', {\n                cameraMode: this.surfaceController?.cameraMode || 'unknown',\n            });\n        } else {\n            if (this.sceneInitializer && typeof this.sceneInitializer.renderSceneWithAtmosphere === 'function') {\n                this.sceneInitializer.renderSceneWithAtmosphere(this.renderer, this.scene, this.camera, dt);\n            } else {\n                if (this.sceneInitializer && typeof this.sceneInitializer.renderAtmosphereDepth === 'function') {\n                    this.sceneInitializer.renderAtmosphereDepth(this.renderer, this.scene, this.camera);\n                }\n                if (this.sceneInitializer && typeof this.sceneInitializer.updateAtmosphereUniforms === 'function') {\n                    this.sceneInitializer.updateAtmosphereUniforms(this.camera);\n                }\n                this.perfStart('gpu.render.legacy');\n                this.renderer.render(this.scene, this.camera);\n                this.perfEnd('gpu.render.legacy');\n            }\n        }\n        this.perfEnd('atmosphere.total');\n        this.perfEnd('render.total');\n        this.perfEnd('render.scene');\n        this._completedRenderFrames = (this._completedRenderFrames || 0) + 1;\n\n        // DOM-backed Three.js auxiliaries (for example CSS2DRenderer labels)\n        // render only after the single WebGL final-frame owner has completed.\n        if (this.onAfterRender) {\n            try {\n                this.onAfterRender(dt, now);\n            } catch (error) {\n                console.warn('AnimationLoop onAfterRender error', error);\n            }\n        }\n\n        // GPU budget enforcement — runs after render so renderer.info is populated\n        if (this.budgetGovernor) {\n            this.budgetGovernor.tick(dt);\n        }\n\n        const renderNow = performance.now();\n        if (Number.isFinite(this._lastRenderTime)) {\n            this._lastRenderIntervalMs = Math.max(0, renderNow - this._lastRenderTime);\n        } else {\n            // First frame after init: seed from the current dt (seconds → ms).\n            // Previously referenced an `elapsedMs` that only exists in the\n            // outer animate() scope, so every frame threw ReferenceError and\n            // the try/catch in animate() swallowed the entire frame body —\n            // that's why continuous phone orientation updates never reached\n            // applySurfaceCamera after initial calibration.\n            this._lastRenderIntervalMs = Math.max(0, dt * 1000);\n        }\n        this._lastRenderTime = renderNow;\n\n        // Update performance metrics (throttled)\n        if (now - this._lastPerfUpdate >= this.metricsThrottleMs) {\n            this.updatePerformanceMetrics(now, dt);\n            this._lastPerfUpdate = now;\n        }\n\n        // Update terrain metrics (throttled)\n        if (now - this._lastTerrainUpdate >= this.metricsThrottleMs) {\n            this.updateTerrainMetrics();\n            this._lastTerrainUpdate = now;\n        }\n\n        // Update network metrics (throttled)\n        if (now - this._lastNetworkUpdate >= this.metricsThrottleMs) {\n            this.updateNetworkMetrics();\n            this._lastNetworkUpdate = now;\n        }\n\n        // Update lighting metrics (throttled)\n        if (now - this._lastLightingUpdate >= this.metricsThrottleMs) {\n            this.updateLightingMetrics();\n            this._lastLightingUpdate = now;\n        }\n\n        // Update position metrics (throttled)\n        if (now - this._lastPositionUpdate >= this.metricsThrottleMs) {\n            this.updatePositionMetrics();\n            this._lastPositionUpdate = now;\n        }\n\n        // Update HUD overlay (every frame for instant feedback)\n        this.updateHud(dt,now);\n\n        // Update LOD overlay (throttled)\n        if (now - this._lastLodOverlayUpdate >= this.metricsThrottleMs) {\n            this.updateLodOverlay(now);\n            this._lastLodOverlayUpdate = now;\n        }\n\n        // Low-FPS mode evaluation (after frame)\n        this._updateLowFpsMode(now, dt);\n\n        // AsyncHarness frame tick — AFTER render + budget governor.\n        // Publishes lastFrameBudgetMs so metrics consumers can read it.\n        asyncTickAfter(performance.now(), (this.perf?.enabled && this.perf?.frameStart)\n            ? (performance.now() - this.perf.frameStart) : 0);\n    }\n\n    /**\n     * Apply an absolute Earth rotation and keep the camera on the same\n     * Earth-fixed coordinate. On the first frame, the prior angle must come\n     * from TriTreeManager because URL/view-state initialization may already\n     * have positioned the camera against that angle before this loop exists.\n     * Dropping that initial delta shifts longitude by the amount Earth rotated\n     * during boot.\n     */\n    _applyEarthRotationFrame(earthRotation, inSurfaceMode) {\n        if (!Number.isFinite(earthRotation)) return;\n\n        let previousRotation = Number.isFinite(this._lastEarthRotation)\n            ? this._lastEarthRotation\n            : null;\n        if (previousRotation === null) {\n            const appliedRotation = this.triTree?.getEarthRotation?.();\n            previousRotation = Number.isFinite(appliedRotation)\n                ? appliedRotation\n                : null;\n        }\n\n        this.triTree?.setEarthRotation?.(earthRotation);\n\n        if (previousRotation !== null) {\n            let delta = earthRotation - previousRotation;\n            if (delta > Math.PI) delta -= Math.PI * 2;\n            if (delta < -Math.PI) delta += Math.PI * 2;\n            if (Math.abs(delta) > 1e-8) {\n                if (inSurfaceMode && typeof this.surfaceController?.applyEarthRotation === 'function') {\n                    this.surfaceController.applyEarthRotation(delta);\n                } else if (!inSurfaceMode && typeof this.surfaceController?.applyEarthRotationOrbit === 'function') {\n                    this.surfaceController.applyEarthRotationOrbit(delta);\n                }\n            }\n        }\n        this._lastEarthRotation = earthRotation;\n    }\n\n    _updateLowFpsMode(now, dt) {\n        const cfg = this.lowFpsMode;\n        if (!cfg || !cfg.enabled) return;\n        const frameIntervalMs = this._getRenderIntervalMs(dt);\n        const fps = frameIntervalMs > 0 ? (1000 / frameIntervalMs) : cfg.lastFps;\n        cfg.lastFps = fps;\n        const minToggleIntervalMs = Number.isFinite(cfg.minToggleIntervalMs) ? cfg.minToggleIntervalMs : 0;\n        const canToggle = !Number.isFinite(cfg.lastToggleMs) || (now - cfg.lastToggleMs) >= minToggleIntervalMs;\n        const recoverThreshold = Number.isFinite(cfg.recoverFpsThreshold)\n            ? cfg.recoverFpsThreshold\n            : cfg.fpsThreshold;\n        if (fps < cfg.fpsThreshold) {\n            cfg.belowCount++;\n            cfg.aboveCount = 0;\n            if (!cfg.active && cfg.belowCount >= cfg.framesRequired && canToggle) {\n                cfg.active = true;\n                cfg.belowCount = 0;\n                cfg.lastToggleMs = now;\n                this.sceneInitializer?.setLowFpsMode?.(true);\n                if (cfg.affectsTerrain) {\n                    this.triTree?.setLowFpsMode?.(true);\n                }\n            }\n        } else {\n            if (fps >= recoverThreshold) {\n                cfg.aboveCount++;\n                cfg.belowCount = 0;\n                if (cfg.active && cfg.aboveCount >= cfg.recoverFrames && canToggle) {\n                    cfg.active = false;\n                    cfg.aboveCount = 0;\n                    cfg.lastToggleMs = now;\n                    if (!this._stallGuard?.active) {\n                        this.sceneInitializer?.setLowFpsMode?.(false);\n                    }\n                    if (cfg.affectsTerrain && !this._stallGuard?.active) {\n                        this.triTree?.setLowFpsMode?.(false);\n                    }\n                }\n            } else {\n                cfg.aboveCount = 0;\n                cfg.belowCount = 0;\n            }\n        }\n    }\n\n    _getRenderIntervalMs(dt) {\n        if (Number.isFinite(this._lastRenderIntervalMs) && this._lastRenderIntervalMs > 0) {\n            return this._lastRenderIntervalMs;\n        }\n        return Number.isFinite(dt) ? dt * 1000 : 0;\n    }\n\n    _setHudVisible(visible) {\n        if (!this.hud || !this.hud.overlay) return;\n        this.hud.overlay.style.display = visible ? '' : 'none';\n    }\n\n    _setPerfOverlayVisible(visible) {\n        const el = document.getElementById('perf-stats-overlay');\n        if (!el) return;\n        el.style.display = visible ? '' : 'none';\n    }\n\n    /**\n     * Update performance metrics and debug panel\n     */\n    updatePerformanceMetrics(now, dt) {\n        const frameIntervalMs = this._getRenderIntervalMs(dt);\n        const frameCpuMs = this.perf.enabled ? (performance.now() - this.perf.frameStart) : null;\n        const frameWaitMs = frameCpuMs !== null ? Math.max(0, frameIntervalMs - frameCpuMs) : null;\n        const longTaskDelta = this._consumeLongTaskDelta();\n        this._lastLongTaskDelta = longTaskDelta;\n\n        if (this.perf.enabled) {\n            this.perf.record('frameInterval', frameIntervalMs);\n            this.perf.record('frameWait', frameWaitMs);\n            if (longTaskDelta > 0) {\n                this.perf.record('cpu.longtask', longTaskDelta);\n            }\n\n            // DIAGNOSTIC: Detect rAF throttling vs actual GPU blocking\n            // True throttling: very long intervals (100ms+) with minimal CPU work (<10ms)\n            // GPU blocking: moderate intervals (30-90ms) with low CPU but GPU work happening\n            const isLikelyThrottled = frameIntervalMs > 100 && frameCpuMs < 10;\n            const isLikelyGPUBound = frameIntervalMs > 30 && frameIntervalMs < 100 && frameCpuMs < 20;\n\n            if (isLikelyThrottled && Math.random() < 0.01) { // Log 1% of throttled frames\n                console.warn('[perf] rAF throttling detected - tab backgrounded, DevTools throttling, or low refresh rate', {\n                    frameIntervalMs: frameIntervalMs.toFixed(1),\n                    frameCpuMs: frameCpuMs.toFixed(1),\n                    frameWaitMs: frameWaitMs.toFixed(1),\n                    fps: (1000 / frameIntervalMs).toFixed(1),\n                    note: 'frameWait is rAF delivery gaps (browser throttling)'\n                });\n            } else if (isLikelyGPUBound && Math.random() < 0.005) { // Log 0.5% of GPU-bound frames\n                console.warn('[perf] GPU-bound - shaders taking longer than 30ms', {\n                    frameIntervalMs: frameIntervalMs.toFixed(1),\n                    frameCpuMs: frameCpuMs.toFixed(1),\n                    frameWaitMs: frameWaitMs.toFixed(1),\n                    fps: (1000 / frameIntervalMs).toFixed(1),\n                    note: 'frameWait approximates GPU execution time (browser waiting for GPU)'\n                });\n            }\n\n            this._logHeavyFrame(frameWaitMs, frameCpuMs, frameIntervalMs, now);\n\n            if (now - this.perf.lastPanelUpdate > 500) {\n                this.perf.lastPanelUpdate = now;\n                this.updateDebugPanel();\n            }\n        }\n\n        this._updateStallGuard(frameIntervalMs, frameCpuMs, longTaskDelta);\n\n        const fps = frameIntervalMs > 0 ? (1000 / frameIntervalMs) : 0;\n        const renderDt = frameIntervalMs > 0 ? (frameIntervalMs / 1000) : dt;\n        this._updateAutoRenderScale(now, renderDt, fps);\n\n        // Update performance stats overlay\n        if (!this._lastPerfOverlayUpdate || now - this._lastPerfOverlayUpdate > 500) {\n            this._lastPerfOverlayUpdate = now;\n            const fpsRounded = frameIntervalMs > 0 ? Math.round(1000 / frameIntervalMs) : 0;\n            const tileUsage = ((this.triTree.tileCount / this.triTree.tileBudget) * 100).toFixed(0);\n            const emergencyMode = this.triTree.tileCount / this.triTree.tileBudget > 0.85 ? ' ⚠️' : '';\n            const stageLevel = this.triTree.surfaceStageProgressLevel;\n            const stagePctRaw = this.triTree.surfaceStageProgress;\n            const stagePct = Number.isFinite(stagePctRaw)\n                ? Math.max(0, Math.min(100, Math.round(stagePctRaw * 100)))\n                : 0;\n            const showStage = this.surfaceController?.isInSurfaceMode() && Number.isFinite(stageLevel);\n            const stageLabel = showStage\n                ? `Elev LOD ${stageLevel}: ${stagePct}%`\n                : 'Elev LOD: --';\n            this.hudStore.setValue('system.fps', String(fpsRounded));\n            this.hudStore.setValue(\n                'system.tiles',\n                `${this.triTree.tileCount}/${this.triTree.tileBudget} (${tileUsage}%)${emergencyMode}`\n            );\n            this.hudStore.setValue('system.stage', stageLabel);\n            this.hudStore.setValue('system.visible', String(this.triTree.visibleTileCount));\n            this.hudStore.setValue('system.maxLod', String(this.triTree.currentMaxLevel));\n            this.hudStore.setValue(\n                'system.elevActive',\n                String(this.triTree.activeElevationTiles?.length ?? 0)\n            );\n            this.hudStore.setValue(\n                'system.elevForce',\n                String(this.triTree.elevationForceCount ?? 0)\n            );\n            const stageBar = document.getElementById('hud-perf-stage-bar');\n            if (stageBar) {\n                stageBar.style.width = showStage ? `${stagePct}%` : '0%';\n            }\n        }\n    }\n\n    setAutoRenderScaleEnabled(enabled) {\n        const state = this.autoRenderScale;\n        if (!state) return;\n        state.enabled = false;\n        state.lowFpsFrames = 0;\n        state.stableFrames = 0;\n        state.integral = 0;\n        state.prevError = 0;\n        state.emaFps = null;\n        state.lastUpdate = performance.now();\n    }\n\n    setRenderCadenceMs(value) {\n        if (!Number.isFinite(value)) return;\n        const next = Math.max(0, value);\n        if (Math.abs(next - this.renderCadenceMs) < 1e-4) return;\n        this.renderCadenceMs = next;\n        this._cadencePrimed = false;\n        this.lastTime = performance.now();\n    }\n\n    setFrameDiscard({ enabled, waitThresholdMs } = {}) {\n        if (typeof enabled === 'boolean') {\n            this.frameDiscard.enabled = enabled;\n        }\n        if (Number.isFinite(waitThresholdMs)) {\n            this.frameDiscard.waitThresholdMs = Math.max(0, waitThresholdMs);\n        }\n    }\n\n    setTerrainWorkBudgets({\n        maxElevationMorphTilesPerFrame,\n        maxGeometryFinalizeTilesPerFrame,\n        maxElevationMorphMsPerFrame,\n        maxGeometryFinalizeMsPerFrame,\n        maxNormalsPerFrame,\n        maxNormalsMsPerFrame\n    } = {}) {\n        if (Number.isFinite(maxElevationMorphTilesPerFrame)) {\n            this.maxElevationMorphTilesPerFrame = Math.max(1, Math.floor(maxElevationMorphTilesPerFrame));\n        }\n        if (Number.isFinite(maxGeometryFinalizeTilesPerFrame)) {\n            this.maxGeometryFinalizeTilesPerFrame = Math.max(1, Math.floor(maxGeometryFinalizeTilesPerFrame));\n        }\n        if (Number.isFinite(maxElevationMorphMsPerFrame)) {\n            this.maxElevationMorphMsPerFrame = Math.max(0, maxElevationMorphMsPerFrame);\n        }\n        if (Number.isFinite(maxGeometryFinalizeMsPerFrame)) {\n            this.maxGeometryFinalizeMsPerFrame = Math.max(0, maxGeometryFinalizeMsPerFrame);\n        }\n        if (Number.isFinite(maxNormalsPerFrame)) {\n            this.maxNormalsPerFrame = Math.max(1, Math.floor(maxNormalsPerFrame));\n        }\n        if (Number.isFinite(maxNormalsMsPerFrame)) {\n            this.maxNormalsMsPerFrame = Math.max(0, maxNormalsMsPerFrame);\n        }\n    }\n\n    _updateAutoRenderScale(_now, _dt, _fps) {\n        const state = this.autoRenderScale;\n        if (state) {\n            state.enabled = false;\n        }\n    }\n\n    _logHeavyFrame(frameWaitMs, frameCpuMs, frameIntervalMs, now) {\n        if (!this.perf || !this.perf.logHeavyFrames) return;\n        if (frameWaitMs < (this.perf.logHeavyFrameThresholdMs || 0)) return;\n\n        // Don't log heavy frames when tab is unfocused - browser rAF throttling is expected\n        const tabHasFocus = typeof document !== 'undefined' && typeof document.hasFocus === 'function'\n            ? document.hasFocus() : true;\n        if (!tabHasFocus) return;\n\n        const minInterval = this.perf.logHeavyFrameIntervalMs || 0;\n        if (minInterval > 0 && now - this._lastHeavyFrameLog < minInterval) return;\n\n        this._lastHeavyFrameLog = now;\n        const lodStats = this.triTree ? this.triTree.debugStats : null;\n        const imageryStats = this.triTree?.imageryManager?.getStats?.({ includeOwnership: false }) || null;\n        const elevStats = this.elevationClient ? {\n            currentBatches: this.elevationClient.currentBatches,\n            vertexRecords: this.elevationClient.vertexMap?.size ?? 0\n        } : null;\n        const renderInfo = this.renderer?.info?.render\n            ? {\n                calls: this.renderer.info.render.calls,\n                triangles: this.renderer.info.render.triangles,\n                lines: this.renderer.info.render.lines,\n                points: this.renderer.info.render.points\n            }\n            : null;\n        const visibilityState = typeof document !== 'undefined' ? document.visibilityState : 'unknown';\n        const hasFocus = typeof document !== 'undefined' && typeof document.hasFocus === 'function'\n            ? document.hasFocus()\n            : null;\n\n        console.log('[perf] heavy frame', {\n            frameWaitMs: frameWaitMs.toFixed(1),\n            frameCpuMs: frameCpuMs.toFixed(1),\n            frameIntervalMs: frameIntervalMs.toFixed(1),\n            lod: lodStats,\n            imagery: imageryStats,\n            elevation: elevStats,\n            render: renderInfo,\n            longTasksMs: this._lastLongTaskDelta ? this._lastLongTaskDelta.toFixed(1) : 0,\n            visibilityState,\n            hasFocus,\n            stallGuardActive: this._stallGuard?.active ?? false\n        });\n    }\n\n    _initLongTaskObserver() {\n        if (typeof PerformanceObserver === 'undefined') return;\n        const supported = PerformanceObserver.supportedEntryTypes || [];\n        if (!supported.includes('longtask')) return;\n        try {\n            this._longTaskObserver = new PerformanceObserver((list) => {\n                for (const entry of list.getEntries()) {\n                    this._longTaskTotal += entry.duration;\n                }\n            });\n            this._longTaskObserver.observe({ entryTypes: ['longtask'] });\n        } catch (error) {\n            this._longTaskObserver = null;\n        }\n    }\n\n    _consumeLongTaskDelta() {\n        const total = this._longTaskTotal;\n        const delta = total - this._lastLongTaskTotal;\n        this._lastLongTaskTotal = total;\n        return Number.isFinite(delta) && delta > 0 ? delta : 0;\n    }\n\n    _updateStallGuard(frameIntervalMs, frameCpuMs, longTaskDelta) {\n        const guard = this._stallGuard;\n        if (!guard || !guard.enabled) return;\n        const visibilityOk = typeof document === 'undefined' ||\n            (document.visibilityState === 'visible' && (!document.hasFocus || document.hasFocus()));\n        this.sceneInitializer?.updateCloudQualityPressure?.(frameIntervalMs, visibilityOk);\n        if (!visibilityOk) {\n            guard.badFrames = 0;\n            guard.goodFrames = 0;\n            return;\n        }\n\n        const waitMs = Number.isFinite(frameCpuMs)\n            ? Math.max(0, frameIntervalMs - frameCpuMs)\n            : frameIntervalMs;\n        const cpuMs = Number.isFinite(frameCpuMs) ? frameCpuMs : 0;\n        const longTaskBlocked = Number.isFinite(longTaskDelta) && longTaskDelta >= 120;\n        const cpuBlocked = cpuMs >= guard.thresholdMs;\n        const waitBlocked = waitMs >= guard.thresholdMs;\n        const intervalBlocked = Number.isFinite(frameIntervalMs) && frameIntervalMs >= guard.thresholdMs + 80;\n        const badFrame = longTaskBlocked || cpuBlocked || waitBlocked || intervalBlocked;\n\n        if (!guard.active) {\n            if (badFrame) {\n                guard.badFrames += 1;\n                guard.goodFrames = 0;\n                if (guard.badFrames >= guard.framesRequired) {\n                    this._setStallGuardActive(true, longTaskBlocked ? 'sustained long tasks' : 'sustained frame stall');\n                }\n            } else {\n                guard.badFrames = 0;\n            }\n            return;\n        }\n\n        if (!badFrame && waitMs <= guard.recoverMs) {\n            guard.goodFrames += 1;\n            if (guard.goodFrames >= guard.recoverFrames) {\n                this._setStallGuardActive(false, 'recovered');\n            }\n        } else {\n            guard.goodFrames = 0;\n        }\n    }\n\n    _setStallGuardActive(active, reason) {\n        const guard = this._stallGuard;\n        if (!guard || guard.active === active) return;\n        guard.active = active;\n\n        if (active) {\n            guard.prevAtmosphere = null;\n            guard.prevSceneLowFps = this.lowFpsMode?.active === true;\n            guard.prevTerrainLowFps = this.triTree?._lowFpsActive === true;\n            // Frame pressure must not rewrite source enablement, stop weather\n            // acquisition or restore a superseded user choice on recovery.\n            // Rain/snow and lighting continue consuming the current data.\n            this.sceneInitializer?.setLowFpsMode?.(true);\n            if (this.lowFpsMode?.affectsTerrain) {\n                this.triTree?.setLowFpsMode?.(true);\n            }\n            console.debug('[perf] stall guard enabled:', reason);\n            return;\n        }\n\n        const keepSceneLowFps = this.lowFpsMode?.active === true || guard.prevSceneLowFps === true;\n        this.sceneInitializer?.setLowFpsMode?.(keepSceneLowFps);\n        if (this.lowFpsMode?.affectsTerrain) {\n            const keepTerrainLowFps = this.lowFpsMode?.active === true || guard.prevTerrainLowFps === true;\n            this.triTree?.setLowFpsMode?.(keepTerrainLowFps);\n        }\n        guard.prevAtmosphere = null;\n        guard.prevSceneLowFps = null;\n        guard.prevTerrainLowFps = null;\n        guard.badFrames = 0;\n        guard.goodFrames = 0;\n        console.debug('[perf] stall guard disabled:', reason);\n    }\n\n    /**\n     * Update terrain-related metrics\n     */\n    updateTerrainMetrics() {\n        const stats = this.elevationClient.getStats();\n        this.metrics.tiles.textContent = this.triTree.visibleTileCount.toString();\n        this.metrics.level.textContent = this.triTree.currentMaxLevel.toString();\n        this.metrics.batches.textContent = stats.currentBatches.toString();\n        this.metrics.verts.textContent = stats.totalVertices.toString();\n\n        this.hudStore.setValue('terrain.tiles', this.triTree.visibleTileCount.toString());\n        this.hudStore.setValue('terrain.lod', this.triTree.currentMaxLevel.toString());\n\n        const stageLevel = this.triTree.surfaceStageProgressLevel;\n        const stagePctRaw = this.triTree.surfaceStageProgress;\n        const stagePct = Number.isFinite(stagePctRaw)\n            ? Math.max(0, Math.min(100, Math.round(stagePctRaw * 100)))\n            : null;\n        if (Number.isFinite(stageLevel) && stagePct !== null) {\n            this.hudStore.setValue('terrain.stage', `L${stageLevel} ${stagePct}%`);\n        } else {\n            this.hudStore.setValue('terrain.stage', '--');\n        }\n\n        // GPU budget governor stats\n        if (this.budgetGovernor) {\n            const gov = this.budgetGovernor.lastSnapshot;\n            if (gov) {\n                this.hudStore.setValue('gpu.tris', (gov.triangles / 1000).toFixed(0) + 'k');\n                this.hudStore.setValue('gpu.draws', gov.calls.toString());\n                this.hudStore.setValue('gpu.geoms', gov.geometries.toString());\n                this.hudStore.setValue('gpu.texs', gov.textures.toString());\n            }\n            const gstats = this.budgetGovernor.getStats();\n            this.hudStore.setValue('gpu.state',\n                gstats.emergencyActive ? 'EMERGENCY' :\n                gstats.throttled ? 'THROTTLED' : 'OK');\n        }\n    }\n\n    /**\n     * Update network-related metrics\n     */\n    updateNetworkMetrics() {\n        const stats = this.elevationClient.getStats();\n        this.metrics.reqs.textContent = stats.requestCount.toString();\n        this.metrics.resps.textContent = stats.responseCount.toString();\n        this.metrics.ptsOut.textContent = stats.pointsRequested.toString();\n        this.metrics.ptsIn.textContent = stats.pointsReceived.toString();\n        this.metrics.kbOut.textContent = (stats.bytesOut / 1024).toFixed(1);\n        this.metrics.kbIn.textContent = (stats.bytesIn / 1024).toFixed(1);\n\n        if (stats.bytesOut > 0) {\n            const ratio = stats.bytesIn / stats.bytesOut;\n            this.metrics.ratio.textContent = ratio.toFixed(2);\n        } else {\n            this.metrics.ratio.textContent = '–';\n        }\n\n        this.hudStore.setValue('link.reqs', stats.requestCount.toString());\n        this.hudStore.setValue('link.resps', stats.responseCount.toString());\n        this.hudStore.setValue('link.kbOut', (stats.bytesOut / 1024).toFixed(1));\n        this.hudStore.setValue('link.kbIn', (stats.bytesIn / 1024).toFixed(1));\n        if (stats.bytesOut > 0) {\n            const ratio = stats.bytesIn / stats.bytesOut;\n            this.hudStore.setValue('link.ratio', ratio.toFixed(2));\n        } else {\n            this.hudStore.setValue('link.ratio', '--');\n        }\n    }\n\n    /**\n     * Update lighting and time metrics\n     */\n    updateLightingMetrics() {\n        const timeInfo = this.lightingSystem.getTimeInfo();\n        const sunDir = this.lightingSystem.getSunDirection();\n\n        this.metrics.currentTime.textContent = `${String(timeInfo.hours).padStart(2, '0')}:${String(timeInfo.minutes).padStart(2, '0')} UTC`;\n        this.metrics.sunDir.textContent = `(${sunDir.x.toFixed(2)}, ${sunDir.y.toFixed(2)}, ${sunDir.z.toFixed(2)})`;\n        this.triTree?.setSunDirection?.(sunDir);\n\n        // Update UTC time overlay (top left)\n        const date = timeInfo.date;\n        const hours = String(date.getUTCHours()).padStart(2, '0');\n        const minutes = String(date.getUTCMinutes()).padStart(2, '0');\n        const seconds = String(date.getUTCSeconds()).padStart(2, '0');\n        const year = date.getUTCFullYear();\n        const month = String(date.getUTCMonth() + 1).padStart(2, '0');\n        const day = String(date.getUTCDate()).padStart(2, '0');\n        const utcDate = `${year}-${month}-${day}`;\n        this.hudStore.setValue('time.utc', `${utcDate} ${hours}:${minutes}:${seconds}`);\n        this.hudStore.setValue('time.utcDate', utcDate);\n\n        // Update local solar time based on current target position\n        let targetPos = null;\n        if (this.surfaceController.isInSurfaceMode()) {\n            targetPos = this.surfaceController.getSurfacePosition();\n        } else {\n            const vDir = this._metricViewDirection;\n            this.camera.getWorldDirection(vDir);\n            const cameraPos = this._getCameraWorldPosition();\n            const planetGroup = this.triTree?.group || null;\n            targetPos = rayEllipsoidIntersection(cameraPos, vDir, planetGroup) ||\n                raySphereIntersection(cameraPos, vDir);\n        }\n\n        if (targetPos) {\n            const ll = worldPosToLatLonLocal(targetPos, this.triTree?.group);\n            if (ll) {\n                const offsetMs = (ll.lonDeg / 15) * 3600 * 1000;\n                const localDate = new Date(date.getTime() + offsetMs);\n                const pad = (n) => String(n).padStart(2, '0');\n                const localYear = localDate.getUTCFullYear();\n                const localMonth = pad(localDate.getUTCMonth() + 1);\n                const localDay = pad(localDate.getUTCDate());\n                const localHours = pad(localDate.getUTCHours());\n                const localMinutes = pad(localDate.getUTCMinutes());\n                const localSeconds = pad(localDate.getUTCSeconds());\n                this.hudStore.setValue('time.local', `${localHours}:${localMinutes}:${localSeconds}`);\n                this.hudStore.setValue('time.localDate', `${localYear}-${localMonth}-${localDay}`);\n            } else {\n                this.hudStore.setValue('time.local', '--:--:--');\n                this.hudStore.setValue('time.localDate', '--');\n            }\n        } else {\n            this.hudStore.setValue('time.local', '--:--:--');\n            this.hudStore.setValue('time.localDate', '--');\n        }\n    }\n\n    /**\n     * Update position (lat/lon) metrics\n     */\n    updatePositionMetrics() {\n        let latlonStr = '–';\n        let targetPos = null;\n        const navOverride = this._navOverride?.active ? this._navOverride : null;\n        const hasOverride = Number.isFinite(navOverride?.lat) && Number.isFinite(navOverride?.lon);\n        this.hudStore.setValue('nav.lat', '--');\n        this.hudStore.setValue('nav.lon', '--');\n        this.hudStore.setData('nav.lat', null);\n        this.hudStore.setData('nav.lon', null);\n\n        const body = this.surfaceController.getBodyAnchor?.() || 'terra';\n        this.hudStore.setData('nav.body', body);\n        if (body !== 'terra') {\n            const lunar = body === 'luna' && this.orbitTelemetry?.values?.body === 'luna'\n                ? this.orbitTelemetry.values : null;\n            this.metrics.latlon.textContent = lunar\n                ? `Moon ${lunar.lat.toFixed(4)}°, ${lunar.lon.toFixed(4)}° E` : body === 'luna' ? 'Moon' : 'Sun';\n            // Earth NAV/weather consumers must never ingest selenographic data.\n            this._applyWeatherSummary('nav', null);\n            return;\n        }\n\n        if (this.surfaceController.isInSurfaceMode()) {\n            // Use standing position in surface mode\n            targetPos = this.surfaceController.getSurfacePosition();\n        } else {\n            // Use camera look direction in orbit mode\n            const vDir = this._metricViewDirection;\n            this.camera.getWorldDirection(vDir);\n            const cameraPos = this._getCameraWorldPosition();\n            const planetGroup = this.triTree?.group || null;\n            targetPos = rayEllipsoidIntersection(cameraPos, vDir, planetGroup) ||\n                raySphereIntersection(cameraPos, vDir);\n        }\n\n        if (hasOverride) {\n            latlonStr = `${navOverride.lat.toFixed(4)}°, ${navOverride.lon.toFixed(4)}°`;\n            this.hudStore.setValue('nav.lat', `${navOverride.lat.toFixed(4)}°`);\n            this.hudStore.setValue('nav.lon', `${navOverride.lon.toFixed(4)}°`);\n            this.hudStore.setData('nav.lat', navOverride.lat);\n            this.hudStore.setData('nav.lon', navOverride.lon);\n        } else if (targetPos) {\n            const ll = worldPosToLatLonLocal(targetPos, this.triTree?.group);\n            if (ll) {\n                latlonStr = `${ll.latDeg.toFixed(4)}°, ${ll.lonDeg.toFixed(4)}°`;\n                this.hudStore.setValue('nav.lat', `${ll.latDeg.toFixed(4)}°`);\n                this.hudStore.setValue('nav.lon', `${ll.lonDeg.toFixed(4)}°`);\n                this.hudStore.setData('nav.lat', ll.latDeg);\n                this.hudStore.setData('nav.lon', ll.lonDeg);\n            }\n        }\n\n        this.metrics.latlon.textContent = latlonStr;\n        const navLat = this.hudStore.getData('nav.lat');\n        const navLon = this.hudStore.getData('nav.lon');\n        if (Number.isFinite(navLat) && Number.isFinite(navLon)) {\n            this.weatherSystem?.updateFromHudValues?.(navLat, navLon);\n        }\n        const navWeather = this.weatherSystem?.getHudWeatherSummary?.('nav') || null;\n        this._applyWeatherSummary('nav', navWeather);\n\n        if (targetPos && this.sceneInitializer?.atmosphereClouds) {\n            const dir = targetPos.clone().normalize();\n            let radius = null;\n            const photoActive = !!this.surfaceController?.photoTileGroup;\n\n            if (photoActive) {\n                // NAV/cloud presentation is read-only. Feeding this selected\n                // surface point into the camera's walkable-floor sampler can\n                // replace physical contact after the accepted render frame.\n                radius = this.surfaceController.isInSurfaceMode?.()\n                    ? this.surfaceController.getSurfaceContactRadius?.(dir)\n                    : this.surfaceController.sampleTerrainRadiusForDir?.(dir, {\n                        mutateCache: false,\n                        requireFreshPhotoHit: true,\n                        allowTriTreeFallback: false,\n                    });\n                if (!Number.isFinite(radius)) return;\n            } else if (this.triTree?.getSurfaceRadiusAtDir) {\n                // Non-photo-tile mode: use triTree terrain radius.\n                radius = this.triTree.getSurfaceRadiusAtDir(dir);\n                if (!Number.isFinite(radius) && typeof this.triTree.sampleTerrainRadiusForDir === 'function') {\n                    radius = this.triTree.sampleTerrainRadiusForDir(dir);\n                }\n            }\n\n            if (Number.isFinite(radius)) {\n                this.sceneInitializer.atmosphereClouds.setRegionalTerrainRadius?.(radius);\n                if (typeof this.sceneInitializer.atmosphereClouds.setTerrainElevationMeters === 'function') {\n                    // Atmosphere bottomRadius is PLANET_RADIUS - baseOffset,\n                    // so its terrain input must use the same spherical datum.\n                    this.sceneInitializer.atmosphereClouds.setTerrainElevationMeters(radius - PLANET_RADIUS);\n                }\n            }\n        }\n    }\n\n    updateHud(dt,now=0) {\n        if (!this.hud || !this.hud.overlay) return;\n        const paintDom = this.renderer?.xr?.isPresenting !== true;\n\n        const inSurface = this.surfaceController?.isInSurfaceMode();\n        const pointerLocked = (typeof this.surfaceController?.isPointerLocked === 'function')\n            ? this.surfaceController.isPointerLocked()\n            : false;\n        if (paintDom && this.hud.layout) {\n            this.hud.layout.classList.toggle('surface', !!inSurface);\n            this.hud.layout.classList.toggle('pointerlock', !!pointerLocked);\n        }\n        if (paintDom) {\n            this.hud.overlay.classList.toggle('surface', !!inSurface);\n            this.hud.overlay.classList.toggle('pointerlock', !!pointerLocked);\n        }\n        const mode = this.surfaceController?.getCameraMode?.() || (inSurface ? 'surface' : 'orbit');\n        const navOverride = this._navOverride?.active ? this._navOverride : null;\n        const overrideLabel = navOverride?.modeLabel || null;\n        const label = overrideLabel || (mode === 'surface' ? 'SURFACE' : mode === 'orbit' ? 'ORBIT' : 'TRANSIT');\n        const prevMode = this.hudStore.getValue('time.mode');\n        if (prevMode !== label) {\n            console.log('[HUD MODE] Display changed from', prevMode, 'to', label, '(cameraMode:', mode, ')');\n        }\n        this.hudStore.setValue('time.mode', label);\n\n        if (mode === 'orbit' && this.surfaceController?.getBodyAnchor?.() === 'luna') {\n            const telemetry = this.orbitTelemetry;\n            const sampled = telemetry?.update(this.camera, null, {\n                enabled: !this.renderer?.xr?.isPresenting, now, body: 'luna', moonMesh: this.moonSystem?.moonMesh,\n            });\n            const lunar = sampled || (telemetry?.values?.body === 'luna' ? telemetry.values : null);\n            for (const key of ['agl', 'msl', 'ground', 'vspeed']) {\n                this.hudStore.setValue(`terrain.${key}`, '--'); this.hudStore.setData(`terrain.${key}`, null);\n            }\n            this.hudStore.setValue('nav.speed', '--'); this.hudStore.setData('nav.speed', null);\n            for (const key of ['heading', 'pitch']) this.hudStore.setValue(`nav.${key}`,\n                Number.isFinite(lunar?.[key]) ? `${lunar[key].toFixed(1)}°` : '--');\n            if (paintDom) {\n                if (this.hud.altTitle) this.hud.altTitle.textContent = 'LUNAR ALT';\n                if (this.hud.altReadout) this.hud.altReadout.textContent = this._formatMetersCompact(lunar?.altitudeM);\n                if (this.hud.altSubReadout) this.hud.altSubReadout.textContent = 'MEAN LUNAR RADIUS';\n            }\n            return;\n        }\n\n        const surfacePos = this.surfaceController?.getSurfacePosition();\n        const groundR = surfacePos ? surfacePos.length() : null;\n        const cameraPos = this._getCameraWorldPosition();\n        const cameraR = cameraPos.length();\n\n        const surfaceUp = this.surfaceController?.surfaceState?.up || null;\n        const hasSurfaceDir = surfaceUp && surfaceUp.lengthSq() > 0;\n        const planetGroup = this.triTree?.group;\n        let ellipsoidR = PLANET_RADIUS;\n        if (hasSurfaceDir || cameraR > 0) {\n            const localDir = this._hudSurfaceLocalDir.copy(hasSurfaceDir ? surfaceUp : cameraPos);\n            if (planetGroup?.getWorldQuaternion) {\n                planetGroup.getWorldQuaternion(this._hudSurfaceLocalQuat);\n                this._hudSurfaceLocalQuat.invert();\n                localDir.applyQuaternion(this._hudSurfaceLocalQuat);\n            }\n            if (localDir.lengthSq() > 0) {\n                localDir.normalize();\n                ellipsoidR = ellipsoidRadiusForDir(localDir);\n            }\n        }\n        const exag = Math.max(ELEVATION_EXAGGERATION || 1, 1e-6);\n        const cameraMsl = cameraR - ellipsoidR;\n        const controllerMsl = inSurface\n            ? this.surfaceController?.getSurfaceAltitudeMSL?.()\n            : null;\n        const altitudeTape = inSurface\n            ? this.surfaceController.getSurfaceAltitudeMeters()\n            : null;\n        const measuredSurfaceAgl = inSurface\n            ? this.surfaceController?.getActualSurfaceAltitudeMeters?.()\n            : null;\n        const groundElevGeom = Number.isFinite(groundR)\n            ? (groundR - ellipsoidR) / exag\n            : null;\n        let agl = inSurface\n            ? (Number.isFinite(measuredSurfaceAgl)\n                ? measuredSurfaceAgl\n                : (Number.isFinite(altitudeTape)\n                    ? altitudeTape\n                    : (Number.isFinite(groundR) ? cameraR - groundR : null)))\n            : (Number.isFinite(groundR) ? cameraR - groundR : null);\n        let msl = inSurface\n            ? (Number.isFinite(controllerMsl)\n                ? controllerMsl\n                : ((Number.isFinite(groundElevGeom) && Number.isFinite(agl))\n                    ? (groundElevGeom + agl)\n                    : null))\n            : (Number.isFinite(cameraMsl) ? cameraMsl : null);\n        let groundElev = (inSurface && Number.isFinite(msl) && Number.isFinite(agl))\n            ? (msl - agl)\n            : groundElevGeom;\n        // Swimming depth is sea-level relative; ground contact and the\n        // photoreal AGL probe clamp at zero, so take heights from the sea.\n        const ocean = inSurface ? this.surfaceController?.getOceanNavigationState?.() : null;\n        const underwater = ocean?.underwater === true;\n        if (underwater) {\n            msl = -Math.max(0, ocean.depthMeters || 0);\n            const seabed = this.surfaceController?.getOceanSeabedElevation?.();\n            groundElev = Number.isFinite(seabed) ? seabed : null;\n            agl = Number.isFinite(seabed) ? msl - seabed : null;\n        } else if (ocean?.isOcean && Number.isFinite(ocean.altitudeAboveSeaMeters)) {\n            // Over open water the ground below is the sea surface, not the\n            // seabed the photoreal probe may hit.\n            agl = ocean.altitudeAboveSeaMeters;\n            msl = agl + (ocean.tideMeters || 0);\n        }\n\n        this.hudStore.setValue('terrain.agl', this._formatMeters(agl));\n        this.hudStore.setValue('terrain.msl', Number.isFinite(msl) ? `${this._formatMeters(msl)} ${seaLevelDatum(msl)}` : '--');\n        this.hudStore.setValue('terrain.ground', this._formatMeters(groundElev));\n        // Publish the already-measured physical clearance; consumers must not\n        // cast a second terrain ray or reinterpret WGS84 altitude as AGL.\n        this.hudStore.setData('terrain.agl', Number.isFinite(agl) ? agl : null);\n        this.hudStore.setData('terrain.msl', Number.isFinite(msl) ? msl : null);\n        this.hudStore.setData('terrain.ground', Number.isFinite(groundElev) ? groundElev : null);\n\n        // Update mobile orbit mode button visibility based on altitude\n        if (paintDom && this.uiController?.hudManager?.updateOrbitModeButtonVisibility) {\n            this.uiController.hudManager.updateOrbitModeButtonVisibility(altitudeTape ?? msl);\n        }\n\n        const altitudePresentation = resolveAltitudeHudPresentation({ inSurface, agl, msl, underwater });\n        // The tape and the numeric readout must share the same physical datum.\n        // `getSurfaceAltitudeMeters()` is the controller's requested AGL and can\n        // temporarily diverge from the measured photoreal contact altitude.\n        // Driving the tape from that requested value left the zero mark pinned\n        // at the floor while the readout correctly reported tens of metres AGL.\n        const actualAltitudeTape = altitudePresentation.primary;\n        if (paintDom && this.hud.altTitle) {\n            this.hud.altTitle.textContent = altitudePresentation.title;\n        }\n        if (paintDom && this.hud.altReadout) {\n            this.hud.altReadout.textContent = this._formatMetersCompact(\n                altitudePresentation.primary\n            );\n        }\n        if (paintDom && this.hud.altSubReadout) {\n            this.hud.altSubReadout.textContent = `${altitudePresentation.secondaryLabel} ${this._formatMetersCompact(\n                altitudePresentation.secondary\n            )}`;\n        }\n\n        const telemetry=this.orbitTelemetry;\n        const orbitBody=this.surfaceController?.getBodyAnchor?.()||'terra';\n        const orbitalInstruments=mode==='orbit'&&['terra','luna'].includes(orbitBody)&&!this.renderer?.xr?.isPresenting;\n        const sampledOrbit=telemetry?.update(this.camera,planetGroup,{enabled:orbitalInstruments,now,body:orbitBody,moonMesh:this.moonSystem?.moonMesh});\n        const orbitPose=orbitalInstruments?(sampledOrbit||telemetry?.values):null;\n        const pitchDeg = inSurface ? this.surfaceController.getSurfacePitchDeg() : orbitPose?.pitch;\n        const headingDeg = inSurface ? this.surfaceController.getSurfaceHeadingDeg() : orbitPose?.heading;\n\n        this.hudStore.setValue('nav.heading', Number.isFinite(headingDeg) ? `${headingDeg.toFixed(1)}°` : '--');\n        if (paintDom) this.uiController?.hudManager?.leftSidebar?.updateHeading?.(headingDeg);\n        this.hudStore.setValue('nav.pitch', Number.isFinite(pitchDeg) ? `${pitchDeg.toFixed(1)}°` : '--');\n        if (paintDom && this.hud.pitchReadout) {\n            this.hud.pitchReadout.textContent = this._formatAngle(pitchDeg);\n        }\n        if (paintDom && this.hud.pitchSubReadout) {\n            this.hud.pitchSubReadout.textContent = inSurface ? 'HORIZON' : 'LOCAL HORIZON';\n        }\n\n        if (paintDom && this.hud.compassReadout) {\n            this.hud.compassReadout.textContent = this._formatHeading(headingDeg);\n        }\n        if (paintDom && this.hud.compassSubReadout) {\n            this.hud.compassSubReadout.textContent = inSurface ? 'HEADING' : 'TRUE NORTH';\n        }\n\n        const fovDeg = this.camera.fov;\n        const showFov = pointerLocked && Number.isFinite(fovDeg);\n        if (paintDom && this.hud.fovReadout) {\n            this.hud.fovReadout.textContent = showFov ? `${fovDeg.toFixed(0)}°` : '--';\n        }\n        if (paintDom && this.hud.fovSubReadout) {\n            this.hud.fovSubReadout.textContent = pointerLocked ? 'CAM FOV' : 'FOV';\n        }\n\n        if (inSurface && surfacePos && dt > 0) {\n            const localDir = this._hudSurfaceLocalDir.copy(surfacePos);\n            const planetGroup = this.triTree?.group;\n            if (planetGroup?.getWorldQuaternion) {\n                planetGroup.getWorldQuaternion(this._hudSurfaceLocalQuat);\n                this._hudSurfaceLocalQuat.invert();\n                localDir.applyQuaternion(this._hudSurfaceLocalQuat);\n            }\n            if (localDir.lengthSq() > 0) {\n                localDir.normalize();\n                if (this._hudHasPrevSurfaceDir) {\n                    const dot = THREE.MathUtils.clamp(this._hudPrevSurfaceDir.dot(localDir), -1, 1);\n                    const angle = Math.acos(dot);\n                    const radius = surfacePos.length();\n                    this._hudSpeed = (angle * radius) / dt;\n                }\n                this._hudPrevSurfaceDir.copy(localDir);\n                this._hudHasPrevSurfaceDir = true;\n            } else {\n                this._hudHasPrevSurfaceDir = false;\n                this._hudSpeed = 0;\n            }\n        } else {\n            this._hudHasPrevSurfaceDir = false;\n            this._hudSpeed = 0;\n        }\n\n        if (inSurface && Number.isFinite(actualAltitudeTape) && dt > 0) {\n            if (Number.isFinite(this._hudPrevAltitude)) {\n                this._hudVSpeed = (actualAltitudeTape - this._hudPrevAltitude) / dt;\n            }\n            this._hudPrevAltitude = actualAltitudeTape;\n        } else {\n            this._hudPrevAltitude = null;\n            this._hudVSpeed = 0;\n        }\n\n        this.hudStore.setValue('nav.speed', inSurface ? this._formatSpeed(this._hudSpeed) : '--');\n        this.hudStore.setData('nav.speed', inSurface ? this._hudSpeed : null);\n        this.hudStore.setValue('terrain.vspeed', inSurface ? this._formatSpeed(this._hudVSpeed) : '--');\n        this.hudStore.setData('terrain.vspeed', inSurface ? this._hudVSpeed : null);\n\n        // Native wrists/navigation retain live data, while the invisible\n        // browser tapes do no DOM writes or forced layout during immersion.\n        if (!paintDom) return;\n\n        if (this.hud.altTicks.length && Number.isFinite(actualAltitudeTape)) {\n            const maxAlt = this.surfaceController.getSurfaceAltitudeMax?.() ?? 100000;\n            const anchorMinimumToEdge = typeof document !== 'undefined'\n                && document.body?.classList?.contains('is-mobile');\n            this._updateScaleTape(this.hud.altTicks, actualAltitudeTape, {\n                unitsPerLine: ALTITUDE_TAPE_SCALE.unitsPerLine,\n                lineSpacing: ALTITUDE_TAPE_SCALE.lineSpacingPx,\n                majorEvery: 5,\n                // Below sea level the tape continues into negative heights.\n                min: actualAltitudeTape < 0 ? -11000 : 0,\n                max: maxAlt,\n                anchorMinimumToEdge,\n                labelFormatter: (val) => this._formatMetersTick(val)\n            });\n        } else if (this.hud.altTicks.length) {\n            this._hideScaleTape(this.hud.altTicks);\n        }\n\n        if (this.hud.pitchTicks.length && Number.isFinite(pitchDeg)) {\n            this._updateScaleTape(this.hud.pitchTicks, pitchDeg, {\n                unitsPerLine: 2,\n                lineSpacing: 16,\n                majorEvery: 5,\n                min: -90,\n                max: 90,\n                labelFormatter: (val) => {\n                    const rounded = Math.round(val);\n                    if (rounded === 0) return '0';\n                    return `${rounded > 0 ? '+' : ''}${rounded}`;\n                },\n                horizon: 0\n            });\n        } else if (this.hud.pitchTicks.length) {\n            this._hideScaleTape(this.hud.pitchTicks);\n        }\n\n        if (this.hud.compassTicks.length && Number.isFinite(headingDeg)) {\n            this._updateCompassTape(this.hud.compassTicks, headingDeg, {\n                unitsPerLine: 5,\n                lineSpacing: 14,\n                majorEvery: 3\n            });\n        } else if (this.hud.compassTicks.length) {\n            this._hideCompassTape(this.hud.compassTicks);\n        }\n\n        if (this.hud.fovTicks.length && showFov) {\n            this._updateLinearTape(this.hud.fovTicks, fovDeg, {\n                unitsPerLine: 5,\n                lineSpacing: 12,\n                majorEvery: 2,\n                min: 10,\n                max: 170,\n                labelFormatter: (val) => `${Math.round(val)}`\n            });\n        } else if (this.hud.fovTicks.length) {\n            this._hideLinearTape(this.hud.fovTicks);\n        }\n    }\n\n    _hideScaleTape(ticks) {\n        ticks.forEach(({ line, label }) => {\n            line.style.opacity = 0;\n            if (label) label.textContent = '';\n        });\n    }\n\n    _hideCompassTape(ticks) {\n        ticks.forEach(({ line, label }) => {\n            line.style.opacity = 0;\n            if (label) label.textContent = '';\n        });\n    }\n\n    _hideLinearTape(ticks) {\n        ticks.forEach(({ line, label }) => {\n            line.style.opacity = 0;\n            if (label) label.textContent = '';\n        });\n    }\n\n    _updateScaleTape(ticks, value, config) {\n        const {\n            unitsPerLine,\n            lineSpacing,\n            majorEvery,\n            min,\n            max,\n            labelFormatter,\n            horizon,\n            anchorMinimumToEdge = false\n        } = config;\n\n        const base = value / unitsPerLine;\n        const baseIndex = Math.floor(base);\n        const center = Math.floor(ticks.length / 2);\n        let edgeShift = 0;\n        let edgeIndexShift = 0;\n        if (anchorMinimumToEdge && Number.isFinite(min)) {\n            const configuredHalfHeight = center * lineSpacing;\n            const windowHeight = ticks[0]?.line?.parentElement?.parentElement?.clientHeight;\n            const visibleHalfHeight = Number.isFinite(windowHeight) && windowHeight > 0\n                ? Math.max(0, (windowHeight * 0.5) - (lineSpacing * 0.5))\n                : configuredHalfHeight;\n            const edgeSpanPx = Math.min(configuredHalfHeight, visibleHalfHeight);\n            const distanceFromMinimum = Math.max(0, value - min);\n            // Edge anchoring is a contact-state affordance, not a low-altitude\n            // range. Release it as soon as the measured altitude leaves the\n            // ground-contact tolerance; otherwise zero remains visually flush\n            // with the bottom for kilometres of the configured tape span.\n            const groundContactTolerance = 0.05;\n            const edgeBlend = distanceFromMinimum <= groundContactTolerance\n                ? 1\n                : 0;\n            edgeShift = edgeSpanPx * edgeBlend;\n            // Reuse the lines that would represent invalid values below the\n            // minimum to fill the upper half revealed by the edge anchor.\n            edgeIndexShift = Math.max(0, Math.floor(\n                (edgeShift / lineSpacing) + 1e-6\n            ));\n        }\n\n        for (let i = 0; i < ticks.length; i++) {\n            const offsetIndex = i - center;\n            const lineIndex = baseIndex + offsetIndex + edgeIndexShift;\n            const lineValue = lineIndex * unitsPerLine;\n            const y = ((base - lineIndex) * lineSpacing) + edgeShift;\n            const { line, label } = ticks[i];\n\n            if (lineValue < min || lineValue > max) {\n                line.style.opacity = 0;\n                if (label) label.textContent = '';\n                continue;\n            }\n\n            line.style.opacity = 0.5;\n            line.style.transform = `translateY(${y.toFixed(2)}px)`;\n\n            const mod = ((lineIndex % majorEvery) + majorEvery) % majorEvery;\n            const isMajor = mod === 0;\n            const isHorizon = Number.isFinite(horizon) && Math.abs(lineValue - horizon) < 0.001;\n\n            line.classList.toggle('major', isMajor);\n            line.classList.toggle('minor', !isMajor);\n            line.classList.toggle('horizon', isHorizon);\n\n            if (label) {\n                if (isMajor || isHorizon) {\n                    label.textContent = labelFormatter ? labelFormatter(lineValue) : `${lineValue}`;\n                } else {\n                    label.textContent = '';\n                }\n            }\n        }\n    }\n\n    updateLodOverlay(now) {\n        const overlay = document.getElementById('lod-metrics-overlay');\n        if (!overlay || !this.triTree) return;\n        if (overlay._lastUpdate && now - overlay._lastUpdate < 500) {\n            return;\n        }\n        overlay._lastUpdate = now;\n\n        const tri = this.triTree;\n        const inSurface = this.surfaceController?.isInSurfaceMode?.();\n        const nearKm = Number.isFinite(tri.surfaceRingNearMeters) ? (tri.surfaceRingNearMeters / 1000) : null;\n        const midKm = Number.isFinite(tri.surfaceRingMidMeters) ? (tri.surfaceRingMidMeters / 1000) : null;\n\n        const ringMetersEl = document.getElementById('lod-ring-meters');\n        if (ringMetersEl) {\n            if (nearKm !== null && midKm !== null) ringMetersEl.textContent = `≤${nearKm.toFixed(1)} / ≤${midKm.toFixed(1)} km`;\n            else ringMetersEl.textContent = 'n/a';\n        }\n\n        const ringCapsEl = document.getElementById('lod-ring-caps');\n        if (ringCapsEl) ringCapsEl.textContent = `N${tri.surfaceCurrentMaxLODNear ?? 'n/a'} | M${tri.surfaceCurrentMaxLODMid ?? 'n/a'} | F${tri.surfaceCurrentMaxLODFar ?? 'n/a'}`;\n\n        const imgCapsEl = document.getElementById('lod-ring-img');\n        if (imgCapsEl && tri.surfaceRingImageryCaps) {\n            imgCapsEl.textContent = `N${tri.surfaceRingImageryCaps.near ?? 'n/a'} | M${tri.surfaceRingImageryCaps.mid ?? 'n/a'} | F${tri.surfaceRingImageryCaps.far ?? 'n/a'}`;\n        } else if (imgCapsEl) {\n            imgCapsEl.textContent = 'n/a';\n        }\n\n        const stageEl = document.getElementById('lod-stage-progress');\n        if (stageEl) {\n            const pctRaw = tri.surfaceStageProgress;\n            const pct = Number.isFinite(pctRaw) ? Math.max(0, Math.min(100, Math.round(pctRaw * 100))) : null;\n            const lvl = tri.surfaceStageProgressLevel ?? '--';\n            stageEl.textContent = Number.isFinite(pct) ? `L${lvl} ${pct}%` : 'n/a';\n        }\n\n        // Determine “underfoot” tile (surface pos if available, otherwise camera focus)\n        const surfacePos = this.surfaceController?.getSurfacePosition?.();\n        let targetDir = null;\n        if (surfacePos) {\n            targetDir = this._lodTargetDirection.copy(surfacePos).normalize();\n        } else {\n            const viewDir = this._lodTargetDirection;\n            this.camera.getWorldDirection(viewDir);\n            const cameraPos = this._getCameraWorldPosition();\n            const planetGroup = this.triTree?.group || null;\n            const hit = rayEllipsoidIntersection(cameraPos, viewDir, planetGroup) ||\n                raySphereIntersection(cameraPos, viewDir);\n            if (hit) targetDir = hit.normalize();\n        }\n\n        const camPos = this._getCameraWorldPosition();\n        let underTile = null;\n        if (targetDir && tri.findLeafTileForWorldDir) {\n            underTile = tri.findLeafTileForWorldDir(targetDir);\n            this.ensureUnderfootImagery(underTile);\n        }\n\n        if (underTile) {\n            const underRingEl = document.getElementById('lod-under-imagery');\n            const zoom = underTile.imageryAtlasZoom ?? underTile.imageryInheritedZoom ?? '--';\n            const status = underTile.imageryReady ? '✓' : (underTile.imageryPendingKey ? '…' : '!');\n            const cap = underTile.surfaceLodCap ?? underTile.level;\n            if (underRingEl) underRingEl.textContent = `z${zoom} (${status}) cap ${cap}`;\n\n            const elevEl = document.getElementById('lod-under-elev');\n            const elevRatio = typeof underTile.getElevationReadyRatio === 'function'\n                ? underTile.getElevationReadyRatio()\n                : null;\n            const elevPct = Number.isFinite(elevRatio) ? Math.round(Math.max(0, Math.min(100, elevRatio * 100))) : null;\n            if (elevEl) elevEl.textContent = elevPct !== null ? `${elevPct}%` : 'n/a';\n        } else {\n            const underRingEl = document.getElementById('lod-under-imagery');\n            const elevEl = document.getElementById('lod-under-elev');\n            if (underRingEl) underRingEl.textContent = 'n/a';\n            if (elevEl) elevEl.textContent = 'n/a';\n        }\n\n        const elevNearEl = document.getElementById('lod-elev-near');\n        const elevMidEl = document.getElementById('lod-elev-mid');\n        const elevFarEl = document.getElementById('lod-elev-far');\n        if (tri.visibleLeafTiles && tri.visibleLeafTiles.length && camPos) {\n            const stats = [\n                { sum: 0, count: 0 },\n                { sum: 0, count: 0 },\n                { sum: 0, count: 0 }\n            ];\n            const worldQuat = tri._getWorldQuaternion ? tri._getWorldQuaternion() : null;\n            for (const tile of tri.visibleLeafTiles) {\n                const dir = tile.centerDir.clone();\n                if (worldQuat) dir.applyQuaternion(worldQuat);\n                const tileCenter = dir.multiplyScalar(tri.radius);\n                const dist = camPos.distanceTo(tileCenter);\n                const ring = tri._surfaceRingIndex ? tri._surfaceRingIndex(camPos, dir) : 2;\n                const ratio = typeof tile.getElevationReadyRatio === 'function'\n                    ? tile.getElevationReadyRatio()\n                    : 1;\n                stats[ring].sum += ratio;\n                stats[ring].count += 1;\n            }\n            const fmt = (s) => {\n                if (!s.count) return '0%(0)';\n                const pct = Math.round(Math.max(0, Math.min(100, (s.sum / s.count) * 100)));\n                return `${pct}%(${s.count})`;\n            };\n            if (elevNearEl) elevNearEl.textContent = fmt(stats[0]);\n            if (elevMidEl) elevMidEl.textContent = fmt(stats[1]);\n            if (elevFarEl) elevFarEl.textContent = fmt(stats[2]);\n        } else {\n            if (elevNearEl) elevNearEl.textContent = '0%(0)';\n            if (elevMidEl) elevMidEl.textContent = '0%(0)';\n            if (elevFarEl) elevFarEl.textContent = '0%(0)';\n        }\n    }\n\n    ensureUnderfootImagery(tile) {\n        if (!tile || tile.imageryReady || tile.imageryPendingKey) return;\n        const tri = this.triTree;\n        const mgr = tri?.imageryManager;\n        if (!tri || !mgr || typeof tri._imageryZoomForTile !== 'function' || typeof tri._buildImageryConfigForTile !== 'function') return;\n        const targetZoom = tri._imageryZoomForTile(tile, this.camera);\n        const z = typeof tri._resolveImageryRequestZoom === 'function'\n            ? tri._resolveImageryRequestZoom(tile, targetZoom, tile._imageryVisibleRing ?? 0)\n            : targetZoom;\n        const baseCfg = typeof mgr.getConfig === 'function' ? mgr.getConfig() : {};\n        const cfg = tri._buildImageryConfigForTile(tile, baseCfg, z);\n        if (!cfg) return;\n        cfg.requestPriority = 2_000_000;\n        cfg.requestContextKey = tri._imageryContextKey;\n        cfg.requestRing = 0;\n        tile.ensureImagery(mgr, cfg, tri.group);\n    }\n\n    _updateCompassTape(ticks, heading, config) {\n        const { unitsPerLine, lineSpacing, majorEvery } = config;\n        const base = heading / unitsPerLine;\n        const baseIndex = Math.floor(base);\n        const frac = base - baseIndex;\n        const center = Math.floor(ticks.length / 2);\n\n        for (let i = 0; i < ticks.length; i++) {\n            const offsetIndex = i - center;\n            const lineIndex = baseIndex + offsetIndex;\n            const lineValue = lineIndex * unitsPerLine;\n            const wrapped = ((lineValue % 360) + 360) % 360;\n            const x = (offsetIndex - frac) * lineSpacing;\n            const { line, label } = ticks[i];\n\n            line.style.opacity = 0.5;\n            line.style.setProperty('--x', `${x.toFixed(2)}px`);\n\n            const mod = ((lineIndex % majorEvery) + majorEvery) % majorEvery;\n            const isMajor = mod === 0;\n            const isCardinal = Math.abs(wrapped % 90) < 0.001;\n\n            line.classList.toggle('major', isMajor);\n            line.classList.toggle('minor', !isMajor);\n            line.classList.toggle('cardinal', isCardinal);\n\n            if (label) {\n                if (isCardinal) {\n                    label.textContent = this._headingToCardinal(wrapped);\n                } else if (isMajor) {\n                    label.textContent = `${Math.round(wrapped)}`;\n                } else {\n                    label.textContent = '';\n                }\n            }\n        }\n    }\n\n    _updateLinearTape(ticks, value, config) {\n        const {\n            unitsPerLine,\n            lineSpacing,\n            majorEvery,\n            min,\n            max,\n            labelFormatter\n        } = config;\n\n        const base = value / unitsPerLine;\n        const baseIndex = Math.floor(base);\n        const frac = base - baseIndex;\n        const center = Math.floor(ticks.length / 2);\n\n        for (let i = 0; i < ticks.length; i++) {\n            const offsetIndex = i - center;\n            const lineIndex = baseIndex + offsetIndex;\n            const lineValue = lineIndex * unitsPerLine;\n            const x = (offsetIndex - frac) * lineSpacing;\n            const { line, label } = ticks[i];\n\n            if (lineValue < min || lineValue > max) {\n                line.style.opacity = 0;\n                if (label) label.textContent = '';\n                continue;\n            }\n\n            line.style.opacity = 1;\n            line.style.setProperty('--x', `${x.toFixed(2)}px`);\n\n            const mod = ((lineIndex % majorEvery) + majorEvery) % majorEvery;\n            const isMajor = mod === 0;\n\n            line.classList.toggle('major', isMajor);\n            line.classList.toggle('minor', !isMajor);\n\n            if (label) {\n                if (isMajor) {\n                    label.textContent = labelFormatter ? labelFormatter(lineValue) : `${lineValue}`;\n                } else {\n                    label.textContent = '';\n                }\n            }\n        }\n    }\n}\n","import * as THREE from 'three';\n\n/**\n * Persistent tracking of visible tiles for stable imagery loading.\n *\n * Problem this solves:\n * - Old system recalculated visible tiles every frame from tree walk\n * - Tree mutations (split/merge) caused tiles to appear/disappear\n * - Imagery requests got orphaned when tiles split\n * - Camera movement blocked all imagery loading\n *\n * Solution:\n * - Maintain persistent visibility state per tile\n * - Track tiles across frames using tile keys\n * - Provide stable priority-sorted list for imagery loading\n * - Decouple visibility from tree mutations\n */\nexport class TileVisibilityTracker {\n    constructor() {\n        // Map: tileKey -> tile state\n        // Using tile keys (e.g., \"face_0_level_5_index_123\") for persistence\n        this._tileStates = new Map();\n\n        // Arrays rebuilt each frame from marked tiles\n        this._visibleLeafTiles = [];\n        this._imageryNeeded = [];\n\n        // Frame stamp for change detection\n        this._frameStamp = 0;\n        this._tilesMarkedThisFrame = new Set();\n\n        // Camera state\n        this._cameraPos = new THREE.Vector3();\n        this._focusDir = new THREE.Vector3();\n    }\n\n    /**\n     * Start a new frame - prepare for visibility marking\n     */\n    beginFrame(camera, focusDir = null) {\n        this._frameStamp++;\n        this._tilesMarkedThisFrame.clear();\n\n        camera.getWorldPosition(this._cameraPos);\n\n        if (focusDir) {\n            this._focusDir.copy(focusDir).normalize();\n        } else {\n            camera.getWorldDirection(this._focusDir);\n        }\n    }\n\n    /**\n     * Mark a tile as visible this frame\n     */\n    markVisible(tile, metadata = {}) {\n        const key = this._getTileKey(tile);\n        this._tilesMarkedThisFrame.add(key);\n\n        let state = this._tileStates.get(key);\n\n        if (!state) {\n            // New tile - create state\n            state = {\n                tile,\n                key,\n                firstSeenFrame: this._frameStamp,\n                lastSeenFrame: this._frameStamp,\n\n                // Tile properties\n                level: tile.level || 0,\n                isLeaf: !tile.children || tile.children.length === 0,\n                hasChildren: !!tile.children && tile.children.length > 0,\n                hasMesh: !!tile.mesh,\n                meshVisible: tile.mesh?.visible || false,\n\n                // Visibility metrics\n                screenPixels: 0,\n                distanceToCamera: 0,\n                angleToFocus: 0,\n                inFrustum: true,\n\n                // Imagery state\n                hasImagery: this._checkTileHasImagery(tile),\n                currentImageryZoom: null,\n                targetImageryZoom: null,\n                imageryPending: !!tile.imageryPendingKey,\n                imageryPendingSince: tile.imageryPendingSince || null,\n                imageryNeedsLoad: false,\n\n                // Priority for loading\n                imageryPriority: 0,\n                underfoot: false,\n                focus: false,\n                viewWeight: 0\n            };\n\n            this._tileStates.set(key, state);\n        }\n\n        // Update state with current frame data\n        state.lastSeenFrame = this._frameStamp;\n        state.isLeaf = !tile.children || tile.children.length === 0;\n        state.hasChildren = !!tile.children && tile.children.length > 0;\n        state.hasMesh = !!tile.mesh;\n        state.meshVisible = tile.mesh?.visible || false;\n\n        // Update metrics from metadata\n        if (metadata.screenPixels !== undefined) state.screenPixels = metadata.screenPixels;\n        if (metadata.distanceToCamera !== undefined) state.distanceToCamera = metadata.distanceToCamera;\n        if (metadata.angleToFocus !== undefined) state.angleToFocus = metadata.angleToFocus;\n        if (metadata.inFrustum !== undefined) state.inFrustum = metadata.inFrustum;\n        if (metadata.underfoot !== undefined) state.underfoot = !!metadata.underfoot;\n        if (metadata.focus !== undefined) state.focus = !!metadata.focus;\n        if (metadata.viewWeight !== undefined && Number.isFinite(metadata.viewWeight)) {\n            state.viewWeight = THREE.MathUtils.clamp(metadata.viewWeight, 0, 1);\n        }\n\n        // Update imagery state\n        state.hasImagery = this._checkTileHasImagery(tile);\n        state.imageryPending = !!tile.imageryPendingKey;\n        state.imageryPendingSince = tile.imageryPendingSince || null;\n\n        if (metadata.targetImageryZoom !== undefined) {\n            state.targetImageryZoom = metadata.targetImageryZoom;\n        }\n\n        // Determine if this tile needs imagery\n        state.imageryNeedsLoad = this._shouldLoadImagery(state, tile);\n\n        // Calculate priority\n        if (state.imageryNeedsLoad) {\n            state.imageryPriority = this._calculatePriority(state);\n        }\n    }\n\n    /**\n     * End frame - rebuild visible tile lists and prune stale entries\n     */\n    endFrame() {\n        // Rebuild visible leaf tiles list\n        this._visibleLeafTiles = [];\n        this._imageryNeeded = [];\n\n        for (const [key, state] of this._tileStates) {\n            // Remove tiles not seen in last 5 frames (allow brief occlusion)\n            if (this._frameStamp - state.lastSeenFrame > 5) {\n                this._tileStates.delete(key);\n                continue;\n            }\n\n            // Only track tiles seen this frame\n            if (state.lastSeenFrame !== this._frameStamp) {\n                continue;\n            }\n\n            // Collect visible leaf tiles\n            if (state.isLeaf && state.meshVisible) {\n                this._visibleLeafTiles.push(state);\n            }\n\n            // Collect tiles needing imagery\n            if (state.imageryNeedsLoad) {\n                this._imageryNeeded.push(state);\n            }\n        }\n\n        // Sort imagery needed by priority (high to low)\n        this._imageryNeeded.sort((a, b) => b.imageryPriority - a.imageryPriority);\n    }\n\n    /**\n     * Get visible leaf tiles (tiles that are rendered)\n     */\n    getVisibleLeafTiles() {\n        return this._visibleLeafTiles;\n    }\n\n    /**\n     * Get tiles that need imagery, sorted by priority\n     */\n    getTilesNeedingImagery(maxCount = Infinity) {\n        if (maxCount < Infinity) {\n            return this._imageryNeeded.slice(0, maxCount);\n        }\n        return this._imageryNeeded;\n    }\n\n    /**\n     * Generate a unique key for a tile\n     */\n    _getTileKey(tile) {\n        if (tile && typeof tile.getTileId === 'function') {\n            return tile.getTileId();\n        }\n\n        // Use tile's unique path through the tree\n        // Format: \"face_level_childPath\"\n        const face = tile.rootIndex ?? tile.faceIndex ?? 0;\n        const level = tile.level || 0;\n\n        // Build child path (e.g., \"0_1_2\" for child 0 -> child 1 -> child 2)\n        let childPath = '';\n        if (tile.childIndex !== undefined && tile.childIndex !== null) {\n            childPath = String(tile.childIndex);\n        }\n\n        // Fallback: use tile object itself if no better key available\n        // This won't survive tile recreation but is better than nothing\n        if (!tile._uniqueKey) {\n            tile._uniqueKey = `f${face}_l${level}_p${childPath}_id${Math.random().toString(36).slice(2, 11)}`;\n        }\n\n        return tile._uniqueKey;\n    }\n\n    /**\n     * Check if tile has imagery loaded\n     */\n    _checkTileHasImagery(tile) {\n        if (!tile) return false;\n        if (tile.imageryReady || tile.imageryInherited) return true;\n        if (tile.imageryPendingKey) return false;\n        if (!tile.mesh || !tile.mesh.material) return false;\n        const map = tile.mesh.material.map;\n        if (!map || !map.image) return false;\n        // Check if it's the default/placeholder texture\n        if (map.image.width === 1 && map.image.height === 1) return false;\n        // Legacy fallback path: only treat map as imagery if tile has atlas/imagery metadata.\n        return !!(\n            tile.imageryTexture ||\n            tile.imageryAtlasKey ||\n            Number.isFinite(tile.imageryAtlasZoom) ||\n            Number.isFinite(tile.imageryZoom)\n        );\n    }\n\n    _nowMs() {\n        if (typeof performance !== 'undefined' && typeof performance.now === 'function') {\n            return performance.now();\n        }\n        return Date.now();\n    }\n\n    /**\n     * Determine if tile should load imagery\n     */\n    _shouldLoadImagery(state, tile) {\n        // Only leaf tiles with meshes need imagery\n        if (!state.isLeaf || !state.hasMesh) return false;\n\n        // Must be visible\n        if (!state.meshVisible) return false;\n\n        // Check if needs imagery or needs upgrade to higher zoom\n        if (state.hasImagery) {\n            // Has imagery - check if needs upgrade\n            const currentZoom = tile.imageryTargetZoom;\n            const targetZoom = state.targetImageryZoom;\n            // Only upgrade, never downgrade (prevents flapping)\n            const needsUpgrade = Number.isFinite(targetZoom) &&\n                                 Number.isFinite(currentZoom) &&\n                                 currentZoom < targetZoom;\n            if (!needsUpgrade) return false;\n        }\n\n        // Already pending (don't re-request unless stalled)\n        if (state.imageryPending) {\n            const now = this._nowMs();\n            const pendingMs = state.imageryPendingSince\n                ? (now - state.imageryPendingSince)\n                : 0;\n            if (pendingMs < 1200) return false; // Short wait before retrying stalled requests\n        }\n\n        return true;\n    }\n\n    /**\n     * Calculate loading priority for a tile\n     * Priority model: nearest highest-LOD tiles first, then expand outward to horizon\n     */\n    _calculatePriority(state) {\n        let priority = 0;\n\n        // PRIMARY: Distance to camera — closest tiles first (DOMINANT factor).\n        // Use 1/distance so near tiles crush far ones in the queue.\n        // At 1m: +100000, 10m: +10000, 100m: +1000, 1km: +100, 10km: +10\n        const distance = Math.max(1, state.distanceToCamera || 1);\n        const distancePriority = Math.min(100000, 100000 / distance);\n        priority += distancePriority;\n\n        // SECONDARY: Angle to focus (center of view first)\n        const angleDeg = (state.angleToFocus || 0) * (180 / Math.PI);\n        priority -= angleDeg * 40;\n\n        // TERTIARY: Screen size (bigger tiles get slight boost)\n        priority += Math.min(500, (state.screenPixels || 0) * 0.5);\n\n        // Level bias (higher LOD preferred — these are the detail tiles we care about)\n        priority += (state.level || 0) * 100;\n\n        // Pending penalty — shorter, just enough to let fresh requests through\n        if (state.imageryPending) {\n            const now = this._nowMs();\n            const pendingMs = state.imageryPendingSince\n                ? (now - state.imageryPendingSince)\n                : 0;\n            if (pendingMs < 1000) {\n                priority -= 300;\n            }\n        }\n\n        // Underfoot boost: absolute top priority\n        if (state.underfoot) {\n            priority += 200_000;\n        }\n        if (state.focus) {\n            priority += 100_000;\n        }\n        priority += (state.viewWeight || 0) * 80_000;\n\n        return priority;\n    }\n\n    /**\n     * Clear all tracked state\n     */\n    clear() {\n        this._tileStates.clear();\n        this._visibleLeafTiles = [];\n        this._imageryNeeded = [];\n        this._tilesMarkedThisFrame.clear();\n    }\n\n    /**\n     * Get statistics\n     */\n    getStats() {\n        return {\n            frameStamp: this._frameStamp,\n            totalTracked: this._tileStates.size,\n            visibleLeafCount: this._visibleLeafTiles.length,\n            imageryNeededCount: this._imageryNeeded.length,\n            markedThisFrame: this._tilesMarkedThisFrame.size\n        };\n    }\n}\n","/* eslint-disable no-shadow */\n/**\n * Photogrammetry utilities - single image canopy/shadow inference\n * Ported from earth/js_copy_files_used_to_refactor/photogram.html\n */\n\nconst clamp01 = (x) => Math.max(0, Math.min(1, x));\nconst lerp = (a, b, t) => a + (b - a) * t;\nconst DEG2RAD = Math.PI / 180;\n\nfunction minMax(arr) {\n  let mn = Infinity;\n  let mx = -Infinity;\n  for (let i = 0; i < arr.length; i += 1) {\n    const v = arr[i];\n    if (v < mn) mn = v;\n    if (v > mx) mx = v;\n  }\n  if (!Number.isFinite(mn)) mn = 0;\n  if (!Number.isFinite(mx)) mx = 1;\n  return { min: mn, max: mx };\n}\n\nfunction buildSAT(src, w, h) {\n  const sat = new Float32Array((w + 1) * (h + 1));\n  for (let y = 1; y <= h; y += 1) {\n    let row = 0;\n    const yOff = y * (w + 1);\n    const yPrev = (y - 1) * (w + 1);\n    const srcOff = (y - 1) * w;\n    for (let x = 1; x <= w; x += 1) {\n      row += src[srcOff + (x - 1)];\n      sat[yOff + x] = sat[yPrev + x] + row;\n    }\n  }\n  return sat;\n}\n\nfunction boxBlurFromSAT(sat, w, h, r, out) {\n  const W = w + 1;\n  for (let y = 0; y < h; y += 1) {\n    const y0 = Math.max(0, y - r);\n    const y1 = Math.min(h - 1, y + r);\n    const sy0 = y0;\n    const sy1 = y1 + 1;\n    for (let x = 0; x < w; x += 1) {\n      const x0 = Math.max(0, x - r);\n      const x1 = Math.min(w - 1, x + r);\n      const sx0 = x0;\n      const sx1 = x1 + 1;\n      const A = sat[sy0 * W + sx0];\n      const B = sat[sy0 * W + sx1];\n      const C = sat[sy1 * W + sx0];\n      const D = sat[sy1 * W + sx1];\n      out[y * w + x] = (D - B - C + A) / ((x1 - x0 + 1) * (y1 - y0 + 1));\n    }\n  }\n}\n\nfunction normalize01(arr) {\n  let mn = Infinity;\n  let mx = -Infinity;\n  for (let i = 0; i < arr.length; i += 1) {\n    const v = arr[i];\n    if (v < mn) mn = v;\n    if (v > mx) mx = v;\n  }\n  const d = (mx - mn) || 1;\n  for (let i = 0; i < arr.length; i += 1) {\n    arr[i] = (arr[i] - mn) / d;\n  }\n}\n\nfunction sobelGXGY(src, w, h, gxOut, gyOut, magOut = null) {\n  for (let y = 1; y < h - 1; y += 1) {\n    const y0 = (y - 1) * w;\n    const y1 = y * w;\n    const y2 = (y + 1) * w;\n    for (let x = 1; x < w - 1; x += 1) {\n      const i = y1 + x;\n      const a00 = src[y0 + x - 1];\n      const a01 = src[y0 + x];\n      const a02 = src[y0 + x + 1];\n      const a10 = src[y1 + x - 1];\n      const a12 = src[y1 + x + 1];\n      const a20 = src[y2 + x - 1];\n      const a21 = src[y2 + x];\n      const a22 = src[y2 + x + 1];\n      const gx = (-a00 + a02) + (-2 * a10 + 2 * a12) + (-a20 + a22);\n      const gy = (-a00 - 2 * a01 - a02) + (a20 + 2 * a21 + a22);\n      gxOut[i] = gx;\n      gyOut[i] = gy;\n      if (magOut) magOut[i] = Math.abs(gx) + Math.abs(gy);\n    }\n  }\n  for (let x = 0; x < w; x += 1) {\n    gxOut[x] = gxOut[w + x];\n    gyOut[x] = gyOut[w + x];\n    gxOut[(h - 1) * w + x] = gxOut[(h - 2) * w + x];\n    gyOut[(h - 1) * w + x] = gyOut[(h - 2) * w + x];\n    if (magOut) {\n      magOut[x] = magOut[w + x];\n      magOut[(h - 1) * w + x] = magOut[(h - 2) * w + x];\n    }\n  }\n  for (let y = 0; y < h; y += 1) {\n    gxOut[y * w] = gxOut[y * w + 1];\n    gyOut[y * w] = gyOut[y * w + 1];\n    gxOut[y * w + w - 1] = gxOut[y * w + w - 2];\n    gyOut[y * w + w - 1] = gyOut[y * w + w - 2];\n    if (magOut) {\n      magOut[y * w] = magOut[y * w + 1];\n      magOut[y * w + w - 1] = magOut[y * w + w - 2];\n    }\n  }\n}\n\nfunction estimateSunFromIllum(illum, w, h) {\n  const gx = new Float32Array(w * h);\n  const gy = new Float32Array(w * h);\n  const mag = new Float32Array(w * h);\n  sobelGXGY(illum, w, h, gx, gy, mag);\n  let sumX = 0;\n  let sumY = 0;\n  let sumM = 0;\n  for (let i = 0; i < mag.length; i += 1) {\n    const m = mag[i];\n    sumM += m;\n    if (m < 0.0005) continue;\n    const wgt = m * m;\n    sumX += gx[i] * wgt;\n    sumY += gy[i] * wgt;\n  }\n  const len = Math.hypot(sumX, sumY);\n  const conf = sumM > 0 ? clamp01(len / (sumM * 2.0)) : 0;\n\n  let theta = Math.atan2(sumY, sumX);\n  if (theta < 0) theta += Math.PI * 2;\n  const dx = Math.cos(theta);\n  const dy = Math.sin(theta);\n\n  let az = Math.atan2(dx, dy);\n  if (az < 0) az += Math.PI * 2;\n  return { dx, dy, azDeg: az * 180 / Math.PI, conf };\n}\n\nfunction computeFieldsAtRes(img, size, illumRadiusPx) {\n  const w = size;\n  const h = size;\n  const c = document.createElement('canvas');\n  c.width = w;\n  c.height = h;\n  const ctx = c.getContext('2d', { willReadFrequently: true });\n\n  const iw = img.width || img.videoWidth || 0;\n  const ih = img.height || img.videoHeight || 0;\n  if (!iw || !ih) {\n    return null;\n  }\n  const s = Math.min(iw, ih);\n  const sx = ((iw - s) * 0.5) | 0;\n  const sy = ((ih - s) * 0.5) | 0;\n  ctx.drawImage(img, sx, sy, s, s, 0, 0, w, h);\n\n  const id = ctx.getImageData(0, 0, w, h);\n  const d = id.data;\n\n  const logL = new Float32Array(w * h);\n  const veg = new Float32Array(w * h);\n  const eps = 1e-4;\n  for (let i = 0, p = 0; i < logL.length; i += 1, p += 4) {\n    const r = d[p] / 255;\n    const g = d[p + 1] / 255;\n    const b = d[p + 2] / 255;\n    const y = 0.2126 * r + 0.7152 * g + 0.0722 * b;\n    logL[i] = Math.log(eps + y);\n\n    const dom = Math.max(0, g - Math.max(r, b));\n    const mx = Math.max(r, g, b);\n    const mn = Math.min(r, g, b);\n    const sat = mx > 0 ? (mx - mn) / mx : 0;\n    veg[i] = clamp01(dom * 2.6 + sat * 0.2);\n  }\n\n  const satL = buildSAT(logL, w, h);\n  const illum = new Float32Array(w * h);\n  boxBlurFromSAT(satL, w, h, Math.max(1, illumRadiusPx | 0), illum);\n\n  const refl = new Float32Array(w * h);\n  for (let i = 0; i < refl.length; i += 1) refl[i] = logL[i] - illum[i];\n\n  const satR = buildSAT(refl, w, h);\n  const blurS = new Float32Array(w * h);\n  const blurB = new Float32Array(w * h);\n  const rS = Math.max(1, (w / 128) | 0);\n  const rB = Math.max(rS + 2, (w / 40) | 0);\n  boxBlurFromSAT(satR, w, h, rS, blurS);\n  boxBlurFromSAT(satR, w, h, rB, blurB);\n  const dog = new Float32Array(w * h);\n  for (let i = 0; i < dog.length; i += 1) dog[i] = blurS[i] - blurB[i];\n\n  const gx = new Float32Array(w * h);\n  const gy = new Float32Array(w * h);\n  const edge = new Float32Array(w * h);\n  sobelGXGY(refl, w, h, gx, gy, edge);\n  normalize01(edge);\n\n  const sunEst = estimateSunFromIllum(illum, w, h);\n  return { cropCanvas: c, w, h, illum, veg, dog, edge, sunEst };\n}\n\nfunction canopyFromShadows(F, params) {\n  const {\n    vegThr,\n    shThr,\n    maxLenPx,\n    canopyBlurPx,\n    sunElDeg,\n    sunDir\n  } = params;\n  const { w, h, illum, veg, sunEst } = F;\n\n  let meanIll = 0;\n  for (let i = 0; i < illum.length; i += 1) meanIll += illum[i];\n  meanIll /= illum.length;\n\n  const sh = new Float32Array(w * h);\n  const SH_SCALE = 5.0;\n  for (let i = 0; i < sh.length; i += 1) {\n    const dark = (meanIll - illum[i]) * SH_SCALE;\n    sh[i] = clamp01(dark);\n  }\n\n  const casterLen = new Float32Array(w * h);\n  const sun = sunDir || sunEst;\n  const dx = sun?.dx ?? 0;\n  const dy = sun?.dy ?? 0;\n  const maxLen = Math.max(1, maxLenPx | 0);\n  const stepInc = 1;\n\n  for (let y = 0; y < h; y += 1) {\n    for (let x = 0; x < w; x += 1) {\n      const i = y * w + x;\n      if (sh[i] < shThr) continue;\n      for (let s = stepInc; s <= maxLen; s += stepInc) {\n        const fx = x + dx * s;\n        const fy = y + dy * s;\n        const ix = fx | 0;\n        const iy = fy | 0;\n        if (ix < 0 || iy < 0 || ix >= w || iy >= h) break;\n        const j = iy * w + ix;\n        if (veg[j] >= vegThr) {\n          if (s > casterLen[j]) casterLen[j] = s;\n          break;\n        }\n      }\n    }\n  }\n\n  const elRad = Math.max(1e-3, sunElDeg * Math.PI / 180);\n  const tanEl = Math.tan(elRad);\n\n  const hRaw = new Float32Array(w * h);\n  const invMax = 1 / Math.max(1, maxLen);\n  for (let i = 0; i < hRaw.length; i += 1) {\n    const lenN = casterLen[i] * invMax;\n    const shaped = Math.pow(lenN, 0.75);\n    hRaw[i] = shaped * tanEl;\n  }\n  normalize01(hRaw);\n\n  const satH = buildSAT(hRaw, w, h);\n  const canopy = new Float32Array(w * h);\n  boxBlurFromSAT(satH, w, h, Math.max(1, canopyBlurPx | 0), canopy);\n\n  const satV = buildSAT(veg, w, h);\n  const vegD = new Float32Array(w * h);\n  boxBlurFromSAT(satV, w, h, Math.max(1, (canopyBlurPx * 0.75) | 0), vegD);\n  normalize01(vegD);\n\n  return { canopy, vegD, sh, meanIll };\n}\n\nfunction sampleBilinear(field, w, h, x, y) {\n  const cx = Math.max(0, Math.min(w - 1, x));\n  const cy = Math.max(0, Math.min(h - 1, y));\n  const x0 = cx | 0;\n  const y0 = cy | 0;\n  const x1 = Math.min(w - 1, x0 + 1);\n  const y1 = Math.min(h - 1, y0 + 1);\n  const tx = cx - x0;\n  const ty = cy - y0;\n  const a = field[y0 * w + x0];\n  const b = field[y0 * w + x1];\n  const c = field[y1 * w + x0];\n  const d = field[y1 * w + x1];\n  return lerp(lerp(a, b, tx), lerp(c, d, tx), ty);\n}\n\nfunction upsampleTo(low, wL, hL, wT, hT) {\n  const out = new Float32Array(wT * hT);\n  for (let y = 0; y < hT; y += 1) {\n    const v = y / (hT - 1);\n    const yL = v * (hL - 1);\n    for (let x = 0; x < wT; x += 1) {\n      const u = x / (wT - 1);\n      const xL = u * (wL - 1);\n      out[y * wT + x] = sampleBilinear(low, wL, hL, xL, yL);\n    }\n  }\n  return out;\n}\n\nexport function buildHeightFieldFromImage(img, options = {}) {\n  const baseRes = Math.max(64, Math.min(2048, Math.floor(options.mapResolution || 512)));\n  const levels = Math.max(1, Math.min(4, Math.floor(options.pyramidLevels || 3)));\n  const usedLevels = levels;\n  const normalizeMode = String(options.normalizeMode || 'tile').toLowerCase();\n  const sizes = [];\n  for (let i = 0; i < usedLevels; i += 1) {\n    sizes.push(Math.max(64, baseRes >> i));\n  }\n\n  const weightsByL = {\n    1: [1.00],\n    2: [0.40, 0.60],\n    3: [0.22, 0.28, 0.50],\n    4: [0.12, 0.18, 0.25, 0.45],\n  };\n  const weights = weightsByL[usedLevels];\n\n  const outH = new Float32Array(baseRes * baseRes);\n  outH.fill(0);\n\n  let fullCanvas = null;\n  let sunEstCoarse = null;\n  const autoSun = options.autoSun !== false;\n  const manualAz = Number.isFinite(options.sunAzimuthDeg)\n    ? options.sunAzimuthDeg\n    : 0;\n  const azNorm = ((manualAz % 360) + 360) % 360;\n  const manualSun = {\n    dx: Math.sin(azNorm * DEG2RAD),\n    dy: Math.cos(azNorm * DEG2RAD),\n    azDeg: azNorm,\n    conf: 1\n  };\n\n  for (let li = 0; li < usedLevels; li += 1) {\n    const size = sizes[li];\n    const scale = baseRes / size;\n    const illumR = Math.max(2, Math.round((options.illumBlurRadius || 34) / scale));\n    const F = computeFieldsAtRes(img, size, illumR);\n    if (!F) return null;\n    const sunDir = (autoSun && F.sunEst) ? F.sunEst : manualSun;\n    if (li === 0) sunEstCoarse = sunDir;\n    if (size === baseRes) fullCanvas = F.cropCanvas;\n\n    const canopyParams = {\n      vegThr: options.vegThreshold ?? 0.35,\n      shThr: options.shadowThreshold ?? 0.22,\n      maxLenPx: Math.max(6, Math.round((options.maxShadowLenPx || 72) / scale)),\n      canopyBlurPx: Math.max(1, Math.round((options.canopyBlurPx || 18) / scale)),\n      sunElDeg: options.sunElevationDeg ?? 35,\n      sunDir\n    };\n    const C = canopyFromShadows(F, canopyParams);\n\n    const w = F.w;\n    const h = F.h;\n    const height = new Float32Array(w * h);\n    const dx = sunDir.dx;\n    const dy = sunDir.dy;\n    const embossStep = 1.6;\n    const coarseBoost = (li < usedLevels - 1) ? 1.15 : 1.0;\n    const detailGain = options.detailGain ?? 1.1;\n    const shadowMicro = options.shadowMicro ?? 0.35;\n    const dirMicro = options.dirMicro ?? 0.85;\n    const canopyScale = options.canopyScale ?? 2.6;\n    const domeStrength = options.domeStrength ?? 0.55;\n\n    for (let y = 0; y < h; y += 1) {\n      for (let x = 0; x < w; x += 1) {\n        const i = y * w + x;\n        let v = (F.dog[i] * 1.35) + (F.edge[i] * 0.45);\n\n        const meanIll = C.meanIll;\n        const SH_SCALE = 5.0;\n        v += (meanIll - F.illum[i]) * SH_SCALE * shadowMicro * 0.25;\n\n        const a = sampleBilinear(F.illum, w, h, x + dx * embossStep, y + dy * embossStep);\n        const b = sampleBilinear(F.illum, w, h, x - dx * embossStep, y - dy * embossStep);\n        v += (a - b) * dirMicro * 0.45;\n\n        v *= (0.65 + detailGain * 0.65);\n\n        const canopy = C.canopy[i];\n        const dome = C.vegD[i];\n        v += (canopy * canopyScale * 1.0 * coarseBoost);\n        v += (Math.pow(dome, 1.6) * domeStrength * coarseBoost);\n\n        height[i] = v;\n      }\n    }\n\n    const extraBlur = li < usedLevels - 1 ? 1 : 0;\n    for (let pass = 0; pass < extraBlur; pass += 1) {\n      const satH = buildSAT(height, w, h);\n      const tmp = new Float32Array(w * h);\n      boxBlurFromSAT(satH, w, h, Math.max(1, (w / 150) | 0), tmp);\n      height.set(tmp);\n    }\n\n    normalize01(height);\n    for (let i = 0; i < height.length; i += 1) height[i] -= 0.5;\n\n    const up = (size === baseRes) ? height : upsampleTo(height, w, h, baseRes, baseRes);\n    const wgt = weights[li];\n    for (let i = 0; i < outH.length; i += 1) outH[i] += up[i] * wgt;\n  }\n\n  const doTileNormalize = normalizeMode === 'tile';\n  if (doTileNormalize) {\n    normalize01(outH);\n    if (options.invertHeight) {\n      for (let i = 0; i < outH.length; i += 1) outH[i] = 1 - outH[i];\n    }\n  }\n\n  const smoothPasses = Math.max(0, Math.floor(options.smoothPasses || 0));\n  for (let pass = 0; pass < smoothPasses; pass += 1) {\n    const sat = buildSAT(outH, baseRes, baseRes);\n    const tmp = new Float32Array(outH.length);\n    boxBlurFromSAT(sat, baseRes, baseRes, Math.max(1, (baseRes / 180) | 0), tmp);\n    outH.set(tmp);\n  }\n  const { min: rawMin, max: rawMax } = minMax(outH);\n  let normalized = false;\n  if (doTileNormalize) {\n    normalize01(outH);\n    normalized = true;\n  }\n\n  return {\n    cropCanvas: fullCanvas,\n    heightField: outH,\n    size: baseRes,\n    sunEst: sunEstCoarse,\n    rawMin,\n    rawMax,\n    normalized\n  };\n}\n\nexport function sampleHeightField(heightField, size, u, v) {\n  if (!heightField || !size) return 0;\n  const x = Math.max(0, Math.min(size - 1, u * (size - 1)));\n  const y = Math.max(0, Math.min(size - 1, v * (size - 1)));\n  return sampleBilinear(heightField, size, size, x, y);\n}\n","import { buildHeightFieldFromImage, sampleHeightField } from './photogrammetry.js';\n\nconst DEFAULT_CONFIG = {\n  enabled: false,\n  ring0Only: true,\n  minImageryZoom: 18,\n  mapResolution: 512,\n  pyramidLevels: 3,\n  illumBlurRadius: 34,\n  displacementScale: 1.35,\n  detailGain: 1.1,\n  shadowMicro: 0.35,\n  dirMicro: 0.85,\n  canopyScale: 2.6,\n  vegThreshold: 0.35,\n  shadowThreshold: 0.22,\n  maxShadowLenPx: 72,\n  canopyBlurPx: 18,\n  domeStrength: 0.55,\n  smoothPasses: 2,\n  invertHeight: false,\n  autoSun: true,\n  sunAzimuthDeg: 50,\n  sunElevationDeg: 35,\n  tilesPerAxis: 4,\n  subdivPerTile: 160,\n  maxSubdiv: 256,\n  normalizeMode: 'tile',\n  offsetClampMeters: 0,\n  minElevationCompletion: 0.85,\n  edgeFade: 0.08,\n  maxConcurrentJobs: 1,\n  maxJobsPerFrame: 1,\n  maxProcessingMs: 12,\n  cacheMaxTiles: 48\n};\n\nconst clampNumber = (value, fallback, { min = null, max = null } = {}) => {\n  if (!Number.isFinite(value)) return fallback;\n  let next = value;\n  if (Number.isFinite(min)) next = Math.max(min, next);\n  if (Number.isFinite(max)) next = Math.min(max, next);\n  return next;\n};\n\nconst safeInt = (value, fallback, { min = null, max = null } = {}) =>\n  Math.floor(clampNumber(value, fallback, { min, max }));\n\nconst buildConfigHash = (config) => {\n  const keys = [\n    'mapResolution',\n    'pyramidLevels',\n    'illumBlurRadius',\n    'displacementScale',\n    'detailGain',\n    'shadowMicro',\n    'dirMicro',\n    'canopyScale',\n    'vegThreshold',\n    'shadowThreshold',\n    'maxShadowLenPx',\n    'canopyBlurPx',\n    'domeStrength',\n    'smoothPasses',\n    'invertHeight',\n    'autoSun',\n    'sunAzimuthDeg',\n    'sunElevationDeg',\n    'tilesPerAxis',\n    'subdivPerTile',\n    'maxSubdiv',\n    'normalizeMode',\n    'offsetClampMeters',\n    'minElevationCompletion',\n    'edgeFade'\n  ];\n  return keys.map((key) => `${key}=${String(config[key])}`).join('|');\n};\n\nconst getTileId = (tile) => {\n  if (!tile) return '';\n  if (typeof tile.getTileId === 'function') return tile.getTileId();\n  if (typeof tile.id === 'string') return tile.id;\n  return `${tile.level || 'L'}-${tile.index || 'T'}`;\n};\n\nconst getTileUvBounds = (uvAttr) => {\n  if (!uvAttr || uvAttr.count <= 0) return null;\n  let minU = 1;\n  let maxU = 0;\n  let minV = 1;\n  let maxV = 0;\n  for (let i = 0; i < uvAttr.count; i += 1) {\n    const u = uvAttr.getX(i);\n    const v = uvAttr.getY(i);\n    if (u < minU) minU = u;\n    if (u > maxU) maxU = u;\n    if (v < minV) minV = v;\n    if (v > maxV) maxV = v;\n  }\n  return {\n    minU: Math.max(0, Math.min(1, minU)),\n    maxU: Math.max(0, Math.min(1, maxU)),\n    minV: Math.max(0, Math.min(1, minV)),\n    maxV: Math.max(0, Math.min(1, maxV)),\n    spanU: Math.max(1e-5, Math.min(1, Math.max(0, maxU - minU))),\n    spanV: Math.max(1e-5, Math.min(1, Math.max(0, maxV - minV)))\n  };\n};\n\nconst extractTileCanvas = (tile, mapResolution) => {\n  if (!tile?.imageryTexture?.image || !tile?.geometry) return null;\n  const image = tile.imageryTexture.image;\n  const width = image.width || image.videoWidth || 0;\n  const height = image.height || image.videoHeight || 0;\n  if (!width || !height) return null;\n  const uvAttr = tile.geometry.getAttribute('uv2') || tile.geometry.getAttribute('uv');\n  const bounds = getTileUvBounds(uvAttr);\n  if (!bounds) return null;\n\n  const { minU, maxU, minV, maxV } = bounds;\n  const sx = Math.max(0, Math.min(width - 1, Math.floor(minU * width)));\n  const sw = Math.max(1, Math.min(width - sx, Math.ceil((maxU - minU) * width)));\n  const sy = Math.max(0, Math.min(height - 1, Math.floor((1 - maxV) * height)));\n  const sh = Math.max(1, Math.min(height - sy, Math.ceil((maxV - minV) * height)));\n\n  const res = safeInt(mapResolution, 512, { min: 64, max: 2048 });\n  const canvas = document.createElement('canvas');\n  canvas.width = res;\n  canvas.height = res;\n  const ctx = canvas.getContext('2d', { willReadFrequently: true });\n  try {\n    ctx.drawImage(image, sx, sy, sw, sh, 0, 0, res, res);\n  } catch (error) {\n    return null;\n  }\n  return { canvas, bounds };\n};\n\nexport class PhotogrammetryManager {\n  constructor(options = {}) {\n    this._config = { ...DEFAULT_CONFIG };\n    this._configHash = buildConfigHash(this._config);\n    this._queue = [];\n    this._queuedTiles = new Set();\n    this._cache = new Map();\n    this._ringStats = new Map();\n    this._ringTiles = new Map();\n    this._imageryConfig = null;\n    this._processing = 0;\n    this._lastConfigKey = this._configHash;\n    this._debug = options.debug || false;\n  }\n\n  get config() {\n    return { ...this._config };\n  }\n\n  setImageryConfig(cfg) {\n    this._imageryConfig = cfg || null;\n  }\n\n  setConfig(next = {}) {\n    const merged = { ...DEFAULT_CONFIG, ...this._config, ...next };\n    merged.enabled = !!merged.enabled;\n    merged.ring0Only = merged.ring0Only !== false;\n    merged.mapResolution = safeInt(merged.mapResolution, DEFAULT_CONFIG.mapResolution, { min: 64, max: 2048 });\n    merged.pyramidLevels = safeInt(merged.pyramidLevels, DEFAULT_CONFIG.pyramidLevels, { min: 1, max: 4 });\n    merged.illumBlurRadius = clampNumber(merged.illumBlurRadius, DEFAULT_CONFIG.illumBlurRadius, { min: 2, max: 128 });\n    merged.displacementScale = clampNumber(merged.displacementScale, DEFAULT_CONFIG.displacementScale, { min: 0, max: 10 });\n    merged.detailGain = clampNumber(merged.detailGain, DEFAULT_CONFIG.detailGain, { min: 0, max: 5 });\n    merged.shadowMicro = clampNumber(merged.shadowMicro, DEFAULT_CONFIG.shadowMicro, { min: -2, max: 2 });\n    merged.dirMicro = clampNumber(merged.dirMicro, DEFAULT_CONFIG.dirMicro, { min: 0, max: 4 });\n    merged.canopyScale = clampNumber(merged.canopyScale, DEFAULT_CONFIG.canopyScale, { min: 0, max: 10 });\n    merged.vegThreshold = clampNumber(merged.vegThreshold, DEFAULT_CONFIG.vegThreshold, { min: 0, max: 1 });\n    merged.shadowThreshold = clampNumber(merged.shadowThreshold, DEFAULT_CONFIG.shadowThreshold, { min: 0, max: 1 });\n    merged.maxShadowLenPx = safeInt(merged.maxShadowLenPx, DEFAULT_CONFIG.maxShadowLenPx, { min: 4, max: 256 });\n    merged.canopyBlurPx = safeInt(merged.canopyBlurPx, DEFAULT_CONFIG.canopyBlurPx, { min: 1, max: 64 });\n    merged.domeStrength = clampNumber(merged.domeStrength, DEFAULT_CONFIG.domeStrength, { min: 0, max: 5 });\n    merged.smoothPasses = safeInt(merged.smoothPasses, DEFAULT_CONFIG.smoothPasses, { min: 0, max: 12 });\n    merged.invertHeight = !!merged.invertHeight;\n    merged.autoSun = merged.autoSun !== false;\n    merged.sunAzimuthDeg = clampNumber(merged.sunAzimuthDeg, DEFAULT_CONFIG.sunAzimuthDeg, { min: 0, max: 360 });\n    merged.sunElevationDeg = clampNumber(merged.sunElevationDeg, DEFAULT_CONFIG.sunElevationDeg, { min: 0, max: 90 });\n    merged.tilesPerAxis = safeInt(merged.tilesPerAxis, DEFAULT_CONFIG.tilesPerAxis, { min: 1, max: 8 });\n    merged.subdivPerTile = safeInt(merged.subdivPerTile, DEFAULT_CONFIG.subdivPerTile, { min: 8, max: 512 });\n    merged.maxSubdiv = safeInt(merged.maxSubdiv, DEFAULT_CONFIG.maxSubdiv, { min: 16, max: 512 });\n    const normalizeMode = String(merged.normalizeMode || 'tile').toLowerCase();\n    merged.normalizeMode = ['tile', 'global', 'none'].includes(normalizeMode) ? normalizeMode : 'tile';\n    merged.offsetClampMeters = Number.isFinite(merged.offsetClampMeters)\n      ? Math.max(0, merged.offsetClampMeters)\n      : 0;\n    merged.minElevationCompletion = clampNumber(\n      merged.minElevationCompletion,\n      DEFAULT_CONFIG.minElevationCompletion,\n      { min: 0, max: 1 }\n    );\n    merged.edgeFade = clampNumber(merged.edgeFade, DEFAULT_CONFIG.edgeFade, { min: 0, max: 0.5 });\n    merged.minImageryZoom = safeInt(merged.minImageryZoom, DEFAULT_CONFIG.minImageryZoom, { min: 0, max: 22 });\n    merged.maxConcurrentJobs = safeInt(merged.maxConcurrentJobs, DEFAULT_CONFIG.maxConcurrentJobs, { min: 1, max: 4 });\n    merged.maxJobsPerFrame = safeInt(merged.maxJobsPerFrame, DEFAULT_CONFIG.maxJobsPerFrame, { min: 1, max: 4 });\n    merged.maxProcessingMs = clampNumber(merged.maxProcessingMs, DEFAULT_CONFIG.maxProcessingMs, { min: 1, max: 50 });\n    merged.cacheMaxTiles = safeInt(merged.cacheMaxTiles, DEFAULT_CONFIG.cacheMaxTiles, { min: 0, max: 200 });\n\n    this._config = merged;\n    this._configHash = buildConfigHash(this._config);\n    if (this._configHash !== this._lastConfigKey) {\n      this._lastConfigKey = this._configHash;\n      this.clearCache();\n      this._ringStats.clear();\n    }\n  }\n\n  clearCache() {\n    this._cache.clear();\n    this._queue.length = 0;\n    this._queuedTiles.clear();\n    this._ringStats.clear();\n    this._ringTiles.clear();\n  }\n\n  considerTile(tile, { ring = null, reason = '' } = {}) {\n    if (!this._config.enabled) return;\n    if (!tile?.imageryReady || !tile.imageryTexture) return;\n    if (this._config.ring0Only && ring !== 0) return;\n    if (Number.isFinite(this._config.minImageryZoom)) {\n      const z = Number.isFinite(tile.imageryAtlasZoom) ? tile.imageryAtlasZoom : tile.imageryZoom;\n      if (Number.isFinite(z) && z < this._config.minImageryZoom) return;\n    }\n    const key = this._buildTileKey(tile);\n    if (tile.photogramKey === key) return;\n    if (this._queuedTiles.has(tile)) return;\n    this._queue.push({ tile, ring, reason });\n    this._queuedTiles.add(tile);\n  }\n\n  update() {\n    if (!this._config.enabled) return;\n    if (!this._queue.length) return;\n    if (this._processing >= this._config.maxConcurrentJobs) return;\n\n    const start = performance.now();\n    let jobs = 0;\n\n    while (this._queue.length && jobs < this._config.maxJobsPerFrame) {\n      const entry = this._queue.shift();\n      if (!entry) break;\n      const tile = entry.tile;\n      this._queuedTiles.delete(tile);\n      if (!tile?.imageryReady || !tile.imageryTexture) continue;\n\n      const didProcess = this._processTile(entry);\n      if (didProcess) jobs += 1;\n\n      const elapsed = performance.now() - start;\n      if (elapsed >= this._config.maxProcessingMs) break;\n    }\n  }\n\n  _getRingStats(ring) {\n    const key = Number.isFinite(ring) ? ring : 0;\n    let stats = this._ringStats.get(key);\n    if (!stats) {\n      stats = { min: Infinity, max: -Infinity, samples: 0 };\n      this._ringStats.set(key, stats);\n    }\n    return stats;\n  }\n\n  _updateRingStats(ring, minValue, maxValue) {\n    const stats = this._getRingStats(ring);\n    const prevMin = stats.min;\n    const prevMax = stats.max;\n    if (Number.isFinite(minValue) && minValue < stats.min) stats.min = minValue;\n    if (Number.isFinite(maxValue) && maxValue > stats.max) stats.max = maxValue;\n    const changed = stats.min !== prevMin || stats.max !== prevMax;\n    stats.samples += 1;\n    return { stats, changed };\n  }\n\n  _trackRingTile(ring, tile) {\n    if (!tile) return;\n    const key = Number.isFinite(ring) ? ring : 0;\n    let set = this._ringTiles.get(key);\n    if (!set) {\n      set = new Set();\n      this._ringTiles.set(key, set);\n    }\n    set.add(tile);\n  }\n\n  _requeueRingTiles(ring, skipTile) {\n    const key = Number.isFinite(ring) ? ring : 0;\n    const set = this._ringTiles.get(key);\n    if (!set || !set.size) return;\n    for (const tile of set) {\n      if (!tile || tile === skipTile) continue;\n      if (!tile.geometry || !tile.imageryReady || !tile.imageryTexture) {\n        set.delete(tile);\n        continue;\n      }\n      if (this._queuedTiles.has(tile)) continue;\n      this._queue.push({ tile, ring: key, reason: 'photogram-global-refresh' });\n      this._queuedTiles.add(tile);\n    }\n  }\n\n  _buildTileKey(tile) {\n    const imageryKey = tile?.imageryAtlasKey || '';\n    const tileId = getTileId(tile);\n    return `${tileId}|${imageryKey}|${this._configHash}`;\n  }\n\n  _computeTargetResolution() {\n    const base = Number.isFinite(this._config.subdivPerTile) ? this._config.subdivPerTile : 64;\n    const res = Number.isFinite(this._config.mapResolution) ? this._config.mapResolution : 512;\n    const scale = res / 512;\n    const tiles = Number.isFinite(this._config.tilesPerAxis) ? this._config.tilesPerAxis : DEFAULT_CONFIG.tilesPerAxis;\n    const tileScale = tiles / (DEFAULT_CONFIG.tilesPerAxis || 1);\n    const target = Math.round(base * scale * tileScale);\n    const maxRes = Number.isFinite(this._config.maxSubdiv) ? this._config.maxSubdiv : 256;\n    const minRes = Math.max(8, Math.min(base, maxRes));\n    return Math.max(minRes, Math.min(maxRes, target));\n  }\n\n  _processTile(entry) {\n    const tile = entry?.tile;\n    const ring = Number.isFinite(entry?.ring) ? entry.ring : 0;\n    const minElev = Number.isFinite(this._config.minElevationCompletion)\n      ? this._config.minElevationCompletion\n      : 0;\n    if (minElev > 0 && typeof tile?.getTileElevationCompleteness === 'function') {\n      const completeness = tile.getTileElevationCompleteness();\n      if (Number.isFinite(completeness) && completeness < minElev) {\n        return false;\n      }\n    }\n    const imageryConfig = this._imageryConfig || null;\n    const mode = this._config.normalizeMode || 'tile';\n    const invertConfig = this._config.invertHeight === true;\n    const targetRes = this._computeTargetResolution();\n    if (Number.isFinite(targetRes) && tile?.photogramResOverride !== targetRes) {\n      tile.photogramPending = true;\n      if (typeof tile.rebuildGeometryForPhotogram === 'function') {\n        tile.rebuildGeometryForPhotogram(targetRes, imageryConfig);\n      }\n      return true;\n    }\n\n    const cacheKey = this._buildTileKey(tile);\n    const cached = this._cache.get(cacheKey);\n    let heightField = cached?.heightField || null;\n    let size = cached?.size || null;\n\n    let bounds = cached?.bounds || null;\n    if (!heightField || !size) {\n      const tileCanvas = extractTileCanvas(tile, this._config.mapResolution);\n      if (!tileCanvas) return false;\n      bounds = tileCanvas.bounds || null;\n      const result = buildHeightFieldFromImage(tileCanvas.canvas, {\n        ...this._config,\n        normalizeMode: mode,\n        invertHeight: mode === 'tile' ? invertConfig : false\n      });\n      if (!result?.heightField) return false;\n      heightField = result.heightField;\n      size = result.size;\n      const rawMin = Number.isFinite(result.rawMin) ? result.rawMin : null;\n      const rawMax = Number.isFinite(result.rawMax) ? result.rawMax : null;\n      const normalized = result.normalized === true;\n      this._cache.set(cacheKey, { heightField, size, bounds, rawMin, rawMax, normalized, ts: performance.now() });\n      this._pruneCache();\n    }\n\n    const uvAttr = tile.geometry?.getAttribute('uv2') || tile.geometry?.getAttribute('uv');\n    if (!uvAttr) return false;\n\n    const count = uvAttr.count;\n    const offsets = new Float32Array(count);\n    const scale = Number.isFinite(this._config.displacementScale)\n      ? this._config.displacementScale\n      : 1;\n    const invert = mode === 'tile' ? false : invertConfig;\n    const clampMeters = Number.isFinite(this._config.offsetClampMeters) && this._config.offsetClampMeters > 0\n      ? this._config.offsetClampMeters\n      : null;\n    const cacheEntry = this._cache.get(cacheKey);\n    const rawMin = Number.isFinite(cacheEntry?.rawMin) ? cacheEntry.rawMin : null;\n    const rawMax = Number.isFinite(cacheEntry?.rawMax) ? cacheEntry.rawMax : null;\n    const normalized = cacheEntry?.normalized === true;\n    let ringStats = null;\n    let ringStatsChanged = false;\n    if (mode === 'global' && rawMin !== null && rawMax !== null) {\n      const update = this._updateRingStats(ring, rawMin, rawMax);\n      ringStats = update.stats;\n      ringStatsChanged = update.changed;\n    } else if (mode === 'global') {\n      ringStats = this._getRingStats(ring);\n    }\n    const gMin = ringStats && Number.isFinite(ringStats.min) ? ringStats.min : null;\n    const gMax = ringStats && Number.isFinite(ringStats.max) ? ringStats.max : null;\n    const edgeFade = Number.isFinite(this._config.edgeFade) ? this._config.edgeFade : 0;\n    const res = Number.isFinite(tile?.resolution) ? tile.resolution : null;\n    const expectedCount = Number.isFinite(res) ? ((res + 1) * (res + 2)) / 2 : count;\n\n    if (Number.isFinite(res) && expectedCount === count) {\n      let idx = 0;\n      const invRes = res > 0 ? 1 / res : 0;\n      for (let i = 0; i <= res; i += 1) {\n        for (let j = 0; j <= res - i; j += 1) {\n          const u = uvAttr.getX(idx);\n          const v = uvAttr.getY(idx);\n          const uLocal = bounds ? (u - bounds.minU) / bounds.spanU : u;\n          const vLocal = bounds ? (v - bounds.minV) / bounds.spanV : v;\n          const h = sampleHeightField(heightField, size, uLocal, 1 - vLocal);\n          let offset = 0;\n          if (mode === 'none') {\n            offset = h * scale;\n            if (invert) offset = -offset;\n          } else {\n            let hNorm = h;\n            if (mode === 'global' && gMin !== null && gMax !== null && gMax !== gMin) {\n              hNorm = (h - gMin) / (gMax - gMin);\n            } else if (!normalized && rawMin !== null && rawMax !== null && rawMax !== rawMin) {\n              hNorm = (h - rawMin) / (rawMax - rawMin);\n            }\n            hNorm = Math.max(0, Math.min(1, hNorm));\n            if (invert) hNorm = 1 - hNorm;\n            offset = (hNorm - 0.5) * scale;\n          }\n          if (clampMeters !== null) {\n            if (offset > clampMeters) offset = clampMeters;\n            else if (offset < -clampMeters) offset = -clampMeters;\n          }\n          let weight = 1;\n          if (edgeFade > 0 && invRes > 0) {\n            const k = res - i - j;\n            const minW = Math.min(i, j, k) * invRes;\n            weight = Math.max(0, Math.min(1, minW / edgeFade));\n          }\n          offsets[idx] = offset * weight;\n          idx += 1;\n        }\n      }\n    } else {\n      for (let i = 0; i < count; i += 1) {\n        const u = uvAttr.getX(i);\n        const v = uvAttr.getY(i);\n        const uLocal = bounds ? (u - bounds.minU) / bounds.spanU : u;\n        const vLocal = bounds ? (v - bounds.minV) / bounds.spanV : v;\n        const h = sampleHeightField(heightField, size, uLocal, 1 - vLocal);\n        let offset = 0;\n        if (mode === 'none') {\n          offset = h * scale;\n          if (invert) offset = -offset;\n        } else {\n          let hNorm = h;\n          if (mode === 'global' && gMin !== null && gMax !== null && gMax !== gMin) {\n            hNorm = (h - gMin) / (gMax - gMin);\n          } else if (!normalized && rawMin !== null && rawMax !== null && rawMax !== rawMin) {\n            hNorm = (h - rawMin) / (rawMax - rawMin);\n          }\n          hNorm = Math.max(0, Math.min(1, hNorm));\n          if (invert) hNorm = 1 - hNorm;\n          offset = (hNorm - 0.5) * scale;\n        }\n        if (clampMeters !== null) {\n          if (offset > clampMeters) offset = clampMeters;\n          else if (offset < -clampMeters) offset = -clampMeters;\n        }\n        offsets[i] = offset;\n      }\n    }\n\n    if (typeof tile.setPhotogramOffsets === 'function') {\n      tile.setPhotogramOffsets(offsets, cacheKey);\n    } else {\n      tile.photogramOffsets = offsets;\n      tile.photogramKey = cacheKey;\n    }\n\n    if (typeof tile.applyPhotogramOffsets === 'function') {\n      tile.applyPhotogramOffsets();\n    }\n    tile.photogramPending = false;\n    this._trackRingTile(ring, tile);\n    if (mode === 'global' && ringStatsChanged) {\n      this._requeueRingTiles(ring, tile);\n    }\n    return true;\n  }\n\n  _pruneCache() {\n    const maxEntries = Number.isFinite(this._config.cacheMaxTiles)\n      ? this._config.cacheMaxTiles\n      : 0;\n    if (!maxEntries || this._cache.size <= maxEntries) return;\n    const entries = Array.from(this._cache.entries());\n    entries.sort((a, b) => (a[1].ts || 0) - (b[1].ts || 0));\n    const toRemove = entries.length - maxEntries;\n    for (let i = 0; i < toRemove; i += 1) {\n      this._cache.delete(entries[i][0]);\n    }\n  }\n}\n","/**\n * Tritree manager for hierarchical LOD system on a sphere\n */\n\nimport * as THREE from 'three';\nimport { clearPooledGeometries, createIcosahedronTiles, releasePooledGeometry, registerFadeInTile } from './tri-tile.js';\nimport { PLANET_RADIUS, DEG2RAD, RAD2DEG, MAX_TILE_LEVEL, AXIAL_TILT_RAD } from './constants.js';\nimport {\n    raySphereIntersection,\n    rayEllipsoidIntersection,\n    worldPosToLatLonLocal,\n    lonLatToTileCoords,\n    dirToLatLonLocal,\n    ellipsoidRadiusForWorldDir\n} from './geometry-utils.js';\nimport { EdgeStitchTopology, CANONICAL_EDGES, getParentEdgeForChildEdge as mapChildEdgeToParent } from './edge-stitch-topology.js';\nimport { TileVisibilityTracker } from './tile-visibility-tracker.js';\nimport { PhotogrammetryManager } from './photogrammetry-manager.js';\nimport { setPlanetFrameEuler } from './celestial-frame.js';\nimport { yieldToEventLoop } from '../refactor/async/scheduler/BudgetScheduler.js';\n\nexport class TriTreeManager {\n    constructor(scene, elevationClient, imageryManager, radius = PLANET_RADIUS) {\n        this.scene = scene;\n        this.radius = radius;\n        this.elevationClient = elevationClient;\n        this.imageryManager = imageryManager;\n        this.photogramManager = new PhotogrammetryManager();\n        this._photogramConfig = null;\n        this._lastImageryConfig = null;\n\n        this.group = new THREE.Group();\n        this.group.name = 'PlanetGroup';\n        setPlanetFrameEuler(this.group.rotation);\n        // Null means no absolute daily-rotation angle has been applied yet.\n        // Do not infer this state from group.rotation.y: zero is itself a valid\n        // sidereal angle, and URL boot may position an Earth-fixed camera\n        // several seconds before the first animation frame advances the clock.\n        this._earthRotationAngle = null;\n\n        // PERSISTENT VISIBILITY TRACKING: Stable tile tracking for imagery loading\n        this.visibilityTracker = new TileVisibilityTracker();\n\n        // Physics system integration for terrain collisions\n        this.physicsSystem = null;\n        this._tileColliders = new Map(); // tile mesh -> collider info\n        this._pendingColliders = new Set(); // Tiles waiting for physics to initialize\n\n        // Apply Earth's axial tilt (23.4397° relative to orbital plane)\n        // Tilt around the vernal equinox line (+Z in our ecliptic frame).\n        // Negative tilt aligns June = summer in the northern hemisphere.\n        // Orientation is shared with CelestialEphemeris and the J2000 sky.\n\n        this.scene.add(this.group);\n\n        this.rootTiles = createIcosahedronTiles(radius, elevationClient);\n        this.edgeTopology = new EdgeStitchTopology();\n        this.edgeTopology.buildRootAdjacency(this.rootTiles);\n        this.useDeterministicNeighborDetection = true;\n\n        // Set up automatic stitching callback for all tiles\n        this._setupAutoStitchCallbacks();\n\n        // Material will be set via setMaterial() after texture loading\n        this.material = new THREE.MeshStandardMaterial({\n            color: 0x4b5563,\n            metalness: 0.0,\n            roughness: 0.95,\n            flatShading: false,\n            side: THREE.DoubleSide,\n        });\n\n        // PHASE 3: Material pooling to reduce cloning overhead\n        // Pool materials by imagery state to enable sharing\n        this.materialPool = new Map(); // Key: imagery state hash, Value: material\n        this.materialRefCounts = new Map(); // Track usage counts\n        // Imagery LOD tuning (WMTS zoom per tritree level)\n        this.imageryZoomPerLevel = 1;   // +1 WMTS z per triangle subdivision level\n        this.imageryZoomPerLevelSurface = 1.0;\n        this.imageryMinZoom = 0;\n        this.imageryMaxZoom = 22;       // Max WMTS zoom for orbit view\n        this.surfaceImageryMaxZoom = 22; // Max WMTS zoom for surface view (underfoot tiles)\n        // Independent imagery resolution boost - adds zoom levels beyond what LOD would normally request\n        // Range: 0 (no boost) to 4 (max available resolution)\n        this.imageryResolutionBoost = 4;\n        this.surfaceImageryFarAngleDeg = 35;\n        this.surfaceImageryFarMaxZoom = this.surfaceImageryMaxZoom;\n        // Atlas scheduling is more expensive than tile selection. Keep the\n        // producer bounded so it cannot outrun image decode/canvas work.\n        this.imageryBudgetPerFrame = 12;\n        this.imageryMinBudget = 3;\n        this.imageryFullCoverageMaxLevel = 5; // Low-LOD threshold to fill all visible tiles\n        this.imageryFallbackLevel = 4; // Level to retain for graceful zoom-out coverage\n        this.imageryContextZoom = 4; // Coarse zoom for imagery queue context\n        this.imageryResetCooldownMs = 1200;\n        this.imageryPendingStallMs = 1800; // Retry blank imagery requests if pending too long\n        // Coverage-first imagery: request coarse coverage rapidly, then upgrade to target zoom.\n        this.imageryCoverFirstEnabled = true;\n        this.imageryCoverBootstrapWindowMs = 4500;\n        this.imageryCoverZoomGap = 3;\n        this.imageryCoverUnderfootZoomGap = 4;\n        this.imageryCoverMinZoom = 4;\n        this.imageryCoverUnderfootMinZoom = 5;\n        this.imageryBootstrapEnabled = true;\n        this.imageryBootstrapDeltaZoom = 3; // First-pass coarse zoom reduction for blank tiles\n        this.imageryBootstrapMaxRing = 2; // Sweep center + nearby rings before high-res upgrade\n        this.imageryBootstrapBudgetMax = 24; // Allow a broad first-pass coverage sweep\n        this.imageryBootstrapMinPriority = 3000;\n        this.imageryBackpressureEnabled = true;\n        this.imageryBackpressureActivateThreshold = 0.62;\n        this.imageryBackpressureReleaseThreshold = 0.38;\n        this.imageryBackpressureTileQueueHardLimit = 384;\n        this.imageryBackpressureAtlasQueueHardLimit = 96;\n        // Quality-preserving backpressure: throttle request admission before reducing zoom/LOD quality.\n        this.imageryBackpressureDropZoomEnabled = false;\n        this.imageryBackpressureSplitBudgetMinScale = 0.45;\n        this.imageryBackpressureImageryBudgetMinScale = 0.4;\n        this.imageryBackpressureElevationScanMinScale = 0.35;\n        this.imageryBackpressureZoomDropNear = 1;\n        this.imageryBackpressureZoomDropMid = 2;\n        this.imageryBackpressureZoomDropFar = 3;\n        this.imageryBackpressureExtraDropThreshold = 0.9;\n        this.imageryBackpressureMinZoom = 10;\n        this._imageryContextDir = null;\n        this._imageryContextAlt = null;\n        this._imageryContextMode = null;\n        this._imageryContextSurface = null;\n        this._imageryContextKey = null;\n        this._imageryContextLastReset = 0;\n        this._imageryBackpressureState = {\n            active: false,\n            pressureScore: 0,\n            tileQueue: 0,\n            atlasQueue: 0,\n            tileQueueRatio: 0,\n            atlasQueueRatio: 0,\n            tileLoadRatio: 0,\n            atlasLoadRatio: 0\n        };\n\n        this.visibleTileCount = 0;\n        this.currentMaxLevel = 0;\n        this.hexPatch = null;\n        this.lodMode = 'orbit';\n        this.viewFocusDir = null;\n        this.visibleMeshes = []; // Track visible leaf meshes for surface raycasting\n        this.visibleLeafTiles = [];\n\n        // When true, all tritree tile meshes are hidden (e.g. photorealistic tiles active)\n        this.suppressTileDisplay = false;\n        // When true, update() is a no-op — all LOD/split/merge/imagery work paused.\n        // State is fully preserved for instant resume.\n        this.suspended = false;\n        this._tileListeners = new Set();\n        this._lastVisibleLeafTiles = new Set();\n        this._elevationVersionTick = 0;\n        this._tilesNeedingElevationUpdate = new Set();\n        this._tilesNeedingGeometryFinalize = new Set();\n        this._tilesToSplit = [];\n        this._tilesToMerge = [];\n        this._tilesToLoadImagery = [];\n        this._hiddenLeafTilesForElevation = [];\n        this._coarseImageryEnqueued = new Set();\n\n        // ── Retirement pool: deferred disposal for merged tiles ──\n        // Tiles go dormant on merge instead of being destroyed. If the parent\n        // re-splits within the grace period the retired children are resurrected\n        // instantly (no re-fetch of elevation/imagery).\n        this._retiredTiles = new Map();           // parent → { children, retiredAt, meshes, tileCount }\n        this._retiredTileCount = 0;\n        this._retirementGraceMs = 8000;           // 8s grace before GPU disposal\n        this._retirementMaxEntries = 200;         // Hard cap on pooled tile sets\n        // An entry-count cap alone is not a memory cap: one merged parent can\n        // retain hundreds of descendants. Bound retained descendants too.\n        this._retirementMaxTiles = 2400;\n        // Desktop may keep detached elevation records for quick re-splits.\n        // Mobile/pressure policies disable that retention.\n        this._retainElevationForRetiredTiles = true;\n        this._retirementLastSweep = 0;\n\n        // ── Global pressure metric: coordinates split/imagery/elevation budgets ──\n        this._globalPressure = 0;                 // 0-1 combined pressure score\n        this._elevationForceTiles = new Set();\n        this.elevationForceCount = 0;\n        this.elevationMissingCount = 0;\n        this._elevationRingDefaults = null;\n        this._elevationSchedulingMode = 'default';\n        this._elevationQueueAnchor = null;\n        this.elevationFetchMode = 'centric';\n        this.elevationCascadeEnabled = false;\n        this.elevationCascadeCoarseReadyRatio = 0.9;\n        this.elevationCascadeTileReadyRatio = 0.08;\n        this.elevationCascadeMinVisibleTiles = 16;\n        this.elevationCascadeCoarseMaxLevel = 8;\n        this._elevationCascadeCoarseReady = true;\n        this._elevationCascadeCoverageRatio = 1;\n        this._elevationCascadeReadyTiles = 0;\n        this._elevationCascadeTotalTiles = 0;\n        this.elevationQueueResetDistance = 200_000;\n        this.elevationQueueResetAngleDeg = 8;\n        // Treat ring 0-1 as center-priority for authoritative (non-placeholder) elevation fetch.\n        this.elevationCenterFullFetchRingLimit = 1;\n        this.elevationForceCompleteStallMs = 0;\n        // Emergency stall force-complete is disabled by default; it can mask real backend fetch state.\n        this.elevationStallForceCompleteEnabled = false;\n        this.elevationForceCompleteCount = 0;\n        this.elevationForceCompleteVertexCount = 0;\n        this._lastElevationForceCompleteLogMs = 0;\n        this._elevationForceCompleteLogIntervalMs = 2000;\n        this.elevationForceCompleteMaxPerFrame = 512;\n        this.elevationForceCompleteMaxPerTile = 64;\n        this.perf = null;\n        this.debugStats = null;\n        this._tmpDir = new THREE.Vector3();\n        this._tmpEdge0 = new THREE.Vector3();\n        this._tmpEdge1 = new THREE.Vector3();\n        this._tmpEdge2 = new THREE.Vector3();\n        this._tmpQuat = new THREE.Quaternion();\n        this._terrainRaycaster = new THREE.Raycaster();\n        this._tmpRayOrigin = new THREE.Vector3();\n        this._tmpRayDir = new THREE.Vector3();\n        this._tmpTileDir = new THREE.Vector3();\n        this._tmpTileCenter = new THREE.Vector3();\n        this._tmpCamDir = new THREE.Vector3();\n        this._tmpSurfaceRingCamDir = new THREE.Vector3();\n        this._tmpViewTileCenter = new THREE.Vector3();\n        this._tmpViewToTile = new THREE.Vector3();\n        this._sunDirectionWorld = new THREE.Vector3(0, 0, 1);\n        this._sunDirectionDirty = true;\n        this._viewportCache = null;\n        this._lastNonOverlapWarnMs = 0;\n        this._lastNonOverlapWarnKey = '';\n        this._nonOverlapHoldoffMs = 900;\n        this._lowFpsActive = false;\n        this._lowFpsBudgetBackup = null;\n        this._lastUpdateCamPos = new THREE.Vector3();\n        this._lastUpdateCamQuat = new THREE.Quaternion();\n        this._lastUpdateFocusDir = new THREE.Vector3();\n        this._lastUpdateWorldQuat = new THREE.Quaternion();\n        this._lastUpdateMode = null;\n        this._lastUpdateSurface = null;\n        this._lastFullUpdateTime = 0;\n        // LOD traversal is CPU-side scene graph work. Twenty evaluations per\n        // second is responsive at walking/flying speeds and leaves materially\n        // more time for the final render than the former 30 Hz traversal.\n        this._fullUpdateIntervalMs = 50;\n        this._lastTraverseTime = 0;\n        this._maxIdleUpdateMs = 200;\n        this.snapshotReplayInitialBudget = 48;\n        this.snapshotReplayPerFrame = 16;\n        this.snapshotReplayUseAtlasHints = false;\n        this.snapshotReplayAtlasMinCoverage = 0.9;\n        this._snapshotReplayQueue = null;\n        this._snapshotReplayStats = {\n            totalQueued: 0,\n            totalApplied: 0,\n            totalImmediateApplied: 0,\n            totalDeferredApplied: 0,\n            elevationSeededVertices: 0,\n            elevationSeededTiles: 0,\n            atlasHintTiles: 0,\n            atlasHintRejected: 0,\n            lastQueued: 0,\n            lastImmediate: 0,\n            lastFrameApplied: 0,\n            pending: 0\n        };\n        this._poseEpsMeters = this.radius * 0.0002; // ~1.3km on Earth\n        this._poseEpsRad = 0.003; // ~0.17°\n        this._focusEpsRad = 0.004; // ~0.23°\n        this._worldEpsRad = 0.0015; // ~0.086°\n        this._viewportStamp = 0;\n        this._cameraFast = false;\n        this._cameraFastUntil = 0;\n\n        this.tileBudget = 5000;  // Max tiles in scene\n        this.splitBudget = 64;   // Startup-safe subdivision budget\n        this.mergeBudget = 64;   // Startup-safe simplification budget\n        // Phase 6 (refactor/async/README.md#phase-6): time-based yield\n        // check added on top of the count budget. When > 0, split/merge\n        // loops break out of the frame once wall-clock exceeds this many\n        // ms and resume next frame. Atomic unit is one tile — we never\n        // split or merge a single tile across frames (that breaks LOD\n        // invariants). Read from window.__noclipAsync.flags.splitTimeBudgetMs\n        // at loop-start each frame so runtime flag flips take effect.\n        // Count budgets alone still allow a burst of expensive child mesh,\n        // elevation-registration, and inherited-imagery work in one frame.\n        // Keep LOD mutation cooperative by default; the runtime flag can still\n        // override this for diagnostics.\n        this.splitTimeBudgetMs = 2.0;\n        // Synchronous atlas coordinate/UV preparation happens before requests\n        // become asynchronous. Bound that CPU admission separately so imagery\n        // convergence cannot monopolize a render frame.\n        this.imageryPreparationTimeBudgetMs = 1.5;\n        this.adaptiveSplitBudgetEnabled = true;\n        this.adaptiveSplitBudgetTargetMs = 33.3;\n        this.adaptiveSplitBudgetMinScale = 0.35;\n        this.adaptiveSplitBudgetMaxScale = 1.0;\n        this.adaptiveSplitBudgetEmaAlpha = 0.2;\n        this.adaptiveSplitBudgetDropLerp = 0.35;\n        this.adaptiveSplitBudgetRiseLerp = 0.08;\n        this._adaptiveSplitFrameMsEma = null;\n        this._adaptiveSplitBudgetScale = 1.0;\n        this.tileCount = this.rootTiles.length;\n        this.renderRules = { wireframe: false };\n        this._wireframeImageryBackup = null;\n        this.maxTileLevel = MAX_TILE_LEVEL;\n        // Progressive LOD staging from 4 (horizon) to 18 (near/underfoot)\n        this.surfaceStageMinLOD = 4;       // Start at LOD 4 for horizon\n        this.surfaceStageMaxLOD = 18;      // Max LOD 18 for near tiles (supports level 22 imagery)\n        this.surfaceCurrentMaxLODNear = this.surfaceStageMinLOD;\n        this.surfaceCurrentMaxLODMid = this.surfaceStageMinLOD + 1;\n        this.surfaceCurrentMaxLODFar = this.surfaceStageMinLOD;\n        this.surfaceStageCooldownMs = 350;  // Startup-safe staging cadence\n        this.surfaceStageLastAdvance = (typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now();\n        this.surfaceCullAngleDeg = 80;\n        this.orbitCullAngleDeg = 170;\n        this.surfaceViewshedMinDeg = 0.15;\n        this.surfaceViewshedMarginDeg = 0.5;\n        this.viewshedHysteresisDeg = 3.0;  // Dead zone: tiles stay visible 3° past cull boundary\n        this.surfaceInstantStaging = true;\n        this.surfaceInstantStageRampEnabled = true;\n        this.surfaceInstantStageCooldownMs = 120;\n        this.surfaceInstantStageDownCooldownMs = 70;\n        this.surfaceInstantStageUpStep = 1;\n        this.surfaceInstantStageDownStep = 2;\n        this.surfaceInstantStageDownHysteresis = 1;\n        this.surfaceInstantStageTargetLOD = this.surfaceStageMinLOD;\n        this.surfaceStageAdvanceMaxBatches = 1;\n        this.surfaceStageFocusAngleDeg = 65;\n        // Surface work follows the camera's real screen viewshed. A modest\n        // off-screen buffer keeps camera rotation seamless without retaining\n        // the former all-directions subdivision/elevation workload.\n        this.surfaceViewCullEnabled = true;\n        this.surfaceViewBufferDeg = 12;\n        this.surfacePeripheralLodDrop = 3;\n        this.surfaceViewCenterImageryBoost = 2;\n        this.surfaceElevationRetryBudget = 128;\n        this.surfaceElevationRetryPerTile = 32;\n        this.surfaceLodNear = 15;\n        this.surfaceLodFar = 6;\n        this.surfaceLodFalloffPower = 0.8\n        this.surfaceLodFalloffStartDeg = 0.5;\n        this.surfaceStageProgress = 0;\n        this.surfaceStageExpected = 0;\n        this.surfaceStageDone = 0;\n        this.surfaceStageProgressLevel = null;\n        this.emergencyMergeThreshold = 0.92;\n        this.emergencyMergeScale = 1.25;\n        this.elevationMergeGraceMs = 2500;\n        this.maxScreenSpaceError = 16;\n        this.refineReadyRatio = 0.65;\n        this.stageReadyRatio = 0.75;\n        this.sseMergeFactor = 0.5;\n        this.activeElevationTiles = [];\n        this._inSurfaceMode = false;\n        // Force a minimum base LOD so we don't stay at level 0 when far away\n        this.minBaseLevel = 2;\n        this.orbitFalloffMarginDeg = 6;\n        this.orbitFalloffAnchorDeg = 65;\n        this.orbitLodFalloffPower = 1.0;\n        this.initialSubdivLevel = 2; // Ensure a coarse LOD2 backbone exists\n        this._rootsSubdivided = false;\n        this.basePreloadEnabled = true;\n        this.basePreloadLevel = 2;\n        this.basePreloadZoom = 4;\n        this.basePreloadMinZoom = 4;\n        this.basePreloadPerFrame = 3;\n        this.basePreloadPriority = -10;\n        this.basePreloadMaxAtlasTiles = null;\n        this.basePreloadPadTiles = null;\n        this._basePreloadQueue = [];\n        this._basePreloadInitialized = false;\n        // Imagery inheritance: parent imagery is \"cookie-cut\" onto child tiles during split\n        // so children display immediately with parent's texture while their own WMTS loads.\n        // _alignAtlasMinXToTileFrame handles wrap-frame alignment to prevent UV drift.\n        this.imageryInheritanceEnabled = true;\n        // Merge-time imagery fallback controls.\n        this.mergeMosaicMaxAtlasTiles = null;\n        this.mergeMosaicPadTiles = 0;\n        this.mergeMosaicMinZoom = 0;\n        this.mergeMosaicPriority = 1000;\n        this.mergeChildAdoptMinCoverage = 0.995;\n\n        // Surface ring configuration for distance-based falloff (meters)\n        // Desktop-tuned rings: generous high-quality radius with long tail\n        this.surfaceRingNearMeters = 14_000;   // 0-14km = near (immediate underfoot)\n        this.surfaceRingMidMeters = 38_000;   // 14-38km = mid\n        this.surfaceRingFarMeters = 100_000;  // 38-100km = far tail for log falloff\n        const ringMidLod = Math.round((this.surfaceLodNear + this.surfaceLodFar) * 0.5);\n        this.surfaceRingLodCaps = {\n            near: this.surfaceStageMaxLOD,\n            mid: Math.max(this.surfaceStageMinLOD, ringMidLod),\n            far: Math.max(this.surfaceStageMinLOD, this.surfaceLodFar)\n        };\n        this.surfaceRingImageryCaps = {\n            near: this.surfaceImageryMaxZoom || this.imageryMaxZoom,\n            mid: this.surfaceImageryMaxZoom || this.imageryMaxZoom,\n            far: this.surfaceImageryMaxZoom || this.imageryMaxZoom\n        };\n        // Quality lock: no staged low-res ring start caps.\n        this.surfaceRingImageryStartCaps = {\n            near: this.surfaceImageryMaxZoom || this.imageryMaxZoom,\n            mid: this.surfaceImageryMaxZoom || this.imageryMaxZoom,\n            far: this.surfaceImageryMaxZoom || this.imageryMaxZoom\n        };\n        this.surfaceRingImageryUpgradeMs = {\n            mid: 0,\n            far: 0\n        };\n        // Fine leaves normally fit the global 4x4 atlas cap. During staged\n        // refinement an underfoot/intermediate leaf may not; preserve native\n        // source zoom only for this small center footprint instead of silently\n        // dropping zoom for the whole near ring.\n        this.surfaceUnderfootMaxAtlasTiles = 8;\n        this.surfaceNearMaxAtlasTiles = 6;\n        this.surfaceNearAtlasRadiusMeters = 900;\n        this.surfacePreloadStartAlt = 50_000;\n        this.surfacePreloadEndAlt = 10_000;\n        this.surfacePreloadLodBias = 2;\n        this.surfacePreloadImageryBias = 2;\n        this.surfacePreloadBudgetScale = 0.8;\n        this._orbitPreloadActive = false;\n        this._orbitPreloadT = 0;\n        this._orbitPreloadMaxLOD = null;\n        this._orbitLodBias = 0;\n        this._orbitImageryBias = 0;\n        this._detailPolicy = null;\n        this.detailAltScaleSurface = 20_000;\n        // Lower orbit detail scale to keep coarse LOD at high altitude.\n        this.detailAltScaleOrbit = 1_000;\n        this.elevationPrefetchBias = 0;\n\n        this.orbitElevationGlobal = true;\n        this.orbitElevationLevel = this.initialSubdivLevel;\n        this._orbitElevationTiles = null;\n        this._orbitElevationTilesLevel = null;\n\n        // Debug flags for testing sign flips\n        this.debugInvertFocusDir = false;\n        this.debugNegateFocusX = false;\n        this.debugNegateFocusZ = false;\n        this.debugInvertCameraDir = false;\n        this.debugInvertCameraPos = false;\n        this.debugNegateCamPosX = false;\n        this.debugNegateCamPosZ = false;\n        this.debugInvertQuaternion = false;\n        this.debugDisableViewportCulling = false;\n\n        // Performance flag: enable/disable neighbor detection\n        this.enableNeighborDetection = false;\n        // Only compute neighbors when needed (surface mode or explicit override).\n        this.forceNeighborDetection = false;\n        this._neighborDetectionActive = false;\n        this._neighborRebuildRequested = false;\n\n        // Edge stitching disabled: keep legacy fields for compatibility but do not use.\n        this.enableEdgeStitching = false;\n        this.edgeStitchMinAuthority = 0.35;\n        this.edgeStitchSkipTargetComplete = 0.9;\n        this.edgeStitchMaxBlend = 0.85;\n        this.edgeStitchMinBlend = 0.15;\n\n        // Cross-LOD seam interpolation (authority-only, no same-LOD stitching).\n        this.enableSeamInterpolation = true;\n        this.seamMinAuthority = 0.9;\n        this.seamSameLodEpsilon = 0.5;\n        this.seamSameLodKeyPrecision = 6;\n        this._seamDirty = true;\n\n        this._surfaceTier = 0;\n        this._surfaceRingCaps = null;\n\n        // Elevation update listeners (tile, vertexIndex)\n        this.elevationListeners = new Set();\n\n        // Edge neighbor map for visualization (populated when neighbor detection runs)\n        this._edgeNeighborMap = null;\n\n        for (const tile of this.rootTiles) {\n            tile.ensureMesh(this.group, this.material, this);\n            tile.applyRenderRules(this.renderRules);\n            tile.setVisible(true);\n        }\n\n        // Pre-subdivide root tiles to a higher level for better initial fidelity\n        this._subdivideRootsToLevel(this.initialSubdivLevel);\n        this._rootsSubdivided = true;\n\n    }\n\n    _computeViewportCache(camera, focusDir, worldQ) {\n        const camPos = this._getCameraPosition(camera);\n        const camDir = camPos.clone().normalize();\n        const camDist = camPos.length() || this.radius;\n        const horizonRad = this._getHorizonRad(camPos);\n        const minRad = (this.surfaceViewshedMinDeg || 0) * DEG2RAD;\n        const marginRadBase = (this.surfaceViewshedMarginDeg || 0) * DEG2RAD;\n        const maxRad = (this.surfaceCullAngleDeg || 80) * DEG2RAD;\n        const orbitMaxRad = (Number.isFinite(this.orbitCullAngleDeg) ? this.orbitCullAngleDeg : (this.surfaceCullAngleDeg || 80)) * DEG2RAD;\n\n        const surfaceMarginRad = Math.max(marginRadBase, horizonRad * 0.6);\n        const surfaceViewshedRad = Math.min(maxRad, Math.max(horizonRad, minRad) + surfaceMarginRad);\n\n        // Allow more wrap past the horizon in orbit to avoid visible edges\n        const orbitMarginRad = Math.max(marginRadBase, horizonRad * 1.2);\n        const orbitViewshedRad = Math.min(orbitMaxRad, Math.max(horizonRad + orbitMarginRad, minRad));\n\n        const referenceDir = (this.lodMode === 'zoom' && focusDir)\n            ? focusDir\n            : camDir;\n\n        const viewDir = new THREE.Vector3();\n        camera.getWorldDirection(viewDir);\n        if (this.debugInvertCameraDir) {\n            viewDir.negate();\n        }\n        const vFovRad = (Number.isFinite(camera.fov) ? camera.fov : 60) * DEG2RAD;\n        const aspect = Number.isFinite(camera.aspect)\n            ? camera.aspect\n            : ((window.innerWidth || 1) / Math.max(1, window.innerHeight || 1));\n        const hFovRad = 2 * Math.atan(Math.tan(vFovRad * 0.5) * Math.max(0.1, aspect));\n        const viewHalfFovRad = Math.max(vFovRad, hFovRad) * 0.5;\n        const marginRad = (Number.isFinite(this.orbitFalloffMarginDeg) ? this.orbitFalloffMarginDeg : 0) * DEG2RAD;\n        const viewEdgeRad = viewHalfFovRad + marginRad;\n        const anchorDeg = Number.isFinite(this.orbitFalloffAnchorDeg) ? this.orbitFalloffAnchorDeg : null;\n        let viewFalloffEndRad = Number.isFinite(anchorDeg)\n            ? anchorDeg * DEG2RAD\n            : (viewEdgeRad + (25 * DEG2RAD));\n        viewFalloffEndRad = Math.max(viewEdgeRad, Math.min(Math.PI, viewFalloffEndRad));\n\n        const hysteresisRad = (this.viewshedHysteresisDeg || 0) * DEG2RAD;\n\n        return {\n            camPos,\n            camDir,\n            surfaceViewshedRad,\n            orbitViewshedRad,\n            referenceDir,\n            worldQ,\n            viewDir,\n            viewHalfFovRad,\n            viewEdgeRad,\n            viewFalloffEndRad,\n            hysteresisRad\n        };\n    }\n\n    _getOrbitElevationTiles() {\n        if (!this.orbitElevationGlobal) return [];\n        const level = Number.isFinite(this.orbitElevationLevel)\n            ? Math.max(0, Math.floor(this.orbitElevationLevel))\n            : (Number.isFinite(this.initialSubdivLevel) ? this.initialSubdivLevel : 0);\n        if (!this._orbitElevationTiles || this._orbitElevationTilesLevel !== level) {\n            if (level > 0) {\n                this._subdivideRootsToLevel(level);\n                this._rootsSubdivided = true;\n            }\n            const tiles = [];\n            const stack = [...this.rootTiles];\n            while (stack.length) {\n                const tile = stack.pop();\n                if (!tile) continue;\n                if (tile.level === level) {\n                    tiles.push(tile);\n                } else if (tile.children && tile.level < level) {\n                    stack.push(...tile.children);\n                }\n            }\n            for (const tile of tiles) {\n                if (!tile.mesh) {\n                    tile.ensureMesh(this.group, this.material, this);\n                }\n                tile.applyRenderRules(this.renderRules);\n            }\n            this._orbitElevationTiles = tiles;\n            this._orbitElevationTilesLevel = level;\n        }\n        return this._orbitElevationTiles || [];\n    }\n\n    _updateOrbitPreload(_altUnits) {\n        // DISABLED: Orbit preload adds too much complexity and causes instability\n        // In orbit mode, we use simple altitude-based LOD without dynamic caps\n        // This prevents constant LOD/imagery changes during camera movement\n        this._orbitPreloadT = 0;\n        this._orbitPreloadActive = false;\n        this._orbitPreloadMaxLOD = null;\n        this._orbitLodBias = 0;\n        this._orbitImageryBias = 0;\n\n        // Note: Surface preload (when descending from orbit) is handled separately\n        // by the progressive staging system in surface mode\n    }\n\n    _computeSurfaceStageTarget(altMeters) {\n        const maxLevel = this.maxTileLevel ?? MAX_TILE_LEVEL;\n        const minLevel = this.minBaseLevel ?? 0;\n        const altScale = Number.isFinite(this.detailAltScaleSurface) ? this.detailAltScaleSurface : 20_000;\n        const altFactor = Math.max(1, Math.max(0, altMeters) / Math.max(1, altScale));\n        const levelFromAlt = Math.floor(maxLevel - Math.log2(altFactor));\n        let target = Math.min(maxLevel, Math.max(minLevel, levelFromAlt));\n        const stageMin = Number.isFinite(this.surfaceStageMinLOD) ? this.surfaceStageMinLOD : minLevel;\n        const stageMax = Number.isFinite(this.surfaceStageMaxLOD) ? this.surfaceStageMaxLOD : maxLevel;\n        target = Math.min(stageMax, Math.max(stageMin, target));\n        return target;\n    }\n\n    _updateSurfaceInstantStage(altMeters, frameNow) {\n        const stageMin = Number.isFinite(this.surfaceStageMinLOD) ? this.surfaceStageMinLOD : 0;\n        const stageMax = Number.isFinite(this.surfaceStageMaxLOD)\n            ? this.surfaceStageMaxLOD\n            : (this.maxTileLevel ?? MAX_TILE_LEVEL);\n        const target = Math.min(stageMax, Math.max(stageMin, this._computeSurfaceStageTarget(altMeters)));\n        this.surfaceInstantStageTargetLOD = target;\n\n        const ringCaps = this.surfaceRingLodCaps || {};\n        const midCap = Number.isFinite(ringCaps.mid) ? ringCaps.mid : target;\n        const farCap = Number.isFinite(ringCaps.far) ? ringCaps.far : midCap;\n\n        let near = Number.isFinite(this.surfaceCurrentMaxLODNear)\n            ? this.surfaceCurrentMaxLODNear\n            : stageMin;\n        near = Math.min(stageMax, Math.max(stageMin, near));\n\n        if (!this.surfaceInstantStageRampEnabled) {\n            this.surfaceCurrentMaxLODNear = target;\n            this.surfaceCurrentMaxLODMid = Math.max(stageMin, Math.min(midCap, target - 1));\n            this.surfaceCurrentMaxLODFar = Math.max(stageMin, Math.min(farCap, this.surfaceCurrentMaxLODMid - 1));\n            return;\n        }\n\n        const upStep = Math.max(1, Math.floor(Number.isFinite(this.surfaceInstantStageUpStep) ? this.surfaceInstantStageUpStep : 1));\n        const downStep = Math.max(1, Math.floor(Number.isFinite(this.surfaceInstantStageDownStep) ? this.surfaceInstantStageDownStep : 2));\n        const downHysteresis = Math.max(0, Math.floor(Number.isFinite(this.surfaceInstantStageDownHysteresis) ? this.surfaceInstantStageDownHysteresis : 1));\n        const upCooldownMs = Math.max(16, Number.isFinite(this.surfaceInstantStageCooldownMs) ? this.surfaceInstantStageCooldownMs : 120);\n        const downCooldownMs = Math.max(16, Number.isFinite(this.surfaceInstantStageDownCooldownMs) ? this.surfaceInstantStageDownCooldownMs : Math.min(upCooldownMs, 70));\n        const lastAdvance = Number.isFinite(this.surfaceStageLastAdvance) ? this.surfaceStageLastAdvance : 0;\n        const elapsed = Math.max(0, frameNow - lastAdvance);\n\n        let nextNear = near;\n        if (target > near) {\n            if (elapsed >= upCooldownMs) {\n                nextNear = Math.min(target, near + upStep);\n                this.surfaceStageLastAdvance = frameNow;\n            }\n        } else if (target < (near - downHysteresis)) {\n            if (elapsed >= downCooldownMs || (near - target) > downStep) {\n                nextNear = Math.max(target, near - downStep);\n                this.surfaceStageLastAdvance = frameNow;\n            }\n        }\n\n        this.surfaceCurrentMaxLODNear = nextNear;\n        this.surfaceCurrentMaxLODMid = Math.max(stageMin, Math.min(midCap, nextNear - 1));\n        this.surfaceCurrentMaxLODFar = Math.max(stageMin, Math.min(farCap, this.surfaceCurrentMaxLODMid - 1));\n    }\n\n    setFrameBudgetHint(frameIntervalMs) {\n        if (!this.adaptiveSplitBudgetEnabled) {\n            this._adaptiveSplitBudgetScale = 1.0;\n            this._adaptiveSplitFrameMsEma = null;\n            return;\n        }\n        if (!Number.isFinite(frameIntervalMs) || frameIntervalMs <= 0) return;\n\n        const alpha = Math.max(0.01, Math.min(1, Number.isFinite(this.adaptiveSplitBudgetEmaAlpha) ? this.adaptiveSplitBudgetEmaAlpha : 0.2));\n        this._adaptiveSplitFrameMsEma = Number.isFinite(this._adaptiveSplitFrameMsEma)\n            ? (this._adaptiveSplitFrameMsEma + alpha * (frameIntervalMs - this._adaptiveSplitFrameMsEma))\n            : frameIntervalMs;\n\n        const minScale = THREE.MathUtils.clamp(\n            Number.isFinite(this.adaptiveSplitBudgetMinScale) ? this.adaptiveSplitBudgetMinScale : 0.35,\n            0.1,\n            1.0\n        );\n        const maxScale = THREE.MathUtils.clamp(\n            Number.isFinite(this.adaptiveSplitBudgetMaxScale) ? this.adaptiveSplitBudgetMaxScale : 1.0,\n            minScale,\n            1.5\n        );\n        const targetMs = Math.max(8, Number.isFinite(this.adaptiveSplitBudgetTargetMs) ? this.adaptiveSplitBudgetTargetMs : 33.3);\n\n        let desiredScale = maxScale;\n        if (this._adaptiveSplitFrameMsEma > targetMs) {\n            desiredScale = THREE.MathUtils.clamp(targetMs / Math.max(1e-3, this._adaptiveSplitFrameMsEma), minScale, maxScale);\n        }\n\n        const currentScale = Number.isFinite(this._adaptiveSplitBudgetScale) ? this._adaptiveSplitBudgetScale : maxScale;\n        const lerpRate = desiredScale < currentScale\n            ? THREE.MathUtils.clamp(Number.isFinite(this.adaptiveSplitBudgetDropLerp) ? this.adaptiveSplitBudgetDropLerp : 0.35, 0.01, 1)\n            : THREE.MathUtils.clamp(Number.isFinite(this.adaptiveSplitBudgetRiseLerp) ? this.adaptiveSplitBudgetRiseLerp : 0.08, 0.01, 1);\n        this._adaptiveSplitBudgetScale = THREE.MathUtils.lerp(currentScale, desiredScale, lerpRate);\n    }\n\n    _computeDetailPolicy(camera, surfacePosition) {\n        const maxLevel = this.maxTileLevel ?? MAX_TILE_LEVEL;\n        const minLevel = this.minBaseLevel ?? 0;\n        const camPos = this._getCameraPosition(camera);\n        const altMeters = this._getAltitudeFromCamPos(camPos);\n        const inSurfaceMode = this.lodMode === 'zoom' && surfacePosition;\n\n        const altScale = inSurfaceMode\n            ? (Number.isFinite(this.detailAltScaleSurface) ? this.detailAltScaleSurface : 20_000)\n            : (Number.isFinite(this.detailAltScaleOrbit) ? this.detailAltScaleOrbit : 30_000);\n        const altFactor = Math.max(1, altMeters / Math.max(1, altScale));\n        const levelFromAlt = Math.floor(maxLevel - Math.log2(altFactor));\n        let altMaxLod = Math.min(maxLevel, Math.max(minLevel, levelFromAlt));\n\n        if (!inSurfaceMode &&\n            this._orbitPreloadActive &&\n            Number.isFinite(this._orbitPreloadMaxLOD)) {\n            altMaxLod = Math.min(altMaxLod, this._orbitPreloadMaxLOD);\n        }\n\n        const stageMax = Number.isFinite(this.surfaceStageMaxLOD)\n            ? this.surfaceStageMaxLOD\n            : maxLevel;\n        const stageCurrent = Number.isFinite(this.surfaceCurrentMaxLODNear)\n            ? this.surfaceCurrentMaxLODNear\n            : stageMax;\n        const renderStageCap = inSurfaceMode ? stageCurrent : maxLevel;\n        let renderMaxLod = Math.min(altMaxLod, renderStageCap);\n        renderMaxLod = Math.min(maxLevel, Math.max(minLevel, renderMaxLod));\n\n        const prefetchBias = Number.isFinite(this.elevationPrefetchBias) ? this.elevationPrefetchBias : 0;\n        let elevationMaxLevel = altMaxLod + prefetchBias;\n        if (inSurfaceMode && Number.isFinite(stageMax)) {\n            elevationMaxLevel = Math.min(elevationMaxLevel, stageMax);\n        }\n        elevationMaxLevel = Math.min(maxLevel, Math.max(minLevel, elevationMaxLevel));\n\n        const imageryMinZoom = Number.isFinite(this.imageryMinZoom) ? this.imageryMinZoom : 0;\n        const imageryMaxZoom = Number.isFinite(this.imageryMaxZoom) ? this.imageryMaxZoom : 19;\n        const lodRatio = maxLevel > 0 ? (altMaxLod / maxLevel) : 0;\n        let imageryCap = Math.round(\n            imageryMinZoom + lodRatio * (imageryMaxZoom - imageryMinZoom)\n        );\n        if (inSurfaceMode && Number.isFinite(this.surfaceImageryMaxZoom)) {\n            imageryCap = Math.min(imageryCap, this.surfaceImageryMaxZoom);\n        }\n        imageryCap = Math.max(imageryMinZoom, Math.min(imageryMaxZoom, imageryCap));\n\n        const metersPerPixel = this._metersPerPixel(Math.max(1, altMeters), camera);\n\n        return {\n            mode: inSurfaceMode ? 'surface' : 'orbit',\n            altMeters,\n            maxLod: altMaxLod,\n            renderMaxLod,\n            elevationMaxLevel,\n            imageryMinZoom,\n            imageryMaxZoom: imageryCap,\n            metersPerPixel\n        };\n    }\n\n    _metersPerPixel(distance, camera) {\n        const viewportHeight = window.innerHeight || 1080;\n        const fovRad = camera.fov * DEG2RAD;\n        const pixelScale = viewportHeight / (2 * Math.tan(fovRad * 0.5));\n        return distance / Math.max(1e-6, pixelScale);\n    }\n\n    _wmtsZoomForMetersPerPixel(metersPerPixel) {\n        const circumference = 2 * Math.PI * this.radius;\n        return Math.log2(circumference / (256 * Math.max(1e-6, metersPerPixel)));\n    }\n\n    setHexPatch(centerDir, radius) {\n        if (!centerDir || !Number.isFinite(radius) || radius <= 0) {\n            this.hexPatch = null;\n        } else {\n            this.hexPatch = {\n                centerDir: centerDir.clone().normalize(),\n                radius\n            };\n        }\n    }\n\n    setLODMode(mode) {\n        const next = (mode === 'zoom') ? 'zoom' : 'orbit';\n        if (this.lodMode === next) return;\n        this.lodMode = next;\n        // Reset surface staging when switching modes\n        if (this.lodMode === 'zoom') {\n            this.surfaceCurrentMaxLODNear = this.surfaceStageMinLOD;\n            this.surfaceCurrentMaxLODMid = this.surfaceRingLodCaps.mid;\n            this.surfaceCurrentMaxLODFar = this.surfaceRingLodCaps.far;\n            this.surfaceStageLastAdvance = (typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now();\n            if (this.elevationCascadeEnabled) {\n                this._elevationCascadeCoarseReady = false;\n                this._elevationCascadeCoverageRatio = 0;\n                this._elevationCascadeReadyTiles = 0;\n                this._elevationCascadeTotalTiles = 0;\n            }\n        } else {\n            this.surfaceCurrentMaxLODNear = this.maxTileLevel;\n            this.surfaceCurrentMaxLODMid = this.maxTileLevel;\n            this.surfaceCurrentMaxLODFar = this.maxTileLevel;\n            this._elevationCascadeCoarseReady = true;\n            this._elevationCascadeCoverageRatio = 1;\n        }\n    }\n\n    setLowFpsMode(active) {\n        this._lowFpsActive = !!active;\n        this._applyLowFpsBudgets(this._lowFpsActive);\n    }\n\n    _applyLowFpsBudgets(active) {\n        if (!active) {\n            if (this._lowFpsBudgetBackup) {\n                this.tileBudget = this._lowFpsBudgetBackup.tileBudget;\n                this.splitBudget = this._lowFpsBudgetBackup.splitBudget;\n                this.mergeBudget = this._lowFpsBudgetBackup.mergeBudget;\n                this.imageryBudgetPerFrame = this._lowFpsBudgetBackup.imageryBudgetPerFrame;\n                this.surfaceStageMaxLOD = this._lowFpsBudgetBackup.surfaceStageMaxLOD;\n                this._lowFpsBudgetBackup = null;\n            }\n            return;\n        }\n        if (!this._lowFpsBudgetBackup) {\n            this._lowFpsBudgetBackup = {\n                tileBudget: this.tileBudget,\n                splitBudget: this.splitBudget,\n                mergeBudget: this.mergeBudget,\n                imageryBudgetPerFrame: this.imageryBudgetPerFrame,\n                surfaceStageMaxLOD: this.surfaceStageMaxLOD\n            };\n        }\n        const base = this._lowFpsBudgetBackup;\n        const baseTileBudget = Number.isFinite(base?.tileBudget) ? base.tileBudget : this.tileBudget;\n        const baseSplitBudget = Number.isFinite(base?.splitBudget) ? base.splitBudget : this.splitBudget;\n        const baseMergeBudget = Number.isFinite(base?.mergeBudget) ? base.mergeBudget : this.mergeBudget;\n        const baseImageryBudget = Number.isFinite(base?.imageryBudgetPerFrame) ? base.imageryBudgetPerFrame : this.imageryBudgetPerFrame;\n        const baseStageMaxLod = Number.isFinite(base?.surfaceStageMaxLOD) ? base.surfaceStageMaxLOD : this.surfaceStageMaxLOD;\n\n        this.tileBudget = Math.max(800, Math.min(baseTileBudget, Math.floor(baseTileBudget * 0.5)));\n        this.splitBudget = Math.max(16, Math.min(baseSplitBudget, Math.floor(baseSplitBudget * 0.5)));\n        this.mergeBudget = Math.max(16, Math.min(baseMergeBudget, Math.floor(baseMergeBudget * 0.5)));\n        this.imageryBudgetPerFrame = Math.max(8, Math.min(baseImageryBudget, Math.floor(baseImageryBudget * 0.5)));\n        this.surfaceStageMaxLOD = baseStageMaxLod;\n    }\n\n    setPerformanceMonitor(perf) {\n        this.perf = perf || null;\n    }\n\n    addElevationListener(handler) {\n        if (typeof handler !== 'function') return;\n        this.elevationListeners.add(handler);\n    }\n\n    removeElevationListener(handler) {\n        if (typeof handler !== 'function') return;\n        this.elevationListeners.delete(handler);\n    }\n\n    addTileListener(handler) {\n        if (typeof handler !== 'function') return;\n        this._tileListeners.add(handler);\n    }\n\n    removeTileListener(handler) {\n        if (typeof handler !== 'function') return;\n        this._tileListeners.delete(handler);\n    }\n\n    _notifyTileListeners(payload) {\n        if (!this._tileListeners.size) return;\n        for (const handler of this._tileListeners) {\n            try {\n                handler(payload);\n            } catch (error) {\n                console.warn('[TriTree] Tile listener error', error);\n            }\n        }\n    }\n\n    _notifyElevationListeners(tile, vertexIndex) {\n        if (!tile) return;\n        if (tile._elevationVersionTick !== this._elevationVersionTick) {\n            tile._elevationVersionTick = this._elevationVersionTick;\n            tile.elevationVersion = Number.isFinite(tile.elevationVersion)\n                ? tile.elevationVersion + 1\n                : 1;\n            this._notifyTileListeners({\n                type: 'elevation',\n                tile,\n                version: tile.elevationVersion\n            });\n        }\n        if (!this.elevationListeners.size) return;\n        for (const handler of this.elevationListeners) {\n            try {\n                handler(tile, vertexIndex);\n            } catch (error) {\n                console.warn('[TriTree] Elevation listener error', error);\n            }\n        }\n    }\n\n    setSurfaceStagingConfig({\n        minLOD,\n        maxLOD,\n        cooldownMs,\n        cullAngleDeg,\n        focusAngleDeg,\n        instantRampEnabled,\n        instantRampCooldownMs,\n        instantRampDownCooldownMs,\n        instantRampUpStep,\n        instantRampDownStep,\n        instantRampDownHysteresis,\n        viewCullEnabled,\n        viewBufferDeg,\n        peripheralLodDrop,\n        viewCenterImageryBoost\n    } = {}) {\n        if (Number.isFinite(minLOD)) this.surfaceStageMinLOD = Math.max(0, Math.floor(minLOD));\n        if (Number.isFinite(maxLOD)) this.surfaceStageMaxLOD = Math.max(this.surfaceStageMinLOD, Math.floor(maxLOD));\n        if (Number.isFinite(cooldownMs)) this.surfaceStageCooldownMs = Math.max(100, Math.floor(cooldownMs));\n        if (Number.isFinite(cullAngleDeg)) this.surfaceCullAngleDeg = Math.max(10, Math.min(170, cullAngleDeg));\n        if (Number.isFinite(focusAngleDeg)) this.surfaceStageFocusAngleDeg = Math.max(1, Math.min(170, focusAngleDeg));\n        if (typeof instantRampEnabled === 'boolean') this.surfaceInstantStageRampEnabled = instantRampEnabled;\n        if (Number.isFinite(instantRampCooldownMs)) this.surfaceInstantStageCooldownMs = Math.max(16, Math.floor(instantRampCooldownMs));\n        if (Number.isFinite(instantRampDownCooldownMs)) this.surfaceInstantStageDownCooldownMs = Math.max(16, Math.floor(instantRampDownCooldownMs));\n        if (Number.isFinite(instantRampUpStep)) this.surfaceInstantStageUpStep = Math.max(1, Math.floor(instantRampUpStep));\n        if (Number.isFinite(instantRampDownStep)) this.surfaceInstantStageDownStep = Math.max(1, Math.floor(instantRampDownStep));\n        if (Number.isFinite(instantRampDownHysteresis)) this.surfaceInstantStageDownHysteresis = Math.max(0, Math.floor(instantRampDownHysteresis));\n        if (typeof viewCullEnabled === 'boolean') this.surfaceViewCullEnabled = viewCullEnabled;\n        if (Number.isFinite(viewBufferDeg)) this.surfaceViewBufferDeg = Math.max(0, Math.min(60, viewBufferDeg));\n        if (Number.isFinite(peripheralLodDrop)) this.surfacePeripheralLodDrop = Math.max(0, Math.floor(peripheralLodDrop));\n        if (Number.isFinite(viewCenterImageryBoost)) this.surfaceViewCenterImageryBoost = Math.max(0, Math.floor(viewCenterImageryBoost));\n\n        this.surfaceCurrentMaxLODNear = Math.min(\n            Math.max(this.surfaceStageMinLOD, this.surfaceCurrentMaxLODNear),\n            this.surfaceStageMaxLOD\n        );\n        this.surfaceCurrentMaxLODMid = Math.min(this.surfaceRingLodCaps.mid, this.surfaceCurrentMaxLODMid);\n        this.surfaceCurrentMaxLODFar = Math.min(this.surfaceRingLodCaps.far, this.surfaceCurrentMaxLODFar);\n    }\n\n    /**\n     * Force immediate LOD cascade to max level for surface mode spawn\n     * Prevents low-LOD tiles from overlapping high-LOD tiles during restoration\n     * Call this when spawning directly in surface mode (e.g., from saved state)\n     */\n    initializeSurfaceLODCascade() {\n        this.surfaceInstantStaging = true;\n    }\n\n    /**\n     * Recursively remove parent tile meshes when they have children\n     * This prevents low-LOD tiles from overlapping high-LOD tiles\n     * @private\n     */\n    _cleanupParentTileMeshes() {\n        let removedCount = 0;\n\n        const cleanupTile = (tile) => {\n            if (!tile) return;\n\n            // If this tile has children and a mesh, remove the parent mesh\n            if (tile.children && tile.children.length > 0) {\n                if (tile.mesh) {\n                    this._removeTileMesh(tile);\n                    tile.deferredRemoval = false; // Clear deferred removal flag\n                    removedCount++;\n                }\n\n                // Recursively cleanup children\n                for (const child of tile.children) {\n                    cleanupTile(child);\n                }\n            }\n        };\n\n        // Process all root tiles\n        for (const rootTile of this.rootTiles) {\n            cleanupTile(rootTile);\n        }\n\n        console.log('[LOD] Cleaned up', removedCount, 'parent tile meshes to prevent overlap');\n    }\n\n    setSurfaceFalloffConfig({ nearLOD, farLOD, falloffPower, startDeg } = {}) {\n        if (Number.isFinite(nearLOD)) {\n            this.surfaceLodNear = Math.max(0, Math.floor(nearLOD));\n        }\n        if (Number.isFinite(farLOD)) {\n            this.surfaceLodFar = Math.max(0, Math.floor(farLOD));\n        }\n        if (Number.isFinite(falloffPower)) {\n            this.surfaceLodFalloffPower = Math.max(0.1, Math.min(5, falloffPower));\n        }\n        if (Number.isFinite(startDeg)) {\n            this.surfaceLodFalloffStartDeg = Math.max(0, Math.min(30, startDeg));\n        }\n\n        if (this.surfaceLodNear < this.surfaceLodFar) {\n            const tmp = this.surfaceLodNear;\n            this.surfaceLodNear = this.surfaceLodFar;\n            this.surfaceLodFar = tmp;\n        }\n\n        const ringMidLod = Math.round((this.surfaceLodNear + this.surfaceLodFar) * 0.5);\n        this.surfaceRingLodCaps = {\n            near: this.surfaceStageMaxLOD,\n            mid: Math.max(this.surfaceStageMinLOD, ringMidLod),\n            far: Math.max(this.surfaceStageMinLOD, this.surfaceLodFar)\n        };\n    }\n\n    setOrbitFalloffConfig({ marginDeg, anchorDeg, power } = {}) {\n        if (Number.isFinite(marginDeg)) {\n            this.orbitFalloffMarginDeg = Math.max(0, Math.min(90, marginDeg));\n        }\n        if (Number.isFinite(anchorDeg)) {\n            this.orbitFalloffAnchorDeg = Math.max(1, Math.min(170, anchorDeg));\n        }\n        if (Number.isFinite(power)) {\n            this.orbitLodFalloffPower = Math.max(0.1, Math.min(5, power));\n        }\n    }\n\n    setElevationCascadeConfig({\n        enabled,\n        coarseReadyRatio,\n        tileReadyRatio,\n        minVisibleTiles,\n        coarseMaxLevel\n    } = {}) {\n        if (typeof enabled === 'boolean') {\n            this.elevationCascadeEnabled = enabled;\n        }\n        if (Number.isFinite(coarseReadyRatio)) {\n            this.elevationCascadeCoarseReadyRatio = THREE.MathUtils.clamp(coarseReadyRatio, 0, 1);\n        }\n        if (Number.isFinite(tileReadyRatio)) {\n            this.elevationCascadeTileReadyRatio = THREE.MathUtils.clamp(tileReadyRatio, 0, 1);\n        }\n        if (Number.isFinite(minVisibleTiles)) {\n            this.elevationCascadeMinVisibleTiles = Math.max(0, Math.floor(minVisibleTiles));\n        }\n        if (Number.isFinite(coarseMaxLevel)) {\n            this.elevationCascadeCoarseMaxLevel = Math.max(0, Math.floor(coarseMaxLevel));\n        }\n        if (!this.elevationCascadeEnabled) {\n            this._elevationCascadeCoarseReady = true;\n            this._elevationCascadeCoverageRatio = 1;\n        } else {\n            this._elevationCascadeCoarseReady = false;\n            this._elevationCascadeCoverageRatio = 0;\n        }\n    }\n\n    setElevationFetchMode(mode = 'centric') {\n        const normalized = String(mode || 'centric').trim().toLowerCase();\n        this.elevationFetchMode = normalized === 'classic' ? 'classic' : 'centric';\n    }\n\n    /**\n     * Phase 6: resolve the per-frame wall-clock time budget for split/merge\n     * loops. Reads the runtime flag from the AsyncHarness (checked every\n     * frame so runtime flips take effect immediately), falling back to the\n     * instance default (0 = disabled, count budget only).\n     *\n     * Migration: refactor/async/README.md#phase-6\n     * @returns {number} budget in milliseconds; 0 disables the check\n     */\n    _resolveSplitTimeBudgetMs() {\n        let v = this.splitTimeBudgetMs || 0;\n        try {\n            const flag = (typeof globalThis !== 'undefined')\n                ? globalThis.__noclipAsync?.flags?.splitTimeBudgetMs\n                : undefined;\n            if (Number.isFinite(flag) && flag >= 0) v = flag;\n        } catch {}\n        return Number.isFinite(v) && v > 0 ? v : 0;\n    }\n\n    setBudgets({ tileBudget, splitBudget, mergeBudget }) {\n        if (Number.isFinite(tileBudget) && tileBudget > 0) {\n            this.tileBudget = Math.max(200, Math.min(16000, Math.floor(tileBudget))); // Increased for LOD 14\n        }\n        if (Number.isFinite(splitBudget) && splitBudget > 0) {\n            this.splitBudget = Math.max(4, Math.min(256, Math.floor(splitBudget))); // Increased max\n        }\n        if (Number.isFinite(mergeBudget) && mergeBudget > 0) {\n            this.mergeBudget = Math.max(4, Math.min(256, Math.floor(mergeBudget))); // Increased max\n        }\n    }\n\n    setFrameWorkBudgets({ lodMutationMsPerFrame, imageryPreparationMsPerFrame } = {}) {\n        if (Number.isFinite(lodMutationMsPerFrame)) {\n            this.splitTimeBudgetMs = THREE.MathUtils.clamp(lodMutationMsPerFrame, 0.25, 8);\n        }\n        if (Number.isFinite(imageryPreparationMsPerFrame)) {\n            this.imageryPreparationTimeBudgetMs = THREE.MathUtils.clamp(\n                imageryPreparationMsPerFrame,\n                0.25,\n                8\n            );\n        }\n    }\n\n    setAdaptiveSplitBudgetConfig({\n        enabled,\n        targetMs,\n        minScale,\n        maxScale,\n        emaAlpha,\n        dropLerp,\n        riseLerp\n    } = {}) {\n        if (typeof enabled === 'boolean') {\n            this.adaptiveSplitBudgetEnabled = enabled;\n            if (!enabled) {\n                this._adaptiveSplitBudgetScale = 1.0;\n                this._adaptiveSplitFrameMsEma = null;\n            }\n        }\n        if (Number.isFinite(targetMs)) {\n            this.adaptiveSplitBudgetTargetMs = Math.max(8, targetMs);\n        }\n        if (Number.isFinite(minScale)) {\n            this.adaptiveSplitBudgetMinScale = THREE.MathUtils.clamp(minScale, 0.1, 1.0);\n        }\n        if (Number.isFinite(maxScale)) {\n            this.adaptiveSplitBudgetMaxScale = THREE.MathUtils.clamp(\n                maxScale,\n                this.adaptiveSplitBudgetMinScale,\n                1.5\n            );\n        }\n        if (Number.isFinite(emaAlpha)) {\n            this.adaptiveSplitBudgetEmaAlpha = THREE.MathUtils.clamp(emaAlpha, 0.01, 1.0);\n        }\n        if (Number.isFinite(dropLerp)) {\n            this.adaptiveSplitBudgetDropLerp = THREE.MathUtils.clamp(dropLerp, 0.01, 1.0);\n        }\n        if (Number.isFinite(riseLerp)) {\n            this.adaptiveSplitBudgetRiseLerp = THREE.MathUtils.clamp(riseLerp, 0.01, 1.0);\n        }\n    }\n\n    setLODRange(minLevel, maxLevel) {\n        if (Number.isFinite(minLevel)) {\n            this.minBaseLevel = Math.max(0, Math.min(MAX_TILE_LEVEL, Math.floor(minLevel)));\n        }\n        if (Number.isFinite(maxLevel)) {\n            this.maxTileLevel = Math.max(this.minBaseLevel, Math.min(MAX_TILE_LEVEL, Math.floor(maxLevel)));\n        }\n    }\n\n    setImageryZoomRange(minZoom, maxZoom) {\n        if (Number.isFinite(minZoom)) {\n            this.imageryMinZoom = Math.max(0, Math.min(19, Math.floor(minZoom)));\n        }\n        if (Number.isFinite(maxZoom)) {\n            this.imageryMaxZoom = Math.max(this.imageryMinZoom, Math.min(22, Math.floor(maxZoom)));\n            // Also update ring caps to match new max\n            if (this.surfaceRingImageryCaps) {\n                this.surfaceRingImageryCaps.near = this.surfaceImageryMaxZoom || this.imageryMaxZoom;\n            }\n        }\n    }\n\n    /**\n     * Set imagery resolution boost and invalidate tile imagery targets to trigger re-fetch\n     */\n    setImageryResolutionBoost(boost) {\n        const newBoost = Math.max(0, Math.min(4, Math.floor(boost)));\n        if (newBoost === this.imageryResolutionBoost) return;\n\n        const oldBoost = this.imageryResolutionBoost;\n        this.imageryResolutionBoost = newBoost;\n\n        console.log(`[IMAGERY] Resolution boost changed: ${oldBoost} → ${newBoost}`);\n\n        // Invalidate imagery target zoom on all tiles to force re-evaluation\n        // This allows tiles to request higher-resolution imagery\n        const stack = [...this.rootTiles];\n        while (stack.length) {\n            const t = stack.pop();\n            // Clear pending state and target zoom to allow re-request at new zoom level\n            t.imageryPendingKey = null;\n            t.imageryRequestedKey = null;\n            t.imageryRequestedZoom = null;\n            t.imageryPendingUv = null;\n            t.imageryPendingSince = null;\n            t.imageryPendingAttempts = 0;\n            t.imageryTargetZoom = null; // Forces recalculation\n            if (t.children) stack.push(...t.children);\n        }\n    }\n\n    async releaseImageryManager(manager) {\n        // Retired children can retain atlas leases too. Release in bounded\n        // batches after presentation stops, checking identity so a replacement\n        // provider cannot be cleared by this older teardown.\n        const seen = new WeakSet();\n        let batch = 0;\n        const roots = (function* (tree) {\n            yield* tree.rootTiles;\n            for (const entry of tree._retiredTiles.values()) yield* entry.children;\n        })(this);\n        for (const root of roots) {\n            const stack = [root];\n            while (stack.length) {\n                const tile = stack.pop();\n                if (seen.has(tile)) continue;\n                seen.add(tile);\n                if (tile.imageryManager === manager) tile.clearImagery();\n                else {\n                    if (tile._pendingInheritedManager === manager) tile._clearPendingInheritedImagery();\n                    if (tile.crossfadePrevManager === manager) tile._releaseCrossfadePrevTexture();\n                }\n                if (tile.children) stack.push(...tile.children);\n                if (++batch >= 16) { batch = 0; await yieldToEventLoop('background'); }\n            }\n        }\n    }\n\n    setImageryConfig(config) {\n        if (!this.imageryManager) return;\n        const cfg = config || {};\n        const prev = (typeof this.imageryManager.getConfig === 'function')\n            ? this.imageryManager.getConfig()\n            : {};\n        this.imageryManager.setConfig(cfg);\n        const next = (typeof this.imageryManager.getConfig === 'function')\n            ? this.imageryManager.getConfig()\n            : {};\n\n        // CRITICAL: If imagery was disabled, clear all existing imagery from tiles\n        const wasEnabled = prev.enabled !== false;\n        const nowEnabled = next.enabled !== false;\n        if (wasEnabled && !nowEnabled) {\n            console.log('[IMAGERY] Imagery disabled - clearing all tile imagery');\n            const stack = [...this.rootTiles];\n            while (stack.length) {\n                const t = stack.pop();\n                if (typeof t.clearImagery === 'function') {\n                    t.clearImagery();\n                }\n                if (t.children) stack.push(...t.children);\n            }\n            return;\n        }\n\n        if (Object.prototype.hasOwnProperty.call(cfg, 'mergeMosaicMaxAtlasTiles')) {\n            if (Number.isFinite(cfg.mergeMosaicMaxAtlasTiles)) {\n                this.mergeMosaicMaxAtlasTiles = Math.max(1, Math.min(32, Math.floor(cfg.mergeMosaicMaxAtlasTiles)));\n            } else {\n                this.mergeMosaicMaxAtlasTiles = null;\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'mergeMosaicPadTiles')) {\n            if (Number.isFinite(cfg.mergeMosaicPadTiles)) {\n                this.mergeMosaicPadTiles = Math.max(0, Math.min(4, Math.floor(cfg.mergeMosaicPadTiles)));\n            } else {\n                this.mergeMosaicPadTiles = 0;\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'mergeMosaicMinZoom')) {\n            if (Number.isFinite(cfg.mergeMosaicMinZoom)) {\n                this.mergeMosaicMinZoom = Math.max(0, Math.min(22, Math.floor(cfg.mergeMosaicMinZoom)));\n            } else {\n                this.mergeMosaicMinZoom = 0;\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'mergeMosaicPriority')) {\n            if (Number.isFinite(cfg.mergeMosaicPriority)) {\n                this.mergeMosaicPriority = cfg.mergeMosaicPriority;\n            } else {\n                this.mergeMosaicPriority = 1000;\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'mergeChildAdoptMinCoverage')) {\n            if (Number.isFinite(cfg.mergeChildAdoptMinCoverage)) {\n                this.mergeChildAdoptMinCoverage = THREE.MathUtils.clamp(cfg.mergeChildAdoptMinCoverage, 0, 1);\n            } else {\n                this.mergeChildAdoptMinCoverage = 0.995;\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'surfaceUnderfootMaxAtlasTiles') &&\n            Number.isFinite(cfg.surfaceUnderfootMaxAtlasTiles)) {\n            this.surfaceUnderfootMaxAtlasTiles = Math.max(\n                4,\n                Math.min(12, Math.floor(cfg.surfaceUnderfootMaxAtlasTiles))\n            );\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'surfaceNearMaxAtlasTiles') &&\n            Number.isFinite(cfg.surfaceNearMaxAtlasTiles)) {\n            this.surfaceNearMaxAtlasTiles = Math.max(\n                4,\n                Math.min(this.surfaceUnderfootMaxAtlasTiles, Math.floor(cfg.surfaceNearMaxAtlasTiles))\n            );\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'surfaceNearAtlasRadiusMeters') &&\n            Number.isFinite(cfg.surfaceNearAtlasRadiusMeters)) {\n            this.surfaceNearAtlasRadiusMeters = THREE.MathUtils.clamp(\n                cfg.surfaceNearAtlasRadiusMeters,\n                100,\n                5_000\n            );\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryInheritanceEnabled')) {\n            this.imageryInheritanceEnabled = cfg.imageryInheritanceEnabled === true;\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryBackpressureDropZoomEnabled')) {\n            this.imageryBackpressureDropZoomEnabled = cfg.imageryBackpressureDropZoomEnabled === true;\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryBackpressureSplitBudgetMinScale')) {\n            if (Number.isFinite(cfg.imageryBackpressureSplitBudgetMinScale)) {\n                this.imageryBackpressureSplitBudgetMinScale = THREE.MathUtils.clamp(cfg.imageryBackpressureSplitBudgetMinScale, 0.1, 1.0);\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryBackpressureImageryBudgetMinScale')) {\n            if (Number.isFinite(cfg.imageryBackpressureImageryBudgetMinScale)) {\n                this.imageryBackpressureImageryBudgetMinScale = THREE.MathUtils.clamp(cfg.imageryBackpressureImageryBudgetMinScale, 0.1, 1.0);\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryBackpressureElevationScanMinScale')) {\n            if (Number.isFinite(cfg.imageryBackpressureElevationScanMinScale)) {\n                this.imageryBackpressureElevationScanMinScale = THREE.MathUtils.clamp(cfg.imageryBackpressureElevationScanMinScale, 0.1, 1.0);\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryCoverFirstEnabled')) {\n            this.imageryCoverFirstEnabled = cfg.imageryCoverFirstEnabled === true;\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryCoverBootstrapWindowMs')) {\n            if (Number.isFinite(cfg.imageryCoverBootstrapWindowMs)) {\n                this.imageryCoverBootstrapWindowMs = Math.max(0, Math.floor(cfg.imageryCoverBootstrapWindowMs));\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryCoverZoomGap')) {\n            if (Number.isFinite(cfg.imageryCoverZoomGap)) {\n                this.imageryCoverZoomGap = Math.max(0, Math.floor(cfg.imageryCoverZoomGap));\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryCoverUnderfootZoomGap')) {\n            if (Number.isFinite(cfg.imageryCoverUnderfootZoomGap)) {\n                this.imageryCoverUnderfootZoomGap = Math.max(0, Math.floor(cfg.imageryCoverUnderfootZoomGap));\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryCoverMinZoom')) {\n            if (Number.isFinite(cfg.imageryCoverMinZoom)) {\n                this.imageryCoverMinZoom = Math.max(0, Math.floor(cfg.imageryCoverMinZoom));\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryCoverUnderfootMinZoom')) {\n            if (Number.isFinite(cfg.imageryCoverUnderfootMinZoom)) {\n                this.imageryCoverUnderfootMinZoom = Math.max(0, Math.floor(cfg.imageryCoverUnderfootMinZoom));\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryBootstrapEnabled')) {\n            this.imageryBootstrapEnabled = cfg.imageryBootstrapEnabled === true;\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryBootstrapDeltaZoom')) {\n            if (Number.isFinite(cfg.imageryBootstrapDeltaZoom)) {\n                this.imageryBootstrapDeltaZoom = Math.max(0, Math.floor(cfg.imageryBootstrapDeltaZoom));\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryBootstrapMaxRing')) {\n            if (Number.isFinite(cfg.imageryBootstrapMaxRing)) {\n                this.imageryBootstrapMaxRing = Math.max(0, Math.floor(cfg.imageryBootstrapMaxRing));\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryBootstrapBudgetMax')) {\n            if (Number.isFinite(cfg.imageryBootstrapBudgetMax)) {\n                this.imageryBootstrapBudgetMax = Math.max(1, Math.floor(cfg.imageryBootstrapBudgetMax));\n            }\n        }\n        if (Object.prototype.hasOwnProperty.call(cfg, 'imageryBootstrapMinPriority')) {\n            if (Number.isFinite(cfg.imageryBootstrapMinPriority)) {\n                this.imageryBootstrapMinPriority = cfg.imageryBootstrapMinPriority;\n            }\n        }\n\n        const needsRebind = prev.versionId !== next.versionId ||\n            prev.zoom !== next.zoom ||\n            prev.maxAtlasTiles !== next.maxAtlasTiles ||\n            prev.padTiles !== next.padTiles;\n        if (!needsRebind) return;\n        // Clear pending requests so tiles can rebind without dropping current imagery\n        const stack = [...this.rootTiles];\n        while (stack.length) {\n            const t = stack.pop();\n            t.imageryPendingKey = null;\n            t.imageryRequestedKey = null;\n            t.imageryRequestedZoom = null;\n            t.imageryPendingUv = null;\n            t.imageryPendingSince = null;\n            t.imageryPendingAttempts = 0;\n            t.imageryVersion = null;\n            t.imageryTargetZoom = null;\n            if (t.children) stack.push(...t.children);\n        }\n    }\n\n    setPhotogramConfig(config = {}) {\n        const wasEnabled = this._photogramConfig?.enabled === true;\n        this._photogramConfig = { ...(config || {}) };\n        if (this.photogramManager && typeof this.photogramManager.setConfig === 'function') {\n            this.photogramManager.setConfig(this._photogramConfig);\n        }\n        const nowEnabled = this._photogramConfig?.enabled === true;\n        if (wasEnabled && !nowEnabled) {\n            const stack = [...this.rootTiles];\n            while (stack.length) {\n                const tile = stack.pop();\n                if (tile?.clearPhotogramOffsets) {\n                    tile.clearPhotogramOffsets();\n                }\n                if (tile?.children) {\n                    stack.push(...tile.children);\n                }\n            }\n        }\n    }\n\n    onTileImageryReady(tile) {\n        if (!tile) return;\n        if (this.photogramManager) {\n            const ring = Number.isFinite(tile._imageryVisibleRing) ? tile._imageryVisibleRing : null;\n            this.photogramManager.considerTile(tile, { ring, reason: 'imagery-ready' });\n        }\n        this._notifyTileListeners({ type: 'imagery', tile });\n    }\n\n    _computeImageryContextKey(focusDir, altUnits) {\n        if (!focusDir || !this.group) return null;\n        const focusWorld = focusDir.clone().multiplyScalar(this.radius);\n        const ll = worldPosToLatLonLocal(focusWorld, this.group);\n        if (!ll) return null;\n        const z = Number.isFinite(this.imageryContextZoom) ? this.imageryContextZoom : 4;\n        const tile = lonLatToTileCoords(ll.lonDeg, ll.latDeg, z);\n        const altBucket = Math.max(0, Math.floor(Math.log2(Math.max(altUnits, 1))));\n        return `${this.lodMode}:${z}:${tile.x}:${tile.y}:a${altBucket}`;\n    }\n\n    getVisibleMeshes() {\n        return this.visibleMeshes;\n    }\n\n    /**\n     * Refresh imagery on all tiles (e.g., after changing wayback version)\n     * Clears existing imagery and triggers reload\n     */\n    refreshAllTileImagery() {\n        if (!this.imageryManager) return;\n\n        // Clear all tile imagery state\n        const stack = [...this.rootTiles];\n        while (stack.length) {\n            const tile = stack.pop();\n            if (tile) {\n                // Reset imagery state to force reload\n                tile.imageryReady = false;\n                tile.imageryAtlasKey = null;\n                tile.imageryPendingKey = null;\n                tile.imageryRequestedKey = null;\n                tile.imageryTexture = null;\n                // Clear material texture\n                if (tile.mesh?.material?.map) {\n                    tile.mesh.material.map = null;\n                    tile.mesh.material.needsUpdate = true;\n                }\n                if (tile.children) {\n                    stack.push(...tile.children);\n                }\n            }\n        }\n\n        console.log('[TriTreeManager] Refreshing all tile imagery');\n    }\n\n    setMaterial(newMaterial) {\n        // Update material reference\n        this.material = newMaterial;\n        this._applyRulesToMaterial();\n\n        // Update all existing tile meshes\n        const stack = [...this.rootTiles];\n        while (stack.length) {\n            const tile = stack.pop();\n            if (tile.mesh) {\n                const prevMap = tile.materialDefault?.map || tile.mesh.material?.map || null;\n                const materialInstance = (typeof newMaterial.clone === 'function')\n                    ? newMaterial.clone()\n                    : newMaterial;\n                if (prevMap) {\n                    materialInstance.map = prevMap;\n                    materialInstance.needsUpdate = true;\n                }\n\n                if (typeof tile.setBaseMaterial === 'function') {\n                    tile.setBaseMaterial(materialInstance);\n                } else {\n                    tile.mesh.material = materialInstance;\n                }\n                tile.applyRenderRules(this.renderRules);\n            }\n            if (tile.children) {\n                stack.push(...tile.children);\n            }\n        }\n    }\n\n    /**\n     * Set the physics system for automatic terrain collision registration\n     * @param {PhysicsSystem} physicsSystem - The physics system instance\n     */\n    setPhysicsSystem(physicsSystem) {\n        this.physicsSystem = physicsSystem;\n        console.log('[TriTreeManager] Physics system registered for terrain collisions');\n\n        // Wait for physics to initialize, then process pending colliders\n        if (physicsSystem.ready) {\n            physicsSystem.ready.then(() => {\n                if (this.physicsSystem === physicsSystem) this._processPendingColliders();\n            }).catch(error => {\n                // Retain pending geometry for an explicit physics retry. The\n                // owner records the error; no unhandled rejection or reload.\n                console.error('[TriTreeManager] Physics initialization failed:', error);\n            });\n        }\n    }\n\n    /**\n     * Process tiles that were queued while physics was initializing\n     */\n    _processPendingColliders() {\n        if (!this._pendingColliders || this._pendingColliders.size === 0) return;\n        if (!this.physicsSystem?.core?.RAPIER) return;\n\n        console.log(`[TriTreeManager] Processing ${this._pendingColliders.size} pending terrain colliders`);\n\n        let addedCount = 0;\n        for (const mesh of this._pendingColliders) {\n            // Check if still visible and valid\n            if (mesh.visible && mesh.geometry) {\n                const colliderData = this.physicsSystem.addStaticCollider(mesh);\n                if (colliderData) {\n                    this._tileColliders.set(mesh, colliderData);\n                    addedCount++;\n                }\n            }\n        }\n\n        this._pendingColliders.clear();\n        console.log(`[TriTreeManager] ✅ Added ${addedCount} terrain colliders (physics ready)`);\n    }\n\n    /**\n     * Add a tile mesh as a static physics collider\n     * @param {THREE.Mesh} mesh - The tile mesh to add\n     */\n    _addTileCollider(mesh) {\n        if (!this.physicsSystem || !mesh) return;\n        if (this._tileColliders.has(mesh)) return; // Already added\n\n        // Only add if physics core is ready\n        if (!this.physicsSystem.core || !this.physicsSystem.core.RAPIER) {\n            // Queue for later if physics not ready yet\n            if (!this._pendingColliders) this._pendingColliders = new Set();\n            this._pendingColliders.add(mesh);\n            return;\n        }\n\n        const colliderData = this.physicsSystem.addStaticCollider(mesh);\n        if (colliderData) {\n            this._tileColliders.set(mesh, colliderData);\n        }\n    }\n\n    /**\n     * Remove a tile mesh from physics colliders\n     * @param {THREE.Mesh} mesh - The tile mesh to remove\n     */\n    _removeTileCollider(mesh) {\n        if (!this.physicsSystem || !mesh) return;\n        if (this._pendingColliders?.has(mesh)) {\n            this._pendingColliders.delete(mesh);\n        }\n        if (!this._tileColliders.has(mesh)) return;\n\n        this.physicsSystem.removeStaticCollider(mesh);\n        this._tileColliders.delete(mesh);\n    }\n\n    _pruneStaleTileColliders() {\n        if (!this.physicsSystem || !this._tileColliders || this._tileColliders.size === 0) return 0;\n        let removed = 0;\n        for (const mesh of Array.from(this._tileColliders.keys())) {\n            if (!mesh || !mesh.visible || !mesh.parent || !mesh.geometry) {\n                this.physicsSystem.removeStaticCollider(mesh);\n                this._tileColliders.delete(mesh);\n                if (this._pendingColliders?.has(mesh)) {\n                    this._pendingColliders.delete(mesh);\n                }\n                removed++;\n            }\n        }\n        return removed;\n    }\n\n    /**\n     * Remove a tile's mesh and its physics collider\n     * @param {TriTile} tile - The tile to remove mesh from\n     */\n    _removeTileMesh(tile) {\n        if (!tile || !tile.mesh) return;\n\n        // Remove physics collider first\n        this._removeTileCollider(tile.mesh);\n\n        // Then remove the mesh\n        tile.removeMesh(this.group);\n    }\n\n    setEarthRotation(angle) {\n        if (typeof angle !== 'number' || !isFinite(angle)) return;\n        this.group.rotation.y = angle;\n        this._earthRotationAngle = angle;\n    }\n\n    getEarthRotation() {\n        return Number.isFinite(this._earthRotationAngle)\n            ? this._earthRotationAngle\n            : null;\n    }\n\n    setSunDirection(direction) {\n        if (!direction) return;\n        const next = this._tmpDir.copy(direction).normalize();\n        if (this._sunDirectionWorld.angleTo(next) < 1e-4 && !this._sunDirectionDirty) return;\n        this._sunDirectionWorld.copy(next);\n        this._sunDirectionDirty = false;\n\n        const applyToMaterial = (material) => {\n            if (!material?.uniforms) return;\n            if (!material.uniforms.sunDirection && material?.fragmentShader?.includes('sunDirection')) {\n                material.uniforms.sunDirection = { value: new THREE.Vector3() };\n                material.needsUpdate = true;\n            }\n            if (!material.uniforms.sunDirection) return;\n            material.uniforms.sunDirection.value.copy(this._sunDirectionWorld);\n        };\n\n        applyToMaterial(this.material);\n        if (Array.isArray(this.visibleLeafTiles)) {\n            for (const tile of this.visibleLeafTiles) {\n                if (tile?.materialDefault) {\n                    applyToMaterial(tile.materialDefault);\n                } else if (tile?.mesh?.material) {\n                    applyToMaterial(tile.mesh.material);\n                }\n            }\n        }\n    }\n\n    setCameraWorldPosition(position) {\n        if (!position) return;\n\n        const applyToMaterial = (material) => {\n            if (!material?.uniforms) return;\n            if (!material.uniforms.cameraWorldPosition && material?.vertexShader?.includes('cameraWorldPosition')) {\n                material.uniforms.cameraWorldPosition = { value: new THREE.Vector3() };\n                material.needsUpdate = true;\n            }\n            if (!material.uniforms.cameraWorldPosition) return;\n            material.uniforms.cameraWorldPosition.value.copy(position);\n        };\n\n        applyToMaterial(this.material);\n        if (Array.isArray(this.visibleLeafTiles)) {\n            for (const tile of this.visibleLeafTiles) {\n                if (tile?.materialDefault) {\n                    applyToMaterial(tile.materialDefault);\n                } else if (tile?.mesh?.material) {\n                    applyToMaterial(tile.mesh.material);\n                }\n            }\n        }\n    }\n\n    exportVisibleTileSnapshot() {\n        if (!Array.isArray(this.visibleLeafTiles)) return [];\n        const out = [];\n        for (const tile of this.visibleLeafTiles) {\n            if (!tile || typeof tile.getTileId !== 'function') continue;\n            const entry = {\n                id: tile.getTileId(),\n                level: tile.level\n            };\n            if (Number.isFinite(tile.imageryAtlasZoom) && tile.imageryInherited !== true) {\n                const zoom = Math.max(0, Math.floor(tile.imageryAtlasZoom));\n                const n = Math.pow(2, zoom);\n                const minXRaw = Number.isFinite(tile.imageryAtlasMinX) ? Math.floor(tile.imageryAtlasMinX) : null;\n                const minX = Number.isFinite(minXRaw)\n                    ? THREE.MathUtils.euclideanModulo(minXRaw, n)\n                    : null;\n                const minY = Number.isFinite(tile.imageryAtlasMinY) ? Math.floor(tile.imageryAtlasMinY) : null;\n                const w = Number.isFinite(tile.imageryAtlasW) ? Math.max(1, Math.floor(tile.imageryAtlasW)) : null;\n                const h = Number.isFinite(tile.imageryAtlasH) ? Math.max(1, Math.floor(tile.imageryAtlasH)) : null;\n                if (Number.isFinite(minX) && Number.isFinite(minY) && Number.isFinite(w) && Number.isFinite(h)) {\n                    entry.imagery = {\n                        zoom,\n                        minX,\n                        minY,\n                        w,\n                        h\n                    };\n                }\n            }\n            out.push(entry);\n        }\n        return out;\n    }\n\n    _parseTileId(tileId) {\n        if (typeof tileId !== 'string') return null;\n        const match = /^R(\\d+)-L(\\d+)-(\\d*)$/.exec(tileId.trim());\n        if (!match) return null;\n        const rootIndex = Number.parseInt(match[1], 10);\n        const level = Number.parseInt(match[2], 10);\n        const path = match[3] || '';\n        if (!Number.isFinite(rootIndex) || rootIndex < 0) return null;\n        if (!Number.isFinite(level) || level < 0) return null;\n        return { rootIndex, level, path };\n    }\n\n    _ensureTilePath(rootTile, path) {\n        let tile = rootTile;\n        if (!tile) return null;\n        for (let i = 0; i < path.length; i += 1) {\n            const digit = path[i];\n            const childIndex = Number.parseInt(digit, 10);\n            if (!Number.isFinite(childIndex) || childIndex < 0 || childIndex > 3) return null;\n            if (!tile.children) {\n                tile.subdivide();\n                tile.prepareChildrenForSplit?.();\n                if (Array.isArray(tile.children)) {\n                    this.tileCount += tile.children.length;\n                }\n                tile.removeMesh?.(this.group);\n            }\n            tile = tile.children?.[childIndex] || null;\n            if (!tile) return null;\n        }\n        return tile;\n    }\n\n    collectSnapshotElevationKeys(entries, {\n        maxTiles = 1024,\n        maxKeys = 160000,\n        focusWorldDir = null\n    } = {}) {\n        if (!Array.isArray(entries) || !entries.length || !this.rootTiles) return [];\n        const tileLimit = Number.isFinite(maxTiles)\n            ? Math.max(1, Math.floor(maxTiles))\n            : 1024;\n        const keyLimit = Number.isFinite(maxKeys)\n            ? Math.max(1, Math.floor(maxKeys))\n            : 160000;\n        const out = [];\n        const seenKeys = new Set();\n        const seenTileIds = new Set();\n        const tmpDir = this._snapshotElevationKeyTmpDir || (this._snapshotElevationKeyTmpDir = new THREE.Vector3());\n        const focusLocalDir = this._resolveSnapshotReplayFocusLocalDir(focusWorldDir);\n        const candidates = [];\n\n        for (const entry of entries) {\n            const parsed = this._parseTileId(entry?.id);\n            if (!parsed) continue;\n            const rootTile = this.rootTiles[parsed.rootIndex];\n            const tile = this._ensureTilePath(rootTile, parsed.path);\n            if (!tile) continue;\n            const tileId = (typeof tile.getTileId === 'function') ? tile.getTileId() : entry?.id;\n            if (!tileId || seenTileIds.has(tileId)) continue;\n            seenTileIds.add(tileId);\n            const score = this._scoreSnapshotReplayCandidate(tile, entry, focusLocalDir);\n            candidates.push({ tile, entry, score });\n        }\n        if (!candidates.length) return out;\n\n        candidates.sort((a, b) => {\n            if (b.score !== a.score) return b.score - a.score;\n            const aLevel = Number.isFinite(a?.tile?.level) ? a.tile.level : 0;\n            const bLevel = Number.isFinite(b?.tile?.level) ? b.tile.level : 0;\n            return bLevel - aLevel;\n        });\n\n        let collectedTiles = 0;\n        for (const candidate of candidates) {\n            if (collectedTiles >= tileLimit || out.length >= keyLimit) break;\n            const tile = candidate.tile;\n            if (!tile) continue;\n            collectedTiles += 1;\n            if (!tile.geometry && typeof tile.buildGeometry === 'function') {\n                tile.buildGeometry();\n            }\n            const baseDirs = tile.baseDirs;\n            const vertexCount = tile.vertexCount || (baseDirs ? (baseDirs.length / 3) : 0);\n            const resolution = tile.resolution;\n            if (!baseDirs || !vertexCount) continue;\n\n            const fullFetch = !!this.elevationClient?.isFullFetchTile?.(tile);\n            for (let i = 0; i < vertexCount; i += 1) {\n                if (!fullFetch &&\n                    this.elevationClient?.shouldRegisterVertex &&\n                    !this.elevationClient.shouldRegisterVertex(tile, i, resolution)) {\n                    continue;\n                }\n                const i3 = i * 3;\n                tmpDir.set(baseDirs[i3 + 0], baseDirs[i3 + 1], baseDirs[i3 + 2]);\n                const { latDeg, lonDeg } = dirToLatLonLocal(tmpDir);\n                const key = `${latDeg.toFixed(6)},${lonDeg.toFixed(6)}`;\n                if (seenKeys.has(key)) continue;\n                seenKeys.add(key);\n                out.push(key);\n                if (out.length >= keyLimit) {\n                    return out;\n                }\n            }\n        }\n\n        return out;\n    }\n\n    _resolveSnapshotReplayFocusLocalDir(focusWorldDir = null) {\n        if (!focusWorldDir || focusWorldDir.lengthSq() <= 1e-8) return null;\n        const worldQ = this._getWorldQuaternion();\n        this._tmpQuat.copy(worldQ).invert();\n        return this._tmpDir.copy(focusWorldDir).normalize().applyQuaternion(this._tmpQuat);\n    }\n\n    _scoreSnapshotReplayCandidate(tile, entry, focusLocalDir = null) {\n        const imageryZoom = Number.isFinite(entry?.imagery?.zoom)\n            ? Math.floor(entry.imagery.zoom)\n            : -1;\n        const level = Number.isFinite(tile?.level) ? tile.level : 0;\n        if (!focusLocalDir || !tile?.centerDir) {\n            return (imageryZoom * 100) + level;\n        }\n        const dot = THREE.MathUtils.clamp(tile.centerDir.dot(focusLocalDir), -1, 1);\n        const focusBoost = dot > 0.9995\n            ? 1_000_000\n            : (dot > 0.995 ? 250_000 : 0);\n        return focusBoost + (dot * 10_000) + (imageryZoom * 100) + level;\n    }\n\n    _hideSnapshotReplayAncestors(tile) {\n        let parent = tile?.parent || null;\n        while (parent) {\n            if (parent.mesh?.visible) {\n                parent.setVisible(false);\n                this._removeTileCollider(parent.mesh);\n                if (this.visibleTileCount > 0) {\n                    this.visibleTileCount -= 1;\n                }\n                if (Array.isArray(this.visibleMeshes) && parent.mesh) {\n                    const meshIdx = this.visibleMeshes.indexOf(parent.mesh);\n                    if (meshIdx >= 0) this.visibleMeshes.splice(meshIdx, 1);\n                }\n            }\n            if (Array.isArray(this.visibleLeafTiles)) {\n                const tileIdx = this.visibleLeafTiles.indexOf(parent);\n                if (tileIdx >= 0) this.visibleLeafTiles.splice(tileIdx, 1);\n            }\n            parent = parent.parent || null;\n        }\n    }\n\n    _restoreSnapshotTileFromCandidate(candidate, {\n        applyImagery = true,\n        forceVisible = true,\n        applyElevationFromCache = true\n    } = {}) {\n        const tile = candidate?.tile;\n        const entry = candidate?.entry;\n        if (!tile) return null;\n\n        tile.ensureMesh(this.group, this.material, this);\n        tile.applyRenderRules(this.renderRules);\n        if (forceVisible) {\n            this._hideSnapshotReplayAncestors(tile);\n            tile.setVisible(true);\n            if (tile.mesh?.visible) {\n                // Replay visibility must stay aligned with interaction state.\n                this._addTileCollider(tile.mesh);\n                if (Array.isArray(this.visibleMeshes) && !this.visibleMeshes.includes(tile.mesh)) {\n                    this.visibleMeshes.push(tile.mesh);\n                    this.visibleTileCount += 1;\n                }\n                if (Array.isArray(this.visibleLeafTiles) && !this.visibleLeafTiles.includes(tile)) {\n                    this.visibleLeafTiles.push(tile);\n                }\n            }\n        }\n\n        if (applyElevationFromCache && typeof tile.primeElevationFromClientCache === 'function') {\n            const seeded = tile.primeElevationFromClientCache({ markDone: true });\n            if (seeded > 0) {\n                this._snapshotReplayStats.elevationSeededVertices += seeded;\n                this._snapshotReplayStats.elevationSeededTiles += 1;\n            }\n        }\n\n        if (applyImagery && this.imageryManager && this.imageryManager.enabled) {\n            const imageryCfg = {\n                ...this.imageryManager.getConfig(),\n                rotation: this._getWorldQuaternion(),\n                rootZoom: this.imageryMinZoom,\n                // Snapshot replay should not be context-cancelled by current camera drift.\n                requestContextKey: null,\n                requestPriority: 3000\n            };\n\n            const snap = entry?.imagery;\n            const snapZoom = Number.isFinite(snap?.zoom) ? Math.max(0, Math.floor(snap.zoom)) : null;\n            const snapMinX = Number.isFinite(snap?.minX) ? Math.floor(snap.minX) : null;\n            const snapMinY = Number.isFinite(snap?.minY) ? Math.floor(snap.minY) : null;\n            const snapW = Number.isFinite(snap?.w) ? Math.max(1, Math.floor(snap.w)) : null;\n            const snapH = Number.isFinite(snap?.h) ? Math.max(1, Math.floor(snap.h)) : null;\n            const hasSnapshotAtlas = Number.isFinite(snapZoom) &&\n                Number.isFinite(snapMinX) &&\n                Number.isFinite(snapMinY) &&\n                Number.isFinite(snapW) &&\n                Number.isFinite(snapH);\n            let useSnapshotAtlas = hasSnapshotAtlas && this.snapshotReplayUseAtlasHints === true;\n            let snapMinXCanonical = snapMinX;\n            if (hasSnapshotAtlas && Number.isFinite(snapZoom)) {\n                const n = Math.max(1, Math.pow(2, snapZoom));\n                snapMinXCanonical = THREE.MathUtils.euclideanModulo(snapMinX, n);\n            }\n            if (useSnapshotAtlas && typeof tile._computeInheritedCoverageRatio === 'function') {\n                const coverageRatio = tile._computeInheritedCoverageRatio({\n                    atlasZoom: snapZoom,\n                    minX: snapMinXCanonical,\n                    minY: snapMinY,\n                    wTiles: snapW,\n                    hTiles: snapH\n                }, this.imageryManager);\n                const minCoverage = THREE.MathUtils.clamp(\n                    Number.isFinite(this.snapshotReplayAtlasMinCoverage)\n                        ? this.snapshotReplayAtlasMinCoverage\n                        : 0.9,\n                    0,\n                    1\n                );\n                if (!Number.isFinite(coverageRatio) || coverageRatio < minCoverage) {\n                    useSnapshotAtlas = false;\n                    this._snapshotReplayStats.atlasHintRejected += 1;\n                }\n            }\n            if (hasSnapshotAtlas && !useSnapshotAtlas && this.snapshotReplayUseAtlasHints !== true) {\n                this._snapshotReplayStats.atlasHintRejected += 1;\n            }\n            if (useSnapshotAtlas) {\n                imageryCfg.zoom = snapZoom;\n                imageryCfg.snapshotAtlas = {\n                    zoom: snapZoom,\n                    minX: snapMinXCanonical,\n                    minY: snapMinY,\n                    w: snapW,\n                    h: snapH\n                };\n                this._snapshotReplayStats.atlasHintTiles += 1;\n            }\n            tile.ensureImagery(this.imageryManager, imageryCfg, this.group);\n        }\n        return tile;\n    }\n\n    _drainSnapshotReplayQueue(maxTiles = null) {\n        const queue = this._snapshotReplayQueue;\n        if (!queue || !Array.isArray(queue.items) || queue.items.length === 0) {\n            this._snapshotReplayStats.lastFrameApplied = 0;\n            this._snapshotReplayStats.pending = 0;\n            return [];\n        }\n\n        const limit = Number.isFinite(maxTiles)\n            ? Math.max(0, Math.floor(maxTiles))\n            : Math.max(0, Math.floor(this.snapshotReplayPerFrame));\n        if (limit <= 0) return [];\n\n        const restored = [];\n        let applied = 0;\n        while (queue.index < queue.items.length && applied < limit) {\n            const candidate = queue.items[queue.index];\n            queue.index += 1;\n            const tile = this._restoreSnapshotTileFromCandidate(candidate, queue.options || {});\n            if (!tile) continue;\n            restored.push(tile);\n            applied += 1;\n        }\n\n        this._snapshotReplayStats.lastFrameApplied = applied;\n        this._snapshotReplayStats.totalApplied += applied;\n        this._snapshotReplayStats.totalDeferredApplied += applied;\n        if (applied > 0) {\n            this._enforceNoOverlap();\n        }\n\n        const pending = Math.max(0, queue.items.length - queue.index);\n        this._snapshotReplayStats.pending = pending;\n        if (pending <= 0) {\n            this._snapshotReplayQueue = null;\n        }\n        return restored;\n    }\n\n    restoreTilesFromSnapshot(entries, {\n        applyImagery = true,\n        forceVisible = true,\n        applyElevationFromCache = true,\n        focusWorldDir = null,\n        initialBudget = null,\n        perFrameBudget = null,\n        deferRemainder = true\n    } = {}) {\n        if (!Array.isArray(entries) || !this.rootTiles) return [];\n        const focusLocalDir = this._resolveSnapshotReplayFocusLocalDir(focusWorldDir);\n        if (Number.isFinite(perFrameBudget) && perFrameBudget > 0) {\n            this.snapshotReplayPerFrame = Math.max(1, Math.floor(perFrameBudget));\n        }\n\n        const candidates = [];\n        const seenTileIds = new Set();\n        for (const entry of entries) {\n            const parsed = this._parseTileId(entry?.id);\n            if (!parsed) continue;\n            const rootTile = this.rootTiles[parsed.rootIndex];\n            const tile = this._ensureTilePath(rootTile, parsed.path);\n            if (!tile) continue;\n            const tileId = (typeof tile.getTileId === 'function') ? tile.getTileId() : entry?.id;\n            if (!tileId || seenTileIds.has(tileId)) continue;\n            seenTileIds.add(tileId);\n            const score = this._scoreSnapshotReplayCandidate(tile, entry, focusLocalDir);\n            candidates.push({ entry, tile, score, tileId });\n        }\n        if (!candidates.length) {\n            this._snapshotReplayQueue = null;\n            this._snapshotReplayStats.lastQueued = 0;\n            this._snapshotReplayStats.lastImmediate = 0;\n            this._snapshotReplayStats.pending = 0;\n            return [];\n        }\n\n        candidates.sort((a, b) => {\n            if (b.score !== a.score) return b.score - a.score;\n            const aLevel = Number.isFinite(a?.tile?.level) ? a.tile.level : 0;\n            const bLevel = Number.isFinite(b?.tile?.level) ? b.tile.level : 0;\n            if (bLevel !== aLevel) return bLevel - aLevel;\n            return 0;\n        });\n        // If a deeper descendant is selected, block its ancestors to avoid replay overlap.\n        const filtered = [];\n        const blockedAncestors = new Set();\n        const ancestryOrder = [...candidates].sort((a, b) => {\n            const aLevel = Number.isFinite(a?.tile?.level) ? a.tile.level : 0;\n            const bLevel = Number.isFinite(b?.tile?.level) ? b.tile.level : 0;\n            if (bLevel !== aLevel) return bLevel - aLevel;\n            if (b.score !== a.score) return b.score - a.score;\n            return 0;\n        });\n        for (const candidate of ancestryOrder) {\n            const tile = candidate?.tile;\n            if (!tile) continue;\n            if (blockedAncestors.has(tile)) continue;\n            filtered.push(candidate);\n            let parent = tile.parent || null;\n            while (parent) {\n                blockedAncestors.add(parent);\n                parent = parent.parent || null;\n            }\n        }\n        if (!filtered.length) {\n            this._snapshotReplayQueue = null;\n            this._snapshotReplayStats.lastQueued = 0;\n            this._snapshotReplayStats.lastImmediate = 0;\n            this._snapshotReplayStats.pending = 0;\n            return [];\n        }\n        filtered.sort((a, b) => {\n            if (b.score !== a.score) return b.score - a.score;\n            const aLevel = Number.isFinite(a?.tile?.level) ? a.tile.level : 0;\n            const bLevel = Number.isFinite(b?.tile?.level) ? b.tile.level : 0;\n            return bLevel - aLevel;\n        });\n\n        const immediateLimit = deferRemainder\n            ? (Number.isFinite(initialBudget) && initialBudget > 0\n                ? Math.max(1, Math.floor(initialBudget))\n                : Math.max(1, Math.floor(this.snapshotReplayInitialBudget)))\n            : filtered.length;\n        const options = { applyImagery, forceVisible, applyElevationFromCache };\n        const immediateCount = Math.min(immediateLimit, filtered.length);\n        const restored = [];\n        for (let i = 0; i < immediateCount; i += 1) {\n            const tile = this._restoreSnapshotTileFromCandidate(filtered[i], options);\n            if (tile) restored.push(tile);\n        }\n\n        this._snapshotReplayStats.lastQueued = filtered.length;\n        this._snapshotReplayStats.lastImmediate = restored.length;\n        this._snapshotReplayStats.totalQueued += filtered.length;\n        this._snapshotReplayStats.totalApplied += restored.length;\n        this._snapshotReplayStats.totalImmediateApplied += restored.length;\n        this._snapshotReplayStats.pending = Math.max(0, filtered.length - immediateCount);\n        if (restored.length > 0) {\n            this._enforceNoOverlap();\n        }\n\n        if (deferRemainder && immediateCount < filtered.length) {\n            this._snapshotReplayQueue = {\n                items: filtered,\n                index: immediateCount,\n                options\n            };\n        } else {\n            this._snapshotReplayQueue = null;\n        }\n\n        return restored;\n    }\n\n    _getWorldQuaternion() {\n        const quat = this.group.getWorldQuaternion(new THREE.Quaternion());\n        // Debug: Invert quaternion if enabled for testing\n        if (this.debugInvertQuaternion) {\n            quat.invert();\n        }\n        return quat;\n    }\n\n    _directionInTileLocal(dir, tile) {\n        if (!dir || !tile) return false;\n        const v0 = tile.v0;\n        const v1 = tile.v1;\n        const v2 = tile.v2;\n        const center = tile.centerDir;\n        const eps = -1e-6;\n\n        const n0 = this._tmpEdge0.crossVectors(v0, v1);\n        if (n0.dot(center) < 0) n0.negate();\n        if (n0.dot(dir) < eps) return false;\n\n        const n1 = this._tmpEdge1.crossVectors(v1, v2);\n        if (n1.dot(center) < 0) n1.negate();\n        if (n1.dot(dir) < eps) return false;\n\n        const n2 = this._tmpEdge2.crossVectors(v2, v0);\n        if (n2.dot(center) < 0) n2.negate();\n        if (n2.dot(dir) < eps) return false;\n\n        return true;\n    }\n\n    _findClosestLeafTileForLocalDir(localDir) {\n        if (!localDir || !Array.isArray(this.rootTiles) || !this.rootTiles.length) return null;\n        let current = null;\n        let bestRootDot = -Infinity;\n        for (const root of this.rootTiles) {\n            if (!root?.centerDir) continue;\n            const dot = root.centerDir.dot(localDir);\n            if (dot > bestRootDot) {\n                bestRootDot = dot;\n                current = root;\n            }\n        }\n        if (!current) return null;\n\n        while (current.children && current.children.length) {\n            let bestChild = null;\n            let bestChildDot = -Infinity;\n            for (const child of current.children) {\n                if (!child?.centerDir) continue;\n                const dot = child.centerDir.dot(localDir);\n                if (dot > bestChildDot) {\n                    bestChildDot = dot;\n                    bestChild = child;\n                }\n            }\n            if (!bestChild) break;\n            current = bestChild;\n        }\n        return current;\n    }\n\n    findLeafTileForWorldDir(worldDir) {\n        if (!worldDir) return null;\n        const worldQ = this._getWorldQuaternion();\n        this._tmpQuat.copy(worldQ).invert();\n        const localDir = this._tmpDir.copy(worldDir).normalize().applyQuaternion(this._tmpQuat);\n\n        let current = null;\n        for (const root of this.rootTiles) {\n            if (this._directionInTileLocal(localDir, root)) {\n                current = root;\n                break;\n            }\n        }\n        if (!current) {\n            return this._findClosestLeafTileForLocalDir(localDir);\n        }\n\n        while (current.children && current.children.length) {\n            let found = null;\n            for (const child of current.children) {\n                if (this._directionInTileLocal(localDir, child)) {\n                    found = child;\n                    break;\n                }\n            }\n            if (!found) {\n                return this._findClosestLeafTileForLocalDir(localDir) || current;\n            }\n            current = found;\n        }\n\n        return current;\n    }\n\n    /**\n     * Sample the surface radius (terrain elevation included) along a world-space direction.\n     * Uses the closest vertex within the leaf tile containing the direction.\n     * @param {THREE.Vector3} worldDir\n     * @returns {number|null} radius in world units, or null if unavailable\n     */\n    getSurfaceRadiusAtDir(worldDir) {\n        if (!worldDir) return null;\n        const tile = this.findLeafTileForWorldDir(worldDir);\n        if (!tile || !tile.positionAttr || !tile.baseDirs) return null;\n\n        const posAttr = tile.positionAttr;\n        const base = tile.baseDirs;\n        const count = tile.vertexCount || (base ? base.length / 3 : 0);\n        if (!Number.isFinite(count) || count <= 0) return null;\n\n        const worldQ = this._getWorldQuaternion();\n        this._tmpQuat.copy(worldQ).invert();\n        const dir = this._tmpDir.copy(worldDir).normalize().applyQuaternion(this._tmpQuat);\n        const tmp = new THREE.Vector3();\n        let bestDot = -Infinity;\n        let bestRadius = null;\n\n        // Tile vertex positions are stored in local coordinates (relative to tile.center)\n        const cx = tile.center ? tile.center.x : 0;\n        const cy = tile.center ? tile.center.y : 0;\n        const cz = tile.center ? tile.center.z : 0;\n\n        for (let i = 0; i < count; i++) {\n            const i3 = i * 3;\n            tmp.set(base[i3 + 0], base[i3 + 1], base[i3 + 2]);\n            const dot = tmp.dot(dir);\n            if (dot > bestDot) {\n                bestDot = dot;\n                // Get local position and add tile center to get world position\n                const px = (posAttr.getX ? posAttr.getX(i) : (posAttr.array ? posAttr.array[i3 + 0] : 0)) + cx;\n                const py = (posAttr.getY ? posAttr.getY(i) : (posAttr.array ? posAttr.array[i3 + 1] : 0)) + cy;\n                const pz = (posAttr.getZ ? posAttr.getZ(i) : (posAttr.array ? posAttr.array[i3 + 2] : 0)) + cz;\n                const r = Math.sqrt(px * px + py * py + pz * pz);\n                bestRadius = r;\n            }\n        }\n\n        return Number.isFinite(bestRadius) ? bestRadius : null;\n    }\n\n    /**\n     * Raycast terrain along a direction (from outside toward the planet center) to get ground radius.\n     * Mirrors the surface camera sampling logic for accurate terrain-following height.\n     * @param {THREE.Vector3} worldDir\n     * @returns {number} radius in world units (falls back to PLANET_RADIUS if no hit)\n     */\n    sampleTerrainRadiusForDir(worldDir) {\n        if (!worldDir || !this.group) return PLANET_RADIUS;\n        this.group.updateMatrixWorld(true);\n\n        const dir = this._tmpDir.copy(worldDir).normalize();\n        const ellipsoidR = ellipsoidRadiusForWorldDir(dir, this.group);\n        const startR = (PLANET_RADIUS * 3.0) + 1_000_000.0;\n        this._tmpRayOrigin.copy(dir).multiplyScalar(startR);\n        this._tmpRayDir.copy(dir).negate();\n\n        this._terrainRaycaster.set(this._tmpRayOrigin, this._tmpRayDir);\n        this._terrainRaycaster.near = 0;\n        this._terrainRaycaster.far = startR + 10.0;\n\n        const intersectMeshRadius = (mesh) => {\n            if (!mesh || !mesh.geometry || mesh.geometry.boundingSphere === null) return null;\n            const prevVisible = mesh.visible;\n            if (!prevVisible) mesh.visible = true;\n            const hits = this._terrainRaycaster.intersectObject(mesh, false);\n            if (mesh.visible !== prevVisible) mesh.visible = prevVisible;\n            if (hits && hits.length && hits[0].point) {\n                return hits[0].point.length();\n            }\n            return null;\n        };\n\n        // First try the leaf under the direction, even if currently hidden\n        const leaf = this.findLeafTileForWorldDir(dir);\n        if (leaf) {\n            leaf.ensureMesh(this.group, this.material, this);\n            leaf.applyRenderRules(this.renderRules);\n            if (leaf.mesh) {\n                leaf.mesh.updateMatrixWorld(true);\n            }\n\n            // CRITICAL: Only trust raycast if tile has actual elevation data\n            // If elevation isn't ready yet, return ellipsoid radius so callers stay WGS84-aligned\n            if (!leaf.elevationHasData) {\n                return ellipsoidR;\n            }\n\n            // Ensure geometry bounds are up to date before raycasting\n            if (leaf.geometry && leaf._boundsDirty) {\n                leaf.geometry.computeBoundingSphere();\n                leaf._boundsDirty = false;\n            }\n\n            const hitR = intersectMeshRadius(leaf.mesh);\n            if (Number.isFinite(hitR)) return hitR;\n        }\n\n        // Fall back to any visible meshes that have elevation data\n        const visibleMeshes = typeof this.getVisibleMeshes === 'function'\n            ? this.getVisibleMeshes()\n            : this.visibleMeshes;\n        const meshes = Array.isArray(visibleMeshes)\n            ? visibleMeshes.filter(m => {\n                if (!m || !m.geometry || m.geometry.boundingSphere === null) return false;\n                const tile = m.userData?.tile;\n                return tile?.elevationHasData === true;\n            })\n            : [];\n        if (meshes.length) {\n            const hits = this._terrainRaycaster.intersectObjects(meshes, false);\n            if (hits && hits.length && hits[0].point) {\n                return hits[0].point.length();\n            }\n        }\n\n        return ellipsoidR;\n    }\n\n    _getCameraPosition(camera) {\n        const worldPos = camera?.userData?.worldPosition;\n        const pos = worldPos ? worldPos.clone() : camera.position.clone();\n        // Debug: Apply position sign flips\n        if (this.debugInvertCameraPos) {\n            pos.negate();\n        }\n        if (this.debugNegateCamPosX) {\n            pos.x = -pos.x;\n        }\n        if (this.debugNegateCamPosZ) {\n            pos.z = -pos.z;\n        }\n        return pos;\n    }\n\n    _getEllipsoidRadiusAtWorldDir(vec) {\n        return ellipsoidRadiusForWorldDir(vec, this.group);\n    }\n\n    _getAltitudeFromCamPos(camPos) {\n        if (!camPos) return 0;\n        const dist = camPos.length();\n        if (!Number.isFinite(dist) || dist <= 0) return 0;\n        const radius = this._getEllipsoidRadiusAtWorldDir(camPos);\n        return Math.max(0, dist - radius);\n    }\n\n    _getHorizonRad(camPos) {\n        if (!camPos) return 0;\n        const dist = camPos.length() || this.radius;\n        const radius = this._getEllipsoidRadiusAtWorldDir(camPos);\n        return Math.acos(THREE.MathUtils.clamp(radius / dist, -1, 1));\n    }\n\n    _getTileRadius(tile, tileDirWorld = null) {\n        if (Number.isFinite(tile?.centerRadius)) return tile.centerRadius;\n        if (tileDirWorld) return this._getEllipsoidRadiusAtWorldDir(tileDirWorld);\n        return this.radius;\n    }\n\n    _surfaceRingIndex(camPos, tileDirWorld, tileAngularRadius = 0) {\n        if (!camPos || !tileDirWorld) return 2;\n        const camDir = this._tmpSurfaceRingCamDir.copy(camPos).normalize();\n        const dot = THREE.MathUtils.clamp(tileDirWorld.dot(camDir), -1, 1);\n        const angle = Math.acos(dot);\n        const angularPad = Number.isFinite(tileAngularRadius) ? tileAngularRadius : 0;\n        const edgeAngle = Math.max(0, angle - angularPad);\n        const surfaceRadius = this._getEllipsoidRadiusAtWorldDir(tileDirWorld);\n        const arcDist = edgeAngle * surfaceRadius; // meters along surface\n        const alt = this._getAltitudeFromCamPos(camPos);\n        const effective = Math.max(arcDist, alt);\n        if (effective <= this.surfaceRingNearMeters) return 0;\n        if (effective <= this.surfaceRingMidMeters) return 1;\n        return 2;\n    }\n\n    _surfaceTierIndex(camPos) {\n        if (!camPos) return 2;\n        const alt = this._getAltitudeFromCamPos(camPos);\n        if (alt <= this.surfaceRingNearMeters) return 0;\n        if (alt <= this.surfaceRingMidMeters) return 1;\n        return 2;\n    }\n\n    _computeSurfaceRingCaps(camPos) {\n        const ringCaps = this.surfaceRingLodCaps || {};\n        const maxLevel = this.maxTileLevel ?? MAX_TILE_LEVEL;\n\n        let near = Number.isFinite(this.surfaceCurrentMaxLODNear) ? this.surfaceCurrentMaxLODNear : maxLevel;\n        let mid = Number.isFinite(this.surfaceCurrentMaxLODMid) ? this.surfaceCurrentMaxLODMid : near;\n        let far = Number.isFinite(this.surfaceCurrentMaxLODFar) ? this.surfaceCurrentMaxLODFar : mid;\n\n        if (Number.isFinite(ringCaps.mid)) mid = Math.min(mid, ringCaps.mid);\n        if (Number.isFinite(ringCaps.far)) far = Math.min(far, ringCaps.far);\n\n        mid = Math.min(mid, near);\n        far = Math.min(far, mid);\n\n        const tier = this._surfaceTierIndex(camPos);\n        if (tier === 1) {\n            near = mid;\n        } else if (tier >= 2) {\n            near = far;\n            mid = far;\n        }\n\n        this._surfaceTier = tier;\n        return { near, mid, far };\n    }\n\n    _surfaceRingLodCap(ring) {\n        const caps = this._surfaceRingCaps;\n        if (caps) {\n            if (ring === 0) return caps.near;\n            if (ring === 1) return caps.mid;\n            return caps.far;\n        }\n        if (ring === 0) return this.surfaceCurrentMaxLODNear;\n        if (ring === 1) return Math.min(this.surfaceRingLodCaps.mid, this.surfaceCurrentMaxLODMid);\n        return Math.min(this.surfaceRingLodCaps.far, this.surfaceCurrentMaxLODFar);\n    }\n\n    _surfaceDistanceLodCap(camPos, tileDirWorld, tileAngularRadius = 0) {\n        if (!camPos || !tileDirWorld) return null;\n\n        const nearDist = Math.max(1, Number.isFinite(this.surfaceRingNearMeters) ? this.surfaceRingNearMeters : 1);\n        let farDist = Number.isFinite(this.surfaceRingFarMeters) ? this.surfaceRingFarMeters : null;\n        if (!Number.isFinite(farDist) || farDist <= nearDist) {\n            const mid = Number.isFinite(this.surfaceRingMidMeters) ? this.surfaceRingMidMeters : nearDist * 2;\n            farDist = Math.max(mid * 8, nearDist * 4);\n        }\n\n        const camDir = camPos.clone().normalize();\n        const dot = THREE.MathUtils.clamp(tileDirWorld.dot(camDir), -1, 1);\n        const angle = Math.acos(dot);\n        const angularPad = Number.isFinite(tileAngularRadius) ? tileAngularRadius : 0;\n        const edgeAngle = Math.max(0, angle - angularPad);\n        const surfaceRadius = this._getEllipsoidRadiusAtWorldDir(tileDirWorld);\n        const arcDist = edgeAngle * surfaceRadius;\n        const alt = this._getAltitudeFromCamPos(camPos);\n        const effective = Math.max(arcDist, alt);\n\n        let nearLod = Number.isFinite(this.surfaceLodNear) ? this.surfaceLodNear : this.surfaceStageMaxLOD;\n        let farLod = Number.isFinite(this.surfaceLodFar) ? this.surfaceLodFar : this.surfaceStageMinLOD;\n        if (nearLod < farLod) {\n            const tmp = nearLod;\n            nearLod = farLod;\n            farLod = tmp;\n        }\n\n        const denom = Math.log1p(farDist / nearDist);\n        const t = denom > 0 ? (Math.log1p(Math.max(0, effective) / nearDist) / denom) : 1;\n        const falloff = THREE.MathUtils.clamp(t, 0, 1);\n        const cap = THREE.MathUtils.lerp(nearLod, farLod, falloff);\n        return THREE.MathUtils.clamp(cap, farLod, nearLod);\n    }\n\n    _tileElevationReadyRatio(tile) {\n        if (!tile) return 1.0;\n        if (tile.elevationFillComplete) {\n            const hasAnyData = !!tile.elevationHasData ||\n                (Number.isFinite(tile.elevationDone) && tile.elevationDone > 0) ||\n                (Number.isFinite(tile.elevationSeededCount) && tile.elevationSeededCount > 0);\n            if (hasAnyData) return 1.0;\n        }\n\n        let ratio = null;\n        if (typeof tile.getElevationReadyRatio === 'function') {\n            ratio = tile.getElevationReadyRatio();\n        } else if (typeof tile.getTileElevationCompleteness === 'function') {\n            ratio = tile.getTileElevationCompleteness();\n        }\n\n        let seededRatio = null;\n        if (Number.isFinite(tile.vertexCount) && tile.vertexCount > 0 &&\n            Number.isFinite(tile.elevationSeededCount)) {\n            seededRatio = tile.elevationSeededCount / tile.vertexCount;\n        }\n\n        const base = Number.isFinite(ratio) ? ratio : 0;\n        const seeded = Number.isFinite(seededRatio) ? seededRatio : 0;\n        return Math.min(1, Math.max(0, Math.max(base, seeded)));\n    }\n\n    _tileElevationAuthoritativeRatio(tile) {\n        if (!tile) return 1.0;\n        if (typeof tile.getElevationFetchStats === 'function') {\n            const stats = tile.getElevationFetchStats();\n            if (Number.isFinite(stats?.ratio)) {\n                return THREE.MathUtils.clamp(stats.ratio, 0, 1);\n            }\n        }\n\n        const count = Number.isFinite(tile.vertexCount) ? tile.vertexCount : 0;\n        const expected = (Number.isFinite(tile.elevationExpected) && tile.elevationExpected > 0)\n            ? tile.elevationExpected\n            : count;\n        const done = Number.isFinite(tile.elevationDone) ? tile.elevationDone : 0;\n        if (expected > 0) {\n            return THREE.MathUtils.clamp(done / expected, 0, 1);\n        }\n        return done > 0 ? 1.0 : 0.0;\n    }\n\n    /**\n     * Check if ring 0 (underfoot) tiles have sufficient elevation data.\n     * Used to delay building/infrastructure loading until terrain is ready.\n     * @param {number} threshold - Minimum readiness ratio (0-1), default 0.8\n     * @returns {boolean} true if ring 0 elevation is ready\n     */\n    isRing0ElevationReady(threshold = 0.8) {\n        if (!this._inSurfaceMode) return true; // No ring concept in orbit\n\n        const camera = this._lastCamera;\n        if (!camera) return false;\n\n        const camPos = this._getCameraPosition(camera);\n        if (!camPos) return false;\n\n        const worldQ = this._getWorldQuaternion();\n        let ring0TileCount = 0;\n        let ring0ReadyCount = 0;\n\n        const stack = [...this.rootTiles];\n        while (stack.length) {\n            const tile = stack.pop();\n            if (!tile) continue;\n\n            // Only check visible tiles\n            if (!tile.visible && !tile.hasPendingSplit) {\n                continue;\n            }\n\n            // Transform tile direction to world space\n            const tileDirWorld = this._tmpTileDir.copy(tile.centerDir);\n            tileDirWorld.applyQuaternion(worldQ);\n\n            const ring = this._surfaceRingIndex(camPos, tileDirWorld, tile.angularRadius);\n\n            if (ring === 0) {\n                ring0TileCount++;\n                const ratio = this._tileElevationReadyRatio(tile);\n                if (ratio >= threshold) {\n                    ring0ReadyCount++;\n                }\n            }\n\n            if (tile.children) {\n                stack.push(...tile.children);\n            }\n        }\n\n        // Need at least one ring 0 tile and majority ready\n        if (ring0TileCount === 0) return false;\n        return (ring0ReadyCount / ring0TileCount) >= 0.5;\n    }\n\n    _surfaceRingImageryCap(ring) {\n        if (ring === 0) return this.surfaceRingImageryCaps.near;\n        if (ring === 1) return this.surfaceRingImageryCaps.mid;\n        return this.surfaceRingImageryCaps.far;\n    }\n\n    _surfaceRingImageryStartCap(ring) {\n        if (ring === 0) return this.surfaceRingImageryStartCaps?.near;\n        if (ring === 1) return this.surfaceRingImageryStartCaps?.mid;\n        return this.surfaceRingImageryStartCaps?.far;\n    }\n\n    _surfaceRingImageryUpgradeMs(ring) {\n        if (ring === 0) return 0;\n        if (ring === 1) return this.surfaceRingImageryUpgradeMs?.mid ?? 0;\n        return this.surfaceRingImageryUpgradeMs?.far ?? 0;\n    }\n\n    _compareImageryCandidatesCenterOut(a, b) {\n        const aUnderfoot = a?.underfoot ? 1 : 0;\n        const bUnderfoot = b?.underfoot ? 1 : 0;\n        if (aUnderfoot !== bUnderfoot) return bUnderfoot - aUnderfoot;\n\n        const aFocus = a?.focus ? 1 : 0;\n        const bFocus = b?.focus ? 1 : 0;\n        if (aFocus !== bFocus) return bFocus - aFocus;\n\n        const aViewWeight = Number.isFinite(a?.viewWeight) ? a.viewWeight : 0;\n        const bViewWeight = Number.isFinite(b?.viewWeight) ? b.viewWeight : 0;\n        if (aViewWeight !== bViewWeight) return bViewWeight - aViewWeight;\n\n        const aRing = Number.isFinite(a?.ring) ? a.ring : Number.POSITIVE_INFINITY;\n        const bRing = Number.isFinite(b?.ring) ? b.ring : Number.POSITIVE_INFINITY;\n        if (aRing !== bRing) return aRing - bRing;\n\n        const aPriority = Number.isFinite(a?.priority) ? a.priority : -Infinity;\n        const bPriority = Number.isFinite(b?.priority) ? b.priority : -Infinity;\n        if (aPriority !== bPriority) return bPriority - aPriority;\n\n        const aLevel = Number.isFinite(a?.level) ? a.level : (a?.tile?.level ?? 0);\n        const bLevel = Number.isFinite(b?.level) ? b.level : (b?.tile?.level ?? 0);\n        return bLevel - aLevel;\n    }\n\n    _hideTileSubtreeMeshes(tile, { includeRoot = true } = {}) {\n        if (!tile) return;\n        const stack = [tile];\n        while (stack.length) {\n            const current = stack.pop();\n            if (!current) continue;\n            if (!includeRoot && current === tile) {\n                // Skip root visibility mutation, but still process descendants.\n            } else if (current.mesh?.visible) {\n                current.setVisible(false);\n                this._removeTileCollider(current.mesh);\n            } else if (current.mesh) {\n                this._removeTileCollider(current.mesh);\n            }\n            current._subtreeVisible = false;\n            if (Array.isArray(current.children) && current.children.length) {\n                for (const child of current.children) stack.push(child);\n            }\n        }\n    }\n\n    _enforceNoOverlap() {\n        let violations = 0;\n        const offenders = [];\n        const now = (typeof performance !== 'undefined' && performance.now)\n            ? performance.now()\n            : Date.now();\n\n        // Post-order traversal: process children first, then bubble up visibility info\n        // This ensures we only traverse each tile once (O(n) instead of O(n²))\n        const postOrderCheck = (tile) => {\n            if (!tile) return false;\n\n            // Leaf tile - return whether it has a visible mesh\n            if (!tile.children || !tile.children.length) {\n                return tile.mesh && tile.mesh.visible;\n            }\n\n            // Internal tile - check if any child subtree has visible meshes\n            let hasVisibleInSubtree = false;\n            for (const child of tile.children) {\n                if (postOrderCheck(child)) {\n                    hasVisibleInSubtree = true;\n                    // Don't break - need to process all children\n                }\n            }\n\n            // If any descendant is visible and this tile is also visible, hide this tile\n            if (hasVisibleInSubtree && tile.mesh && tile.mesh.visible) {\n                tile.setVisible(false);\n                this._removeTileCollider(tile.mesh);\n                tile._nonOverlapSuppressedUntil = now + (this._nonOverlapHoldoffMs || 0);\n                violations += 1;\n                if (this.visibleTileCount > 0) {\n                    this.visibleTileCount -= 1;\n                }\n                if (this.visibleMeshes && this.visibleMeshes.length) {\n                    const idx = this.visibleMeshes.indexOf(tile.mesh);\n                    if (idx >= 0) this.visibleMeshes.splice(idx, 1);\n                }\n                if (this.visibleLeafTiles && this.visibleLeafTiles.length) {\n                    const tileIdx = this.visibleLeafTiles.indexOf(tile);\n                    if (tileIdx >= 0) this.visibleLeafTiles.splice(tileIdx, 1);\n                }\n                if (offenders.length < 6) {\n                    const id = typeof tile.getTileId === 'function'\n                        ? tile.getTileId()\n                        : `L${tile.level}:${tile.index}`;\n                    offenders.push(id);\n                }\n            }\n\n            // Return true if this subtree has any visible mesh (either this tile or descendants)\n            return hasVisibleInSubtree || (tile.mesh && tile.mesh.visible);\n        };\n\n        // Process each root tile\n        for (const rootTile of this.rootTiles) {\n            postOrderCheck(rootTile);\n        }\n\n        if (violations > 0) {\n            const key = offenders.join(',');\n            const shouldWarn = (now - this._lastNonOverlapWarnMs) >= 1000 || key !== this._lastNonOverlapWarnKey;\n            if (shouldWarn) {\n                console.warn(\n                    `[LOD] Non-overlap violated; hid ${violations} parent tiles`,\n                    offenders\n                );\n                this._lastNonOverlapWarnMs = now;\n                this._lastNonOverlapWarnKey = key;\n            }\n        }\n    }\n\n    _orbitFalloffScale(camDistOrPos) {\n        const marginDeg = Number.isFinite(this.orbitFalloffMarginDeg)\n            ? Math.max(0, this.orbitFalloffMarginDeg)\n            : 0;\n        const anchorDeg = Number.isFinite(this.orbitFalloffAnchorDeg)\n            ? Math.max(1, this.orbitFalloffAnchorDeg)\n            : 65;\n        const camPos = camDistOrPos && typeof camDistOrPos.length === 'function'\n            ? camDistOrPos\n            : null;\n        const camDist = camPos ? camPos.length() : camDistOrPos;\n        if (!Number.isFinite(camDist) || camDist <= 0) return 1;\n        const horizonRad = camPos\n            ? this._getHorizonRad(camPos)\n            : Math.acos(THREE.MathUtils.clamp(this.radius / camDist, -1, 1));\n        const horizonDeg = horizonRad * RAD2DEG;\n        const targetDeg = horizonDeg + marginDeg;\n        if (!Number.isFinite(targetDeg) || targetDeg <= anchorDeg) return 1;\n        return anchorDeg / targetDeg;\n    }\n\n    _applyRulesToMaterial() {\n        if (!this.material) return;\n        this.material.wireframe = false;\n    }\n\n    setRenderRules(rules = {}) {\n        this.renderRules = { ...this.renderRules, ...rules };\n        this._applyRulesToMaterial();\n\n        // Unified mode: imagery loading stays active in both modes. Wireframe just\n        // swaps the material — elevation, LOD tree, and imagery state are untouched.\n        // Imagery continues loading in the background during wireframe so everything\n        // is ready when switching back to textured.\n\n        const stack = [...this.rootTiles];\n        while (stack.length) {\n            const tile = stack.pop();\n            tile.applyRenderRules(this.renderRules);\n            if (tile.children) stack.push(...tile.children);\n        }\n\n        this._enforceNoOverlap();\n    }\n\n    /**\n     * Refresh wireframe overlays on all tiles\n     * Called when wireframe line overlay setting changes\n     */\n    refreshWireframeOverlays() {\n        if (!this.renderRules?.wireframe) return;\n        const stack = [...this.rootTiles];\n        while (stack.length) {\n            const tile = stack.pop();\n            if (tile.wireframeEnabled && tile.mesh) {\n                // Re-call _ensureWireframeOverlay to apply current setting\n                tile._ensureWireframeOverlay?.();\n            }\n            if (tile.children) stack.push(...tile.children);\n        }\n    }\n\n    _subdivideRootsToLevel(targetLevel = 2) {\n        if (targetLevel <= 0) return;\n        const stack = [...this.rootTiles];\n        while (stack.length) {\n            const tile = stack.pop();\n            if (tile.level >= targetLevel) continue;\n            if (!tile.children) {\n                tile.subdivide();\n                // EDGE CASE FIX: Prepare children for split even during initial subdivision\n                // This ensures fallback colors are inherited from parent imagery\n                tile.prepareChildrenForSplit();\n                this.tileCount += tile.children.length;\n                // Never leave parent meshes visible once children exist.\n                tile.removeMesh?.(this.group);\n            }\n            stack.push(...tile.children);\n        }\n    }\n\n    _initBasePreloadQueue() {\n        if (!this.basePreloadEnabled || this._basePreloadInitialized) return;\n        if (!this.imageryManager || !this.imageryManager.enabled) {\n            this._basePreloadInitialized = true;\n            return;\n        }\n        const level = Number.isFinite(this.basePreloadLevel)\n            ? Math.max(0, Math.floor(this.basePreloadLevel))\n            : 0;\n        if (level <= 0) {\n            this._basePreloadInitialized = true;\n            return;\n        }\n\n        if (!this._rootsSubdivided) {\n            this._subdivideRootsToLevel(level);\n            this._rootsSubdivided = true;\n        }\n\n        const queue = [];\n        const stack = [...this.rootTiles];\n        while (stack.length) {\n            const tile = stack.pop();\n            if (!tile) continue;\n            if (tile.level === level) {\n                queue.push(tile);\n            } else if (tile.children && tile.level < level) {\n                stack.push(...tile.children);\n            }\n        }\n\n        for (const tile of queue) {\n            tile.ensureMesh(this.group, this.material, this);\n            tile.applyRenderRules(this.renderRules);\n        }\n\n        this._basePreloadQueue = queue;\n        this._basePreloadInitialized = true;\n    }\n\n    _processBasePreloadQueue() {\n        if (!this.basePreloadEnabled || !this.imageryManager || !this.imageryManager.enabled) return;\n        if (!this._basePreloadInitialized) this._initBasePreloadQueue();\n        if (!this._basePreloadQueue || this._basePreloadQueue.length === 0) return;\n\n        const zoom = Number.isFinite(this.basePreloadZoom)\n            ? Math.max(0, Math.floor(this.basePreloadZoom))\n            : null;\n        if (!Number.isFinite(zoom)) return;\n        const minZoom = Number.isFinite(this.basePreloadMinZoom)\n            ? Math.max(0, Math.floor(this.basePreloadMinZoom))\n            : null;\n        const maxAtlasTiles = Number.isFinite(this.basePreloadMaxAtlasTiles)\n            ? Math.max(1, Math.floor(this.basePreloadMaxAtlasTiles))\n            : this.imageryManager.maxAtlasTiles;\n        const padTiles = Number.isFinite(this.basePreloadPadTiles)\n            ? Math.max(0, Math.floor(this.basePreloadPadTiles))\n            : this.imageryManager.padTiles;\n        const perFrame = Number.isFinite(this.basePreloadPerFrame)\n            ? Math.max(1, Math.floor(this.basePreloadPerFrame))\n            : 4;\n        const priority = Number.isFinite(this.basePreloadPriority)\n            ? this.basePreloadPriority\n            : -10;\n        const versionId = this.imageryManager.versionId;\n        const contextKey = this._imageryContextKey;\n\n        let processed = 0;\n        while (processed < perFrame && this._basePreloadQueue.length) {\n            const tile = this._basePreloadQueue[0];\n            if (!tile) {\n                this._basePreloadQueue.shift();\n                continue;\n            }\n\n            if (this._hasBaseImageryCoverage(tile, versionId)) {\n                this._basePreloadQueue.shift();\n                continue;\n            }\n\n            if (tile.imageryPendingKey) {\n                const pendingVersionMatches = !tile.imageryVersion || tile.imageryVersion === versionId;\n                if (!pendingVersionMatches) {\n                    tile.imageryPendingKey = null;\n                    tile.imageryRequestedZoom = null;\n                    tile.imageryPendingUv = null;\n                    tile.imageryPendingSince = null;\n                    tile.imageryPendingAttempts = 0;\n                } else {\n                    // Let pending requests complete. Base preload runs at a fixed zoom, and\n                    // valid regional fallback can settle at lower atlas zooms.\n                    this._basePreloadQueue.push(this._basePreloadQueue.shift());\n                    processed++;\n                    continue;\n                }\n            }\n\n            tile.ensureMesh(this.group, this.material, this);\n            tile.applyRenderRules(this.renderRules);\n\n            tile.ensureImagery(this.imageryManager, {\n                enabled: true,\n                versionId,\n                zoom,\n                minZoom,\n                maxAtlasTiles,\n                padTiles,\n                requestPriority: priority,\n                requestContextKey: contextKey\n            }, this.group);\n\n            this._basePreloadQueue.push(this._basePreloadQueue.shift());\n            processed++;\n        }\n    }\n\n    _enqueueBasePreloadTile(tile, reason = '') {\n        if (!this.basePreloadEnabled || !tile) return;\n        if (!Number.isFinite(this.basePreloadLevel)) return;\n        if (tile.level > this.basePreloadLevel) return;\n        if (!this._basePreloadQueue) this._basePreloadQueue = [];\n        if (this._basePreloadQueue.includes(tile)) return;\n        this._basePreloadQueue.push(tile);\n        if (reason) {\n            console.log(`[IMAGERY] Re-queued base preload tile L${tile.level} (${reason})`);\n        }\n    }\n\n    _hasBaseImageryCoverage(tile, versionId) {\n        if (!tile) return false;\n        if (versionId && tile.imageryVersion && tile.imageryVersion !== versionId) return false;\n        if (typeof tile.hasImageryCoverage === 'function' && tile.hasImageryCoverage()) {\n            return true;\n        }\n        const map = tile.mesh?.material?.map || tile.materialDefault?.map;\n        const image = map?.image || map?.source?.data || map?.source?.image;\n        const width = Number(image?.videoWidth ?? image?.naturalWidth ?? image?.width ?? 0);\n        const height = Number(image?.videoHeight ?? image?.naturalHeight ?? image?.height ?? 0);\n        const hasRenderableMap = width > 1 && height > 1;\n        const atlasZoom = Number.isFinite(tile.imageryAtlasZoom) ? tile.imageryAtlasZoom : tile.imageryZoom;\n        const hasAtlasBinding = !!(\n            tile.imageryTexture &&\n            tile.imageryAtlasKey &&\n            Number.isFinite(atlasZoom) &&\n            Number.isFinite(tile.imageryAtlasMinX) &&\n            Number.isFinite(tile.imageryAtlasMinY) &&\n            Number.isFinite(tile.imageryAtlasW) &&\n            tile.imageryAtlasW > 0 &&\n            Number.isFinite(tile.imageryAtlasH) &&\n            tile.imageryAtlasH > 0\n        );\n        return hasRenderableMap && hasAtlasBinding;\n    }\n\n    _buildImageryConfigForTile(tile, baseConfig, zoom, request = null) {\n        if (!baseConfig) return null;\n\n        const config = {\n            ...baseConfig,\n            zoom\n        };\n\n        // CRITICAL FIX: The pre-subdivided level-2 tiles are so massive that they collapse to\n        // zoom 0-2 no matter what atlas budget we give them, causing all ~320 tiles to calculate\n        // identical WMTS bounds and receive the same texture on page load.\n        //\n        // SOLUTION: Don't load imagery for initial pre-subdivided tiles via the dynamic path.\n        // Base preload handles LOD2 imagery upfront so it can be inherited as fallback.\n        // Child tiles (level 3+) will load their own unique imagery normally.\n        if (this.basePreloadEnabled && tile.level <= this.initialSubdivLevel) {\n            const hasReadyImagery = this._hasBaseImageryCoverage(tile, baseConfig.versionId);\n            if (hasReadyImagery) {\n                return null;\n            }\n        }\n\n        // Normal tiles (level 3+): standard config\n        if (baseConfig.padTiles === undefined && this.imageryManager) {\n            config.padTiles = this.imageryManager.padTiles;\n        }\n        if (baseConfig.maxAtlasTiles === undefined && this.imageryManager) {\n            config.maxAtlasTiles = this.imageryManager.maxAtlasTiles;\n        }\n\n        if (this._inSurfaceMode && tile.level > this.initialSubdivLevel) {\n            // Half-texel UV clamping already prevents atlas bleed. A full tile\n            // of padding turns a fine one-tile leaf into a 3x3 request and\n            // multiplies both downloads and canvas work for no visible gain.\n            config.padTiles = 0;\n            config.maxAtlasTiles = Math.min(\n                4,\n                Math.max(1, Number.isFinite(config.maxAtlasTiles) ? config.maxAtlasTiles : 4)\n            );\n\n            // An atlas span larger than the cap makes TriTile step down source\n            // zoom until it fits. That is correct for broad coverage, but it\n            // made the not-yet-fully-subdivided center visibly blurry even\n            // though native z18/z19 imagery was available. Permit a bounded\n            // larger atlas only underfoot and within the immediate local\n            // footprint; nearby/far leaves retain the low-lag 4x4 contract.\n            const underfoot = request?.underfoot === true;\n            const focus = request?.focus === true;\n            const edgeDistance = Number.isFinite(tile?._surfaceEdgeDistanceM)\n                ? tile._surfaceEdgeDistanceM\n                : Infinity;\n            const nearRadius = Number.isFinite(this.surfaceNearAtlasRadiusMeters)\n                ? Math.max(0, this.surfaceNearAtlasRadiusMeters)\n                : 0;\n            const immediateNear = edgeDistance <= nearRadius;\n            if (underfoot) {\n                config.maxAtlasTiles = Math.max(\n                    config.maxAtlasTiles,\n                    Math.max(4, Math.floor(this.surfaceUnderfootMaxAtlasTiles || 8))\n                );\n            } else if (immediateNear || (focus && edgeDistance <= nearRadius * 2)) {\n                config.maxAtlasTiles = Math.max(\n                    config.maxAtlasTiles,\n                    Math.max(4, Math.floor(this.surfaceNearMaxAtlasTiles || 6))\n                );\n            }\n        }\n\n        if (this.imageryCoverageRequiredForRefinement === false && !tile.hasImageryCoverage()) {\n            // A small regional atlas provides first coverage quickly. Its\n            // lower requested zoom remains eligible for the normal native\n            // upgrade after it binds; native quality targets do not change.\n            config.zoom = Math.min(config.zoom, tile.level + 1);\n        }\n        return config;\n    }\n\n    _computeImageryBackpressureState() {\n        const fallbackState = {\n            active: false,\n            pressureScore: 0,\n            tileQueue: 0,\n            atlasQueue: 0,\n            tileQueueRatio: 0,\n            atlasQueueRatio: 0,\n            tileLoadRatio: 0,\n            atlasLoadRatio: 0\n        };\n\n        if (!this.imageryBackpressureEnabled || !this.imageryManager?.getStats) {\n            this._imageryBackpressureState = fallbackState;\n            return this._imageryBackpressureState;\n        }\n\n        const managerCfg = (typeof this.imageryManager.getConfig === 'function')\n            ? (this.imageryManager.getConfig() || {})\n            : {};\n        const isDesktopImageryProfile = managerCfg.useMobileTiles !== true;\n        if (!isDesktopImageryProfile) {\n            this._imageryBackpressureState = fallbackState;\n            return this._imageryBackpressureState;\n        }\n\n        const stats = this.imageryManager.getStats({ includeOwnership: false }) || {};\n        const tileQueue = Number.isFinite(stats.tileQueue) ? stats.tileQueue : 0;\n        const atlasQueue = Number.isFinite(stats.atlasQueue) ? stats.atlasQueue : 0;\n        const maxQueuedTileRequests = Number.isFinite(managerCfg.maxQueuedTileRequests)\n            ? Math.max(1, Math.floor(managerCfg.maxQueuedTileRequests))\n            : 4096;\n        const maxQueuedAtlasRequests = Number.isFinite(managerCfg.maxQueuedAtlasRequests)\n            ? Math.max(1, Math.floor(managerCfg.maxQueuedAtlasRequests))\n            : 1024;\n        const tileQueueRatio = tileQueue / maxQueuedTileRequests;\n        const atlasQueueRatio = atlasQueue / maxQueuedAtlasRequests;\n\n        const currentTileLoads = Number.isFinite(stats.currentTileLoads) ? stats.currentTileLoads : 0;\n        const maxConcurrentTileLoads = Number.isFinite(stats.maxConcurrentTileLoads)\n            ? Math.max(1, Math.floor(stats.maxConcurrentTileLoads))\n            : 1;\n        const currentAtlasBuilds = Number.isFinite(stats.currentAtlasBuilds) ? stats.currentAtlasBuilds : 0;\n        const maxConcurrentAtlasBuilds = Number.isFinite(stats.maxConcurrentAtlasBuilds)\n            ? Math.max(1, Math.floor(stats.maxConcurrentAtlasBuilds))\n            : 1;\n        const tileLoadRatio = currentTileLoads / maxConcurrentTileLoads;\n        const atlasLoadRatio = currentAtlasBuilds / maxConcurrentAtlasBuilds;\n\n        const pressureScore = Math.max(tileQueueRatio, atlasQueueRatio, tileLoadRatio, atlasLoadRatio);\n        const hardQueuePressure = tileQueue >= this.imageryBackpressureTileQueueHardLimit ||\n            atlasQueue >= this.imageryBackpressureAtlasQueueHardLimit;\n        const wasActive = !!this._imageryBackpressureState?.active;\n        const shouldEnable = hardQueuePressure || pressureScore >= this.imageryBackpressureActivateThreshold;\n        const shouldDisable = !hardQueuePressure && pressureScore <= this.imageryBackpressureReleaseThreshold;\n        const active = wasActive ? !shouldDisable : shouldEnable;\n\n        if (active !== wasActive) {\n            const scoreText = Number.isFinite(pressureScore) ? pressureScore.toFixed(2) : 'n/a';\n            console.info(\n                `[IMAGERY] backpressure ${active ? 'enabled' : 'cleared'} ` +\n                `(score=${scoreText}, tileQ=${tileQueue}, atlasQ=${atlasQueue}, ` +\n                `tileLoads=${currentTileLoads}/${maxConcurrentTileLoads}, ` +\n                `atlasBuilds=${currentAtlasBuilds}/${maxConcurrentAtlasBuilds})`\n            );\n        }\n\n        this._imageryBackpressureState = {\n            active,\n            pressureScore,\n            tileQueue,\n            atlasQueue,\n            tileQueueRatio,\n            atlasQueueRatio,\n            tileLoadRatio,\n            atlasLoadRatio\n        };\n\n        return this._imageryBackpressureState;\n    }\n\n    _resolveImageryRequestZoom(tile, targetZoom, ringOrOptions = null) {\n        if (!Number.isFinite(targetZoom)) return targetZoom;\n\n        let ring = null;\n        let isBlankOpt = null;\n        let underfoot = false;\n        let focus = false;\n\n        if (ringOrOptions && typeof ringOrOptions === 'object' && !Array.isArray(ringOrOptions)) {\n            ring = ringOrOptions.ring;\n            if (typeof ringOrOptions.isBlank === 'boolean') {\n                isBlankOpt = ringOrOptions.isBlank;\n            }\n            underfoot = !!ringOrOptions.underfoot;\n            focus = !!ringOrOptions.focus;\n        } else {\n            ring = ringOrOptions;\n        }\n\n        const minZoom = Number.isFinite(this.imageryMinZoom)\n            ? Math.max(0, Math.floor(this.imageryMinZoom))\n            : 0;\n        const clampedTarget = Math.max(minZoom, Math.floor(targetZoom));\n        let requestZoom = clampedTarget;\n\n        const hasImagery = !!(tile?.imageryReady || tile?.imageryInherited);\n        const isBlank = (typeof isBlankOpt === 'boolean') ? isBlankOpt : !hasImagery;\n        const now = Number.isFinite(this._frameNow)\n            ? this._frameNow\n            : ((typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now());\n\n        const resolvedRing = Number.isFinite(ring)\n            ? Math.max(0, Math.floor(ring))\n            : (Number.isFinite(tile?._imageryVisibleRing) ? Math.max(0, Math.floor(tile._imageryVisibleRing)) : 2);\n\n        if (this.imageryCoverFirstEnabled) {\n            // Keep lower-zoom pending requests alive long enough for first coverage to appear.\n            const pendingZoom = Number.isFinite(tile?.imageryRequestedZoom)\n                ? tile.imageryRequestedZoom\n                : tile?.imageryTargetZoom;\n            const pendingAgeMs = Number.isFinite(tile?.imageryPendingSince)\n                ? (now - tile.imageryPendingSince)\n                : Infinity;\n            if (isBlank &&\n                tile?.imageryPendingKey &&\n                Number.isFinite(pendingZoom) &&\n                pendingAgeMs <= this.imageryPendingStallMs) {\n                requestZoom = Math.min(requestZoom, Math.max(minZoom, Math.floor(pendingZoom)));\n            } else if (isBlank && this._inSurfaceMode && !underfoot && !focus) {\n                const visibleSince = Number.isFinite(tile?._imageryVisibleSince) ? tile._imageryVisibleSince : now;\n                const visibleAgeMs = Math.max(0, now - visibleSince);\n                if (visibleAgeMs <= this.imageryCoverBootstrapWindowMs) {\n                    const treatAsUnderfoot = underfoot || resolvedRing === 0;\n                    const gap = treatAsUnderfoot\n                        ? this.imageryCoverUnderfootZoomGap\n                        : this.imageryCoverZoomGap;\n                    const minCoverZoom = treatAsUnderfoot\n                        ? this.imageryCoverUnderfootMinZoom\n                        : this.imageryCoverMinZoom;\n                    const coverZoom = Math.max(\n                        minZoom,\n                        Number.isFinite(minCoverZoom) ? Math.floor(minCoverZoom) : minZoom,\n                        requestZoom - Math.max(0, Math.floor(gap))\n                    );\n                    if (coverZoom < requestZoom) {\n                        requestZoom = coverZoom;\n                    }\n                }\n            }\n        }\n\n        if (this._inSurfaceMode && this.imageryBootstrapEnabled && isBlank && !underfoot && !focus) {\n            const maxRing = Number.isFinite(this.imageryBootstrapMaxRing)\n                ? Math.max(0, Math.floor(this.imageryBootstrapMaxRing))\n                : 1;\n            if (underfoot || focus || resolvedRing <= maxRing) {\n                const delta = Number.isFinite(this.imageryBootstrapDeltaZoom)\n                    ? Math.max(0, Math.floor(this.imageryBootstrapDeltaZoom))\n                    : 0;\n                if (delta > 0) {\n                    requestZoom = Math.max(minZoom, requestZoom - delta);\n                    const ringStartCap = this._surfaceRingImageryStartCap(resolvedRing);\n                    if (Number.isFinite(ringStartCap)) {\n                        requestZoom = Math.min(requestZoom, Math.floor(ringStartCap));\n                    }\n                }\n            }\n        }\n\n        const backpressureState = this._imageryBackpressureState;\n        if (backpressureState?.active && this.imageryBackpressureDropZoomEnabled) {\n            const preserveCenterQuality = underfoot || focus || resolvedRing === 0;\n            if (!preserveCenterQuality) {\n                let zoomDrop = this.imageryBackpressureZoomDropFar;\n                if (resolvedRing <= 1) {\n                    zoomDrop = this.imageryBackpressureZoomDropMid;\n                }\n                if (resolvedRing <= 0) {\n                    zoomDrop = this.imageryBackpressureZoomDropNear;\n                }\n                if (Number.isFinite(backpressureState.pressureScore) &&\n                    backpressureState.pressureScore >= this.imageryBackpressureExtraDropThreshold) {\n                    zoomDrop += 1;\n                }\n                const minBackpressureZoom = Number.isFinite(this.imageryBackpressureMinZoom)\n                    ? Math.max(minZoom, Math.floor(this.imageryBackpressureMinZoom))\n                    : minZoom;\n                requestZoom = Math.max(minBackpressureZoom, requestZoom - Math.max(0, Math.floor(zoomDrop)));\n            }\n        }\n\n        return Math.min(clampedTarget, requestZoom);\n    }\n\n\n    _imageryZoomForTile(tile, camera) {\n        const camPos = this._getCameraPosition(camera);\n\n        // Transform tile direction to world space (accounting for Earth rotation AND axial tilt)\n        const cache = this._viewportCache;\n        const tileDirWorld = this._tmpTileDir.copy(tile.centerDir);\n        const worldQ = cache?.worldQ || this._getWorldQuaternion();\n        tileDirWorld.applyQuaternion(worldQ);\n\n        const tileRadius = this._getTileRadius(tile, tileDirWorld);\n        const tileCenterWorld = this._tmpTileCenter.copy(tileDirWorld).multiplyScalar(tileRadius);\n        const distance = Math.max(1, camPos.distanceTo(tileCenterWorld));\n        const metersPerPixel = this._metersPerPixel(distance, camera);\n        let z = this._wmtsZoomForMetersPerPixel(metersPerPixel);\n\n        if (!this._inSurfaceMode && this._orbitPreloadActive && this._orbitImageryBias) {\n            z += this._orbitImageryBias;\n        }\n\n        const focusDir = this.viewFocusDir || camPos.clone().normalize();\n        const dotF = THREE.MathUtils.clamp(tileDirWorld.dot(focusDir), -1, 1);\n        const angleDeg = Math.acos(dotF) * RAD2DEG;\n        const surfaceRing = this._surfaceRingIndex(camPos, tileDirWorld, tile.angularRadius);\n        const camDir = this._tmpCamDir.copy(camPos).normalize();\n        const camAngle = Math.acos(THREE.MathUtils.clamp(tileDirWorld.dot(camDir), -1, 1));\n        const surfaceEdgeAngle = Math.max(0, camAngle - (tile.angularRadius || 0));\n        const surfaceEdgeDistance = surfaceEdgeAngle * this._getEllipsoidRadiusAtWorldDir(tileDirWorld);\n        tile._surfaceEdgeDistanceM = surfaceEdgeDistance;\n        const containsCameraSubpoint = surfaceEdgeAngle <= 1e-9;\n        const viewMetric = this._inSurfaceMode\n            ? this._cacheSurfaceTileViewMetrics(tile, camera, tileDirWorld)\n            : null;\n\n        z = Math.floor(z);\n\n        // Taper the resolution boost continuously through the near field.\n        // This keeps the center sharp without forcing a multi-kilometre ring\n        // of unrelated triangles to request the same maximum zoom.\n        if (this.imageryResolutionBoost > 0 && surfaceRing === 0) {\n            const nearMeters = Math.max(1, this.surfaceRingNearMeters || 1);\n            const nearWeight = 1 - THREE.MathUtils.clamp(surfaceEdgeDistance / nearMeters, 0, 1);\n            z += Math.ceil(this.imageryResolutionBoost * nearWeight);\n        }\n        if (this._inSurfaceMode && this.surfaceViewCenterImageryBoost > 0) {\n            const viewWeight = Number.isFinite(viewMetric?._surfaceViewWeight)\n                ? viewMetric._surfaceViewWeight\n                : 0;\n            z += Math.ceil(this.surfaceViewCenterImageryBoost * viewWeight);\n        }\n\n        let surfaceCap = null;\n        if (this._inSurfaceMode) {\n            surfaceCap = Number.isFinite(this.surfaceImageryMaxZoom)\n                ? this.surfaceImageryMaxZoom\n                : this.imageryMaxZoom;\n\n            // Pin only the triangle that actually contains the camera's surface\n            // subpoint. Nearby leaves keep the screen-resolution result above,\n            // producing a smooth center-out imagery pyramid.\n            if (surfaceRing === 0 && containsCameraSubpoint) {\n                z = surfaceCap;\n            } else {\n                const farAngle = Number.isFinite(this.surfaceImageryFarAngleDeg)\n                    ? this.surfaceImageryFarAngleDeg\n                    : null;\n                if (farAngle !== null && angleDeg > farAngle) {\n                    const farCap = Number.isFinite(this.surfaceImageryFarMaxZoom)\n                        ? this.surfaceImageryFarMaxZoom\n                        : surfaceCap;\n                    z = Math.min(z, Math.min(surfaceCap, farCap));\n                } else {\n                    z = Math.min(z, surfaceCap);\n                }\n\n                const ringZoomCap = this._surfaceRingImageryCap(surfaceRing);\n                let effectiveRingCap = ringZoomCap;\n                if (surfaceRing > 0 && Number.isFinite(ringZoomCap)) {\n                    const ringStartCap = this._surfaceRingImageryStartCap(surfaceRing);\n                    if (Number.isFinite(ringStartCap)) {\n                        const now = Number.isFinite(this._frameNow)\n                            ? this._frameNow\n                            : ((typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now());\n                        const since = Number.isFinite(tile._imageryVisibleSince) ? tile._imageryVisibleSince : now;\n                        const ageMs = Math.max(0, now - since);\n                        const upgradeMs = this._surfaceRingImageryUpgradeMs(surfaceRing);\n                        const t = upgradeMs > 0 ? THREE.MathUtils.clamp(ageMs / upgradeMs, 0, 1) : 1;\n                        const minCap = Math.min(ringStartCap, ringZoomCap);\n                        const maxCap = Math.max(ringStartCap, ringZoomCap);\n                        effectiveRingCap = THREE.MathUtils.lerp(minCap, maxCap, t);\n                    }\n                }\n                if (Number.isFinite(effectiveRingCap)) {\n                    z = Math.min(z, Math.floor(effectiveRingCap));\n                }\n            }\n        }\n\n        const policyMin = Number.isFinite(this._detailPolicy?.imageryMinZoom)\n            ? this._detailPolicy.imageryMinZoom\n            : this.imageryMinZoom;\n        // For ring 0 in surface mode, use full surface cap (not policy-limited)\n        // This ensures underfoot tiles always request maximum imagery resolution\n        const policyMax = (this._inSurfaceMode && surfaceRing === 0)\n            ? (Number.isFinite(surfaceCap) ? surfaceCap : this.imageryMaxZoom)\n            : (Number.isFinite(this._detailPolicy?.imageryMaxZoom)\n                ? this._detailPolicy.imageryMaxZoom\n                : this.imageryMaxZoom);\n        return Math.max(policyMin, Math.min(policyMax, z));\n    }\n\n    /**\n     * Cache an allocation-free screen-space view metric on a tile for the\n     * current traversal. The tile's projected angular radius is subtracted\n     * from its center angle, so large ancestors remain traversable when any\n     * part of their footprint intersects the camera view.\n     */\n    _cacheSurfaceTileViewMetrics(tile, camera, tileDirWorld = null) {\n        if (!tile) return null;\n        if (tile._surfaceViewMetricStamp === this._viewportStamp) return tile;\n\n        const cache = this._viewportCache;\n        const camPos = cache?.camPos || this._getCameraPosition(camera);\n        const viewDir = cache?.viewDir;\n        const halfFov = Number.isFinite(cache?.viewHalfFovRad)\n            ? cache.viewHalfFovRad\n            : ((Number.isFinite(camera?.fov) ? camera.fov : 60) * DEG2RAD * 0.5);\n        const bufferRad = Math.max(0, Number(this.surfaceViewBufferDeg) || 0) * DEG2RAD;\n\n        let edgeAngle = 0;\n        let centerAngle = 0;\n        let apparentRadius = Math.PI * 0.5;\n        if (viewDir && camPos) {\n            const worldQ = cache?.worldQ || this._getWorldQuaternion();\n            const direction = tileDirWorld || this._tmpTileDir.copy(tile.centerDir).applyQuaternion(worldQ);\n            const tileRadius = this._getTileRadius(tile, direction);\n            const tileCenter = this._tmpViewTileCenter.copy(direction).multiplyScalar(tileRadius);\n            const toTile = this._tmpViewToTile.copy(tileCenter).sub(camPos);\n            const distance = Math.max(1e-6, toTile.length());\n            toTile.multiplyScalar(1 / distance);\n            centerAngle = Math.acos(THREE.MathUtils.clamp(toTile.dot(viewDir), -1, 1));\n            const physicalRadius = Math.max(\n                1,\n                tileRadius * Math.sin(Math.min(Math.PI * 0.5, Math.max(0, tile.angularRadius || 0)))\n            );\n            apparentRadius = Math.asin(THREE.MathUtils.clamp(physicalRadius / distance, 0, 1));\n            edgeAngle = Math.max(0, centerAngle - apparentRadius);\n        }\n\n        const safeHalfFov = Math.max(1e-6, halfFov);\n        const viewWeight = 1 - THREE.MathUtils.clamp(edgeAngle / safeHalfFov, 0, 1);\n        tile._surfaceViewMetricStamp = this._viewportStamp;\n        tile._surfaceViewCenterAngleRad = centerAngle;\n        tile._surfaceViewApparentRadiusRad = apparentRadius;\n        tile._surfaceViewEdgeAngleRad = edgeAngle;\n        tile._surfaceViewWeight = viewWeight;\n        tile._surfaceViewInFrame = edgeAngle <= halfFov;\n        tile._surfaceViewBuffered = edgeAngle <= (halfFov + bufferRad);\n        return tile;\n    }\n\n    /**\n     * Check if tile is within camera's view frustum\n     * @returns {boolean} true if tile should be processed\n     */\n    _isTileInViewport(tile, camera, focusDir) {\n        if (tile._viewportStamp === this._viewportStamp) {\n            return !!tile._inViewport;\n        }\n        const cache = this._viewportCache;\n        const camPos = cache?.camPos || this._getCameraPosition(camera);\n        const camDir = cache?.camDir || camPos.clone().normalize();\n\n        // Transform tile direction to world space (accounting for Earth rotation AND axial tilt)\n        const tileDirWorld = this._tmpTileDir.copy(tile.centerDir);\n        const worldQ = cache?.worldQ || this._getWorldQuaternion();\n        tileDirWorld.applyQuaternion(worldQ);\n\n        // First check: hemisphere culling (quick rejection)\n        // In surface mode, use focus direction (standing position)\n        // In orbit, use camera position direction\n        const referenceDir = cache?.referenceDir || ((this.lodMode === 'zoom' && focusDir)\n            ? focusDir\n            : camDir);\n        const dotCam = tileDirWorld.dot(referenceDir);\n        const viewshedRad = (this.lodMode === 'zoom')\n            ? cache?.surfaceViewshedRad\n            : cache?.orbitViewshedRad;\n        if (Number.isFinite(viewshedRad)) {\n            const maxAngle = Math.min(Math.PI, viewshedRad + (tile.angularRadius || 0));\n            const dotThreshold = Math.cos(maxAngle);\n            if (dotCam < dotThreshold) {\n                tile._viewportStamp = this._viewportStamp;\n                tile._inViewport = false;\n                return false; // Outside viewshed\n            }\n        } else if (dotCam < -0.1) {\n            tile._viewportStamp = this._viewportStamp;\n            tile._inViewport = false;\n            return false; // Behind standing position/camera\n        }\n\n        // Hysteresis: tiles that were visible last frame get extra margin before culling.\n        // This prevents flapping at frustum boundaries from camera jitter.\n        const wasVisible = !!tile._inViewport;\n        const hysteresis = wasVisible ? (cache?.hysteresisRad || 0) : 0;\n\n        let inViewport = true;\n        if (this.lodMode === 'zoom') {\n            // SURFACE MODE: radial horizon first, then the real camera view\n            // plus a configurable prefetch buffer. Underfoot lineage bypasses\n            // this method in update(), so terrain beneath the camera is never\n            // discarded even while looking horizontally.\n            const surfaceViewshedRad = viewshedRad;\n            if (!Number.isFinite(surfaceViewshedRad)) {\n                tile._viewportStamp = this._viewportStamp;\n                tile._inViewport = true;\n                return true;\n            }\n            const angleToCam = Math.acos(THREE.MathUtils.clamp(tileDirWorld.dot(camDir), -1, 1));\n            if (angleToCam - tile.angularRadius > surfaceViewshedRad + hysteresis) inViewport = false;\n            if (inViewport && this.surfaceViewCullEnabled) {\n                const metric = this._cacheSurfaceTileViewMetrics(tile, camera, tileDirWorld);\n                if (metric && !metric._surfaceViewBuffered) {\n                    const edgeAngle = Number.isFinite(metric._surfaceViewEdgeAngleRad)\n                        ? metric._surfaceViewEdgeAngleRad\n                        : Infinity;\n                    const halfFov = Number.isFinite(cache?.viewHalfFovRad) ? cache.viewHalfFovRad : 0;\n                    const buffer = Math.max(0, Number(this.surfaceViewBufferDeg) || 0) * DEG2RAD;\n                    if (edgeAngle > halfFov + buffer + hysteresis) inViewport = false;\n                }\n            }\n        } else {\n            // ORBIT MODE: Mirror Zoom Focus horizon handling to avoid jagged wrap\n            const orbitViewshedRad = viewshedRad;\n            if (!Number.isFinite(orbitViewshedRad)) {\n                tile._viewportStamp = this._viewportStamp;\n                tile._inViewport = true;\n                return true;\n            }\n            const angleToCam = Math.acos(THREE.MathUtils.clamp(tileDirWorld.dot(camDir), -1, 1));\n            if (angleToCam - tile.angularRadius > orbitViewshedRad + hysteresis) inViewport = false;\n        }\n\n        if (!this._inSurfaceMode && inViewport) {\n            const viewDir = cache?.viewDir;\n            const viewFalloffEndRad = cache?.viewFalloffEndRad;\n            let effectiveFalloffRad = viewFalloffEndRad;\n            if (Number.isFinite(cache?.orbitViewshedRad)) {\n                effectiveFalloffRad = Number.isFinite(effectiveFalloffRad)\n                    ? Math.max(effectiveFalloffRad, cache.orbitViewshedRad)\n                    : cache.orbitViewshedRad;\n            }\n            if (viewDir && Number.isFinite(effectiveFalloffRad)) {\n                const tileRadius = this._getTileRadius(tile, tileDirWorld);\n                const tileCenterWorld = tileDirWorld.clone().multiplyScalar(tileRadius);\n                const toTile = tileCenterWorld.sub(camPos).normalize();\n                const dotView = THREE.MathUtils.clamp(toTile.dot(viewDir), -1, 1);\n                const angleToView = Math.acos(dotView);\n                const edgeAngle = Math.max(0, angleToView - (tile.angularRadius || 0));\n                if (edgeAngle > effectiveFalloffRad + hysteresis) {\n                    inViewport = false;\n                }\n            }\n        }\n\n        tile._viewportStamp = this._viewportStamp;\n        tile._inViewport = inViewport;\n        return inViewport;\n    }\n\n    /**\n     * Register neighbor relationships for all visible leaf tiles.\n     * Uses hierarchical edge matching to find tiles that share edges,\n     * even when they have different LOD levels.\n     * Called once per frame after LOD traversal completes.\n     */\n    _registerNeighbors() {\n        if (this.edgeTopology && this.useDeterministicNeighborDetection) {\n            this._registerNeighborsDeterministic();\n            return;\n        }\n        // PATH-BASED + SPATIAL FILTERING: Use hierarchical relationships and spatial proximity\n\n        // Clear existing neighbor relationships\n        for (const tile of this.visibleLeafTiles) {\n            tile.neighbors.clear();\n        }\n\n        this._edgeNeighborMap = new Map();\n\n        // Build tile array - only tiles with elevation\n        const visibleTiles = this.visibleLeafTiles.filter(t =>\n            t.mesh && t.positionAttr && t.positionAttr.count > 0\n        );\n\n        if (visibleTiles.length === 0) return;\n\n        // Build spatial index: group tiles by centroid proximity\n        const spatialIndex = this._buildSpatialIndex(visibleTiles);\n\n        // For each tile, check each edge\n        for (const tile of visibleTiles) {\n            const edges = ['v0v1', 'v1v2', 'v2v0']; // Must match event-manager edge names!\n\n            for (const edgeName of edges) {\n                const edgeCorners = this._getTileEdgeCorners(tile, edgeName);\n                if (!edgeCorners) continue;\n\n                const tileEdgeKey = `${tile.getTileId()}_${edgeName}`;\n                const neighbors = [];\n\n                // PRIORITY 1: Check siblings first (same parent cluster)\n                // This ensures center tile (child 0) connects to all 3 corner tiles\n                if (tile.parent && tile.parent.children) {\n                    for (const sibling of tile.parent.children) {\n                        if (sibling === tile || !visibleTiles.includes(sibling)) continue;\n\n                        // Check all three edges of the sibling\n                        const otherEdges = ['v0v1', 'v1v2', 'v2v0'];\n                        for (const otherEdgeName of otherEdges) {\n                            const otherCorners = this._getTileEdgeCorners(sibling, otherEdgeName);\n                            if (!otherCorners) continue;\n\n                            // Do these edges overlap?\n                            if (this._edgesOverlap(edgeCorners.v0, edgeCorners.v1, otherCorners.v0, otherCorners.v1)) {\n                                neighbors.push({ tile: sibling, edgeName: otherEdgeName });\n                                break; // Found matching edge on this sibling\n                            }\n                        }\n                    }\n                }\n\n                // PRIORITY 2: Check spatial candidates for external neighbors\n                const tileCentroid = tile.getCentroid();\n                const tileMaxEdge = tile.getMaxEdgeLength();\n                const searchRadius = tileMaxEdge * 3;\n                const candidates = this._getNearbyCandidates(spatialIndex, tileCentroid, searchRadius);\n\n                for (const other of candidates) {\n                    if (tile === other) continue;\n\n                    // Skip if already found as sibling\n                    if (neighbors.some(n => n.tile === other)) continue;\n\n                    // Check all three edges of the other tile\n                    const otherEdges = ['v0v1', 'v1v2', 'v2v0'];\n                    for (const otherEdgeName of otherEdges) {\n                        const otherCorners = this._getTileEdgeCorners(other, otherEdgeName);\n                        if (!otherCorners) continue;\n\n                        // Do these edges overlap?\n                        if (this._edgesOverlap(edgeCorners.v0, edgeCorners.v1, otherCorners.v0, otherCorners.v1)) {\n                            neighbors.push({ tile: other, edgeName: otherEdgeName });\n                            break; // Found matching edge on this tile, move to next tile\n                        }\n                    }\n                }\n\n                // Store neighbors for this edge\n                if (neighbors.length > 0) {\n                    // Store neighbor info: { tile, edgeName }\n                    this._edgeNeighborMap.set(tileEdgeKey, neighbors);\n\n                    // Track ALL neighbors for LOD constraint enforcement\n                    // Store all neighbors, not just coarsest, for accurate constraint checking\n                    for (const { tile: neighborTile } of neighbors) {\n                        tile.neighbors.set(edgeName, neighborTile);\n                    }\n                }\n            }\n        }\n    }\n\n    _registerNeighborsDeterministic() {\n        for (const tile of this.visibleLeafTiles) {\n            if (tile.neighbors) tile.neighbors.clear();\n        }\n\n        this._edgeNeighborMap = new Map();\n\n        const visibleTiles = this.visibleLeafTiles.filter(t =>\n            t.mesh && t.positionAttr && t.positionAttr.count > 0\n        );\n        if (visibleTiles.length === 0) return;\n\n        const visibleSet = new Set(visibleTiles);\n        if (this.edgeTopology && this.edgeTopology.getRootEdgeMap().size === 0) {\n            this.edgeTopology.buildRootAdjacency(this.rootTiles);\n        }\n\n        const resolveNeighbor = (descriptor) => {\n            if (!descriptor) return null;\n            let tile = this.rootTiles[descriptor.rootIndex];\n            if (!tile) return null;\n\n            for (const slot of descriptor.path) {\n                if (tile.children && tile.children[slot]) {\n                    tile = tile.children[slot];\n                } else {\n                    break;\n                }\n            }\n\n            if (descriptor.reason === 'sibling' && !visibleSet.has(tile)) {\n                return null;\n            }\n\n            let edgeName = descriptor.edgeName;\n            while (tile && !visibleSet.has(tile)) {\n                const slot = tile.parent ? (tile.index - tile.parent.index * 4) : null;\n                if (slot === null || !tile.parent) break;\n                const parentEdge = mapChildEdgeToParent(slot, edgeName);\n                if (!parentEdge) break;\n                edgeName = parentEdge;\n                tile = tile.parent;\n            }\n\n            if (!tile || !visibleSet.has(tile)) return null;\n            return { tile, edgeName };\n        };\n\n        for (const tile of visibleTiles) {\n            for (const edgeName of CANONICAL_EDGES) {\n                const descriptor = this.edgeTopology.resolveNeighborDescriptor(tile, edgeName);\n                if (!descriptor) continue;\n\n                const resolved = resolveNeighbor(descriptor);\n                if (!resolved) continue;\n                const neighbor = resolved.tile;\n                const neighborEdgeName = resolved.edgeName;\n\n                if (!neighbor || neighbor === tile) continue;\n                if (!neighbor.positionAttr || neighbor.positionAttr.count === 0) continue;\n\n                const tileEdgeKey = `${tile.getTileId()}_${edgeName}`;\n                const neighbors = this._edgeNeighborMap.get(tileEdgeKey) || [];\n                if (!neighbors.some(entry => entry.tile === neighbor)) {\n                    neighbors.push({\n                        tile: neighbor,\n                        edgeName: neighborEdgeName,\n                        originRange: descriptor.originRange,\n                        neighborRange: descriptor.neighborRange,\n                        reverseForIndices: descriptor.reverseForIndices,\n                        flip: descriptor.flip,\n                        reason: descriptor.reason\n                    });\n                    this._edgeNeighborMap.set(tileEdgeKey, neighbors);\n                }\n\n                tile.neighbors.set(edgeName, neighbor);\n            }\n        }\n    }\n\n    _clearNeighborDetection() {\n        if (!this._edgeNeighborMap) return;\n        for (const tile of this.visibleLeafTiles) {\n            if (tile.neighbors) tile.neighbors.clear();\n        }\n        this._edgeNeighborMap = null;\n    }\n\n    /**\n     * Build a simple spatial hash index for fast neighbor lookup\n     */\n    _buildSpatialIndex(tiles) {\n        const index = new Map();\n        const cellSize = 0.5; // Spatial grid cell size\n\n        for (const tile of tiles) {\n            const centroid = tile.getCentroid();\n            const cellKey = this._getSpatialCellKey(centroid, cellSize);\n\n            if (!index.has(cellKey)) {\n                index.set(cellKey, []);\n            }\n            index.get(cellKey).push(tile);\n        }\n\n        return index;\n    }\n\n    requestNeighborRebuild() {\n        this._neighborRebuildRequested = true;\n    }\n\n    clearSeamCaches() {\n        const stack = Array.isArray(this.rootTiles) ? [...this.rootTiles] : [];\n        while (stack.length > 0) {\n            const tile = stack.pop();\n            if (!tile) continue;\n            if (typeof tile.clearSeamEdgeCache === 'function') {\n                tile.clearSeamEdgeCache(0);\n            }\n            if (typeof tile.clearSameLodSeamCache === 'function') {\n                tile.clearSameLodSeamCache();\n            }\n            if (tile.children && tile.children.length) {\n                stack.push(...tile.children);\n            }\n        }\n    }\n\n    queueElevationUpdate(tile) {\n        if (!tile) return;\n        this._tilesNeedingElevationUpdate.add(tile);\n    }\n\n    queueGeometryFinalize(tile) {\n        if (!tile) return;\n        this._tilesNeedingGeometryFinalize.add(tile);\n    }\n\n    _flushDeferredEdgeElevations() {\n        if (!this.visibleLeafTiles || this.visibleLeafTiles.length === 0) return 0;\n        let applied = 0;\n        for (const tile of this.visibleLeafTiles) {\n            if (tile && typeof tile.flushDeferredEdgeElevations === 'function') {\n                applied += tile.flushDeferredEdgeElevations();\n            }\n        }\n        return applied;\n    }\n\n    /**\n     * Get spatial cell key for a position\n     */\n    _getSpatialCellKey(position, cellSize) {\n        const x = Math.floor(position.x / cellSize);\n        const y = Math.floor(position.y / cellSize);\n        const z = Math.floor(position.z / cellSize);\n        return `${x},${y},${z}`;\n    }\n\n    /**\n     * Get nearby tile candidates from spatial index\n     */\n    _getNearbyCandidates(spatialIndex, centroid, searchRadius) {\n        const candidates = new Set();\n        const cellSize = 0.5;\n\n        // Check surrounding cells (3x3x3 = 27 cells)\n        for (let dx = -1; dx <= 1; dx++) {\n            for (let dy = -1; dy <= 1; dy++) {\n                for (let dz = -1; dz <= 1; dz++) {\n                    const testPos = new THREE.Vector3(\n                        centroid.x + dx * cellSize,\n                        centroid.y + dy * cellSize,\n                        centroid.z + dz * cellSize\n                    );\n                    const cellKey = this._getSpatialCellKey(testPos, cellSize);\n                    const cellTiles = spatialIndex.get(cellKey);\n\n                    if (cellTiles) {\n                        for (const tile of cellTiles) {\n                            // Further filter by actual distance\n                            if (tile.getCentroid().distanceTo(centroid) <= searchRadius) {\n                                candidates.add(tile);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        return Array.from(candidates);\n    }\n\n    /**\n     * Map child edge to parent edge based on subdivision topology\n     */\n    _getParentEdgeForChildEdge(childTile, childEdge) {\n        if (!childTile.parent) return null;\n\n        const childSlot = childTile.index - childTile.parent.index * 4;\n\n        // Subdivision pattern:\n        // Child 0 (center): no external edges\n        // Child 1 (v0 corner): v0v1→parent.v0v1, v2v0→parent.v2v0\n        // Child 2 (v1 corner): v0v1→parent.v0v1, v2v1→parent.v2v1\n        // Child 3 (v2 corner): v2v0→parent.v2v0, v2v1→parent.v2v1\n\n        const edgeMap = {\n            0: {}, // Center has no external edges\n            1: { 'v0v1': 'v0v1', 'v2v0': 'v2v0' },\n            2: { 'v0v1': 'v0v1', 'v2v1': 'v2v1' },\n            3: { 'v2v0': 'v2v0', 'v2v1': 'v2v1' }\n        };\n\n        return edgeMap[childSlot]?.[childEdge] || null;\n    }\n\n    /**\n     * Check if two tiles share an edge\n     */\n    _tilesShareEdge(tileA, edgeNameA, tileB) {\n        const edgeA = this._getTileEdgeCorners(tileA, edgeNameA);\n        if (!edgeA) return false;\n\n        const edgesB = ['v2v0', 'v2v1', 'v0v1'];\n        for (const edgeNameB of edgesB) {\n            const edgeB = this._getTileEdgeCorners(tileB, edgeNameB);\n            if (!edgeB) continue;\n\n            // Use _edgesOverlap for cross-LOD support (works for both same-LOD and cross-LOD)\n            if (this._edgesOverlap(edgeA.v0, edgeA.v1, edgeB.v0, edgeB.v1)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Get corner positions for a tile's edge\n     */\n    _getTileEdgeCorners(tile, edgeName) {\n        if (edgeName === 'v0v1') return { v0: tile.v0, v1: tile.v1 };\n        if (edgeName === 'v1v2') return { v0: tile.v1, v1: tile.v2 };\n        if (edgeName === 'v2v0') return { v0: tile.v2, v1: tile.v0 };\n        // Legacy support for old naming\n        if (edgeName === 'v2v1') return { v0: tile.v2, v1: tile.v1 };\n        return null;\n    }\n\n    /**\n     * Find ALL neighbors for a specific tile's edge.\n     * This is a simple lookup into the pre-computed edge neighbor map.\n     * Returns array of neighboring tiles that touch this edge.\n     */\n    findEdgeNeighbors(tile, edgeName) {\n        const neighborInfos = this.getEdgeNeighborInfos(tile, edgeName);\n        return neighborInfos.map(info => info.tile);\n    }\n\n    getEdgeNeighborInfos(tile, edgeName) {\n        if (!tile) return [];\n\n        // Look up in the pre-computed map (only exists when neighbor detection is enabled)\n        const tileKey = `${tile.getTileId ? tile.getTileId() : 'unknown'}_${edgeName}`;\n        const neighborInfos = this._edgeNeighborMap ? this._edgeNeighborMap.get(tileKey) : null;\n        return neighborInfos || [];\n    }\n\n    // Shared seam injection for auto + manual stitching; routes through elevation pipeline.\n    _getEdgeStitchOptions(authorityTile, authorityEdgeName, targetTile, targetEdgeName) {\n        if (!authorityTile || !targetTile) return null;\n        const minAuthority = Number.isFinite(this.edgeStitchMinAuthority) ? this.edgeStitchMinAuthority : 0;\n        const skipTarget = Number.isFinite(this.edgeStitchSkipTargetComplete) ? this.edgeStitchSkipTargetComplete : 1;\n        const maxBlend = Number.isFinite(this.edgeStitchMaxBlend) ? this.edgeStitchMaxBlend : 1;\n        const minBlend = Number.isFinite(this.edgeStitchMinBlend) ? this.edgeStitchMinBlend : 0;\n\n        if (typeof authorityTile.getEdgeElevationCompleteness !== 'function' ||\n            typeof targetTile.getEdgeElevationCompleteness !== 'function') {\n            return { blendAlpha: Math.min(1, Math.max(0, maxBlend)) };\n        }\n\n        const authorityCompleteness = authorityTile.getEdgeElevationCompleteness(authorityEdgeName);\n        const targetCompleteness = targetTile.getEdgeElevationCompleteness(targetEdgeName);\n\n        if (authorityCompleteness < minAuthority) return null;\n        if (targetCompleteness >= skipTarget) return null;\n\n        const targetFactor = 1 - Math.min(1, Math.max(0, targetCompleteness));\n        let blendAlpha = authorityCompleteness * (0.5 + 0.5 * targetFactor);\n        blendAlpha = Math.min(maxBlend, Math.max(minBlend, blendAlpha));\n\n        return { blendAlpha };\n    }\n\n    stitchEdgeFromAuthority(targetTile, targetEdgeName, authorityTile, authorityEdgeName, lockMode = 'soft', reason = 'auto', options = null) {\n        if (!targetTile || !authorityTile) return 0;\n        if (typeof authorityTile.getEdgeElevations !== 'function' || typeof targetTile.applyEdgeElevations !== 'function') {\n            return 0;\n        }\n\n        const authorityRange = options && options.authorityRange ? options.authorityRange : null;\n        const canonical = options && typeof options.canonical === 'boolean' ? options.canonical : !!authorityRange;\n        const blendAlpha = options && Number.isFinite(options.blendAlpha) ? options.blendAlpha : null;\n        let authorityElevations = authorityTile.getEdgeElevations(authorityEdgeName, {\n            range: authorityRange,\n            canonical\n        });\n        if (!authorityElevations || authorityElevations.length < 2) return 0;\n\n        if (typeof this._validateEdgeOrientation === 'function') {\n            if (typeof targetTile.createBaseElevationSnapshot === 'function' && !targetTile.baseElevations) {\n                targetTile.createBaseElevationSnapshot();\n            }\n            authorityElevations = this._validateEdgeOrientation(targetTile, targetEdgeName, authorityElevations);\n        }\n\n        return targetTile.applyEdgeElevations(\n            targetEdgeName,\n            authorityElevations,\n            {\n                neighborTile: authorityTile,\n                neighborLevel: authorityTile.level,\n                neighborEdgeName: authorityEdgeName,\n                lockMode,\n                reason,\n                blendAlpha\n            }\n        );\n    }\n\n    /**\n     * Check if two edges overlap on the sphere surface.\n     * Handles different LOD levels by checking if one edge contains the other.\n     *\n     * Edge A: v0A→v1A\n     * Edge B: v0B→v1B\n     *\n     * Returns true if the edges share the same great circle arc.\n     */\n    _edgesOverlap(v0A, v1A, v0B, v1B) {\n        const tolerance = 1e-4; // Increased for numerical stability with same-LOD siblings\n\n        // Check if all four vertices are coplanar (lie on same great circle)\n        // Great circle normal = v0 × v1\n        const normalA = new THREE.Vector3().crossVectors(v0A, v1A).normalize();\n        const normalB = new THREE.Vector3().crossVectors(v0B, v1B).normalize();\n\n        // If normals are parallel (or anti-parallel), edges are on same great circle\n        const dotNormals = Math.abs(normalA.dot(normalB));\n        if (dotNormals < 1 - tolerance) return false; // Different great circles\n\n        // Edges are on same great circle - now check if they overlap\n        // Check if B's endpoints lie on A's arc, or vice versa\n\n        // Check if endpoints lie on arcs\n        const v0B_on_A = this._pointOnArc(v0B, v0A, v1A, tolerance);\n        const v1B_on_A = this._pointOnArc(v1B, v0A, v1A, tolerance);\n        const v0A_on_B = this._pointOnArc(v0A, v0B, v1B, tolerance);\n        const v1A_on_B = this._pointOnArc(v1A, v0B, v1B, tolerance);\n\n        // Count matches for each direction\n        const bPointsOnA = (v0B_on_A ? 1 : 0) + (v1B_on_A ? 1 : 0);\n        const aPointsOnB = (v0A_on_B ? 1 : 0) + (v1A_on_B ? 1 : 0);\n\n        // Edges are neighbors if:\n        // 1. BOTH endpoints of B lie on A (B is subset/equal to A)\n        // 2. BOTH endpoints of A lie on B (A is subset/equal to B)\n        // 3. One endpoint from each lies on the other (partial overlap for cross-LOD)\n        //\n        // CRITICAL: Single point overlap (corner touch) is NOT enough!\n\n        // Same LOD or exact overlap: both edges share both endpoints\n        if (bPointsOnA === 2 || aPointsOnB === 2) {\n            return true;\n        }\n\n        // Cross-LOD: One edge is subset of another, OR they have significant overlap\n        // For cross-LOD, at least one edge must have BOTH endpoints on the other\n        // AND at least one point from the other edge must also match\n        if ((bPointsOnA === 2 && aPointsOnB >= 1) || (aPointsOnB === 2 && bPointsOnA >= 1)) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Check if point P lies on arc from v0 to v1 (on sphere surface).\n     * Works by checking if p is coplanar AND within the arc bounds.\n     */\n    _pointOnArc(p, v0, v1, tolerance) {\n        // Normalize all vectors\n        const pN = p.clone().normalize();\n        const v0N = v0.clone().normalize();\n        const v1N = v1.clone().normalize();\n\n        // Check if p is coplanar with v0 and v1 (on same great circle)\n        const normal = new THREE.Vector3().crossVectors(v0N, v1N);\n        if (normal.lengthSq() < tolerance * tolerance) {\n            // v0 and v1 are collinear - degenerate case\n            return pN.distanceTo(v0N) < tolerance || pN.distanceTo(v1N) < tolerance;\n        }\n        normal.normalize();\n\n        const distToPlane = Math.abs(normal.dot(pN));\n        if (distToPlane > tolerance) return false; // Not on great circle\n\n        // Check if p is at an endpoint\n        if (pN.distanceTo(v0N) < tolerance || pN.distanceTo(v1N) < tolerance) {\n            return true;\n        }\n\n        // Check if p is between v0 and v1 along the arc\n        // Use angular distance: if angle(v0,p) + angle(p,v1) ≈ angle(v0,v1), p is on arc\n        const angle_v0_v1 = Math.acos(Math.max(-1, Math.min(1, v0N.dot(v1N))));\n        const angle_v0_p = Math.acos(Math.max(-1, Math.min(1, v0N.dot(pN))));\n        const angle_p_v1 = Math.acos(Math.max(-1, Math.min(1, pN.dot(v1N))));\n\n        // P is on arc if sum of angles equals total arc angle (within tolerance)\n        const angleDiff = Math.abs((angle_v0_p + angle_p_v1) - angle_v0_v1);\n        return angleDiff < tolerance;\n    }\n\n    /**\n     * Cross-LOD seam interpolation:\n     * Align higher-LOD edge vertices to the lower-LOD edge via linear interpolation.\n     * Skips same-LOD neighbors. Fine-edge vertices retain the authoritative\n     * coarse-edge position while their own elevations stream, then restore\n     * their saved values when the cross-LOD relationship retires.\n     */\n    _applyCrossLodEdgeSeams() {\n        if (!this._edgeNeighborMap) return 0;\n\n        const minAuthority = Number.isFinite(this.seamMinAuthority) ? this.seamMinAuthority : 0.9;\n        const edgeBit = {\n            v2v0: 1,\n            v0v1: 2,\n            v1v2: 4,\n            v2v1: 4\n        };\n        const tileById = new Map();\n        for (const tile of this.visibleLeafTiles) {\n            const id = tile.getTileId ? tile.getTileId() : null;\n            if (id) tileById.set(id, tile);\n        }\n\n        const processed = new Set();\n        const activeEdgeMaskByTile = new Map();\n        let seamCount = 0;\n\n        for (const [edgeKey, neighbors] of this._edgeNeighborMap.entries()) {\n            const lastUnderscore = edgeKey.lastIndexOf('_');\n            const tileId = edgeKey.substring(0, lastUnderscore);\n            const edgeName = edgeKey.substring(lastUnderscore + 1);\n            const primaryTile = tileById.get(tileId);\n            if (!primaryTile) continue;\n\n            for (const neighborInfo of neighbors) {\n                const neighbor = neighborInfo.tile;\n                if (!neighbor || neighbor.disposed) continue;\n                if (neighbor.level === primaryTile.level) continue;\n\n                let coarseTile;\n                let fineTile;\n                let coarseEdgeName;\n                let fineEdgeName;\n                let authorityRange = null;\n\n                if (primaryTile.level < neighbor.level) {\n                    coarseTile = primaryTile;\n                    fineTile = neighbor;\n                    coarseEdgeName = edgeName;\n                    fineEdgeName = neighborInfo.edgeName;\n                    authorityRange = neighborInfo.originRange || null;\n                } else {\n                    coarseTile = neighbor;\n                    fineTile = primaryTile;\n                    coarseEdgeName = neighborInfo.edgeName;\n                    fineEdgeName = edgeName;\n                    authorityRange = neighborInfo.neighborRange || null;\n                }\n\n                if (!coarseEdgeName || !fineEdgeName) continue;\n\n                const fineId = fineTile.getTileId ? fineTile.getTileId() : 'fine';\n                const coarseId = coarseTile.getTileId ? coarseTile.getTileId() : 'coarse';\n                const seamKey = `${fineId}_${fineEdgeName}_${coarseId}_${coarseEdgeName}`;\n                if (processed.has(seamKey)) continue;\n                processed.add(seamKey);\n\n                if (typeof coarseTile.getEdgeElevationCompleteness !== 'function') continue;\n                const authorityCompleteness = coarseTile.getEdgeElevationCompleteness(coarseEdgeName);\n                if (!Number.isFinite(authorityCompleteness) || authorityCompleteness < minAuthority) continue;\n\n                const bit = edgeBit[fineEdgeName] || 0;\n                if (bit) {\n                    activeEdgeMaskByTile.set(fineTile, (activeEdgeMaskByTile.get(fineTile) || 0) | bit);\n                }\n\n                const options = authorityRange ? { authorityRange, canonical: true } : null;\n                const updatedCount = this.stitchEdgeFromAuthority(\n                    fineTile,\n                    fineEdgeName,\n                    coarseTile,\n                    coarseEdgeName,\n                    'hard',\n                    'seam-cross-lod',\n                    options\n                );\n                if (updatedCount > 0) seamCount++;\n            }\n        }\n\n        for (const tile of this.visibleLeafTiles) {\n            if (typeof tile.clearSeamEdgeCache === 'function') {\n                const mask = activeEdgeMaskByTile.get(tile) || 0;\n                tile.clearSeamEdgeCache(mask);\n            }\n        }\n\n        return seamCount;\n    }\n\n    _applySameLodEdgeSnaps() {\n        let cleared = 0;\n        for (const tile of this.visibleLeafTiles) {\n            if (tile && typeof tile.clearSameLodSeamCache === 'function') {\n                cleared += tile.clearSameLodSeamCache();\n            }\n        }\n        return cleared;\n    }\n\n    /**\n     * NEW: Stitch edges based on accurate geometric overlap detection.\n     * Uses the same edge overlap logic as the arrow visualization.\n     * Lower LOD tile acts as authority, higher LOD tile moves vertices to seal gaps.\n     */\n    _applyGeometricEdgeStitching() {\n        if (!this._edgeNeighborMap) return;\n\n        let stitchCount = 0;\n\n        const getAuthorityRange = (primaryTile, neighborInfo, authorityTile) => {\n            if (!neighborInfo || !authorityTile) return null;\n            if (authorityTile === primaryTile) return neighborInfo.originRange || null;\n            return neighborInfo.neighborRange || null;\n        };\n\n        const buildOptions = (range) => range ? { authorityRange: range, canonical: true } : null;\n\n        // PHASE 1: Create base elevation snapshots for all visible tiles\n        // This preserves ground-truth elevations before any stitching modifications\n        for (const tile of this.visibleLeafTiles) {\n            if (typeof tile.createBaseElevationSnapshot === 'function') {\n                tile.createBaseElevationSnapshot();\n            }\n        }\n\n        // Process each edge that has neighbors\n        for (const [edgeKey, neighbors] of this._edgeNeighborMap.entries()) {\n            // Parse edge key: \"tileId_edgeName\"\n            const lastUnderscore = edgeKey.lastIndexOf('_');\n            const tileId = edgeKey.substring(0, lastUnderscore);\n            const edgeName = edgeKey.substring(lastUnderscore + 1);\n\n            // Find the primary tile\n            const primaryTile = this.visibleLeafTiles.find(t =>\n                (t.getTileId ? t.getTileId() : 'unknown') === tileId\n            );\n            if (!primaryTile) continue;\n\n            // Process each neighbor (neighbors array contains { tile, edgeName })\n            for (const neighborInfo of neighbors) {\n                const neighbor = neighborInfo.tile;\n                const neighborEdgeName = neighborInfo.edgeName;\n                const lodDelta = neighbor.level - primaryTile.level;\n\n                // Apply stitching based on LOD delta\n                if (lodDelta > 0) {\n                    // Neighbor is HIGHER LOD (finer) - it should stitch to primary (coarser)\n                    // Primary tile is authority - extract elevation data and apply to neighbor\n\n                    // CORRECT APPROACH: Get elevation data from authority tile and inject through updateVertex()\n                    const authorityRange = getAuthorityRange(primaryTile, neighborInfo, primaryTile);\n                    const edgeOptions = this._getEdgeStitchOptions(primaryTile, edgeName, neighbor, neighborEdgeName);\n                    if (!edgeOptions) continue;\n                    const updatedCount = this.stitchEdgeFromAuthority(\n                        neighbor,\n                        neighborEdgeName,\n                        primaryTile,\n                        edgeName,\n                        'soft',\n                        'auto-cross-lod',\n                        { ...(buildOptions(authorityRange) || {}), ...edgeOptions }\n                    );\n                    if (updatedCount > 0) stitchCount++;\n                } else if (lodDelta < 0) {\n                    // Neighbor is LOWER LOD (coarser) - primary should stitch to neighbor\n                    // Neighbor is authority - extract elevation data and apply to primary\n                    const authorityRange = getAuthorityRange(primaryTile, neighborInfo, neighbor);\n                    const edgeOptions = this._getEdgeStitchOptions(neighbor, neighborEdgeName, primaryTile, edgeName);\n                    if (!edgeOptions) continue;\n                    const updatedCount = this.stitchEdgeFromAuthority(\n                        primaryTile,\n                        edgeName,\n                        neighbor,\n                        neighborEdgeName,\n                        'soft',\n                        'auto-cross-lod',\n                        { ...(buildOptions(authorityRange) || {}), ...edgeOptions }\n                    );\n                    if (updatedCount > 0) stitchCount++;\n                } else {\n                    continue;\n                }\n            }\n        }\n\n        // Log summary\n        const now = performance.now();\n        if (!this._lastGeometricStitchLog || now - this._lastGeometricStitchLog > 1000) {\n            console.log(`Geometric stitching: ${stitchCount} edges stitched`);\n            this._lastGeometricStitchLog = now;\n        }\n    }\n\n    /**\n     * Stitch a single tile with its neighbors (called automatically when elevation updates)\n     * @param {TriTile} tile - The tile that received elevation updates\n     */\n    stitchTileWithNeighbors(tile) {\n        if (!tile || !this._edgeNeighborMap) return;\n\n        const tileKey = tile.getTileId ? tile.getTileId() : null;\n        if (!tileKey) return;\n\n        const edges = ['v0v1', 'v1v2', 'v2v0'];\n        let stitchCount = 0;\n\n        for (const edgeName of edges) {\n            const neighborPairs = this.getEdgeNeighborInfos(tile, edgeName);\n            if (!neighborPairs || neighborPairs.length === 0) continue;\n\n            for (const neighborInfo of neighborPairs) {\n                const neighbor = neighborInfo.tile;\n                const neighborEdgeName = neighborInfo.edgeName;\n                if (!neighbor || neighbor.disposed) continue;\n\n                // Same logic as _applyGeometricEdgeStitching but for a single tile\n                const lodDelta = tile.level - neighbor.level;\n\n                if (lodDelta < 0) {\n                    // Tile is coarser than neighbor - neighbor should stitch to tile\n                    // CORRECT APPROACH: Get elevation data from authority (tile) and inject to neighbor\n                    const authorityRange = neighborInfo.originRange || null;\n                    const edgeOptions = this._getEdgeStitchOptions(tile, edgeName, neighbor, neighborEdgeName);\n                    if (!edgeOptions) continue;\n                    const updatedCount = this.stitchEdgeFromAuthority(\n                        neighbor,\n                        neighborEdgeName,\n                        tile,\n                        edgeName,\n                        'soft',\n                        'auto-cross-lod',\n                        authorityRange\n                            ? { authorityRange, canonical: true, ...edgeOptions }\n                            : edgeOptions\n                    );\n                    if (updatedCount > 0) stitchCount++;\n                } else if (lodDelta === 0) {\n                    continue;\n                } else if (lodDelta > 0) {\n                    // Tile is finer than neighbor - stitch tile to coarser authority\n                    const authorityRange = neighborInfo.neighborRange || null;\n                    const edgeOptions = this._getEdgeStitchOptions(neighbor, neighborEdgeName, tile, edgeName);\n                    if (!edgeOptions) continue;\n                    const updatedCount = this.stitchEdgeFromAuthority(\n                        tile,\n                        edgeName,\n                        neighbor,\n                        neighborEdgeName,\n                        'soft',\n                        'auto-cross-lod',\n                        authorityRange\n                            ? { authorityRange, canonical: true, ...edgeOptions }\n                            : edgeOptions\n                    );\n                    if (updatedCount > 0) stitchCount++;\n                }\n            }\n        }\n\n        if (stitchCount > 0) {\n            console.log(`[Auto-Stitch] Stitched ${stitchCount} edges for tile ${tileKey}`);\n        }\n    }\n\n    // ── Retirement pool: deferred disposal ──────────────────────────────\n\n    /**\n     * Retire a tile's children instead of destroying them immediately.\n     * Children are hidden and detached from the scene but keep their\n     * geometry, elevation, and imagery data alive. If the parent\n     * re-splits within the grace period, _resurrectChildren() restores\n     * them instantly without re-fetching.\n     *\n     * @param {Object} tile  Parent tile whose children are being merged\n     * @returns {number}  Count of tiles removed from the active tree\n     */\n    _retireChildren(tile) {\n        if (!tile.children) return 0;\n        // Cache elevation from children into parent (same as destroyChildren)\n        tile.cacheElevationFromChildren();\n        tile.applyElevationCacheToMesh();\n\n        // Try imagery adoption from children (same as destroyChildren)\n        const canInheritImagery = this.imageryInheritanceEnabled === true;\n        if (canInheritImagery) {\n            const adoptedMosaic = tile._tryAdoptChildMosaicImagery?.();\n            const minCoverageRatio = Number.isFinite(this.mergeChildAdoptMinCoverage)\n                ? this.mergeChildAdoptMinCoverage : 0.995;\n            const adoptedChild = adoptedMosaic\n                ? false\n                : tile._adoptChildImagery?.({ minCoverageRatio });\n            if (!adoptedChild && !adoptedMosaic && tile.imageryInherited) {\n                tile.clearImagery();\n            }\n        } else if (tile.imageryInherited) {\n            tile.clearImagery();\n        }\n\n        const entry = { children: tile.children, retiredAt: this._frameNow, meshes: [], tileCount: 0 };\n        let count = 0;\n        const stack = [...tile.children];\n        while (stack.length) {\n            const t = stack.pop();\n            if (t.children) stack.push(...t.children);\n            // Hide mesh but keep GPU resources alive\n            if (t.mesh) {\n                this._removeTileCollider(t.mesh);\n                t.mesh.visible = false;\n                this.group.remove(t.mesh);\n                entry.meshes.push(t.mesh);\n            }\n            // Clear neighbor tracking (may be stale after topology change)\n            if (t.neighbors) t.neighbors.clear();\n            if (t.edgeElevationCache) t.edgeElevationCache.clear();\n            if (t.stitchedEdges) t.stitchedEdges.clear();\n            if (t.deferredEdgeElevations) t.deferredEdgeElevations.clear();\n            t.edgeVertexMask = null;\n            count++;\n        }\n        entry.tileCount = count;\n\n        tile.children = null;\n        tile.childrenPrepared = false;\n\n        // Store in retirement map (keyed by parent tile)\n        this._retiredTiles.set(tile, entry);\n        this._retiredTileCount += entry.tileCount;\n\n        // Bound both parent entries and their total descendant resources.\n        if (this._retiredTiles.size > this._retirementMaxEntries\n            || this._retiredTileCount > this._retirementMaxTiles) {\n            this._sweepRetirementPool(true);\n        }\n\n        return count;\n    }\n\n    /**\n     * Attempt to resurrect previously retired children of a tile.\n     * Returns true if resurrection succeeded (children restored with\n     * all their existing data), false if no retired entry exists.\n     */\n    _resurrectChildren(tile) {\n        const entry = this._retiredTiles.get(tile);\n        if (!entry) return false;\n\n        this._retiredTiles.delete(tile);\n        this._retiredTileCount = Math.max(0, this._retiredTileCount - (entry.tileCount || 0));\n        tile.children = entry.children;\n        tile.childrenPrepared = true;\n\n        // Re-attach meshes to scene\n        for (const mesh of entry.meshes) {\n            if (mesh && !mesh.parent) {\n                this.group.add(mesh);\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Sweep the retirement pool, destroying entries older than the grace\n     * period. Called once per frame after merge/split phases.\n     * @param {boolean} force  If true, evict oldest entries to stay under cap\n     */\n    _sweepRetirementPool(force = false) {\n        const now = this._frameNow;\n        const grace = this._retirementGraceMs;\n        const toDelete = [];\n\n        let plannedTileCount = 0;\n        for (const [parent, entry] of this._retiredTiles) {\n            const entryUnderCap = this._retiredTiles.size - toDelete.length <= this._retirementMaxEntries;\n            const tileUnderCap = this._retiredTileCount - plannedTileCount <= this._retirementMaxTiles;\n            if (force && entryUnderCap && tileUnderCap) break;\n            if (force || (now - entry.retiredAt) > grace) {\n                toDelete.push(parent);\n                plannedTileCount += entry?.tileCount || 0;\n            }\n        }\n\n        for (const parent of toDelete) {\n            const entry = this._retiredTiles.get(parent);\n            this._retiredTiles.delete(parent);\n            if (!entry) continue;\n            this._retiredTileCount = Math.max(0, this._retiredTileCount - (entry.tileCount || 0));\n\n            // Full destroy — release GPU resources\n            const stack = [...entry.children];\n            while (stack.length) {\n                const t = stack.pop();\n                if (t.children) stack.push(...t.children);\n                t.clearImagery?.();\n                t._disposeWireframeAssets?.();\n                if (t.mesh) {\n                    if (t.mesh.parent) t.mesh.parent.remove(t.mesh);\n                    if (t.mesh.geometry) releasePooledGeometry(t.mesh.geometry, t.resolution);\n                    if (t.mesh.material) t.mesh.material.dispose();\n                    t.mesh.geometry = null;\n                    t.mesh.material = null;\n                    t.mesh = null;\n                }\n                t.geometry = null;\n                t.baseDirs = null;\n                t.baseRadii = null;\n                t.positionAttr = null;\n                t.elevationState = null;\n                t.elevationSeeded = null;\n                t.elevationFillMask = null;\n                t.elevationMorphCurrent = null;\n                t.elevationMorphTarget = null;\n                t.elevationMorphPending = null;\n                t.elevationHoldPending = null;\n                t.waterMaskAttr = null;\n                t.children = null;\n                if (this.elevationClient?.pruneTile) {\n                    this.elevationClient.pruneTile(t, {\n                        keepRecords: this._retainElevationForRetiredTiles,\n                    });\n                }\n            }\n        }\n    }\n\n    /** Bound the warm merge cache independently of the visible LOD budget. */\n    setRetirementPolicy({ graceMs, maxEntries, maxTiles, retainElevation } = {}) {\n        if (Number.isFinite(graceMs)) {\n            this._retirementGraceMs = Math.max(0, Math.min(30_000, Math.floor(graceMs)));\n        }\n        if (Number.isFinite(maxEntries)) {\n            this._retirementMaxEntries = Math.max(0, Math.min(2000, Math.floor(maxEntries)));\n        }\n        if (Number.isFinite(maxTiles)) {\n            this._retirementMaxTiles = Math.max(0, Math.min(20_000, Math.floor(maxTiles)));\n        }\n        if (typeof retainElevation === 'boolean') {\n            this._retainElevationForRetiredTiles = retainElevation;\n        }\n        if (this._retiredTiles.size > this._retirementMaxEntries\n            || this._retiredTileCount > this._retirementMaxTiles) {\n            this._sweepRetirementPool(true);\n        }\n    }\n\n    /** Governor hook: pressure must prefer releasing stale subtrees to warmth. */\n    applyMemoryPressure(level) {\n        const pressure = THREE.MathUtils.clamp(Number(level) || 0, 0, 1);\n        if (pressure < 0.35) return;\n        this._retainElevationForRetiredTiles = false;\n        if (pressure >= 0.8) {\n            this._retirementGraceMs = 0;\n            this._retirementMaxEntries = 0;\n            this._retirementMaxTiles = 0;\n            this._sweepRetirementPool(true);\n        }\n    }\n\n    /**\n     * Collapse active terrain to its roots and destroy every retired\n     * descendant. Unlike `suspended`, this is a real GPU-memory release for the\n     * mobile camera lifecycle; the normal LOD cascade rebuilds after resume.\n     */\n    beginCameraExclusiveMode() {\n        if (this._cameraExclusiveState) return this._cameraExclusiveState;\n        const state = {\n            suspended: this.suspended,\n            suppressTileDisplay: this.suppressTileDisplay,\n            groupVisible: this.group.visible,\n            retirementGraceMs: this._retirementGraceMs,\n            retirementMaxEntries: this._retirementMaxEntries,\n            retirementMaxTiles: this._retirementMaxTiles,\n            retainElevation: this._retainElevationForRetiredTiles,\n            releasedTiles: 0,\n        };\n        this._cameraExclusiveState = state;\n        this.suspended = true;\n        this.suppressTileDisplay = true;\n        this.group.visible = false;\n\n        this._tilesToSplit.length = 0;\n        this._tilesToMerge.length = 0;\n        this._tilesToLoadImagery.length = 0;\n        this._hiddenLeafTilesForElevation.length = 0;\n        this._coarseImageryEnqueued.clear();\n        this._basePreloadQueue.length = 0;\n        this._snapshotReplayQueue = null;\n\n        for (const root of this.rootTiles) {\n            if (root.children) {\n                const removed = this._retireChildren(root);\n                state.releasedTiles += removed;\n                this.tileCount = Math.max(this.rootTiles.length, this.tileCount - removed);\n            }\n            root.clearImagery?.();\n            root.setVisible?.(false);\n            if (root.mesh) this._removeTileCollider(root.mesh);\n        }\n\n        this._retirementGraceMs = 0;\n        this._retirementMaxEntries = 0;\n        this._retirementMaxTiles = 0;\n        this._retainElevationForRetiredTiles = false;\n        this._sweepRetirementPool(true);\n        state.releasedPooledGeometries = clearPooledGeometries();\n        for (const material of this.materialPool.values()) material?.dispose?.();\n        this.materialPool.clear();\n        this.materialRefCounts.clear();\n        this.tileCount = this.rootTiles.length;\n        this.visibleTileCount = 0;\n        this.currentMaxLevel = 0;\n        this.visibleMeshes.length = 0;\n        this.visibleLeafTiles.length = 0;\n        this._lastVisibleLeafTiles.clear();\n        this._pendingColliders.clear();\n        this._orbitElevationTiles = null;\n        this._rootsSubdivided = false;\n        this._basePreloadInitialized = false;\n        return state;\n    }\n\n    resumeAfterCameraExclusiveMode(state = this._cameraExclusiveState) {\n        if (!state || state !== this._cameraExclusiveState) return false;\n        this._retirementGraceMs = state.retirementGraceMs;\n        this._retirementMaxEntries = state.retirementMaxEntries;\n        this._retirementMaxTiles = state.retirementMaxTiles;\n        this._retainElevationForRetiredTiles = state.retainElevation;\n        this.group.visible = state.groupVisible;\n        this.suppressTileDisplay = state.suppressTileDisplay;\n        this.suspended = state.suspended;\n        this._cameraExclusiveState = null;\n        return true;\n    }\n\n    /**\n     * Enforce the 1-LOD constraint: tiles cannot differ by more than 1 LOD level from neighbors.\n     * This prevents geometric discontinuities, T-junction cascades, and stitching failures.\n     *\n     * If a tile has a neighbor that is 2+ levels higher, mark the tile for subdivision.\n     * This may cascade multiple frames as tiles progressively subdivide to match neighbors.\n     *\n     * @param {Array} tilesToSplit - Array of split candidates to add constraint-violating tiles to\n     */\n    _enforce1LODConstraint(tilesToSplit) {\n        for (const tile of this.visibleLeafTiles) {\n            // Skip tiles already at max level\n            if (tile.level >= this.maxTileLevel) continue;\n\n            // Check if this tile violates the 1-LOD constraint\n            let maxNeighborLevel = tile.level;\n            let hasViolation = false;\n\n            for (const neighbor of tile.neighbors.values()) {\n                if (!neighbor || typeof neighbor.level !== 'number') continue;\n\n                const lodDelta = neighbor.level - tile.level;\n\n                if (lodDelta >= 2) {\n                    // Neighbor is 2+ levels HIGHER - we must subdivide\n                    hasViolation = true;\n                    maxNeighborLevel = Math.max(maxNeighborLevel, neighbor.level);\n                }\n            }\n\n            if (hasViolation) {\n                // Add to split queue with HIGH priority\n                // Priority based on how many levels behind we are\n                const levelsBehind = maxNeighborLevel - tile.level;\n                const priority = 10000 + (levelsBehind * 1000); // Very high priority\n\n                // Check if already in split queue\n                const alreadyQueued = tilesToSplit.some(entry => entry.tile === tile);\n\n                if (!alreadyQueued) {\n                    tilesToSplit.push({ tile, priority });\n                }\n            }\n        }\n    }\n\n    /**\n     * Validate and correct edge orientation by comparing endpoint positions.\n     * Uses endpoint cost comparison to detect if edge positions should be reversed.\n     *\n     * @param {TriTile} fineTile - The fine resolution tile\n     * @param {string} fineEdgeName - Edge name on fine tile\n     * @param {Array<Vector3>|Float32Array} coarseData - Ordered positions (Vector3) or heights (legacy) from coarse edge\n     * @returns {Array<Vector3>|Float32Array} Corrected data (reversed if needed)\n     */\n    _validateEdgeOrientation(fineTile, fineEdgeName, coarseData) {\n        if (!coarseData || coarseData.length < 2) {\n            return coarseData;\n        }\n\n        const fineIndices = fineTile._edgeVertexIndices(fineEdgeName);\n        if (!fineIndices || fineIndices.length < 2) return coarseData;\n\n        // Detect if we have Vector3 positions or scalar elevations\n        const isPositionMode = (Array.isArray(coarseData) &&\n                                coarseData[0] &&\n                                coarseData[0].isVector3);\n\n        let cost, costRev;\n\n        if (isPositionMode && fineTile.positionAttr) {\n            // Position-based validation: compare 3D distances\n            const fineStartIdx = fineIndices[0];\n            const fineEndIdx = fineIndices[fineIndices.length - 1];\n\n            const fineStart = new THREE.Vector3(\n                fineTile.positionAttr.getX(fineStartIdx),\n                fineTile.positionAttr.getY(fineStartIdx),\n                fineTile.positionAttr.getZ(fineStartIdx)\n            );\n            const fineEnd = new THREE.Vector3(\n                fineTile.positionAttr.getX(fineEndIdx),\n                fineTile.positionAttr.getY(fineEndIdx),\n                fineTile.positionAttr.getZ(fineEndIdx)\n            );\n\n            const c0 = coarseData[0];\n            const c1 = coarseData[coarseData.length - 1];\n\n            // Cost = sum of endpoint distances\n            cost = fineStart.distanceTo(c0) + fineEnd.distanceTo(c1);\n            costRev = fineStart.distanceTo(c1) + fineEnd.distanceTo(c0);\n        } else if (fineTile.baseElevations) {\n            // Legacy elevation-based validation\n            const fineStartH = fineTile.baseElevations[fineIndices[0]];\n            const fineEndH = fineTile.baseElevations[fineIndices[fineIndices.length - 1]];\n\n            const c0 = coarseData[0];\n            const c1 = coarseData[coarseData.length - 1];\n\n            cost = Math.abs(fineStartH - c0) + Math.abs(fineEndH - c1);\n            costRev = Math.abs(fineStartH - c1) + Math.abs(fineEndH - c0);\n        } else {\n            return coarseData;\n        }\n\n        // If reversed is better, flip the array\n        if (costRev + 1e-6 < cost) {\n            console.log(`[STITCH] Reversing edge ${fineEdgeName} (cost ${cost.toFixed(2)} -> ${costRev.toFixed(2)})`);\n            // Create reversed copy\n            if (isPositionMode) {\n                return coarseData.slice().reverse();\n            } else {\n                const reversed = new Float32Array(coarseData.length);\n                for (let i = 0; i < coarseData.length; i++) {\n                    reversed[i] = coarseData[coarseData.length - 1 - i];\n                }\n                return reversed;\n            }\n        }\n\n        return coarseData;\n    }\n\n    _desiredLevelForTile(tile, camera, screenPixels = null) {\n        const maxLevel = this.maxTileLevel ?? MAX_TILE_LEVEL;\n        const policyRenderMax = Number.isFinite(this._detailPolicy?.renderMaxLod)\n            ? this._detailPolicy.renderMaxLod\n            : maxLevel;\n        const surfaceStageCap = Math.min(policyRenderMax, maxLevel);\n\n        let desired = tile.level;\n        let tileDirWorld = null;\n\n        const sse = this._tileScreenSpaceError(tile, camera);\n        const maxSSE = Math.max(1e-6, this.maxScreenSpaceError || 16);\n        const ratio = sse / maxSSE;\n        if (ratio > 1) {\n            desired = tile.level + Math.ceil(Math.log2(ratio));\n        } else if (ratio < this.sseMergeFactor) {\n            const mergeRatio = Math.max(ratio, 1e-6);\n            desired = tile.level - Math.floor(Math.log2(this.sseMergeFactor / mergeRatio));\n        }\n\n        if (this._inSurfaceMode) {\n            const focusDir = this.viewFocusDir || this._getCameraPosition(camera).normalize();\n            const camPos = this._getCameraPosition(camera);\n            const worldQ = this._viewportCache?.worldQ || this._getWorldQuaternion();\n            tileDirWorld = this._tmpTileDir.copy(tile.centerDir).applyQuaternion(worldQ);\n            const cap = this._computeSurfaceLodCap(tile, camera, focusDir, camPos, tileDirWorld);\n            if (Number.isFinite(cap)) {\n                desired = Math.min(desired, cap);\n                tile.surfaceLodCap = cap;\n            } else {\n                tile.surfaceLodCap = null;\n            }\n\n            const ring = this._surfaceRingIndex(camPos, tileDirWorld, tile.angularRadius);\n\n            const dotF = THREE.MathUtils.clamp(tileDirWorld.dot(focusDir), -1, 1);\n            const angleToFocus = Math.acos(dotF);\n            const stageFocusRad = (this.surfaceStageFocusAngleDeg || 65) * DEG2RAD;\n            if (ring === 0 || angleToFocus <= (stageFocusRad + (tile.angularRadius || 0))) {\n                if (Number.isFinite(this.surfaceStageMinLOD)) {\n                    const distanceCap = Number.isFinite(tile.surfaceLodDistanceCap)\n                        ? tile.surfaceLodDistanceCap\n                        : null;\n                    const floor = Number.isFinite(distanceCap)\n                        ? Math.min(this.surfaceStageMinLOD, distanceCap)\n                        : this.surfaceStageMinLOD;\n                    desired = Math.max(desired, floor);\n                }\n            }\n        } else {\n            tile.surfaceLodCap = null;\n        }\n\n        if (!this._inSurfaceMode) {\n            const cache = this._viewportCache;\n            const viewDir = cache?.viewDir;\n            const viewEdgeRad = cache?.viewEdgeRad;\n            const viewFalloffEndRad = cache?.viewFalloffEndRad;\n            if (viewDir && Number.isFinite(viewEdgeRad) && Number.isFinite(viewFalloffEndRad)) {\n                if (!tileDirWorld) {\n                    const worldQ = cache?.worldQ || this._getWorldQuaternion();\n                    tileDirWorld = this._tmpTileDir.copy(tile.centerDir).applyQuaternion(worldQ);\n                }\n                const camPos = cache?.camPos || this._getCameraPosition(camera);\n                const tileRadius = this._getTileRadius(tile, tileDirWorld);\n                const tileCenterWorld = this._tmpTileCenter.copy(tileDirWorld).multiplyScalar(tileRadius);\n                const toTile = tileCenterWorld.sub(camPos).normalize();\n                const dotView = THREE.MathUtils.clamp(toTile.dot(viewDir), -1, 1);\n                const angleToView = Math.acos(dotView);\n                const edgeAngle = Math.max(0, angleToView - (tile.angularRadius || 0));\n                if (edgeAngle > viewEdgeRad) {\n                    const denom = Math.max(1e-6, viewFalloffEndRad - viewEdgeRad);\n                    const t = THREE.MathUtils.clamp((edgeAngle - viewEdgeRad) / denom, 0, 1);\n                    const power = Number.isFinite(this.orbitLodFalloffPower) ? this.orbitLodFalloffPower : 1.0;\n                    const falloff = Math.pow(t, Math.max(0.01, power));\n                    const nearLod = policyRenderMax;\n                    let farLod = Number.isFinite(this.imageryFallbackLevel)\n                        ? this.imageryFallbackLevel\n                        : (Number.isFinite(this.basePreloadLevel) ? this.basePreloadLevel : this.minBaseLevel);\n                    farLod = Math.max(this.minBaseLevel, Math.min(farLod, nearLod));\n                    const cap = THREE.MathUtils.lerp(nearLod, farLod, falloff);\n                    desired = Math.min(desired, Math.floor(cap + 1e-6));\n                }\n            }\n        }\n\n        // Hex patch focus\n        let levelFromPatch = 0;\n        const patch = this.hexPatch;\n        if (patch && patch.centerDir) {\n            const dotP = THREE.MathUtils.clamp(tile.centerDir.dot(patch.centerDir), -1, 1);\n            const angleToPatch = Math.acos(dotP);\n\n            if (angleToPatch - tile.angularRadius <= patch.radius * 1.1) {\n                if (angleToPatch < patch.radius * 0.3) levelFromPatch = maxLevel;\n                else if (angleToPatch < patch.radius * 0.6) levelFromPatch = Math.max(4, maxLevel - 1);\n                else levelFromPatch = 3;\n            }\n        }\n\n        desired = Math.max(desired, levelFromPatch);\n        desired = Math.max(0, Math.min(maxLevel, desired));\n        desired = Math.max(desired, this.minBaseLevel);\n\n        if (!this._inSurfaceMode && this.lodMode === 'zoom' && this.viewFocusDir) {\n            if (!tileDirWorld) {\n                const worldQ = this._viewportCache?.worldQ || this._getWorldQuaternion();\n                tileDirWorld = this._tmpTileDir.copy(tile.centerDir).applyQuaternion(worldQ);\n            }\n            const dotFocus = THREE.MathUtils.clamp(tileDirWorld.dot(this.viewFocusDir), -1, 1);\n            const angleFocus = Math.acos(dotFocus) * RAD2DEG;\n            if (angleFocus < 2) {\n                desired = Math.min(maxLevel, desired + 2);\n            }\n        }\n\n        // Apply progressive surface staging cap\n        desired = Math.min(desired, surfaceStageCap);\n\n        return desired;\n    }\n\n    _tileScreenSpaceError(tile, camera) {\n        const camPos = this._getCameraPosition(camera);\n        const tileDirWorld = this._tmpTileDir.copy(tile.centerDir).applyQuaternion(this._getWorldQuaternion());\n        const tileRadius = this._getTileRadius(tile, tileDirWorld);\n        const tileCenterWorld = tileDirWorld.multiplyScalar(tileRadius);\n        const distance = Math.max(1, camPos.distanceTo(tileCenterWorld));\n        const viewportHeight = window.innerHeight || 1080;\n        const fovRad = camera.fov * DEG2RAD;\n        const pixelScale = viewportHeight / (2 * Math.tan(fovRad * 0.5));\n        return (tile.geometricError || 0) / distance * pixelScale;\n    }\n\n    _tileScreenPixels(tile, camera) {\n        const viewportHeight = window.innerHeight || 1080;\n        const fovRad = camera.fov * DEG2RAD;\n        const tanHalfFov = Math.tan(fovRad * 0.5) || 1e-4;\n        const focalLength = viewportHeight / (2 * tanHalfFov);\n        const camPos = this._getCameraPosition(camera);\n        const tileDirWorld = this._tmpTileDir.copy(tile.centerDir).applyQuaternion(this._getWorldQuaternion());\n        const tileRadius = this._getTileRadius(tile, tileDirWorld);\n        const tileCenterWorld = this._tmpTileCenter.copy(tileDirWorld).multiplyScalar(tileRadius);\n        const distance = Math.max(1, camPos.distanceTo(tileCenterWorld));\n        const tileChord = 2 * tileRadius * Math.sin(tile.angularRadius);\n        const approx = (tileChord * focalLength) / distance;\n        if (this._inSurfaceMode) return approx;\n        const camDir = this._tmpCamDir.copy(camPos).normalize();\n        const cosFactor = Math.max(0, tileDirWorld.dot(camDir));\n        return approx * cosFactor;\n    }\n\n    _cameraAltitudeAtTile(tile, camera) {\n        const camPos = this._getCameraPosition(camera);\n        const tileDirWorld = this._tmpTileDir.copy(tile.centerDir).applyQuaternion(this._getWorldQuaternion());\n        const tileRadius = Number.isFinite(tile.centerRadius)\n            ? tile.centerRadius\n            : this._getEllipsoidRadiusAtWorldDir(tileDirWorld);\n        const tileCenterWorld = tileDirWorld.multiplyScalar(tileRadius);\n        const dist = camPos.distanceTo(tileCenterWorld);\n        return Math.max(0, dist - tileRadius);\n    }\n\n    _splitDistanceThreshold(level, localAlt = 0) {\n        const base = 400_000;\n        const decay = Math.pow(0.55, Math.max(0, level));\n        const altFactor = Math.max(0, 1 - Math.min(localAlt, 100_000) / 100_000);\n        const boost = 1 + altFactor * 2; // up to 3× closer\n        return Math.max(1_000, base * decay * boost);\n    }\n\n    _mergeDistanceThreshold(level, localAlt = 0) {\n        // HYSTERESIS: Merge threshold must exceed split threshold at the PARENT level\n        // to prevent flapping. Split decay per level is 0.55×, so the merge factor\n        // must be > 1/0.55 ≈ 1.82 for cross-level stability. Using 2.0 gives a\n        // 10% safety margin: mergeThreshold(K+1) = splitThreshold(K) × 1.1.\n        return this._splitDistanceThreshold(level, localAlt) * 2.0;\n    }\n\n    _computeSurfaceLodCap(tile, camera, focusDir, camPos = null, tileDirWorld = null) {\n        if (!tile || !camera || !focusDir) return null;\n\n        const camPosResolved = camPos || this._getCameraPosition(camera);\n        const camDist = camPosResolved.length() || this.radius;\n        const horizonRad = this._getHorizonRad(camPosResolved);\n        const rawStartRad = Math.max(0, (this.surfaceLodFalloffStartDeg || 0) * DEG2RAD);\n        const startRad = Math.min(rawStartRad, Math.max(0, horizonRad - 1e-6));\n        const denom = Math.max(1e-6, horizonRad - startRad);\n\n        const worldQ = this._getWorldQuaternion();\n        const tileDir = tileDirWorld || this._tmpTileDir.copy(tile.centerDir).applyQuaternion(worldQ);\n        const dotF = THREE.MathUtils.clamp(tileDir.dot(focusDir), -1, 1);\n        const angleToFocus = Math.acos(dotF);\n        const edgeAngle = Math.max(0, angleToFocus - (tile.angularRadius || 0));\n        const t = THREE.MathUtils.clamp((edgeAngle - startRad) / denom, 0, 1);\n        const power = Number.isFinite(this.surfaceLodFalloffPower) ? this.surfaceLodFalloffPower : 1.0;\n        const falloff = Math.pow(t, Math.max(0.01, power));\n\n        let nearLod = Number.isFinite(this.surfaceLodNear) ? this.surfaceLodNear : this.surfaceStageMaxLOD;\n        let farLod = Number.isFinite(this.surfaceLodFar) ? this.surfaceLodFar : this.surfaceStageMinLOD;\n        if (nearLod < farLod) {\n            const tmp = nearLod;\n            nearLod = farLod;\n            farLod = tmp;\n        }\n\n        let cap = THREE.MathUtils.lerp(nearLod, farLod, falloff);\n        cap = THREE.MathUtils.clamp(cap, farLod, nearLod);\n\n        const maxLevel = this.maxTileLevel ?? MAX_TILE_LEVEL;\n        const policyRenderMax = Number.isFinite(this._detailPolicy?.renderMaxLod)\n            ? this._detailPolicy.renderMaxLod\n            : maxLevel;\n\n        cap = Math.min(cap, policyRenderMax);\n        cap = Math.max(cap, this.minBaseLevel);\n        const distanceCap = this._surfaceDistanceLodCap(camPosResolved, tileDir, tile.angularRadius);\n        tile.surfaceLodDistanceCap = Number.isFinite(distanceCap) ? distanceCap : null;\n        if (Number.isFinite(distanceCap)) {\n            cap = Math.min(cap, distanceCap);\n        }\n        if (this.surfaceViewCullEnabled) {\n            const metric = this._cacheSurfaceTileViewMetrics(tile, camera, tileDir);\n            if (metric && !metric._surfaceViewInFrame) {\n                const halfFov = Math.max(1e-6, this._viewportCache?.viewHalfFovRad || 0);\n                const buffer = Math.max(1e-6, (Number(this.surfaceViewBufferDeg) || 0) * DEG2RAD);\n                const edgeAngle = Number.isFinite(metric._surfaceViewEdgeAngleRad)\n                    ? metric._surfaceViewEdgeAngleRad\n                    : (halfFov + buffer);\n                const bufferT = THREE.MathUtils.clamp((edgeAngle - halfFov) / buffer, 0, 1);\n                const drop = Math.ceil((Number(this.surfacePeripheralLodDrop) || 0) * bufferT);\n                cap = Math.max(this.minBaseLevel, cap - drop);\n            }\n        }\n        return Math.floor(cap + 1e-6);\n    }\n\n    update(camera, surfacePosition = null) {\n        // Full sleep: skip all LOD, split/merge, imagery work.\n        // State is preserved so resume is instant.\n        if (this.suspended) {\n            // Even when suspended, honour suppressTileDisplay so photorealistic\n            // tiles don't render on top of visible tritree meshes.\n            if (this.suppressTileDisplay) {\n                for (const mesh of this.visibleMeshes) {\n                    mesh.visible = false;\n                }\n            }\n            return;\n        }\n\n        const perf = this.perf;\n        const perfEnabled = perf && perf.enabled;\n        const frameNow = (typeof performance !== 'undefined' && performance.now)\n            ? performance.now()\n            : Date.now();\n        this._frameNow = frameNow;\n        this._elevationVersionTick += 1;\n        // Ensure root pre-subdivision in case constructor path was skipped\n        if (!this._rootsSubdivided) {\n            this._subdivideRootsToLevel(this.initialSubdivLevel);\n            this._rootsSubdivided = true;\n        }\n        const prevSurfaceMode = this._inSurfaceMode;\n        const inSurfaceMode = this.lodMode === 'zoom' && surfacePosition;\n        this._inSurfaceMode = !!inSurfaceMode;\n        // Cold satellite imagery must not wait on broad ancestor DEM coverage.\n        // Elevation continues through the normal bounded local fetch lane.\n        const elevationCascadeEnabled = this.elevationCascadeEnabled\n            && this.imageryCoverageRequiredForRefinement !== false;\n        if (this._inSurfaceMode && !prevSurfaceMode) {\n            this._cleanupParentTileMeshes();\n        }\n        if (this._snapshotReplayQueue) {\n            this._drainSnapshotReplayQueue(this.snapshotReplayPerFrame);\n        } else {\n            this._snapshotReplayStats.lastFrameApplied = 0;\n            this._snapshotReplayStats.pending = 0;\n        }\n        const camPos = this._getCameraPosition(camera);\n        const altUnits = this._getAltitudeFromCamPos(camPos);\n        this._updateOrbitPreload(altUnits);\n        // Note: preSurfaceActive removed - orbit preload system disabled for stability\n        const stageActive = this._inSurfaceMode;\n        // Apply low-fps shedding if requested\n        this._applyLowFpsBudgets(this._lowFpsActive);\n        // CRITICAL: In surface mode, use standing position as source of truth\n        // This prevents LOD and imagery from changing when looking around\n        if (this.lodMode === 'zoom' && surfacePosition) {\n            // Use the normalized surface position (where we're standing)\n            this.viewFocusDir = surfacePosition.clone().normalize();\n            if (this.surfaceInstantStaging) {\n                this._updateSurfaceInstantStage(altUnits, frameNow);\n            } else {\n                this.surfaceCurrentMaxLODNear = Math.min(\n                    Math.max(this.surfaceStageMinLOD, this.surfaceCurrentMaxLODNear),\n                    this.surfaceStageMaxLOD\n                );\n                this.surfaceCurrentMaxLODMid = Math.max(\n                    Math.min(this.surfaceRingLodCaps.mid, this.surfaceCurrentMaxLODNear - 1),\n                    this.surfaceStageMinLOD\n                );\n                this.surfaceCurrentMaxLODFar = Math.max(\n                    Math.min(this.surfaceRingLodCaps.far, this.surfaceCurrentMaxLODNear - 2),\n                    this.surfaceStageMinLOD\n                );\n            }\n        } else {\n            // Orbit mode: use camera look direction\n            const viewDir = new THREE.Vector3();\n            camera.getWorldDirection(viewDir);\n\n            // Debug: Invert camera direction if enabled\n            if (this.debugInvertCameraDir) {\n                viewDir.negate();\n            }\n\n            const hit = rayEllipsoidIntersection(camPos, viewDir, this.group) ||\n                raySphereIntersection(camPos, viewDir);\n\n            if (hit) {\n                this.viewFocusDir = hit.clone().normalize();\n            } else {\n                // When ray misses, use camera position\n                this.viewFocusDir = camPos.clone().normalize();\n            }\n        }\n\n        // Debug: Apply optional sign flips to viewFocusDir\n        if (this.viewFocusDir) {\n            if (this.debugInvertFocusDir) {\n                this.viewFocusDir.negate();\n            }\n            if (this.debugNegateFocusX) {\n                this.viewFocusDir.x = -this.viewFocusDir.x;\n            }\n            if (this.debugNegateFocusZ) {\n                this.viewFocusDir.z = -this.viewFocusDir.z;\n            }\n        }\n\n        if (inSurfaceMode &&\n            elevationCascadeEnabled &&\n            !this._elevationCascadeCoarseReady &&\n            Number.isFinite(this.elevationCascadeCoarseMaxLevel)) {\n            const coarseCap = Math.max(\n                this.surfaceStageMinLOD,\n                Math.min(this.surfaceStageMaxLOD, Math.floor(this.elevationCascadeCoarseMaxLevel))\n            );\n            this.surfaceCurrentMaxLODNear = Math.min(this.surfaceCurrentMaxLODNear, coarseCap);\n            this.surfaceCurrentMaxLODMid = Math.min(\n                this.surfaceCurrentMaxLODMid,\n                Math.max(this.surfaceStageMinLOD, coarseCap - 1)\n            );\n            this.surfaceCurrentMaxLODFar = Math.min(\n                this.surfaceCurrentMaxLODFar,\n                Math.max(this.surfaceStageMinLOD, coarseCap - 2)\n            );\n        }\n\n        this._surfaceRingCaps = this._computeSurfaceRingCaps(camPos);\n\n        const policy = this._computeDetailPolicy(camera, surfacePosition);\n        this._detailPolicy = policy;\n        if (this.elevationClient && typeof this.elevationClient.setTargetMaxLevel === 'function') {\n            let targetMax = Number.isFinite(policy?.elevationMaxLevel)\n                ? policy.elevationMaxLevel\n                : null;\n            if (inSurfaceMode &&\n                elevationCascadeEnabled &&\n                !this._elevationCascadeCoarseReady &&\n                Number.isFinite(this.elevationCascadeCoarseMaxLevel)) {\n                targetMax = Number.isFinite(targetMax)\n                    ? Math.min(targetMax, this.elevationCascadeCoarseMaxLevel)\n                    : this.elevationCascadeCoarseMaxLevel;\n            }\n            this.elevationClient.setTargetMaxLevel(targetMax, { fullFetch: false });\n        }\n        if (this.elevationClient && typeof this.elevationClient.setRingLodCaps === 'function') {\n            const baseCap = Number.isFinite(policy?.elevationMaxLevel)\n                ? policy.elevationMaxLevel\n                : (this.maxTileLevel ?? MAX_TILE_LEVEL);\n            const ringCaps = this._surfaceRingCaps || {\n                near: baseCap,\n                mid: baseCap,\n                far: baseCap\n            };\n            const nearCap = Math.min(baseCap, Number.isFinite(ringCaps.near) ? ringCaps.near : baseCap);\n            const midCap = Math.min(baseCap, Number.isFinite(ringCaps.mid) ? ringCaps.mid : nearCap);\n            const farCap = Math.min(baseCap, Number.isFinite(ringCaps.far) ? ringCaps.far : midCap);\n            this.elevationClient.setRingLodCaps({ near: nearCap, mid: midCap, far: farCap });\n        }\n\n        const worldQ = this._getWorldQuaternion();\n        const posDelta = camPos.distanceTo(this._lastUpdateCamPos);\n        const rotDelta = this._lastUpdateCamQuat.angleTo(camera.quaternion);\n        const focusDelta = (this.viewFocusDir && this._lastUpdateFocusDir.lengthSq() > 0)\n            ? this._lastUpdateFocusDir.angleTo(this.viewFocusDir)\n            : Math.PI;\n        const worldDelta = this._lastUpdateWorldQuat.angleTo(worldQ);\n        const modeChanged = this._lastUpdateMode !== this.lodMode || this._lastUpdateSurface !== this._inSurfaceMode;\n        const poseChanged = posDelta > this._poseEpsMeters ||\n            rotDelta > this._poseEpsRad ||\n            focusDelta > this._focusEpsRad ||\n            worldDelta > this._worldEpsRad ||\n            modeChanged;\n        const idleExpired = (frameNow - this._lastFullUpdateTime) > this._maxIdleUpdateMs;\n\n        // Detect camera motion to gate heavy work\n        // RELAXED THRESHOLDS: Prevent constant fast/slow toggling during orbit navigation\n        // Old: 3km/0.57° was too sensitive, caused budget scaling to oscillate\n        const fastPosThresh = this.radius * 0.002; // ~13km for Earth radius (was ~3km)\n        const fastRotThresh = 0.05; // ~2.86° (was ~0.57°)\n        const movingFast = (posDelta > fastPosThresh) || (rotDelta > fastRotThresh);\n        if (movingFast) {\n            this._cameraFast = true;\n            // Extend cooldown to prevent rapid on/off toggling\n            this._cameraFastUntil = frameNow + (this.surfaceStageCooldownMs * 1.5);\n        } else if (this._cameraFast && frameNow > this._cameraFastUntil) {\n            this._cameraFast = false;\n        }\n\n        if (!this._basePreloadInitialized) {\n            this._initBasePreloadQueue();\n        }\n        const basePreloadPending = this.basePreloadEnabled &&\n            this._basePreloadQueue &&\n            this._basePreloadQueue.length > 0;\n\n        if (poseChanged &&\n            !modeChanged &&\n            !idleExpired &&\n            !basePreloadPending &&\n            (frameNow - this._lastTraverseTime) < this._fullUpdateIntervalMs) {\n            // Still sweep retired tiles during throttled frames (#2)\n            if (this._retiredTiles.size > 0) this._sweepRetirementPool();\n            return;\n        }\n\n        if (!poseChanged && !idleExpired && !basePreloadPending) {\n            // Still sweep retired tiles during idle frames (#2)\n            if (this._retiredTiles.size > 0) this._sweepRetirementPool();\n            return;\n        }\n\n        this._lastUpdateCamPos.copy(camPos);\n        this._lastUpdateCamQuat.copy(camera.quaternion);\n        if (this.viewFocusDir) {\n            this._lastUpdateFocusDir.copy(this.viewFocusDir);\n        }\n        this._lastUpdateWorldQuat.copy(worldQ);\n        this._lastUpdateMode = this.lodMode;\n        this._lastUpdateSurface = this._inSurfaceMode;\n\n        // SIMPLIFIED BUDGET SCALING: Remove aggressive orbit penalties that caused glitchy behavior\n        // In orbit mode, use consistent budgets instead of scaling down to 0.5x/0.4x\n        const modeScale = this._inSurfaceMode ? 1.0 : 0.85; // Orbit: 85% (was 50%)\n        const motionScale = this._cameraFast ? 0.85 : 1.0; // Fast motion: 85% to keep imagery converging while moving\n        const adaptiveSplitScale = this.adaptiveSplitBudgetEnabled\n            ? THREE.MathUtils.clamp(\n                Number.isFinite(this._adaptiveSplitBudgetScale) ? this._adaptiveSplitBudgetScale : 1.0,\n                this.adaptiveSplitBudgetMinScale || 0.35,\n                this.adaptiveSplitBudgetMaxScale || 1.0\n            )\n            : 1.0;\n        let effectiveSplitBudget = Math.max(2, Math.floor(this.splitBudget * modeScale * motionScale * adaptiveSplitScale));\n        const effectiveMergeBudgetBase = Math.max(2, Math.floor(this.mergeBudget * modeScale * motionScale));\n        let effectiveImageryBudget = Math.max(this.imageryMinBudget, Math.floor(this.imageryBudgetPerFrame * modeScale * motionScale));\n        const orbitTileScale = 0.9; // Orbit: 90% tile budget (was 70%)\n        const effectiveTileBudget = this._inSurfaceMode\n            ? this.tileBudget\n            : Math.max(1000, Math.floor(this.tileBudget * orbitTileScale));\n\n        // ── Global pressure metric (#4) ──\n        // Combines tile headroom, imagery backpressure, and retirement pool occupancy\n        // into a 0-1 score. High pressure throttles splits; low pressure lifts throttle.\n        {\n            const tileRatio = this.tileCount / Math.max(1, effectiveTileBudget);\n            const imageryPressure = this.imageryManager?.getStats?.({ includeOwnership: false })?.pressureScore ?? 0;\n            const retirementRatio = this._retiredTiles.size / Math.max(1, this._retirementMaxEntries);\n            this._globalPressure = THREE.MathUtils.clamp(\n                tileRatio * 0.5 + imageryPressure * 0.3 + retirementRatio * 0.2,\n                0, 1\n            );\n            // When pressure > 0.7, progressively throttle splits (down to 25% at pressure 1.0)\n            if (this._globalPressure > 0.7) {\n                const throttle = 1.0 - (this._globalPressure - 0.7) * (0.75 / 0.3); // 1.0 → 0.25\n                effectiveSplitBudget = Math.max(2, Math.floor(effectiveSplitBudget * Math.max(0.25, throttle)));\n            }\n        }\n\n        const focusLeafTile = (this._inSurfaceMode && this.viewFocusDir)\n            ? this.findLeafTileForWorldDir(this.viewFocusDir)\n            : null;\n\n        // Cache viewport math for this frame to avoid per-tile recompute\n        this._viewportCache = this._computeViewportCache(camera, this.viewFocusDir, worldQ);\n        this._viewportStamp += 1;\n        this._lastFullUpdateTime = frameNow;\n        this._lastTraverseTime = frameNow;\n\n        let forceImageryReset = false;\n        const imageryFocusDir = this.viewFocusDir ? this.viewFocusDir.clone().normalize() : null;\n        if (this.imageryManager && imageryFocusDir) {\n            const prevDir = this._imageryContextDir;\n            const prevAlt = this._imageryContextAlt;\n            const prevMode = this._imageryContextMode;\n            const prevSurface = this._imageryContextSurface;\n\n            const dirDeltaDeg = prevDir ? prevDir.angleTo(imageryFocusDir) * RAD2DEG : 0;\n            const altJump = prevAlt !== null\n                ? Math.abs(Math.log2((altUnits + 1) / (prevAlt + 1)))\n                : 0;\n            const modeChanged = prevMode !== null && prevMode !== this.lodMode;\n            const surfaceChanged = prevSurface !== null && prevSurface !== this._inSurfaceMode;\n\n            // RELAXED THRESHOLDS: Prevent constant imagery resets during orbit camera movement\n            // Old: fastSweep at 15°/600ms caused texture churn during normal navigation\n            // Old: hardDir at 35° was too sensitive for orbit camera panning\n            const fastSweep = dirDeltaDeg > 45 && (frameNow - this._imageryContextLastReset) > 2000;\n            const hardDir = dirDeltaDeg > 90; // Only reset on major direction changes (quarter sphere)\n            const hardAlt = altJump > 3.5; // Only reset on 8x+ altitude changes (was 2x/4x)\n\n            if ((hardDir || hardAlt || modeChanged || surfaceChanged || fastSweep) &&\n                frameNow - this._imageryContextLastReset > this.imageryResetCooldownMs) {\n                forceImageryReset = true;\n                this._imageryContextLastReset = frameNow;\n            }\n\n            const contextKey = this._computeImageryContextKey(imageryFocusDir, altUnits);\n            this._imageryContextKey = contextKey;\n            if (typeof this.imageryManager.setRequestContext === 'function') {\n                this.imageryManager.setRequestContext(contextKey, { hardReset: forceImageryReset });\n            }\n        }\n\n        // PERSISTENT VISIBILITY TRACKING: Begin new frame\n        this.visibilityTracker.beginFrame(camera, this.viewFocusDir);\n\n        this.visibleTileCount = 0;\n        this.currentMaxLevel = 0;\n        this.visibleMeshes.length = 0; // Clear visible meshes array\n        this.visibleLeafTiles.length = 0;\n        const hiddenLeafTilesForElevation = this._hiddenLeafTilesForElevation;\n        hiddenLeafTilesForElevation.length = 0;\n\n        const tilesToSplit = this._tilesToSplit;\n        tilesToSplit.length = 0;\n        const tilesToMerge = this._tilesToMerge;\n        tilesToMerge.length = 0;\n        const tilesToLoadImagery = this._tilesToLoadImagery; // Collect tiles needing imagery for prioritization\n        tilesToLoadImagery.length = 0;\n        const coarseImageryEnqueued = this._coarseImageryEnqueued; // Track parent/coarse backfill requests\n        coarseImageryEnqueued.clear();\n        const HYST = 1;\n        let imageryAppliedCount = 0;\n        let imageryVisibleCount = 0;\n        let imageryBudget = 0;\n        let imageryFullCoverage = false;\n        let imageryBackpressureState = this._imageryBackpressureState;\n        let mergesDone = 0;\n        let splitsDone = 0;\n\n        // Imagery config (shared across all tiles in this frame)\n        let imageryCfg = null;\n        if (this.imageryManager && this.imageryManager.enabled) {\n            const cfg = this.imageryManager.getConfig() || {};\n            imageryCfg = {\n                ...cfg,\n                rotation: worldQ,\n                rootZoom: this.imageryMinZoom\n            };\n            imageryBackpressureState = this._computeImageryBackpressureState();\n        } else {\n            imageryBackpressureState = {\n                active: false,\n                pressureScore: 0,\n                tileQueue: 0,\n                atlasQueue: 0,\n                tileQueueRatio: 0,\n                atlasQueueRatio: 0,\n                tileLoadRatio: 0,\n                atlasLoadRatio: 0\n            };\n            this._imageryBackpressureState = imageryBackpressureState;\n        }\n        if (imageryBackpressureState?.active) {\n            // Quality-preserving strategy: scale request admission rates, not texture/LOD targets.\n            const pressure = Number.isFinite(imageryBackpressureState.pressureScore)\n                ? THREE.MathUtils.clamp(imageryBackpressureState.pressureScore, 0, 2)\n                : 0;\n            const pressureFactor = THREE.MathUtils.clamp(1 - (pressure * 0.45), 0.1, 1.0);\n            const splitMin = Number.isFinite(this.imageryBackpressureSplitBudgetMinScale)\n                ? THREE.MathUtils.clamp(this.imageryBackpressureSplitBudgetMinScale, 0.1, 1.0)\n                : 0.45;\n            const imageryMin = Number.isFinite(this.imageryBackpressureImageryBudgetMinScale)\n                ? THREE.MathUtils.clamp(this.imageryBackpressureImageryBudgetMinScale, 0.1, 1.0)\n                : 0.4;\n            const splitScale = Math.max(splitMin, pressureFactor);\n            const imageryScale = Math.max(imageryMin, pressureFactor);\n            effectiveSplitBudget = Math.max(2, Math.floor(effectiveSplitBudget * splitScale));\n            effectiveImageryBudget = Math.max(this.imageryMinBudget, Math.floor(effectiveImageryBudget * imageryScale));\n        }\n        this._lastImageryConfig = imageryCfg;\n        if (this.photogramManager) {\n            this.photogramManager.setImageryConfig(imageryCfg);\n        }\n        const camPosSurface = camPos;\n        const focusDir = this.viewFocusDir || camPosSurface.clone().normalize();\n        const underfootLeafTile = this._inSurfaceMode\n            ? this.findLeafTileForWorldDir(camPosSurface.clone().normalize())\n            : null;\n        const underfootLineage = new Set();\n        if (underfootLeafTile) {\n            let cursor = underfootLeafTile;\n            while (cursor) {\n                underfootLineage.add(cursor);\n                cursor = cursor.parent || null;\n            }\n        }\n        const focusLineage = new Set();\n        if (focusLeafTile) {\n            let cursor = focusLeafTile;\n            while (cursor) {\n                focusLineage.add(cursor);\n                cursor = cursor.parent || null;\n            }\n        }\n        const elevationMergeGraceMs = Number.isFinite(this.elevationMergeGraceMs)\n            ? Math.max(0, this.elevationMergeGraceMs)\n            : 0;\n        const hasRecentElevationProgress = (rootTile) => {\n            if (!inSurfaceMode || elevationMergeGraceMs <= 0 || !rootTile) return false;\n            const nowMs = frameNow;\n            const stack = [rootTile];\n            while (stack.length) {\n                const tile = stack.pop();\n                if (!tile) continue;\n                const done = Number.isFinite(tile.elevationDone) ? tile.elevationDone : 0;\n                const hasData = !!tile.elevationHasData || done > 0;\n                const lastProgress = Number.isFinite(tile._elevationLastProgressMs)\n                    ? tile._elevationLastProgressMs\n                    : 0;\n                if (hasData && lastProgress > 0 && (nowMs - lastProgress) <= elevationMergeGraceMs) {\n                    return true;\n                }\n                if (Array.isArray(tile.children) && tile.children.length) {\n                    for (const child of tile.children) stack.push(child);\n                }\n            }\n            return false;\n        };\n        const isMergeProtectedTile = (tile) => {\n            if (!inSurfaceMode || !tile) return false;\n            if (underfootLineage.has(tile) || focusLineage.has(tile)) return true;\n            return hasRecentElevationProgress(tile);\n        };\n        const stageFocusRad = (this.surfaceStageFocusAngleDeg || 65) * DEG2RAD;\n        const stageRingLimit = this._inSurfaceMode ? 0 : 1;\n\n        const fallbackCoverageLevel = Number.isFinite(this.initialSubdivLevel)\n            ? Math.max(0, Math.floor(this.initialSubdivLevel))\n            : 2;\n        const tileHasRenderableImagery = (t) => !!(\n            t &&\n            typeof t.hasImageryCoverage === 'function' &&\n            t.hasImageryCoverage()\n        );\n        const tileHasVisibleCoverage = (t) => {\n            if (!t) return false;\n            if (tileHasRenderableImagery(t)) return true;\n            if (inSurfaceMode && t.mesh) return true;\n            if (t.mesh && t.level <= fallbackCoverageLevel) return true;\n            // Keep tiles visible while real imagery is in-flight to avoid blank-world regressions.\n            if (t.mesh && (t.imageryPendingKey || t.imageryReady || t.imageryInherited)) return true;\n            return false;\n        };\n        const tileHasSplitCoverage = (t) => {\n            if (!t) return false;\n            // A cold satellite replacement must reach the local footprint\n            // without waiting for continent-sized ancestor atlases. Count,\n            // time, viewshed and LOD limits still own every subdivision.\n            if (this.imageryCoverageRequiredForRefinement === false && t.level < 8) return !!t.mesh;\n            if (tileHasRenderableImagery(t)) return true;\n            return !!(t.mesh && t.level <= fallbackCoverageLevel);\n        };\n\n        const visit = (tile, suppressVisibility = false) => {\n            // CRITICAL: Early viewport culling to prevent processing off-screen tiles\n            // Can be disabled via debug flag for testing\n            const bypassUnderfootCulling = this._inSurfaceMode && underfootLineage.has(tile);\n            if (!this.debugDisableViewportCulling && !bypassUnderfootCulling) {\n                const inViewport = this._isTileInViewport(tile, camera, focusDir);\n\n                // If tile is completely outside viewport, skip subdivision and mark for merge\n                if (!inViewport) {\n                    if (tile.children) {\n                        // Tile has children but is off-screen - merge it\n                        tilesToMerge.push(tile);\n                        this._hideTileSubtreeMeshes(tile, { includeRoot: true });\n                        tile._subtreeImageryReady = false;\n                        tile._subtreeVisible = false;\n                        // Don't visit children - they're all off-screen too\n                    } else {\n                        // Leaf tile off-screen - hide it\n                        tile.setVisible(false);\n                        if (tile.mesh) this._removeTileCollider(tile.mesh);\n                        tile._subtreeVisible = false;\n                    }\n                    return;\n                }\n            } else if (bypassUnderfootCulling) {\n                // Ensure the spawn-underfoot branch is always processed in surface mode,\n                // even if transient frustum/viewshed math says otherwise.\n                tile._viewportStamp = this._viewportStamp;\n                tile._inViewport = true;\n            }\n\n            // Tile is in viewport - process normally\n            const screenPixels = this._tileScreenPixels(tile, camera);\n            const desired = this._desiredLevelForTile(tile, camera, screenPixels);\n            this.currentMaxLevel = Math.max(this.currentMaxLevel, tile.level);\n\n            if (tile.children) {\n                // IMAGERY HOLDOVER: Keep parent visible until all leaf descendants\n                // have their own WMTS imagery. Uses previous frame's state (one-frame\n                // lag is imperceptible) to avoid visiting children twice.\n                const allChildrenReady = tile.children.every(c => c._subtreeImageryReady === true);\n                const parentHasImagery = !!(tile.mesh && tileHasRenderableImagery(tile));\n                const anyDescendantVisible = tile.children.some((child) =>\n                    !!((child?.mesh && child.mesh.visible) || child?._subtreeVisible === true)\n                );\n                const parentSuppressedUntil = Number.isFinite(tile._nonOverlapSuppressedUntil)\n                    ? tile._nonOverlapSuppressedUntil\n                    : 0;\n                const parentHoldSuppressed = frameNow < parentSuppressedUntil;\n                if (!parentHoldSuppressed && parentSuppressedUntil > 0) {\n                    tile._nonOverlapSuppressedUntil = 0;\n                }\n                const holdParent = !suppressVisibility &&\n                    !allChildrenReady &&\n                    parentHasImagery &&\n                    !anyDescendantVisible &&\n                    !parentHoldSuppressed;\n                const parentAlt = this._cameraAltitudeAtTile(tile, camera);\n                // HYSTERESIS: Use merge threshold (larger than split) to prevent flapping\n                const childThreshold = this._mergeDistanceThreshold(tile.level + 1, parentAlt);\n                const canMerge = tile.level >= this.minBaseLevel;\n                const mergeDueToDistance = canMerge && parentAlt > childThreshold;\n                const mergeDueToDesired = canMerge && tile.level >= desired + HYST;\n\n                // Do not re-show parent if it is already merge-eligible.\n                const allowParentVisible = holdParent && !mergeDueToDistance && !mergeDueToDesired;\n                // CRITICAL: Apply render rules before making visible to ensure wireframe mode is respected\n                if (tile.mesh && allowParentVisible) {\n                    tile.applyRenderRules(this.renderRules);\n                }\n                tile.setVisible(allowParentVisible);\n                if (tile.mesh && tile.mesh.visible) {\n                    this.visibleTileCount++;\n                    this.visibleMeshes.push(tile.mesh);\n                    this._addTileCollider(tile.mesh);\n                }\n                if (canMerge) {\n                    if (mergeDueToDistance) {\n                        tilesToMerge.push(tile);\n                        tile._subtreeImageryReady = false;\n                        tile._subtreeVisible = anyDescendantVisible || !!(tile.mesh && tile.mesh.visible);\n                        return;\n                    }\n\n                    if (mergeDueToDesired) {\n                        tilesToMerge.push(tile);\n                    }\n                }\n                // Parent mesh management — only cleanup when NOT holding parent visible\n                if (!allowParentVisible && tile.mesh) {\n                    if (tile.level <= 4) {\n                        // Keep low LOD parents resident for fast zoom-out, just hide\n                        tile.mesh.visible = false;\n                        // Remove physics collider when tile becomes invisible\n                        this._removeTileCollider(tile.mesh);\n                    } else {\n                        tile.deferredRemoval = false;\n                        this._removeTileMesh(tile);\n                    }\n                }\n                // Suppress children when parent is holding to avoid z-fighting.\n                // Children still get meshes created and imagery scheduled.\n                const suppressChildren = suppressVisibility || allowParentVisible;\n                for (const child of tile.children) visit(child, suppressChildren);\n                // Update subtree imagery state for next frame's holdover decision\n                tile._subtreeImageryReady = tile.children.every(c => c._subtreeImageryReady === true);\n                tile._subtreeVisible = tile.children.some((child) =>\n                    !!((child?.mesh && child.mesh.visible) || child?._subtreeVisible === true)\n                ) || !!(tile.mesh && tile.mesh.visible);\n            } else {\n                const tileDirWorld = this._tmpTileDir.copy(tile.centerDir).applyQuaternion(worldQ);\n                const dotF = THREE.MathUtils.clamp(tileDirWorld.dot(focusDir), -1, 1);\n                const angleToFocus = Math.acos(dotF);\n                const angleDeg = angleToFocus * RAD2DEG;\n                const surfaceViewMetric = this._inSurfaceMode\n                    ? this._cacheSurfaceTileViewMetrics(tile, camera, tileDirWorld)\n                    : null;\n                const viewWeight = Number.isFinite(surfaceViewMetric?._surfaceViewWeight)\n                    ? surfaceViewMetric._surfaceViewWeight\n                    : 0;\n                const inCameraViewshed = !!surfaceViewMetric?._surfaceViewInFrame;\n                const inBufferedViewshed = !!surfaceViewMetric?._surfaceViewBuffered;\n                const viewEdgeAngle = Number.isFinite(surfaceViewMetric?._surfaceViewEdgeAngleRad)\n                    ? surfaceViewMetric._surfaceViewEdgeAngleRad\n                    : angleToFocus;\n                const inStageFocus = angleToFocus <= (stageFocusRad + (tile.angularRadius || 0));\n                const ring = stageActive\n                    ? this._surfaceRingIndex(camPosSurface, tileDirWorld, tile.angularRadius)\n                    : 2;\n                const inNearRing = ring === 0;\n                const inStageRing = ring <= stageRingLimit;\n                const atStageCap = tile.level >= this.surfaceCurrentMaxLODNear;\n                const forceUnderfoot = !!(underfootLeafTile && tile === underfootLeafTile);\n                const centerRingLimit = Number.isFinite(this.elevationCenterFullFetchRingLimit)\n                    ? Math.max(0, Math.floor(this.elevationCenterFullFetchRingLimit))\n                    : 0;\n                const inCenterFetchRing = ring <= centerRingLimit;\n                const cascadeAllowsRefine = !elevationCascadeEnabled || this._elevationCascadeCoarseReady;\n                const expected = Number.isFinite(tile.elevationExpected) ? tile.elevationExpected : 0;\n                const count = Number.isFinite(tile.vertexCount) ? tile.vertexCount : 0;\n                const done = Number.isFinite(tile.elevationDone) ? tile.elevationDone : 0;\n                const seeded = Number.isFinite(tile.elevationSeededCount) ? tile.elevationSeededCount : 0;\n                const hasMissing = typeof tile.hasMissingElevation === 'function'\n                    ? tile.hasMissingElevation()\n                    : (expected > 0 && count > 0 && done < expected) ||\n                      (expected === 0 && count > 0 && done === 0 && seeded === 0);\n                // Keep forced full-fetch centered underfoot to avoid queue thrash.\n                const forceNearRings = !!(stageActive && inStageFocus && (inCameraViewshed || forceUnderfoot) && (\n                    elevationCascadeEnabled ? (inCenterFetchRing && cascadeAllowsRefine) : inCenterFetchRing\n                ));\n                const shouldStickNearRings = stageActive && hasMissing && (inCameraViewshed || forceUnderfoot) && (\n                    elevationCascadeEnabled ? (inCenterFetchRing && cascadeAllowsRefine) : inCenterFetchRing\n                );\n                if (shouldStickNearRings) {\n                    tile._surfaceForceFullFetch = true;\n                } else if (tile._surfaceForceFullFetch && (!hasMissing || (elevationCascadeEnabled && !cascadeAllowsRefine))) {\n                    tile._surfaceForceFullFetch = false;\n                }\n                // Only force full fetch for critical near-surface tiles.\n                tile.forceFullFetch = !!(\n                    forceUnderfoot ||\n                    tile === focusLeafTile ||\n                    forceNearRings ||\n                    tile._surfaceForceFullFetch\n                );\n                if (stageActive && tile.elevationHoldUntilComplete && typeof tile.disableElevationHold === 'function') {\n                    tile.disableElevationHold({ flushPending: true });\n                }\n                if (stageActive) {\n                    if (elevationCascadeEnabled) {\n                        // Cascade mode: lightweight fill while awaiting coarse coverage.\n                        tile.elevationFillMaxPerFrame = inNearRing ? 48 : (ring === 1 ? 24 : 12);\n                        tile.elevationFillIntervalMs = inNearRing ? 24 : (ring === 1 ? 40 : 75);\n                    } else {\n                        // OPTIMIZED: Aggressive fill rates for rapid elevation loading (Cesium-like)\n                        tile.elevationFillMaxPerFrame = inNearRing ? 128 : (ring === 1 ? 64 : 32);\n                        tile.elevationFillIntervalMs = inNearRing ? 16 : (ring === 1 ? 33 : 66);\n                    }\n                } else {\n                    tile.elevationFillMaxPerFrame = 8;\n                    tile.elevationFillIntervalMs = 200;\n                }\n\n                tile.ensureMesh(this.group, this.material, this);\n                tile.applyRenderRules(this.renderRules);\n                if (!this.imageryInheritanceEnabled && tile.imageryInherited && typeof tile.clearImagery === 'function') {\n                    tile.clearImagery();\n                }\n                const leafHasCoverage = tileHasVisibleCoverage(tile);\n                const allowVisible = leafHasCoverage && !suppressVisibility;\n                if (this._inSurfaceMode) {\n                    if (allowVisible) {\n                        if (tile._imageryVisibleRing !== ring || !Number.isFinite(tile._imageryVisibleSince)) {\n                            tile._imageryVisibleRing = ring;\n                            tile._imageryVisibleSince = frameNow;\n                        }\n                    } else if (tile._imageryVisibleSince) {\n                        tile._imageryVisibleSince = null;\n                        tile._imageryVisibleRing = null;\n                    }\n                }\n                tile.setVisible(allowVisible);\n                if (typeof tile._setImageryLoading === 'function') {\n                    const hasLiveMap = !!(tile.mesh?.material && tile.mesh.material.map);\n                    const shouldAnimate = allowVisible &&\n                        !hasLiveMap &&\n                        !tile.imageryReady &&\n                        !tile.imageryInherited;\n                    const start = Number.isFinite(tile.imageryPendingSince) ? tile.imageryPendingSince : frameNow;\n                    tile._setImageryLoading(shouldAnimate, start);\n                }\n\n                if (allowVisible && this.photogramManager && tile.imageryReady) {\n                    this.photogramManager.considerTile(tile, { ring, reason: 'visible' });\n                }\n\n                if ((forceUnderfoot || (stageActive && (elevationCascadeEnabled ? (ring === 0 && cascadeAllowsRefine) : ring === 0))) &&\n                    typeof tile.retryRegisterMissingVertices === 'function') {\n                    if (count > 0 && (expected < count || hasMissing)) {\n                        tile.retryRegisterMissingVertices(count);\n                    }\n                }\n\n                const tileHasImageryCoverage = typeof tile.hasImageryCoverage === 'function'\n                    ? tile.hasImageryCoverage()\n                    : !!(tile.imageryReady || tile.imageryInherited);\n                if (!tileHasImageryCoverage && !tile.imageryPendingKey) {\n                    this._enqueueBasePreloadTile(tile, 'visible-no-imagery');\n                }\n\n                if (!allowVisible && tile.mesh) {\n                    // Keep physics collider lifecycle strictly tied to render visibility.\n                    this._removeTileCollider(tile.mesh);\n                }\n\n                // PERSISTENT VISIBILITY TRACKING: Mark this tile as visible\n                if (allowVisible) {\n                    const targetZoom = this._imageryZoomForTile(tile, camera);\n                    this.visibilityTracker.markVisible(tile, {\n                        screenPixels,\n                        distanceToCamera: this._cameraAltitudeAtTile(tile, camera),\n                        angleToFocus: viewEdgeAngle,\n                        inFrustum: inCameraViewshed || !this._inSurfaceMode,\n                        targetImageryZoom: targetZoom,\n                        underfoot: !!(underfootLeafTile && tile === underfootLeafTile),\n                        focus: inCameraViewshed && viewWeight >= 0.35,\n                        viewWeight\n                    });\n                }\n\n                if (tile.mesh && tile.mesh.visible) {\n                    this.visibleTileCount++;\n                    this.visibleMeshes.push(tile.mesh);\n                    this.visibleLeafTiles.push(tile);\n                    // Add tile as physics collider when it becomes visible\n                    this._addTileCollider(tile.mesh);\n                } else if (tile.mesh && inSurfaceMode) {\n                    // Ensure elevation fetch covers nearby tiles even when imagery isn't ready.\n                    hiddenLeafTilesForElevation.push(tile);\n                }\n                tile._subtreeVisible = !!(tile.mesh && tile.mesh.visible);\n\n                // Collect tiles that need imagery (prioritize later).\n                if (imageryCfg) {\n                    if (forceImageryReset && tile.imageryPendingKey) {\n                        tile.imageryPendingKey = null;\n                        tile.imageryRequestedZoom = null;\n                        tile.imageryPendingUv = null;\n                        tile.imageryPendingSince = null;\n                        tile.imageryPendingAttempts = 0;\n                    }\n\n                    const z = this._imageryZoomForTile(tile, camera);\n\n                    // Only upgrade imagery, never downgrade (prevents flapping)\n                    // If tile already has higher zoom imagery, keep it\n                    const currentZoom = tile.imageryTargetZoom;\n                    const needsUpgrade = !Number.isFinite(currentZoom) || currentZoom < z;\n\n                    const totalCount = tile.positionAttr?.count || tile.vertexCount || 0;\n                    const needsUvRefresh = Number.isFinite(totalCount) &&\n                        Number.isFinite(tile._imageryVertexCount) &&\n                        tile._imageryVertexCount !== totalCount;\n                    const needs =\n                        !tile.imageryReady ||\n                        tile.imageryVersion !== imageryCfg.versionId ||\n                        needsUpgrade ||\n                        needsUvRefresh;\n\n                    const isBlank = typeof tile.hasImageryCoverage === 'function'\n                        ? !tile.hasImageryCoverage()\n                        : (!tile.imageryReady && !tile.imageryInherited);\n                    const nearRingTile = Number.isFinite(tile._imageryVisibleRing) && tile._imageryVisibleRing <= 1;\n                    const allowImageryScheduling = !this._cameraFast ||\n                        isBlank ||\n                        nearRingTile ||\n                        tile === focusLeafTile ||\n                        tile === underfootLeafTile;\n                    if (allowImageryScheduling) {\n                        const camPosForRing = this._getCameraPosition(camera);\n                        const tileDirForRing = this._tmpTileDir.copy(tile.centerDir).applyQuaternion(this._getWorldQuaternion());\n                        const ring = this._surfaceRingIndex(camPosForRing, tileDirForRing, tile.angularRadius);\n\n                        let allowPendingOverride = false;\n                        if (tile.imageryPendingKey) {\n                            const pendingZoom = Number.isFinite(tile.imageryRequestedZoom)\n                                ? tile.imageryRequestedZoom\n                                : tile.imageryTargetZoom;\n                            const pendingAgeMs = Number.isFinite(tile.imageryPendingSince)\n                                ? (frameNow - tile.imageryPendingSince)\n                                : Infinity;\n                            const clearPending = () => {\n                                tile.imageryPendingKey = null;\n                                tile.imageryRequestedZoom = null;\n                                tile.imageryPendingUv = null;\n                                tile.imageryPendingSince = null;\n                            };\n\n                            if (this._inSurfaceMode) {\n                                // Surface mode: allow override if pending zoom is lower than target (upgrade)\n                                // Never cancel if pending is higher (would cause flapping)\n                                if (Number.isFinite(pendingZoom) && pendingZoom < z) {\n                                    if (!isBlank || pendingAgeMs > this.imageryPendingStallMs) {\n                                        clearPending();\n                                        allowPendingOverride = true;\n                                    }\n                                } else if (isBlank && pendingAgeMs > this.imageryPendingStallMs) {\n                                    // Surface mode stall recovery: blank tiles must not remain pending indefinitely.\n                                    clearPending();\n                                    allowPendingOverride = true;\n                                }\n                            } else {\n                                // Orbit mode: allow override if pending is much higher than needed (downgrade)\n                                if (Number.isFinite(pendingZoom) && pendingZoom > z + 1) {\n                                    clearPending();\n                                    allowPendingOverride = true;\n                                } else if (isBlank && pendingAgeMs > this.imageryPendingStallMs) {\n                                    clearPending();\n                                    allowPendingOverride = true;\n                                }\n                            }\n                        }\n\n                        if (needs && (!tile.imageryPendingKey || allowPendingOverride)) {\n                            // Priority model:\n                            // 1) Center-out for blank tiles (underfoot/focus, then ring, then higher LOD).\n                            // 2) Then angle/level/focus boosts for non-blank upgrade requests.\n                            const isUnderfoot = !!(underfootLeafTile && tile === underfootLeafTile);\n                            const isFocus = !!(\n                                (focusLeafTile && tile === focusLeafTile) ||\n                                (inCameraViewshed && viewWeight >= 0.35)\n                            );\n                            let priority = 0;\n                            if (isBlank) {\n                                const ringPriority = ring === 0 ? 3_000_000 : (ring === 1 ? 1_000_000 : 250_000);\n                                const levelPriority = Math.max(0, tile.level) * 8_000;\n                                const centerPriority = Math.max(0, 60_000 - (angleDeg * 800));\n                                priority = ringPriority + levelPriority + centerPriority;\n                                if (isUnderfoot) priority += 2_000_000;\n                                if (isFocus) priority += 1_000_000;\n                                priority += Math.floor(viewWeight * 1_500_000);\n                            } else {\n                                priority = 1000.0 * Math.exp(-angleDeg / 15.0);\n                                priority *= (1.0 + tile.level * 2.0);\n                                // Downweight mid/far rings for non-blanks\n                                const ringFactor = ring === 0 ? 1.0 : (ring === 1 ? 0.6 : 0.3);\n                                priority *= ringFactor;\n                                priority += viewWeight * 25_000;\n                            }\n\n                            if (focusLeafTile && tile === focusLeafTile) {\n                                priority = Math.max(priority, 100000);\n                            }\n\n                            // PHASE 1: Massive priority boost for recently subdivided tiles\n                            // This ensures children get their imagery quickly after subdivision\n                            if (tile.parent && tile.parent.subdivisionTimestamp) {\n                                const age = frameNow - tile.parent.subdivisionTimestamp;\n                                if (age < 2000) { // Within 2 seconds of subdivision\n                                    priority *= 10.0; // 10x priority multiplier\n                                }\n                            }\n\n                            tilesToLoadImagery.push({\n                                tile,\n                                z,\n                                priority,\n                                isBlank,\n                                ring,\n                                underfoot: isUnderfoot,\n                                focus: isFocus,\n                                viewWeight,\n                                level: tile.level\n                            });\n\n                            // Parent fallback backbone: always request at least one coarser parent\n                            // for blank tiles so coverage appears before high-res finishes.\n                            const parent = tile.parent;\n                            if (isBlank &&\n                                parent &&\n                                !parent.imageryReady &&\n                                !parent.imageryPendingKey &&\n                                !coarseImageryEnqueued.has(parent)) {\n                                coarseImageryEnqueued.add(parent);\n                                const parentDirWorld = this._tmpTileDir.copy(parent.centerDir).applyQuaternion(this._getWorldQuaternion());\n                                const parentRadius = this._getTileRadius(parent, parentDirWorld);\n                                const parentRing = this._surfaceRingIndex(camPosForRing, parentDirWorld, parent.angularRadius);\n                                const parentPriority = Math.max(1500, priority * 0.35);\n                                const parentZ = this._imageryZoomForTile(parent, camera);\n                                tilesToLoadImagery.push({\n                                    tile: parent,\n                                    z: parentZ,\n                                    priority: parentPriority,\n                                    isBlank: true,\n                                    ring: parentRing,\n                                    underfoot: false,\n                                    focus: false,\n                                    level: parent.level\n                                });\n                            }\n                        }\n                    }\n                }\n\n\n                // Track whether this leaf has imagery for parent holdover.\n                // Inherited imagery counts as ready — children display parent's\n                // texture immediately, own WMTS loads asynchronously.\n                tile._subtreeImageryReady = !!(tile.imageryReady || tile.imageryInherited);\n\n                const localAlt = this._cameraAltitudeAtTile(tile, camera);\n                const localThreshold = this._splitDistanceThreshold(tile.level, localAlt);\n                if (tile.level >= this.minBaseLevel && localAlt > localThreshold) {\n                    return;\n                }\n\n                const forceMinLevel = tile.level < this.minBaseLevel;\n                const canSplitByPixels = screenPixels >= 1;\n                const hasCoverageForSplit = tileHasSplitCoverage(tile);\n                let shouldSplit = hasCoverageForSplit && (forceMinLevel || (tile.level < desired && canSplitByPixels));\n\n                if (shouldSplit && tile.level < this.maxTileLevel) {\n                    // CRITICAL: In surface mode, prevent splitting beyond current stage cap\n                    // This ensures we don't create half-fetched tiles at multiple LOD levels\n                    if (stageActive && tile.level >= this.surfaceCurrentMaxLODNear) {\n                        shouldSplit = false; // Don't split beyond current stage LOD\n                    } else if (stageActive && tile.level >= this.surfaceStageMinLOD && !this.imageryInheritanceEnabled) {\n                        // Within staging range: gate by elevation readiness.\n                        // When imagery inheritance is enabled, children get parent imagery\n                        // and interpolated elevation on split — no visual degradation,\n                        // so this gate is unnecessary. Elevation loads asynchronously.\n                        const readyRatio = this._tileElevationReadyRatio(tile);\n                        if (readyRatio < this.refineReadyRatio) {\n                            shouldSplit = false;\n                        }\n                    }\n                }\n\n                if (shouldSplit && tile.level < this.maxTileLevel) {\n                    // CRITICAL: Only split tiles that are reasonably close to focus\n                    // This prevents global tile explosion when zooming\n                    const altUnits = this._getAltitudeFromCamPos(this._getCameraPosition(camera));\n                    let maxAngle = 90; // Default: split anything in view\n\n                    if (altUnits < 10_000) {\n                        // Close to surface: very tight focus (only split what you're looking at)\n                        maxAngle = 30;\n                    } else if (altUnits < 100_000) {\n                        // Medium altitude: moderate focus\n                        maxAngle = 45;\n                    } else if (altUnits < 500_000) {\n                        // High altitude: wider focus\n                        maxAngle = 60;\n                    }\n\n                    // During fast motion: tighter angle cone, only nearest tiles (#5)\n                    if (this._cameraFast) {\n                        maxAngle = Math.min(maxAngle, 20);\n                    }\n\n                    const splitInFocus = this._inSurfaceMode\n                        ? (forceUnderfoot || (inBufferedViewshed && (!this._cameraFast || inCameraViewshed)))\n                        : angleDeg < maxAngle;\n                    if (splitInFocus) {\n                        // Priority model: split closer tiles first, then by LOD need\n                        // Calculate distance to tile center\n                        const tileRadius = this._getTileRadius(tile, tileDirWorld);\n                        const tileCenterWorld = this._tmpTileCenter.copy(tileDirWorld).multiplyScalar(tileRadius);\n                        const distanceToTile = camPos.distanceTo(tileCenterWorld);\n\n                        // Base priority: how many levels behind this tile is\n                        let priority = (desired - tile.level) * 100;\n\n                        // Distance factor: closer tiles get higher priority\n                        // Use inverse log scale: at 1m +1000, at 100m +600, at 10km +200\n                        const distancePriority = Math.max(0, 1000 - Math.log10(Math.max(1, distanceToTile)) * 200);\n\n                        // During motion, massively boost distance priority so closest tiles\n                        // are split first — peripheral tiles can wait (#5)\n                        if (this._cameraFast) {\n                            priority += distancePriority * 3;\n                            priority += viewWeight * 2200;\n                            priority -= viewEdgeAngle * RAD2DEG * 10;\n                        } else {\n                            priority += distancePriority;\n                            priority += viewWeight * 1400;\n                            priority -= viewEdgeAngle * RAD2DEG * 2;\n                        }\n\n                        tilesToSplit.push({ tile, priority });\n                    }\n                }\n            }\n        };\n\n        if (perfEnabled) perf.start('lod.traverse');\n        for (const root of this.rootTiles) {\n            visit(root, false);\n        }\n        if (perfEnabled) perf.end('lod.traverse');\n\n        // PERSISTENT VISIBILITY TRACKING: End frame and rebuild lists\n        this.visibilityTracker.endFrame();\n\n        // Enforce 1-LOD constraint: mark tiles for subdivision if neighbors are 2+ levels higher\n        // ENABLED for surface mode to prevent gaps and ensure proper stitching\n        if (inSurfaceMode && !this._cameraFast) {\n            if (perfEnabled) perf.start('lod.constraint');\n            this._enforce1LODConstraint(tilesToSplit);\n            if (perfEnabled) perf.end('lod.constraint');\n        }\n\n        // Elevation registration retries + stage readiness check\n        let stageReady = true;\n        let stageTileCount = 0;\n        let stageProgressSum = 0;\n        let stageReadyCount = 0;\n        let fullTileCount = 0;\n        let fullTileReadyCount = 0;\n        if (perfEnabled) perf.start('lod.stage');\n        if (stageActive && !this._cameraFast) {\n            let retryBudget = this.surfaceElevationRetryBudget;\n            const stageTiles = hiddenLeafTilesForElevation.length\n                ? this.visibleLeafTiles.concat(hiddenLeafTilesForElevation)\n                : this.visibleLeafTiles;\n            for (const tile of stageTiles) {\n                const tileDirWorld = this._tmpTileDir.copy(tile.centerDir).applyQuaternion(worldQ);\n                const dotF = THREE.MathUtils.clamp(tileDirWorld.dot(focusDir), -1, 1);\n                const angleToFocus = Math.acos(dotF);\n                const inStageFocus = angleToFocus <= (stageFocusRad + (tile.angularRadius || 0));\n                if (!inStageFocus) continue;\n                const ring = this._surfaceRingIndex(camPosSurface, tileDirWorld, tile.angularRadius);\n                if (ring > stageRingLimit) continue;\n\n                const needsFullFetch = !!(tile.forceFullFetch &&\n                    Number.isFinite(tile.vertexCount) &&\n                    tile.vertexCount > 0 &&\n                    tile.elevationExpected !== tile.vertexCount);\n                const hasMissing = typeof tile.hasMissingElevation === 'function' && tile.hasMissingElevation();\n                if (retryBudget > 0 &&\n                    typeof tile.retryRegisterMissingVertices === 'function' &&\n                    (hasMissing || needsFullFetch)) {\n                    const retryScale = ring === 0 ? 4 : 1;\n                    const perTile = Math.min(this.surfaceElevationRetryPerTile * retryScale, retryBudget);\n                    const added = tile.retryRegisterMissingVertices(perTile);\n                    retryBudget -= added;\n                }\n\n                // CRITICAL FIX: Track tiles at or near stage cap in focus cone\n                // Track tiles at current cap OR one level below (approaching tiles)\n                // This ensures we always have tiles to track for progression\n                const nearStageCap = tile.level >= (this.surfaceCurrentMaxLODNear - 1);\n                if (nearStageCap && inStageFocus) {\n                    stageTileCount++;\n                    const readyRatio = (elevationCascadeEnabled && inSurfaceMode)\n                        ? this._tileElevationAuthoritativeRatio(tile)\n                        : this._tileElevationReadyRatio(tile);\n\n                    if (tile.forceFullFetch && typeof tile.isElevationComplete === 'function') {\n                        fullTileCount++;\n                        if (readyRatio >= this.refineReadyRatio) fullTileReadyCount++;\n                    }\n\n                    stageProgressSum += Math.min(1, Math.max(0, readyRatio));\n                    if (readyRatio >= this.refineReadyRatio) stageReadyCount++;\n                }\n            }\n\n            if (stageTileCount === 0) {\n                stageReady = false;\n            } else {\n                const ratioReady = (stageReadyCount / stageTileCount) >= this.stageReadyRatio;\n                // CRITICAL FIX: Only require tiles AT the current LOD cap to be complete\n                // Don't block on tiles that are still being created or haven't started fetching yet\n                const fullReady = fullTileCount === 0 ||\n                                  (fullTileReadyCount / Math.max(1, fullTileCount)) >= this.stageReadyRatio;\n                stageReady = ratioReady && fullReady;\n            }\n        } else {\n            stageReady = false;\n        }\n        if (perfEnabled) perf.end('lod.stage');\n        this.surfaceStageExpected = stageTileCount;\n        this.surfaceStageDone = stageProgressSum;\n        this.surfaceStageProgress = stageTileCount > 0 ? (stageProgressSum / stageTileCount) : 0;\n        this.surfaceStageProgressLevel = stageActive ? this.surfaceCurrentMaxLODNear : null;\n\n        // Debug: Log staging status (disabled for performance - re-enable for debugging)\n        // const shouldLog = frameNow - (this._lastStageLog || 0) > 1000;\n        // if (stageActive && shouldLog) { ... }\n\n        if (perfEnabled) perf.start('lod.activeElevation');\n        if (this.elevationClient && typeof this.elevationClient.setActiveTiles === 'function') {\n            // FIXED: Always allow elevation fetching in all modes\n            // ElevationClient handles its own network throttling\n            const allowFetch = true;\n            const centricFetchMode = inSurfaceMode && this.elevationFetchMode !== 'classic';\n            const coarseCascadePhase = inSurfaceMode && elevationCascadeEnabled && !this._elevationCascadeCoarseReady;\n            if (allowFetch) {\n                if (this.elevationClient) {\n                    const canSetSchedulingProfile = typeof this.elevationClient.setSchedulingProfile === 'function';\n                    if (!this._elevationRingDefaults && typeof this.elevationClient.getSchedulingProfile === 'function') {\n                        this._elevationRingDefaults = this.elevationClient.getSchedulingProfile();\n                    }\n                    if (inSurfaceMode && canSetSchedulingProfile) {\n                        if (centricFetchMode) {\n                            const targetMode = coarseCascadePhase ? 'cascade-coarse' : 'centric';\n                            if (this._elevationSchedulingMode !== targetMode &&\n                                typeof this.elevationClient.getSchedulingProfile === 'function') {\n                                const currentProfile = this.elevationClient.getSchedulingProfile();\n                                if (currentProfile) {\n                                    this._elevationRingDefaults = currentProfile;\n                                }\n                            }\n                            if (coarseCascadePhase) {\n                                // Coarse coverage-first scheduling: fill nearby rings before center refinement.\n                                this.elevationClient.setSchedulingProfile({\n                                    ringBudgetWeights: { near: 0.52, mid: 0.33, far: 0.15 },\n                                    ringStrideMultiplier: { near: 1, mid: 1, far: 1 },\n                                    sampleStrideMultiplier: 1\n                                });\n                                this._elevationSchedulingMode = 'cascade-coarse';\n                            } else {\n                                this.elevationClient.setSchedulingProfile({\n                                    ringBudgetWeights: { near: 0.94, mid: 0.05, far: 0.01 },\n                                    ringStrideMultiplier: { near: 1, mid: 2, far: 3 },\n                                    sampleStrideMultiplier: 1\n                                });\n                                this._elevationSchedulingMode = 'centric';\n                            }\n                        } else {\n                            if ((this._elevationSchedulingMode === 'centric' || this._elevationSchedulingMode === 'cascade-coarse') &&\n                                this._elevationRingDefaults) {\n                                this.elevationClient.setSchedulingProfile(this._elevationRingDefaults);\n                            }\n                            this._elevationSchedulingMode = 'classic';\n                        }\n                    } else if ((this._elevationSchedulingMode === 'centric' || this._elevationSchedulingMode === 'cascade-coarse') &&\n                        this._elevationRingDefaults &&\n                        canSetSchedulingProfile) {\n                        this.elevationClient.setSchedulingProfile(this._elevationRingDefaults);\n                        this._elevationSchedulingMode = 'default';\n                    } else if (!inSurfaceMode) {\n                        this._elevationSchedulingMode = 'default';\n                    } else if (this._elevationRingDefaults && canSetSchedulingProfile) {\n                        // Ensure defaults are restored if no explicit mode was applied yet.\n                        if (this._elevationSchedulingMode !== 'classic') {\n                            this.elevationClient.setSchedulingProfile(this._elevationRingDefaults);\n                            this._elevationSchedulingMode = 'classic';\n                        }\n                    }\n                }\n                if (inSurfaceMode && camPosSurface && focusDir) {\n                    const anchor = this._elevationQueueAnchor;\n                    if (!anchor) {\n                        this._elevationQueueAnchor = {\n                            pos: camPosSurface.clone(),\n                            dir: focusDir.clone().normalize()\n                        };\n                        if (elevationCascadeEnabled) {\n                            this._elevationCascadeCoarseReady = false;\n                            this._elevationCascadeCoverageRatio = 0;\n                            this._elevationCascadeReadyTiles = 0;\n                            this._elevationCascadeTotalTiles = 0;\n                        }\n                    } else {\n                        const dist = anchor.pos.distanceTo(camPosSurface);\n                        const angle = anchor.dir.angleTo(focusDir);\n                        const maxDist = Math.max(\n                            this.elevationQueueResetDistance,\n                            (Number.isFinite(this.surfaceRingFarMeters) ? this.surfaceRingFarMeters : 0) * 2\n                        );\n                        const maxAngle = (this.elevationQueueResetAngleDeg || 0) * DEG2RAD;\n                        const distanceReset = dist > maxDist;\n                        const angleReset = Number.isFinite(maxAngle) && maxAngle > 0 && angle > maxAngle;\n                        if (distanceReset || angleReset) {\n                            this._elevationQueueAnchor = {\n                                pos: camPosSurface.clone(),\n                                dir: focusDir.clone().normalize()\n                            };\n                            if (elevationCascadeEnabled && distanceReset) {\n                                this._elevationCascadeCoarseReady = false;\n                                this._elevationCascadeCoverageRatio = 0;\n                                this._elevationCascadeReadyTiles = 0;\n                                this._elevationCascadeTotalTiles = 0;\n                            }\n                            if (distanceReset && this.elevationClient && typeof this.elevationClient.kickSurfaceMode === 'function') {\n                                this.elevationClient.kickSurfaceMode({ clearPending: distanceReset });\n                            } else if (distanceReset && this.elevationClient && typeof this.elevationClient.clearPendingRequests === 'function') {\n                                this.elevationClient.clearPendingRequests({ immediateReschedule: true });\n                            }\n                        }\n                    }\n                }\n\n                if (this._elevationForceTiles.size) {\n                    for (const tile of this._elevationForceTiles) {\n                        if (tile) tile._elevForceFetch = false;\n                    }\n                }\n                this._elevationForceTiles.clear();\n                let forceCount = 0;\n                let missingCount = 0;\n                const coverageEntries = [];\n                const coverageTileSet = new Set(this.visibleLeafTiles || []);\n                if (Array.isArray(hiddenLeafTilesForElevation) && hiddenLeafTilesForElevation.length) {\n                    for (const tile of hiddenLeafTilesForElevation) {\n                        if (tile) coverageTileSet.add(tile);\n                    }\n                }\n                if (underfootLeafTile) coverageTileSet.add(underfootLeafTile);\n                if (focusLeafTile) coverageTileSet.add(focusLeafTile);\n                const coverageTiles = Array.from(coverageTileSet);\n                let allRetryBudget = 0;\n                let cascadeAllowsRefine = true;\n                if (inSurfaceMode) {\n                    const baseBudget = Number.isFinite(this.surfaceElevationRetryBudget)\n                        ? this.surfaceElevationRetryBudget\n                        : 256;\n                    const tileCount = coverageTiles.length;\n                    allRetryBudget = Math.min(4096, Math.max(baseBudget * 2, tileCount * 12));\n\n                    const tileReadyThreshold = Number.isFinite(this.elevationCascadeTileReadyRatio)\n                        ? THREE.MathUtils.clamp(this.elevationCascadeTileReadyRatio, 0, 1)\n                        : 0.08;\n                    const coarseReadyThreshold = Number.isFinite(this.elevationCascadeCoarseReadyRatio)\n                        ? THREE.MathUtils.clamp(this.elevationCascadeCoarseReadyRatio, 0, 1)\n                        : 0.9;\n                    const minVisibleTiles = Number.isFinite(this.elevationCascadeMinVisibleTiles)\n                        ? Math.max(0, Math.floor(this.elevationCascadeMinVisibleTiles))\n                        : 0;\n                    let coarseReadyTiles = 0;\n                    let coarseTotalTiles = 0;\n                    for (const tile of coverageTiles) {\n                        if (!tile) continue;\n                        const count = Number.isFinite(tile.vertexCount) ? tile.vertexCount : 0;\n                        if (count <= 0) continue;\n                        coarseTotalTiles++;\n                        const readyRatio = this._tileElevationAuthoritativeRatio(tile);\n                        if (readyRatio >= tileReadyThreshold) {\n                            coarseReadyTiles++;\n                        }\n                    }\n                    const coverageRatio = coarseTotalTiles > 0\n                        ? (coarseReadyTiles / coarseTotalTiles)\n                        : 1;\n                    const shouldGateRefine = elevationCascadeEnabled &&\n                        coarseTotalTiles >= minVisibleTiles;\n                    cascadeAllowsRefine = !shouldGateRefine || coverageRatio >= coarseReadyThreshold;\n                    this._elevationCascadeReadyTiles = coarseReadyTiles;\n                    this._elevationCascadeTotalTiles = coarseTotalTiles;\n                    this._elevationCascadeCoverageRatio = coverageRatio;\n                    this._elevationCascadeCoarseReady = cascadeAllowsRefine;\n                } else {\n                    this._elevationCascadeReadyTiles = 0;\n                    this._elevationCascadeTotalTiles = 0;\n                    this._elevationCascadeCoverageRatio = 1;\n                    this._elevationCascadeCoarseReady = true;\n                }\n                if (inSurfaceMode) {\n                    const camDir = camPosSurface.clone().normalize();\n                    const centerFullFetchRingLimit = Number.isFinite(this.elevationCenterFullFetchRingLimit)\n                        ? Math.max(0, Math.floor(this.elevationCenterFullFetchRingLimit))\n                        : 0;\n                    for (const tile of coverageTiles) {\n                        if (!tile) continue;\n                        const count = Number.isFinite(tile.vertexCount) ? tile.vertexCount : 0;\n                        const tileDirWorld = this._tmpTileDir.copy(tile.centerDir).applyQuaternion(worldQ);\n                        const ring = this._surfaceRingIndex(camPosSurface, tileDirWorld, tile.angularRadius);\n                        const inCenterFetchRing = ring <= centerFullFetchRingLimit;\n                        const viewMetric = this._cacheSurfaceTileViewMetrics(tile, camera, tileDirWorld);\n                        const viewWeight = Number.isFinite(viewMetric?._surfaceViewWeight)\n                            ? viewMetric._surfaceViewWeight\n                            : 0;\n                        const inElevationViewshed = !!viewMetric?._surfaceViewInFrame;\n                        let shouldForceFullFetch;\n                        if (elevationCascadeEnabled) {\n                            // Cascade mode: coarse coverage first, then center refinement.\n                            const forceFocus = tile === focusLeafTile;\n                            const forceUnderfoot = tile === underfootLeafTile;\n                            const centerCandidate = forceFocus || forceUnderfoot ||\n                                (inCenterFetchRing && inElevationViewshed);\n                            const done = Number.isFinite(tile.elevationDone) ? tile.elevationDone : 0;\n                            const seeded = Number.isFinite(tile.elevationSeededCount) ? tile.elevationSeededCount : 0;\n                            const expectedFromTile = (Number.isFinite(tile.elevationExpected) && tile.elevationExpected > 0)\n                                ? tile.elevationExpected\n                                : count;\n                            const hasMissingFromTile = typeof tile.hasMissingElevation === 'function'\n                                ? tile.hasMissingElevation()\n                                : (expectedFromTile > 0 && done < expectedFromTile);\n                            // In cascade mode, only underfoot/focus bypass the coarse gate.\n                            // Center rings switch to full-fetch after coarse coverage is ready.\n                            const fullFetchGateOpen = cascadeAllowsRefine || forceUnderfoot || forceFocus;\n                            const shouldStickFullFetch = centerCandidate && fullFetchGateOpen && hasMissingFromTile;\n                            if (shouldStickFullFetch) {\n                                tile._surfaceForceFullFetch = true;\n                            } else if (tile._surfaceForceFullFetch && (!hasMissingFromTile || !fullFetchGateOpen)) {\n                                tile._surfaceForceFullFetch = false;\n                            }\n                            shouldForceFullFetch = !!(\n                                forceUnderfoot ||\n                                forceFocus ||\n                                (fullFetchGateOpen && centerCandidate) ||\n                                tile._surfaceForceFullFetch\n                            );\n                        } else {\n                            // Non-cascade path: prioritize underfoot/focus and center rings.\n                            shouldForceFullFetch = !!(\n                                tile.forceFullFetch ||\n                                tile._surfaceForceFullFetch ||\n                                tile === focusLeafTile ||\n                                tile === underfootLeafTile ||\n                                (inCenterFetchRing && inElevationViewshed)\n                            );\n                            tile._surfaceForceFullFetch = shouldForceFullFetch;\n                        }\n                        tile.forceFullFetch = shouldForceFullFetch;\n                        const done = Number.isFinite(tile.elevationDone) ? tile.elevationDone : 0;\n                        const seeded = Number.isFinite(tile.elevationSeededCount) ? tile.elevationSeededCount : 0;\n                        const expected = (tile.forceFullFetch && count > 0)\n                            ? count\n                            : (Number.isFinite(tile.elevationExpected) && tile.elevationExpected > 0\n                                ? tile.elevationExpected\n                                : count);\n                        const hasMissing = typeof tile.hasMissingElevation === 'function'\n                            ? tile.hasMissingElevation()\n                            : (expected > 0 && done < expected);\n                        const centerPriorityTile = shouldForceFullFetch ||\n                            tile === focusLeafTile ||\n                            tile === underfootLeafTile ||\n                            ((!elevationCascadeEnabled || cascadeAllowsRefine) &&\n                                inCenterFetchRing && inElevationViewshed);\n                        const authoritativeMissing = count > 0 && done < count;\n                        const missing = centerPriorityTile\n                            ? authoritativeMissing\n                            : (hasMissing || (expected === 0 && tile.vertexCount > 0 && done === 0 && seeded === 0));\n                        if (missing && allRetryBudget > 0 &&\n                            typeof tile.retryRegisterMissingVertices === 'function' &&\n                            count > 0) {\n                            const perTile = inCenterFetchRing ? 96 : (ring === 1 ? 24 : 8);\n                            const budget = Math.min(perTile, allRetryBudget);\n                            const added = tile.retryRegisterMissingVertices(budget);\n                            allRetryBudget -= added;\n                        }\n                        if (!missing) continue;\n                        const dot = THREE.MathUtils.clamp(tileDirWorld.dot(camDir), -1, 1);\n                        const angle = Math.acos(dot);\n                        const edgeAngle = Math.max(0, angle - (tile.angularRadius || 0));\n                        const surfaceRadius = this._getTileRadius(tile, tileDirWorld);\n                        const arcDist = edgeAngle * surfaceRadius;\n                        const alt = this._getAltitudeFromCamPos(camPosSurface);\n                        const distance = Math.max(arcDist, alt);\n                        const visibleSince = Number.isFinite(tile._imageryVisibleSince)\n                            ? tile._imageryVisibleSince\n                            : frameNow;\n                        const visibleAgeMs = Math.max(0, frameNow - visibleSince);\n                        const shouldForceQueueFetch = shouldForceFullFetch || (\n                            elevationCascadeEnabled &&\n                            ring <= 1 &&\n                            missing &&\n                            visibleAgeMs >= 3000\n                        );\n                        if (shouldForceQueueFetch) {\n                            tile._elevForceFetch = true;\n                            this._elevationForceTiles.add(tile);\n                            forceCount++;\n                        }\n                        coverageEntries.push({\n                            tile,\n                            level: Number.isFinite(tile.level) ? tile.level : 0,\n                            distance,\n                            ring,\n                            viewWeight,\n                            inView: inElevationViewshed\n                        });\n                        missingCount++;\n                    }\n                }\n                this.elevationForceCount = forceCount;\n                this.elevationMissingCount = missingCount;\n\n                if (typeof this.elevationClient.setActiveScanLimits === 'function') {\n                    const visibleCount = this.visibleLeafTiles.length;\n                    const orbitTileCount = (!inSurfaceMode && this.orbitElevationGlobal)\n                        ? this._getOrbitElevationTiles().length\n                        : 0;\n                    const baseTileScan = Number.isFinite(this.elevationClient.activeTileScanMaxBase)\n                        ? this.elevationClient.activeTileScanMaxBase\n                        : this.elevationClient.activeTileScanMax;\n                    const baseCandidateMax = Number.isFinite(this.elevationClient.activeCandidateMaxBase)\n                        ? this.elevationClient.activeCandidateMaxBase\n                        : this.elevationClient.activeCandidateMax;\n                    const perTileLimit = Number.isFinite(this.elevationClient.activeTileScanPerTile)\n                        ? Math.max(16, Math.floor(this.elevationClient.activeTileScanPerTile))\n                        : 256;\n                    const visibleScale = Math.min(4, Math.max(1, visibleCount / 256));\n                    const forceScale = forceCount > 0 ? Math.min(3, 1 + forceCount / 128) : 1;\n                    let scale = Math.max(visibleScale, forceScale);\n                    if (inSurfaceMode && missingCount > 0) {\n                        scale = Math.max(scale, 2.0);\n                    }\n                    let tileMax = Math.min(\n                        4096,\n                        Math.max(\n                            baseTileScan,\n                            visibleCount,\n                            missingCount,\n                            forceCount,\n                            orbitTileCount,\n                            Math.ceil(baseTileScan * scale)\n                        )\n                    );\n                    let candidateMax = Math.min(\n                        65536,\n                        Math.max(baseCandidateMax, Math.ceil(forceCount * Math.max(32, perTileLimit * 0.5)))\n                    );\n                    if (inSurfaceMode && missingCount > 0) {\n                        candidateMax = Math.min(65536, Math.max(candidateMax, Math.ceil(missingCount * Math.max(64, perTileLimit * 0.5))));\n                    }\n                    if (imageryBackpressureState?.active) {\n                        // Keep full-quality targets, but reduce scan churn during queue pressure.\n                        const pressure = Number.isFinite(imageryBackpressureState.pressureScore)\n                            ? THREE.MathUtils.clamp(imageryBackpressureState.pressureScore, 0, 2)\n                            : 0;\n                        const minScale = Number.isFinite(this.imageryBackpressureElevationScanMinScale)\n                            ? THREE.MathUtils.clamp(this.imageryBackpressureElevationScanMinScale, 0.1, 1.0)\n                            : 0.35;\n                        const pressureScale = Math.max(minScale, THREE.MathUtils.clamp(1 - (pressure * 0.5), 0.1, 1.0));\n                        if (tileMax > baseTileScan) {\n                            tileMax = Math.max(\n                                baseTileScan,\n                                Math.floor(baseTileScan + ((tileMax - baseTileScan) * pressureScale))\n                            );\n                        }\n                        if (candidateMax > baseCandidateMax) {\n                            candidateMax = Math.max(\n                                baseCandidateMax,\n                                Math.floor(baseCandidateMax + ((candidateMax - baseCandidateMax) * pressureScale))\n                            );\n                        }\n                    }\n                    this.elevationClient.setActiveScanLimits({ tileMax, candidateMax });\n                }\n\n                const activeTiles = [];\n                const seen = new Map();\n                const pushTile = (tile, priority) => {\n                    if (!tile) return;\n                    const index = seen.get(tile);\n                    if (index === undefined) {\n                        seen.set(tile, activeTiles.length);\n                        activeTiles.push({ tile, priority });\n                        return;\n                    }\n                    if (priority > activeTiles[index].priority) {\n                        activeTiles[index].priority = priority;\n                    }\n                };\n                if (coverageEntries.length) {\n                    const basePriority = 1_000_000_000;\n                    const ringBoosts = inSurfaceMode\n                        ? (coarseCascadePhase\n                            ? [340_000_000, 300_000_000, 250_000_000]\n                            : (centricFetchMode\n                            ? [1_000_000_000, 80_000_000, 1_000_000]\n                            : [900_000_000, 220_000_000, 25_000_000]))\n                        : [200_000_000, 100_000_000, 0];\n                    const levelWeight = 1_000_000;\n                    const coarseLevelCap = Number.isFinite(this.elevationCascadeCoarseMaxLevel)\n                        ? Math.max(0, Math.floor(this.elevationCascadeCoarseMaxLevel))\n                        : 8;\n                    const distClamp = 50_000_000;\n                    for (const entry of coverageEntries) {\n                        const level = Number.isFinite(entry.level) ? entry.level : 0;\n                        const distance = Number.isFinite(entry.distance)\n                            ? Math.min(entry.distance, distClamp)\n                            : distClamp;\n                        const ring = Number.isFinite(entry.ring) ? entry.ring : 2;\n                        const ringBoost = ringBoosts[Math.min(2, Math.max(0, ring))] || 0;\n                        const viewBoost = Math.floor((Number(entry.viewWeight) || 0) * 500_000_000);\n                        const levelScore = coarseCascadePhase\n                            ? Math.max(0, coarseLevelCap - level)\n                            : level;\n                        const priority = basePriority + ringBoost + viewBoost + (levelScore * levelWeight) - distance;\n                        pushTile(entry.tile, priority);\n                    }\n                }\n                if (inSurfaceMode) {\n                    const tilePriorityMap = new Map();\n                    const centerPriorityActive = !coarseCascadePhase && centricFetchMode && forceCount > 0 && missingCount > 0;\n                    const queueTile = (tile, priority) => {\n                        if (!tile) return;\n                        const tileDirWorld = this._tmpTileDir.copy(tile.centerDir).applyQuaternion(worldQ);\n                        const ring = this._surfaceRingIndex(camPosSurface, tileDirWorld, tile.angularRadius);\n                        const viewMetric = this._cacheSurfaceTileViewMetrics(tile, camera, tileDirWorld);\n                        const viewWeight = Number.isFinite(viewMetric?._surfaceViewWeight)\n                            ? viewMetric._surfaceViewWeight\n                            : 0;\n                        const ringBias = coarseCascadePhase\n                            ? (ring === 0 ? 3_000_000 : (ring === 1 ? 2_000_000 : 1_000_000))\n                            : (centricFetchMode\n                            ? (ring === 0 ? 10_000_000 : (ring === 1 ? 100_000 : 1_000))\n                            : (ring === 0 ? 1_000_000 : (ring === 1 ? 100_000 : 10_000)));\n                        const combinedPriority = ringBias + (viewWeight * 8_000_000) +\n                            (Number.isFinite(priority) ? priority : 0);\n                        const entry = tilePriorityMap.get(tile);\n                        if (!entry || combinedPriority > entry.priority) {\n                            tilePriorityMap.set(tile, { tile, priority: combinedPriority, ring });\n                        }\n                    };\n                    for (const tile of this.visibleLeafTiles) {\n                        const sse = this._tileScreenSpaceError(tile, camera);\n                        const priority = Number.isFinite(sse) ? sse : 0;\n                        queueTile(tile, priority);\n                    }\n                    for (const tile of hiddenLeafTilesForElevation) {\n                        const sse = this._tileScreenSpaceError(tile, camera);\n                        const priority = (Number.isFinite(sse) ? sse : 0) * 0.6;\n                        queueTile(tile, priority);\n                    }\n                    if (focusLeafTile) {\n                        queueTile(focusLeafTile, Number.MAX_SAFE_INTEGER);\n                    }\n                    if (underfootLeafTile) {\n                        queueTile(underfootLeafTile, Number.MAX_SAFE_INTEGER);\n                    }\n\n                    const ringBuckets = [[], [], []];\n                    for (const entry of tilePriorityMap.values()) {\n                        const ring = Math.min(2, Math.max(0, entry.ring ?? 2));\n                        ringBuckets[ring].push(entry);\n                    }\n\n                    const baseMaxActiveTiles = Number.isFinite(this.elevationClient?.activeTileScanMax)\n                        ? Math.max(16, Math.floor(this.elevationClient.activeTileScanMax))\n                        : 256;\n                    const maxActiveTiles = Math.max(baseMaxActiveTiles, activeTiles.length);\n                    const remainingBudget = Math.max(0, maxActiveTiles - activeTiles.length);\n                    const ringWeights = coarseCascadePhase\n                        ? { near: 0.45, mid: 0.35, far: 0.20 }\n                        : (centricFetchMode\n                        ? (centerPriorityActive\n                            ? { near: 0.92, mid: 0.06, far: 0.02 }\n                            : { near: 0.88, mid: 0.09, far: 0.03 })\n                        : { near: 0.80, mid: 0.15, far: 0.05 });\n                    let nearBudget = remainingBudget > 0\n                        ? Math.max(1, Math.floor(remainingBudget * ringWeights.near))\n                        : 0;\n                    let midBudget = remainingBudget > 0\n                        ? Math.max(0, Math.floor(remainingBudget * ringWeights.mid))\n                        : 0;\n                    let farBudget = Math.max(0, remainingBudget - nearBudget - midBudget);\n                    if (ringBuckets[2].length > 0 && remainingBudget >= 3 && farBudget < 1) {\n                        farBudget = 1;\n                        if (nearBudget > midBudget && nearBudget > 1) nearBudget -= 1;\n                        else if (midBudget > 0) midBudget -= 1;\n                        else if (nearBudget > 0) nearBudget -= 1;\n                    }\n\n                    for (const bucket of ringBuckets) {\n                        bucket.sort((a, b) => b.priority - a.priority);\n                    }\n\n                    for (const entry of ringBuckets[0].slice(0, nearBudget)) {\n                        pushTile(entry.tile, entry.priority);\n                    }\n                    for (const entry of ringBuckets[1].slice(0, midBudget)) {\n                        pushTile(entry.tile, entry.priority);\n                    }\n                    for (const entry of ringBuckets[2].slice(0, farBudget)) {\n                        pushTile(entry.tile, entry.priority);\n                    }\n\n                    if (activeTiles.length < maxActiveTiles) {\n                        const remaining = [];\n                        for (const bucket of ringBuckets) {\n                            for (const entry of bucket) {\n                                if (seen.has(entry.tile)) continue;\n                                remaining.push(entry);\n                            }\n                        }\n                        remaining.sort((a, b) => b.priority - a.priority);\n                        for (const entry of remaining) {\n                            if (activeTiles.length >= maxActiveTiles) break;\n                            pushTile(entry.tile, entry.priority);\n                        }\n                    }\n                } else {\n                    const orbitTiles = this._getOrbitElevationTiles();\n                    for (const tile of orbitTiles) {\n                        pushTile(tile, -1000);\n                    }\n                    for (const tile of this.visibleLeafTiles) {\n                        const tileDirWorld = this._tmpTileDir.copy(tile.centerDir).applyQuaternion(worldQ);\n                        const ring = this._surfaceRingIndex(camPosSurface, tileDirWorld, tile.angularRadius);\n                        if (ring > stageRingLimit) continue;\n                        const cosLimit = Math.cos(stageFocusRad + (tile.angularRadius || 0));\n                        if (tileDirWorld.dot(focusDir) < cosLimit) continue;\n                        const sse = this._tileScreenSpaceError(tile, camera);\n                        const priority = (Number.isFinite(sse) ? sse : 0) * 0.5;\n                        pushTile(tile, priority);\n                    }\n                }\n                this.activeElevationTiles = activeTiles;\n                this.elevationClient.setActiveTiles(activeTiles);\n\n                // Force-complete path intentionally disabled: stale synthetic elevations can cause\n                // parent/child LOD churn and visible terrain collapse under load.\n                this.elevationForceCompleteCount = 0;\n                this.elevationForceCompleteVertexCount = 0;\n            } else {\n                this.activeElevationTiles = [];\n                this.elevationClient.setActiveTiles([]);\n                this.elevationForceCompleteCount = 0;\n                this.elevationForceCompleteVertexCount = 0;\n            }\n        }\n        if (perfEnabled) perf.end('lod.activeElevation');\n\n        // Progressive surface LOD staging advance (when stable and work is drained)\n        if (stageActive && !this.surfaceInstantStaging) {\n            const canAdvance = this.surfaceCurrentMaxLODNear < this.surfaceStageMaxLOD;\n            const cooldownElapsed = frameNow - this.surfaceStageLastAdvance >= this.surfaceStageCooldownMs;\n\n            if (stageReady && canAdvance && cooldownElapsed) {\n                const prevLOD = this.surfaceCurrentMaxLODNear;\n                this.surfaceCurrentMaxLODNear += 1;\n                this.surfaceCurrentMaxLODMid = Math.min(this.surfaceRingLodCaps.mid, this.surfaceCurrentMaxLODNear - 1);\n                this.surfaceCurrentMaxLODFar = Math.min(this.surfaceRingLodCaps.far, this.surfaceCurrentMaxLODMid);\n                this.surfaceStageLastAdvance = frameNow;\n\n                console.log(`[LOD ADVANCE] ${prevLOD} → ${this.surfaceCurrentMaxLODNear}`, {\n                    progress: (this.surfaceStageProgress * 100).toFixed(1) + '%',\n                    stageTiles: stageTileCount,\n                    readyCount: stageReadyCount,\n                    fullTiles: fullTileCount,\n                    fullReady: fullTileReadyCount\n                });\n            }\n        } else if (!stageActive) {\n            this.surfaceCurrentMaxLODNear = this.maxTileLevel;\n            this.surfaceCurrentMaxLODMid = this.maxTileLevel;\n            this.surfaceCurrentMaxLODFar = this.maxTileLevel;\n        }\n\n        // REFACTORED: Use persistent visibility tracker for stable imagery loading\n        if (perfEnabled) perf.start('lod.imagery');\n        if (imageryCfg) {\n            // Get tiles needing imagery from tracker (already sorted by priority)\n            const tilesNeedingImagery = this.visibilityTracker.getTilesNeedingImagery(effectiveImageryBudget * 2);\n            imageryVisibleCount = tilesNeedingImagery.length;\n\n            // Simple budget: don't overthink it\n            // In orbit with low LOD, load more to ensure full coverage\n            const isFullCoverageOrbit =\n                !this._inSurfaceMode && this.currentMaxLevel <= this.imageryFullCoverageMaxLevel;\n            imageryFullCoverage = isFullCoverageOrbit;\n\n            const baseBudget = isFullCoverageOrbit\n                ? Math.min(tilesNeedingImagery.length, effectiveImageryBudget * 2)\n                : effectiveImageryBudget;\n            imageryBudget = Math.max(this.imageryMinBudget, baseBudget);\n\n            // Load imagery for top priority tiles\n            let imageryApplied = 0;\n            let bootstrapApplied = 0;\n            const loadedTiles = new Set();\n            const imageryPrepareStart = performance.now();\n            const imageryPrepareBudgetMs = Number.isFinite(this.imageryPreparationTimeBudgetMs)\n                ? Math.max(0.25, this.imageryPreparationTimeBudgetMs)\n                : 1.5;\n            // Always admit one highest-priority request, then yield once its\n            // synchronous coordinate/UV preparation consumes this frame's\n            // allowance. Network/decode/canvas work remains separately queued\n            // by ImageryManager.\n            const imageryPrepareBudgetExceeded = () =>\n                loadedTiles.size > 0 &&\n                (performance.now() - imageryPrepareStart) >= imageryPrepareBudgetMs;\n\n            // Bootstrap pass: request coarse imagery for blank center tiles first.\n            // This makes underfoot/focus areas visible quickly, then normal upgrades refine them.\n            const bootstrapBudgetCap = Number.isFinite(this.imageryBootstrapBudgetMax)\n                ? Math.max(1, Math.floor(this.imageryBootstrapBudgetMax))\n                : 8;\n            const bootstrapBudget = (this._inSurfaceMode && this.imageryBootstrapEnabled)\n                ? Math.max(1, Math.min(bootstrapBudgetCap, Math.floor(imageryBudget * 0.7)))\n                : 0;\n            const bootstrapMinPriority = Number.isFinite(this.imageryBootstrapMinPriority)\n                ? this.imageryBootstrapMinPriority\n                : 2000;\n            if (bootstrapBudget > 0 && tilesToLoadImagery.length) {\n                const bootstrapCandidates = tilesToLoadImagery\n                    .filter((entry) => entry?.tile && entry.isBlank === true)\n                    .sort((a, b) => this._compareImageryCandidatesCenterOut(a, b));\n                const bootstrapSeen = new Set();\n\n                for (const entry of bootstrapCandidates) {\n                    if (bootstrapApplied >= bootstrapBudget || imageryApplied >= imageryBudget) break;\n                    if (imageryPrepareBudgetExceeded()) break;\n                    const tile = entry?.tile;\n                    if (!tile || bootstrapSeen.has(tile) || loadedTiles.has(tile)) continue;\n                    bootstrapSeen.add(tile);\n                    if (tile.imageryReady || tile.imageryInherited) continue;\n\n                    const requestZoom = this._resolveImageryRequestZoom(tile, entry.z, {\n                        ring: entry.ring,\n                        isBlank: true,\n                        underfoot: !!entry.underfoot,\n                        focus: !!entry.focus\n                    });\n                    const tileCfg = this._buildImageryConfigForTile(tile, imageryCfg, requestZoom, entry);\n                    if (!tileCfg) continue;\n\n                    tileCfg.requestPriority = Math.max(entry.priority || 0, bootstrapMinPriority);\n                    tileCfg.requestContextKey = null;\n                    if (Number.isFinite(entry.ring)) {\n                        tileCfg.requestRing = entry.ring;\n                    } else if (Number.isFinite(tile._imageryVisibleRing)) {\n                        tileCfg.requestRing = tile._imageryVisibleRing;\n                    }\n\n                    tile.ensureImagery(this.imageryManager, tileCfg, this.group);\n                    loadedTiles.add(tile);\n                    imageryApplied++;\n                    bootstrapApplied++;\n                }\n            }\n\n            for (const tileState of tilesNeedingImagery) {\n                if (imageryApplied >= imageryBudget) break;\n                if (imageryPrepareBudgetExceeded()) break;\n\n                const { tile, targetImageryZoom } = tileState;\n                if (!tile) continue;\n\n                const tileIsBlank = typeof tile.hasImageryCoverage === 'function'\n                    ? !tile.hasImageryCoverage()\n                    : (!tile.imageryReady && !tile.imageryInherited);\n                const tileRing = Number.isFinite(tile._imageryVisibleRing)\n                    ? tile._imageryVisibleRing\n                    : null;\n                const requestZoom = this._resolveImageryRequestZoom(tile, targetImageryZoom, {\n                    ring: tileRing,\n                    isBlank: tileIsBlank,\n                    underfoot: !!tileState.underfoot,\n                    focus: !!tileState.focus\n                });\n\n                const tileCfg = this._buildImageryConfigForTile(tile, imageryCfg, requestZoom, {\n                    ring: tileRing,\n                    underfoot: !!tileState.underfoot,\n                    focus: !!tileState.focus,\n                    viewWeight: tileState.viewWeight\n                });\n                if (!tileCfg) continue;\n\n                tileCfg.requestPriority = tileState.imageryPriority;\n                if (tileState.underfoot) {\n                    tileCfg.requestPriority = Math.max(tileCfg.requestPriority, 200_000);\n                }\n                tileCfg.requestContextKey = tileIsBlank ? null : this._imageryContextKey;\n                if (Number.isFinite(tileRing)) {\n                    tileCfg.requestRing = tileRing;\n                }\n\n                // Load imagery\n                tile.ensureImagery(this.imageryManager, tileCfg, this.group);\n                loadedTiles.add(tile);\n                imageryApplied++;\n            }\n\n            // Rescue pass: keep at least a small stream of blank/fallback requests alive\n            // so flashing tiles can recover without requiring underfoot focus.\n            let rescueApplied = 0;\n            const rescueBudget = Math.max(2, Math.min(6, Math.floor(imageryBudget * 0.6)));\n            if (rescueBudget > 0 && tilesToLoadImagery.length) {\n                const rescueCandidates = tilesToLoadImagery\n                    .filter((entry) => entry?.tile && entry.isBlank === true)\n                    .sort((a, b) => this._compareImageryCandidatesCenterOut(a, b));\n\n                for (const entry of rescueCandidates) {\n                    if (rescueApplied >= rescueBudget) break;\n                    if (imageryPrepareBudgetExceeded()) break;\n                    const tile = entry.tile;\n                    if (!tile || loadedTiles.has(tile)) continue;\n                    if (tile.imageryReady || tile.imageryInherited) continue;\n\n                    const requestZoom = this._resolveImageryRequestZoom(tile, entry.z, {\n                        ring: entry.ring,\n                        isBlank: true,\n                        underfoot: !!entry.underfoot,\n                        focus: !!entry.focus\n                    });\n                    const tileCfg = this._buildImageryConfigForTile(tile, imageryCfg, requestZoom, entry);\n                    if (!tileCfg) continue;\n\n                    tileCfg.requestPriority = Math.max(entry.priority || 0, 2000);\n                    tileCfg.requestContextKey = null;\n                    if (Number.isFinite(entry.ring)) {\n                        tileCfg.requestRing = entry.ring;\n                    } else if (Number.isFinite(tile._imageryVisibleRing)) {\n                        tileCfg.requestRing = tile._imageryVisibleRing;\n                    }\n\n                    tile.ensureImagery(this.imageryManager, tileCfg, this.group);\n                    loadedTiles.add(tile);\n                    rescueApplied++;\n                }\n            }\n\n            imageryAppliedCount = imageryApplied + rescueApplied;\n        }\n        if (perfEnabled) perf.end('lod.imagery');\n\n        // EMERGENCY BRAKE: If we're near tile budget limit, prioritize merging over splitting\n        const tileUsageRatio = this.tileCount / Math.max(1, effectiveTileBudget);\n        const emergencyThreshold = Number.isFinite(this.emergencyMergeThreshold)\n            ? THREE.MathUtils.clamp(this.emergencyMergeThreshold, 0.5, 0.99)\n            : 0.92;\n        const emergencyMode = tileUsageRatio > emergencyThreshold;\n\n        // Phase 6: wall-clock yield budget (on top of count budget).\n        // Resolved once per frame; loops break when exceeded. See\n        // refactor/async/README.md#phase-6 and _resolveSplitTimeBudgetMs.\n        const lodLoopStartMs = performance.now();\n        const lodTimeBudgetMs = this._resolveSplitTimeBudgetMs();\n\n        if (perfEnabled) perf.start('lod.merge');\n        if (tilesToMerge.length) {\n            tilesToMerge.sort((a, b) => b.level - a.level);\n            mergesDone = 0;\n            const emergencyMergeScale = Number.isFinite(this.emergencyMergeScale)\n                ? THREE.MathUtils.clamp(this.emergencyMergeScale, 1.0, 2.0)\n                : 1.25;\n            const effectiveMergeBudget = emergencyMode\n                ? Math.max(effectiveMergeBudgetBase, Math.floor(effectiveMergeBudgetBase * emergencyMergeScale))\n                : effectiveMergeBudgetBase;\n            for (const tile of tilesToMerge) {\n                if (mergesDone >= effectiveMergeBudget) break;\n                // Phase 6 time-budget yield (additive to count budget).\n                if (lodTimeBudgetMs > 0\n                    && (performance.now() - lodLoopStartMs) >= lodTimeBudgetMs) break;\n                if (!tile.children) continue;\n                if (isMergeProtectedTile(tile)) continue;\n                if (inSurfaceMode && this.imageryInheritanceEnabled) {\n                    const tileRing = Number.isFinite(tile._imageryVisibleRing)\n                        ? tile._imageryVisibleRing\n                        : null;\n                    const isNearSurfaceRing = !Number.isFinite(tileRing) || tileRing <= 2;\n                    if (isNearSurfaceRing) {\n                        const parentRenderable = tileHasRenderableImagery(tile);\n                        const anyChildRenderable = tile.children.some((child) =>\n                            tileHasRenderableImagery(child) || child?._subtreeImageryReady === true\n                        );\n                        // Never collapse textured near-surface children into an untextured parent.\n                        if (!parentRenderable && anyChildRenderable) {\n                            continue;\n                        }\n                    }\n                }\n                // Ensure parent mesh exists so we can adopt child imagery before removing children.\n                tile.ensureMesh(this.group, this.material, this);\n                tile.applyRenderRules(this.renderRules);\n                tile.setVisible(false);\n                // Retire children instead of destroying them — they stay dormant in GPU\n                // memory for _retirementGraceMs so rapid re-splits can resurrect instantly.\n                const removed = this._retireChildren(tile);\n                this.tileCount -= removed;\n                this._notifyTileListeners({\n                    type: 'merge',\n                    tile,\n                    removed\n                });\n                const mergedTileVisible = tileHasVisibleCoverage(tile);\n                tile.setVisible(mergedTileVisible);\n                // LOD fade transition (#3): parent fades in after merge so the\n                // visual swap from children → parent is gradual, not abrupt.\n                if (mergedTileVisible && tile.fadeInEnabled && tile.mesh?.material) {\n                    tile.fadeInComplete = false;\n                    tile.fadeInStart = performance.now();\n                    tile.mesh.material.transparent = true;\n                    tile.mesh.material.opacity = 0;\n                    tile.mesh.material.needsUpdate = true;\n                    registerFadeInTile(tile);\n                }\n                mergesDone++;\n                this._enqueueBasePreloadTile(tile, 'post-merge');\n            }\n        }\n        if (perfEnabled) perf.end('lod.merge');\n\n        // Only allow splitting if we have headroom\n        if (perfEnabled) perf.start('lod.split');\n        if (tilesToSplit.length && this.tileCount < effectiveTileBudget * 0.90) {\n            tilesToSplit.sort((a, b) => b.priority - a.priority);\n            splitsDone = 0;\n            const maxSplitsPossible = Math.floor((effectiveTileBudget - this.tileCount) / 4);\n            const splitLimit = Math.min(effectiveSplitBudget, maxSplitsPossible);\n\n            for (const { tile } of tilesToSplit) {\n                if (splitsDone >= splitLimit) break;\n                // Phase 6 time-budget yield (additive to count budget).\n                // Atomic unit = one tile; we never split mid-tile.\n                if (lodTimeBudgetMs > 0\n                    && (performance.now() - lodLoopStartMs) >= lodTimeBudgetMs) break;\n                if (tile.children) continue;\n\n                // Try to resurrect retired children before doing a fresh subdivide.\n                // Resurrected tiles retain elevation, imagery, and GPU resources.\n                const resurrected = this._resurrectChildren(tile);\n                if (!resurrected) {\n                    tile.subdivide();\n                    // EDGE CASE FIX: Call prepareChildrenForSplit explicitly since we're not removing mesh immediately\n                    // This ensures children inherit fallback colors from parent imagery\n                    tile.prepareChildrenForSplit();\n                }\n                this._notifyTileListeners({\n                    type: 'split',\n                    tile,\n                    children: tile.children || []\n                });\n\n                if (inSurfaceMode) {\n                    // With imagery inheritance, children already have parent imagery\n                    // applied by prepareChildrenForSplit(). Show them immediately and\n                    // retire the parent — no holdover frame needed.\n                    // Without inheritance, hold parent until children load own WMTS.\n                    const childrenInherited = this.imageryInheritanceEnabled &&\n                        tile.children.every((c) => tileHasRenderableImagery(c));\n                    let parentCanHold = !childrenInherited && !!tile.mesh && tileHasRenderableImagery(tile);\n\n                    // Underfoot readiness gate (#6): ring-0 tiles (directly beneath camera)\n                    // MUST keep parent visible until children have imagery — prevents blank\n                    // terrain flashes right under the user's feet.\n                    if (!parentCanHold && !childrenInherited) {\n                        const tileDirWorld = this._tmpTileDir.copy(tile.centerDir).applyQuaternion(worldQ);\n                        const ring = this._surfaceRingIndex(camPosSurface, tileDirWorld, tile.angularRadius);\n                        if (ring === 0 && tile.mesh && tileHasRenderableImagery(tile)) {\n                            parentCanHold = true;\n                        }\n                    }\n                    for (const child of tile.children) {\n                        child.ensureMesh(this.group, this.material, this);\n                        child.applyRenderRules(this.renderRules);\n                        child.setVisible(!parentCanHold);\n                        child._subtreeImageryReady = !!(child.imageryReady || child.imageryInherited);\n                        // LOD fade transition (#3): resurrected or newly split children\n                        // fade in for a smooth visual transition.\n                        if (!parentCanHold && resurrected && child.fadeInEnabled && child.mesh?.material) {\n                            child.fadeInComplete = false;\n                            child.fadeInStart = performance.now();\n                            child.mesh.material.transparent = true;\n                            child.mesh.material.opacity = 0;\n                            child.mesh.material.needsUpdate = true;\n                            registerFadeInTile(child);\n                        }\n                    }\n                    if (tile.mesh) {\n                        if (parentCanHold) {\n                            tile.setVisible(true);\n                        } else {\n                            tile.deferredRemoval = false;\n                            this._removeTileMesh(tile);\n                        }\n                    }\n                } else {\n                    // ORBIT MODE: Immediately hide parent to prevent overlap\n                    // Children will get meshes in next visit() traversal\n                    if (tile.mesh) {\n                        tile.setVisible(false);\n                        // For level <= 4, keep mesh resident but hidden\n                        // For level > 4, remove mesh entirely\n                        if (tile.level > 4) {\n                            tile.deferredRemoval = false;\n                            this._removeTileMesh(tile);\n                        }\n                    }\n                }\n                // INSTANT SUBDIVISION: Parent mesh already removed/hidden above\n                this.tileCount += tile.children.length;\n                splitsDone++;\n            }\n        }\n        if (imageryFocusDir) {\n            this._imageryContextDir = imageryFocusDir.clone();\n            const camPos = this._getCameraPosition(camera);\n            this._imageryContextAlt = this._getAltitudeFromCamPos(camPos);\n            this._imageryContextMode = this.lodMode;\n            this._imageryContextSurface = this._inSurfaceMode;\n        }\n        if (perfEnabled) perf.end('lod.split');\n\n        this._enforceNoOverlap();\n\n        // Neighbor discovery is expensive; only run it when needed (surface mode).\n        const shouldDetectNeighbors = (this.enableNeighborDetection || this.enableSeamInterpolation) &&\n            (this._inSurfaceMode || this.forceNeighborDetection);\n        const needsNeighborBuild = (splitsDone > 0 || mergesDone > 0 || this._neighborRebuildRequested ||\n            (shouldDetectNeighbors && !this._neighborDetectionActive));\n        let neighborsRebuilt = false;\n        if (shouldDetectNeighbors && needsNeighborBuild) {\n            if (perfEnabled) perf.start('lod.neighbors');\n            this._registerNeighbors();\n            if (perfEnabled) perf.end('lod.neighbors');\n            this._neighborRebuildRequested = false;\n            this._neighborDetectionActive = true;\n            neighborsRebuilt = true;\n        } else if (!shouldDetectNeighbors && this._neighborDetectionActive) {\n            this._clearNeighborDetection();\n            this._neighborDetectionActive = false;\n        }\n\n        if (this._inSurfaceMode && this._neighborDetectionActive) {\n            this._flushDeferredEdgeElevations();\n        }\n\n        if (this.enableSeamInterpolation &&\n            this._inSurfaceMode &&\n            this._neighborDetectionActive &&\n            (splitsDone > 0 || mergesDone > 0 || this._seamDirty || neighborsRebuilt)) {\n            if (perfEnabled) perf.start('lod.seams');\n            this._applyCrossLodEdgeSeams();\n            this._applySameLodEdgeSnaps();\n            if (perfEnabled) perf.end('lod.seams');\n            this._seamDirty = false;\n        }\n\n        this._processBasePreloadQueue();\n\n        // Sweep retired tiles: destroy entries older than grace period,\n        // releasing their GPU resources via the geometry pool.\n        if (this._retiredTiles.size > 0) {\n            this._sweepRetirementPool();\n        }\n\n        const staleCollidersRemoved = this._pruneStaleTileColliders();\n\n        if (this._tileListeners.size) {\n            const nextVisible = new Set(this.visibleLeafTiles);\n            for (const tile of nextVisible) {\n                if (!this._lastVisibleLeafTiles.has(tile)) {\n                    this._notifyTileListeners({ type: 'visible-added', tile });\n                }\n            }\n            for (const tile of this._lastVisibleLeafTiles) {\n                if (!nextVisible.has(tile)) {\n                    this._notifyTileListeners({ type: 'visible-removed', tile });\n                }\n            }\n            this._lastVisibleLeafTiles = nextVisible;\n        } else if (this._lastVisibleLeafTiles.size) {\n            this._lastVisibleLeafTiles.clear();\n        }\n\n        if (this.photogramManager) {\n            this.photogramManager.update();\n        }\n\n        // When photorealistic tiles are active, hide all tritree tile meshes\n        if (this.suppressTileDisplay) {\n            for (const mesh of this.visibleMeshes) {\n                mesh.visible = false;\n            }\n        }\n\n        if (perfEnabled) {\n            const imageryStats = this.imageryManager?.getStats?.({ includeOwnership: false }) || null;\n            const elevationStats = this.elevationClient?.getStats?.() || null;\n            this.debugStats = {\n                mode: this._inSurfaceMode ? 'surface' : 'orbit',\n                visibleLeafTiles: this.visibleLeafTiles.length,\n                tilesToSplit: tilesToSplit.length,\n                tilesToMerge: tilesToMerge.length,\n                splitsDone,\n                mergesDone,\n                globalPressure: this._globalPressure,\n                retiredTilesSets: this._retiredTiles.size,\n                retiredTileCount: this._retiredTileCount,\n                retirementMaxEntries: this._retirementMaxEntries,\n                retirementMaxTiles: this._retirementMaxTiles,\n                imageryCandidates: tilesToLoadImagery.length,\n                imageryVisible: imageryVisibleCount,\n                imageryBudget,\n                imageryApplied: imageryAppliedCount,\n                imageryFullCoverage,\n                imageryBackpressureActive: imageryBackpressureState?.active ?? false,\n                imageryBackpressureScore: imageryBackpressureState?.pressureScore ?? 0,\n                imageryBackpressureTileQueue: imageryBackpressureState?.tileQueue ?? 0,\n                imageryBackpressureAtlasQueue: imageryBackpressureState?.atlasQueue ?? 0,\n                detailPolicy: this._detailPolicy,\n                tileCount: this.tileCount,\n                tileBudget: this.tileBudget,\n                currentMaxLevel: this.currentMaxLevel,\n                elevationForceCompleteCount: this.elevationForceCompleteCount,\n                elevationForceCompleteVertexCount: this.elevationForceCompleteVertexCount,\n                elevationCascadeEnabled: elevationCascadeEnabled,\n                elevationCascadeCoarseReady: this._elevationCascadeCoarseReady,\n                elevationCascadeCoverageRatio: this._elevationCascadeCoverageRatio,\n                elevationCascadeReadyTiles: this._elevationCascadeReadyTiles,\n                elevationCascadeTotalTiles: this._elevationCascadeTotalTiles,\n                snapshotReplayPending: this._snapshotReplayStats.pending,\n                snapshotReplayLastQueued: this._snapshotReplayStats.lastQueued,\n                snapshotReplayLastImmediate: this._snapshotReplayStats.lastImmediate,\n                snapshotReplayLastFrameApplied: this._snapshotReplayStats.lastFrameApplied,\n                snapshotReplayTotalQueued: this._snapshotReplayStats.totalQueued,\n                snapshotReplayTotalApplied: this._snapshotReplayStats.totalApplied,\n                snapshotReplayElevationSeededVertices: this._snapshotReplayStats.elevationSeededVertices,\n                snapshotReplayElevationSeededTiles: this._snapshotReplayStats.elevationSeededTiles,\n                snapshotReplayAtlasHintTiles: this._snapshotReplayStats.atlasHintTiles,\n                snapshotReplayAtlasHintRejected: this._snapshotReplayStats.atlasHintRejected,\n                imageryIdbTileHitRatio: imageryStats?.idbTileHitRatio ?? null,\n                imageryNetworkFetches: imageryStats?.tileNetworkFetches ?? null,\n                imageryEstimatedNetworkAvoidedTiles: imageryStats?.estimatedNetworkAvoidedTiles ?? null,\n                elevationCacheLookupHitRatio: elevationStats?.cacheLookupHitRatio ?? null,\n                elevationPersistentImportedCount: elevationStats?.persistentImportedCount ?? null,\n                adaptiveSplitScale: this._adaptiveSplitBudgetScale,\n                adaptiveSplitFrameMs: this._adaptiveSplitFrameMsEma,\n                terrainColliders: this._tileColliders.size,\n                terrainCollidersPruned: staleCollidersRemoved\n            };\n        }\n    }\n\n    /**\n     * SIMPLIFIED: Always clone materials - no pooling/sharing\n     * Material pooling was causing imagery flapping when tiles shared materials\n     * Each tile gets its own material instance that it can modify independently\n     */\n    getSharedMaterial(baseMaterial) {\n        // ALWAYS clone - no sharing between tiles\n        return baseMaterial.clone();\n    }\n\n    /**\n     * PHASE 3: Release a shared material reference\n     * Disposes material when ref count reaches zero\n     */\n    releaseSharedMaterial(imageryKey) {\n        if (!imageryKey || !this.materialRefCounts.has(imageryKey)) return;\n\n        const refCount = this.materialRefCounts.get(imageryKey) - 1;\n        if (refCount <= 0) {\n            // No more references - dispose material\n            const material = this.materialPool.get(imageryKey);\n            if (material) {\n                material.dispose();\n            }\n            this.materialPool.delete(imageryKey);\n            this.materialRefCounts.delete(imageryKey);\n        } else {\n            this.materialRefCounts.set(imageryKey, refCount);\n        }\n    }\n\n    /**\n     * Set up automatic stitching callbacks on all tiles (including future children)\n     */\n    _setupAutoStitchCallbacks() {\n        const setupCallback = (tile) => {\n            if (!tile) return;\n\n            // Set the callback to trigger stitching when elevation updates\n            tile.onElevationUpdate = (updatedTile, vertexIndex) => {\n                if (this.enableSeamInterpolation) {\n                    this._seamDirty = true;\n                }\n                this._notifyElevationListeners(updatedTile, vertexIndex);\n            };\n\n            // Also set callback on children when they're created\n            // CRITICAL: Only wrap once to prevent infinite recursion\n            if (!tile._prepareChildrenWrapped) {\n                const originalPrepareChildren = tile.prepareChildrenForSplit;\n                if (originalPrepareChildren) {\n                    tile.prepareChildrenForSplit = function() {\n                        originalPrepareChildren.call(this);\n                        if (this.children) {\n                            for (const child of this.children) {\n                                setupCallback(child);\n                            }\n                        }\n                    };\n                    tile._prepareChildrenWrapped = true;\n                }\n            }\n        };\n\n        // Setup callbacks on root tiles\n        for (const tile of this.rootTiles) {\n            setupCallback(tile);\n        }\n    }\n}\n","function contactResolution(object) {\n    for (let node = object; node; node = node.parent) {\n        if (Number.isFinite(node.userData?.photoContactGeometricError)) return {\n            error: node.userData.photoContactGeometricError,\n            depth: node.userData.photoContactDepth || 0,\n        };\n    }\n    return null;\n}\n\n/** Native fading ancestors remain renderable, but must not compete with their\n * finer contact surface. Keep every intersection within the winning LOD so\n * street/bridge/roof classification still sees the real vertical topology. */\nexport function finestSurfaceContactHits(hits) {\n    let error = Infinity, depth = -Infinity;\n    for (const hit of hits) {\n        const resolution = contactResolution(hit.object);\n        if (!resolution) continue;\n        if (resolution.error < error || (resolution.error === error && resolution.depth > depth)) {\n            error = resolution.error;depth = resolution.depth;\n        }\n    }\n    if (!Number.isFinite(error)) return hits;\n    return hits.filter(hit => {\n        const resolution = contactResolution(hit.object);\n        return resolution && resolution.error === error && resolution.depth === depth;\n    });\n}\n\n/** Independent exterior samples validate a curved terrain patch; only an\n * actual center triangle hit may become contact. Cardinal samples constrain\n * separate east/north curvatures; no unobserved mixed derivative is invented. */\nexport function curvedSurfaceGroundRadius(hits, referenceR, slopeDot = 0.58) {\n    if (!Number.isFinite(referenceR)) return null;\n    const centers = hits.filter(h => h.isCenter && Number.isFinite(h.r)\n        && (!Number.isFinite(h.radialNormalDot) || h.radialNormalDot >= slopeDot));\n    const rays = new Map();\n    for (const h of hits) {\n        if (h.isCenter || !Number.isFinite(h.r) || !Number.isFinite(h.dE) || !Number.isFinite(h.dN)\n            || (Number.isFinite(h.radialNormalDot) && h.radialNormalDot < slopeDot)) continue;\n        const key = h.sampleKey || `${h.dE}:${h.dN}`;\n        if (!rays.has(key) || rays.get(key).r > h.r) rays.set(key, h);\n    }\n    const points = [...rays.values()];\n    if (points.length < 6 || !centers.length) return null;\n    const basis = p => { const x=p.dE/30,y=p.dN/30;return [1,x,y,x*x,y*y]; };\n    const fit = samples => {\n        const matrix = Array.from({length:5},()=>new Float64Array(6));\n        for (const p of samples) {\n            const row=basis(p),height=p.r-referenceR;\n            for(let i=0;i<5;i++){for(let j=0;j<5;j++)matrix[i][j]+=row[i]*row[j];matrix[i][5]+=row[i]*height;}\n        }\n        for(let i=0;i<5;i++){\n            let pivot=i;for(let j=i+1;j<5;j++)if(Math.abs(matrix[j][i])>Math.abs(matrix[pivot][i]))pivot=j;\n            if(Math.abs(matrix[pivot][i])<1e-10)return null;\n            [matrix[i],matrix[pivot]]=[matrix[pivot],matrix[i]];\n            const scale=matrix[i][i];for(let j=i;j<6;j++)matrix[i][j]/=scale;\n            for(let row=0;row<5;row++)if(row!==i){const weight=matrix[row][i];for(let j=i;j<6;j++)matrix[row][j]-=weight*matrix[i][j];}\n        }\n        return matrix.map(row=>row[5]);\n    };\n    const evaluate = (coeff,p) => basis(p).reduce((sum,value,i)=>sum+value*coeff[i],0);\n    const maxGradient=Math.sqrt(Math.max(0,1/(slopeDot*slopeDot)-1));\n    let best=null;\n    // Leave-one-out models tolerate one exterior outlier without allowing a\n    // center protrusion to participate in its own support evidence.\n    for(let omit=-1;omit<points.length;omit++){\n        const coeff=fit(points.filter((_,i)=>i!==omit));if(!coeff)continue;\n        const inliers=points.filter(p=>Math.abs(evaluate(coeff,p)-(p.r-referenceR))<=1.5);\n        if(inliers.length<6)continue;\n        const east=inliers.map(p=>p.dE),north=inliers.map(p=>p.dN);\n        if(Math.min(...east)>=0||Math.max(...east)<=0||Math.min(...north)>=0||Math.max(...north)<=0\n            ||Math.max(...east)-Math.min(...east)<25||Math.max(...north)-Math.min(...north)<25)continue;\n        const refined=fit(inliers);if(!refined)continue;\n        const tooSteep=[{dE:0,dN:0},...inliers].some(p=>Math.hypot(\n            (refined[1]+2*refined[3]*p.dE/30)/30,\n            (refined[2]+2*refined[4]*p.dN/30)/30)>maxGradient);\n        if(tooSteep)continue;\n        const error=inliers.reduce((sum,p)=>sum+(evaluate(refined,p)-(p.r-referenceR))**2,0);\n        for(const center of centers){\n            const residual=Math.abs(center.r-referenceR-refined[0]);if(residual>2)continue;\n            if(!best||inliers.length>best.count||(inliers.length===best.count&&error<best.error)){\n                best={radius:center.r,count:inliers.length,error};\n            }\n        }\n    }\n    return best?.radius ?? null;\n}\n","// Split strategy constants\n\n/**\n * Option for splitting each BVH node down the center of the longest axis of the bounds.\n *\n * This is the fastest construction option and will yield a good, performant bounds.\n * @type {number}\n */\nexport const CENTER = 0;\n\n/**\n * Option for splitting each BVH node at the average point along the longest axis for\n * all triangle centroids in the bounds.\n *\n * This strategy may be better than `CENTER` with some geometry.\n * @type {number}\n */\nexport const AVERAGE = 1;\n\n/**\n * Option to use a Surface Area Heuristic to split the bounds more optimally. This SAH\n * implementation tests 8 discrete splits in each node along each axis to determine\n * which split is the lowest cost, or every primitive center in small nodes.\n *\n * This is the slowest construction option but will yield the best bounds of the three\n * options and use the least memory.\n * @type {number}\n */\nexport const SAH = 2;\n\n// Traversal constants\n\n/**\n * Indicates the shape did not intersect the given bounding box.\n * @type {number}\n */\nexport const NOT_INTERSECTED = 0;\n\n/**\n * Indicates the shape did intersect the given bounding box.\n * @type {number}\n */\nexport const INTERSECTED = 1;\n\n/**\n * Indicate the shape entirely contains the given bounding box.\n * @type {number}\n */\nexport const CONTAINED = 2;\n\n// SAH cost constants\n// TODO: hone these costs more. The relative difference between them should be the\n// difference in measured time to perform a primitive intersection vs traversing\n// bounds.\n// TODO: could be tuned per primitive type (triangles vs lines vs points)\nexport const PRIMITIVE_INTERSECT_COST = 1.25;\nexport const TRAVERSAL_COST = 1;\n\n\n// Build constants\nexport const BYTES_PER_NODE = 6 * 4 + 4 + 4;\nexport const UINT32_PER_NODE = BYTES_PER_NODE / 4;\nexport const IS_LEAFNODE_FLAG = 0xFFFF;\n\n// Bit masks for 32 bit node data\nexport const LEAFNODE_MASK_32 = IS_LEAFNODE_FLAG << 16;\n\n// EPSILON for computing floating point error during build\n// https://en.wikipedia.org/wiki/Machine_epsilon#Values_for_standard_hardware_floating_point_arithmetics\nexport const FLOAT32_EPSILON = Math.pow( 2, - 24 );\n\nexport const SKIP_GENERATION = Symbol( 'SKIP_GENERATION' );\n\nexport const DEFAULT_OPTIONS = {\n\tstrategy: CENTER,\n\tmaxDepth: 40,\n\ttargetLeafSize: 10,\n\tuseSharedArrayBuffer: false,\n\tsetBoundingBox: true,\n\tonProgress: null,\n\tindirect: false,\n\tverbose: true,\n\trange: null,\n\t[ SKIP_GENERATION ]: false,\n};\n\n","export function arrayToBox( nodeIndex32, array, target ) {\n\n\ttarget.min.x = array[ nodeIndex32 ];\n\ttarget.min.y = array[ nodeIndex32 + 1 ];\n\ttarget.min.z = array[ nodeIndex32 + 2 ];\n\n\ttarget.max.x = array[ nodeIndex32 + 3 ];\n\ttarget.max.y = array[ nodeIndex32 + 4 ];\n\ttarget.max.z = array[ nodeIndex32 + 5 ];\n\n\treturn target;\n\n}\n\nexport function makeEmptyBounds( target ) {\n\n\ttarget[ 0 ] = target[ 1 ] = target[ 2 ] = Infinity;\n\ttarget[ 3 ] = target[ 4 ] = target[ 5 ] = - Infinity;\n\n}\n\nexport function getLongestEdgeIndex( bounds ) {\n\n\tlet splitDimIdx = - 1;\n\tlet splitDist = - Infinity;\n\n\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\tconst dist = bounds[ i + 3 ] - bounds[ i ];\n\t\tif ( dist > splitDist ) {\n\n\t\t\tsplitDist = dist;\n\t\t\tsplitDimIdx = i;\n\n\t\t}\n\n\t}\n\n\treturn splitDimIdx;\n\n}\n\n// expands the given bounds by the provided primitive bounds\nexport function expandByPrimitiveBounds( startIndex, primitiveBounds, bounds ) {\n\n\tfor ( let d = 0; d < 3; d ++ ) {\n\n\t\tconst tCenter = primitiveBounds[ startIndex + 2 * d ];\n\t\tconst tHalf = primitiveBounds[ startIndex + 2 * d + 1 ];\n\n\t\tconst tMin = tCenter - tHalf;\n\t\tconst tMax = tCenter + tHalf;\n\n\t\tif ( tMin < bounds[ d ] ) {\n\n\t\t\tbounds[ d ] = tMin;\n\n\t\t}\n\n\t\tif ( tMax > bounds[ d + 3 ] ) {\n\n\t\t\tbounds[ d + 3 ] = tMax;\n\n\t\t}\n\n\t}\n\n}\n\n// compute bounds surface area\nexport function computeSurfaceArea( bounds ) {\n\n\tconst d0 = bounds[ 3 ] - bounds[ 0 ];\n\tconst d1 = bounds[ 4 ] - bounds[ 1 ];\n\tconst d2 = bounds[ 5 ] - bounds[ 2 ];\n\n\treturn 2 * ( d0 * d1 + d1 * d2 + d2 * d0 );\n\n}\n","import { IS_LEAFNODE_FLAG, UINT32_PER_NODE } from '../Constants.js';\n\nexport function IS_LEAF( n16, uint16Array ) {\n\n\treturn uint16Array[ n16 + 15 ] === IS_LEAFNODE_FLAG;\n\n}\n\nexport function OFFSET( n32, uint32Array ) {\n\n\treturn uint32Array[ n32 + 6 ];\n\n}\n\nexport function COUNT( n16, uint16Array ) {\n\n\treturn uint16Array[ n16 + 14 ];\n\n}\n\n// Returns the uint32-aligned offset of the left child node for performance\nexport function LEFT_NODE( n32 ) {\n\n\treturn n32 + UINT32_PER_NODE;\n\n}\n\n// Returns the uint32-aligned offset of the right child node for performance\nexport function RIGHT_NODE( n32, uint32Array ) {\n\n\t// stored value is relative offset from parent, convert to absolute uint32 index\n\tconst relativeOffset = uint32Array[ n32 + 6 ];\n\treturn n32 + relativeOffset * UINT32_PER_NODE;\n\n}\n\nexport function SPLIT_AXIS( n32, uint32Array ) {\n\n\treturn uint32Array[ n32 + 7 ];\n\n}\n\nexport function BOUNDING_DATA_INDEX( n32 ) {\n\n\treturn n32;\n\n}\n","// computes the union of the bounds of all of the given primitives and puts the resulting box in \"target\".\n// A bounding box is computed for the centroids of the primitives, as well, and placed in \"centroidTarget\".\n// These are computed together to avoid redundant accesses to bounds array.\nexport function getBounds( primitiveBounds, offset, count, target, centroidTarget ) {\n\n\tlet minx = Infinity;\n\tlet miny = Infinity;\n\tlet minz = Infinity;\n\tlet maxx = - Infinity;\n\tlet maxy = - Infinity;\n\tlet maxz = - Infinity;\n\n\tlet cminx = Infinity;\n\tlet cminy = Infinity;\n\tlet cminz = Infinity;\n\tlet cmaxx = - Infinity;\n\tlet cmaxy = - Infinity;\n\tlet cmaxz = - Infinity;\n\n\tconst boundsOffset = primitiveBounds.offset || 0;\n\tfor ( let i = ( offset - boundsOffset ) * 6, end = ( offset + count - boundsOffset ) * 6; i < end; i += 6 ) {\n\n\t\tconst cx = primitiveBounds[ i + 0 ];\n\t\tconst hx = primitiveBounds[ i + 1 ];\n\t\tconst lx = cx - hx;\n\t\tconst rx = cx + hx;\n\t\tif ( lx < minx ) minx = lx;\n\t\tif ( rx > maxx ) maxx = rx;\n\t\tif ( cx < cminx ) cminx = cx;\n\t\tif ( cx > cmaxx ) cmaxx = cx;\n\n\t\tconst cy = primitiveBounds[ i + 2 ];\n\t\tconst hy = primitiveBounds[ i + 3 ];\n\t\tconst ly = cy - hy;\n\t\tconst ry = cy + hy;\n\t\tif ( ly < miny ) miny = ly;\n\t\tif ( ry > maxy ) maxy = ry;\n\t\tif ( cy < cminy ) cminy = cy;\n\t\tif ( cy > cmaxy ) cmaxy = cy;\n\n\t\tconst cz = primitiveBounds[ i + 4 ];\n\t\tconst hz = primitiveBounds[ i + 5 ];\n\t\tconst lz = cz - hz;\n\t\tconst rz = cz + hz;\n\t\tif ( lz < minz ) minz = lz;\n\t\tif ( rz > maxz ) maxz = rz;\n\t\tif ( cz < cminz ) cminz = cz;\n\t\tif ( cz > cmaxz ) cmaxz = cz;\n\n\t}\n\n\ttarget[ 0 ] = minx;\n\ttarget[ 1 ] = miny;\n\ttarget[ 2 ] = minz;\n\n\ttarget[ 3 ] = maxx;\n\ttarget[ 4 ] = maxy;\n\ttarget[ 5 ] = maxz;\n\n\tcentroidTarget[ 0 ] = cminx;\n\tcentroidTarget[ 1 ] = cminy;\n\tcentroidTarget[ 2 ] = cminz;\n\n\tcentroidTarget[ 3 ] = cmaxx;\n\tcentroidTarget[ 4 ] = cmaxy;\n\tcentroidTarget[ 5 ] = cmaxz;\n\n}\n","import { getLongestEdgeIndex, computeSurfaceArea, expandByPrimitiveBounds } from '../../utils/ArrayBoxUtilities.js';\nimport { CENTER, AVERAGE, SAH, PRIMITIVE_INTERSECT_COST, TRAVERSAL_COST } from '../Constants.js';\n\nconst BIN_COUNT = 8;\n\n// nodes with fewer primitives than this test a split at every primitive center instead of binning\nconst SWEEP_COUNT = 8;\n\n// per bin primitive count and bounds, and the union of the bounds from each bin to the last\nconst binCounts = /* @__PURE__ */ new Int32Array( BIN_COUNT );\nconst binBounds = /* @__PURE__ */ new Float32Array( BIN_COUNT * 6 );\nconst binRightBounds = /* @__PURE__ */ new Float32Array( BIN_COUNT * 6 );\nconst leftBounds = /* @__PURE__ */ new Float32Array( 6 );\nconst rightBounds = /* @__PURE__ */ new Float32Array( 6 );\n\n// the primitives of a small node ordered along an axis, and the bounds of the tail from each position\nconst sweepOrder = /* @__PURE__ */ new Int32Array( SWEEP_COUNT );\nconst sweepRightBounds = /* @__PURE__ */ new Float32Array( SWEEP_COUNT * 6 );\n\n// expands the bounds stored at \"offset\" in \"bounds\" by the primitive at \"startIndex\"\nfunction expandBoundsAt( startIndex, primitiveBounds, bounds, offset ) {\n\n\tfor ( let d = 0; d < 3; d ++ ) {\n\n\t\tconst center = primitiveBounds[ startIndex + 2 * d ];\n\t\tconst half = primitiveBounds[ startIndex + 2 * d + 1 ];\n\t\tconst min = center - half;\n\t\tconst max = center + half;\n\t\tif ( min < bounds[ offset + d ] ) bounds[ offset + d ] = min;\n\t\tif ( max > bounds[ offset + d + 3 ] ) bounds[ offset + d + 3 ] = max;\n\n\t}\n\n}\n\nfunction computeSurfaceAreaAt( array, offset ) {\n\n\tconst d0 = array[ offset + 3 ] - array[ offset ];\n\tconst d1 = array[ offset + 4 ] - array[ offset + 1 ];\n\tconst d2 = array[ offset + 5 ] - array[ offset + 2 ];\n\n\treturn 2 * ( d0 * d1 + d1 * d2 + d2 * d0 );\n\n}\n\nexport function getOptimalSplit( nodeBoundingData, centroidBoundingData, primitiveBounds, offset, count, strategy ) {\n\n\tlet axis = - 1;\n\tlet pos = 0;\n\n\t// Center\n\tif ( strategy === CENTER ) {\n\n\t\taxis = getLongestEdgeIndex( centroidBoundingData );\n\t\tif ( axis !== - 1 ) {\n\n\t\t\tpos = ( centroidBoundingData[ axis ] + centroidBoundingData[ axis + 3 ] ) / 2;\n\n\t\t}\n\n\t} else if ( strategy === AVERAGE ) {\n\n\t\taxis = getLongestEdgeIndex( nodeBoundingData );\n\t\tif ( axis !== - 1 ) {\n\n\t\t\tpos = getAverage( primitiveBounds, offset, count, axis );\n\n\t\t}\n\n\t} else if ( strategy === SAH ) {\n\n\t\tconst rootSurfaceArea = computeSurfaceArea( nodeBoundingData );\n\t\tlet bestCost = PRIMITIVE_INTERSECT_COST * count;\n\n\t\t// iterate over all axes\n\t\tconst boundsOffset = primitiveBounds.offset || 0;\n\t\tconst cStart = ( offset - boundsOffset ) * 6;\n\t\tconst cEnd = ( offset + count - boundsOffset ) * 6;\n\t\tfor ( let a = 0; a < 3; a ++ ) {\n\n\t\t\tconst axisLeft = centroidBoundingData[ a ];\n\t\t\tconst axisRight = centroidBoundingData[ a + 3 ];\n\t\t\tconst axisLength = axisRight - axisLeft;\n\t\t\tconst binWidth = axisLength / BIN_COUNT;\n\n\t\t\t// If we have fewer primitives than we're planning to split then just check all\n\t\t\t// the primitive positions because it will be faster.\n\t\t\tif ( count < SWEEP_COUNT ) {\n\n\t\t\t\t// order the primitives by center along the axis\n\t\t\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\t\t\tconst c = cStart + i * 6;\n\t\t\t\t\tconst center = primitiveBounds[ c + 2 * a ];\n\t\t\t\t\tlet j = i;\n\t\t\t\t\twhile ( j > 0 && primitiveBounds[ sweepOrder[ j - 1 ] + 2 * a ] > center ) {\n\n\t\t\t\t\t\tsweepOrder[ j ] = sweepOrder[ j - 1 ];\n\t\t\t\t\t\tj --;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tsweepOrder[ j ] = c;\n\n\t\t\t\t}\n\n\t\t\t\t// the bounds of the primitives from each position to the end\n\t\t\t\tfor ( let d = 0; d < 3; d ++ ) {\n\n\t\t\t\t\tleftBounds[ d ] = Infinity;\n\t\t\t\t\tleftBounds[ d + 3 ] = - Infinity;\n\t\t\t\t\trightBounds[ d ] = Infinity;\n\t\t\t\t\trightBounds[ d + 3 ] = - Infinity;\n\n\t\t\t\t}\n\n\t\t\t\tfor ( let i = count - 1; i >= 0; i -- ) {\n\n\t\t\t\t\texpandByPrimitiveBounds( sweepOrder[ i ], primitiveBounds, rightBounds );\n\t\t\t\t\tsweepRightBounds.set( rightBounds, i * 6 );\n\n\t\t\t\t}\n\n\t\t\t\t// sweep the splits between consecutive centers, growing the left bounds as we go\n\t\t\t\tfor ( let i = 0; i < count - 1; i ++ ) {\n\n\t\t\t\t\texpandByPrimitiveBounds( sweepOrder[ i ], primitiveBounds, leftBounds );\n\n\t\t\t\t\t// a primitive whose center lies on the split plane is considered to be on the right\n\t\t\t\t\t// side, so equal centers cannot be split apart\n\t\t\t\t\tconst candidate = primitiveBounds[ sweepOrder[ i + 1 ] + 2 * a ];\n\t\t\t\t\tif ( primitiveBounds[ sweepOrder[ i ] + 2 * a ] === candidate ) {\n\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// check the cost of this split\n\t\t\t\t\tconst leftCount = i + 1;\n\t\t\t\t\tconst rightCount = count - leftCount;\n\t\t\t\t\tconst leftProb = computeSurfaceArea( leftBounds ) / rootSurfaceArea;\n\t\t\t\t\tconst rightProb = computeSurfaceAreaAt( sweepRightBounds, leftCount * 6 ) / rootSurfaceArea;\n\t\t\t\t\tconst cost = TRAVERSAL_COST + PRIMITIVE_INTERSECT_COST * (\n\t\t\t\t\t\tleftProb * leftCount + rightProb * rightCount\n\t\t\t\t\t);\n\n\t\t\t\t\tif ( cost < bestCost ) {\n\n\t\t\t\t\t\taxis = a;\n\t\t\t\t\t\tbestCost = cost;\n\t\t\t\t\t\tpos = candidate;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// reset the bins\n\t\t\t\tfor ( let i = 0; i < BIN_COUNT; i ++ ) {\n\n\t\t\t\t\tbinCounts[ i ] = 0;\n\t\t\t\t\tfor ( let d = 0; d < 3; d ++ ) {\n\n\t\t\t\t\t\tbinBounds[ i * 6 + d ] = Infinity;\n\t\t\t\t\t\tbinBounds[ i * 6 + d + 3 ] = - Infinity;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// iterate over all center positions\n\t\t\t\tfor ( let c = cStart; c < cEnd; c += 6 ) {\n\n\t\t\t\t\tconst triCenter = primitiveBounds[ c + 2 * a ];\n\t\t\t\t\tconst relativeCenter = triCenter - axisLeft;\n\n\t\t\t\t\t// in the partition function if the centroid lies on the split plane then it is\n\t\t\t\t\t// considered to be on the right side of the split\n\t\t\t\t\tlet binIndex = ~ ~ ( relativeCenter / binWidth );\n\t\t\t\t\tif ( binIndex >= BIN_COUNT ) binIndex = BIN_COUNT - 1;\n\n\t\t\t\t\tbinCounts[ binIndex ] ++;\n\t\t\t\t\texpandBoundsAt( c, primitiveBounds, binBounds, binIndex * 6 );\n\n\t\t\t\t}\n\n\t\t\t\t// cache the unioned bounds from right to left so we don't have to regenerate them each time\n\t\t\t\tconst last = ( BIN_COUNT - 1 ) * 6;\n\t\t\t\tfor ( let d = 0; d < 6; d ++ ) {\n\n\t\t\t\t\tbinRightBounds[ last + d ] = binBounds[ last + d ];\n\n\t\t\t\t}\n\n\t\t\t\tfor ( let i = BIN_COUNT - 2; i >= 0; i -- ) {\n\n\t\t\t\t\tconst o = i * 6;\n\t\t\t\t\tconst next = o + 6;\n\t\t\t\t\tfor ( let d = 0; d < 3; d ++ ) {\n\n\t\t\t\t\t\tbinRightBounds[ o + d ] = Math.min( binBounds[ o + d ], binRightBounds[ next + d ] );\n\t\t\t\t\t\tbinRightBounds[ o + d + 3 ] = Math.max( binBounds[ o + d + 3 ], binRightBounds[ next + d + 3 ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tlet leftCount = 0;\n\t\t\t\tfor ( let i = 0; i < BIN_COUNT - 1; i ++ ) {\n\n\t\t\t\t\tconst o = i * 6;\n\t\t\t\t\tconst binCount = binCounts[ i ];\n\n\t\t\t\t\t// don't do anything with the bounds if the new bounds have no primitives\n\t\t\t\t\tif ( binCount !== 0 ) {\n\n\t\t\t\t\t\tfor ( let d = 0; d < 3; d ++ ) {\n\n\t\t\t\t\t\t\tif ( leftCount === 0 ) {\n\n\t\t\t\t\t\t\t\tleftBounds[ d ] = binBounds[ o + d ];\n\t\t\t\t\t\t\t\tleftBounds[ d + 3 ] = binBounds[ o + d + 3 ];\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tleftBounds[ d ] = Math.min( leftBounds[ d ], binBounds[ o + d ] );\n\t\t\t\t\t\t\t\tleftBounds[ d + 3 ] = Math.max( leftBounds[ d + 3 ], binBounds[ o + d + 3 ] );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tleftCount += binCount;\n\n\t\t\t\t\t// check the cost of this split\n\t\t\t\t\tlet leftProb = 0;\n\t\t\t\t\tlet rightProb = 0;\n\n\t\t\t\t\tif ( leftCount !== 0 ) {\n\n\t\t\t\t\t\tleftProb = computeSurfaceArea( leftBounds ) / rootSurfaceArea;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tconst rightCount = count - leftCount;\n\t\t\t\t\tif ( rightCount !== 0 ) {\n\n\t\t\t\t\t\trightProb = computeSurfaceAreaAt( binRightBounds, o + 6 ) / rootSurfaceArea;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tconst cost = TRAVERSAL_COST + PRIMITIVE_INTERSECT_COST * (\n\t\t\t\t\t\tleftProb * leftCount + rightProb * rightCount\n\t\t\t\t\t);\n\n\t\t\t\t\tif ( cost < bestCost ) {\n\n\t\t\t\t\t\taxis = a;\n\t\t\t\t\t\tbestCost = cost;\n\t\t\t\t\t\tpos = axisLeft + binWidth + i * binWidth;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t} else {\n\n\t\tconsole.warn( `BVH: Invalid build strategy value ${ strategy } used.` );\n\n\t}\n\n\treturn { axis, pos };\n\n}\n\n// returns the average coordinate on the specified axis of all the provided primitives\nfunction getAverage( primitiveBounds, offset, count, axis ) {\n\n\tlet avg = 0;\n\tconst boundsOffset = primitiveBounds.offset;\n\tfor ( let i = offset, end = offset + count; i < end; i ++ ) {\n\n\t\tavg += primitiveBounds[ ( i - boundsOffset ) * 6 + axis * 2 ];\n\n\t}\n\n\treturn avg / count;\n\n}\n","// reorders the partition buffer such that for `count` elements after `offset`, elements on the left side of the split\n// will be on the left and elements on the right side of the split will be on the right. returns the index\n// of the first element on the right side, or offset + count if there are no elements on the right side.\nexport function partition( buffer, stride, primitiveBounds, offset, count, split ) {\n\n\tlet left = offset;\n\tlet right = offset + count - 1;\n\tconst pos = split.pos;\n\tconst axisOffset = split.axis * 2;\n\tconst boundsOffset = primitiveBounds.offset || 0;\n\n\t// hoare partitioning, see e.g. https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme\n\twhile ( true ) {\n\n\t\twhile ( left <= right && primitiveBounds[ ( left - boundsOffset ) * 6 + axisOffset ] < pos ) {\n\n\t\t\tleft ++;\n\n\t\t}\n\n\t\t// if a primitive center lies on the partition plane it is considered to be on the right side\n\t\twhile ( left <= right && primitiveBounds[ ( right - boundsOffset ) * 6 + axisOffset ] >= pos ) {\n\n\t\t\tright --;\n\n\t\t}\n\n\t\tif ( left < right ) {\n\n\t\t\t// we need to swap all of the information associated with the primitives at index\n\t\t\t// left and right; that's the elements in the partition buffer and the bounds\n\t\t\tfor ( let i = 0; i < stride; i ++ ) {\n\n\t\t\t\tlet t0 = buffer[ left * stride + i ];\n\t\t\t\tbuffer[ left * stride + i ] = buffer[ right * stride + i ];\n\t\t\t\tbuffer[ right * stride + i ] = t0;\n\n\t\t\t}\n\n\t\t\t// swap bounds\n\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\tconst l = left - boundsOffset;\n\t\t\t\tconst r = right - boundsOffset;\n\t\t\t\tconst tb = primitiveBounds[ l * 6 + i ];\n\t\t\t\tprimitiveBounds[ l * 6 + i ] = primitiveBounds[ r * 6 + i ];\n\t\t\t\tprimitiveBounds[ r * 6 + i ] = tb;\n\n\t\t\t}\n\n\t\t\tleft ++;\n\t\t\tright --;\n\n\t\t} else {\n\n\t\t\treturn left;\n\n\t\t}\n\n\t}\n\n}\n","import { getBounds } from './computeBoundsUtils.js';\nimport { getOptimalSplit } from './splitUtils.js';\nimport { getLongestEdgeIndex } from '../../utils/ArrayBoxUtilities.js';\nimport { BYTES_PER_NODE, UINT32_PER_NODE, IS_LEAFNODE_FLAG } from '../Constants.js';\nimport { partition } from './sortUtils.js';\n\nconst MAX_POINTER = Math.pow( 2, 32 );\n\n// the bounds and centroid bounds of the node about to be split\nconst _nodeBounds = /* @__PURE__ */ new Float32Array( 6 );\nconst _centroidBounds = /* @__PURE__ */ new Float32Array( 6 );\n\n// Builds the tree over the given primitive range directly into a packed node buffer and returns\n// it trimmed to the nodes written. Nodes are written depth first, so a left child directly follows\n// its parent and the right child is stored as a relative node offset.\n//\n// pack structure\n// boundingData  \t\t\t\t: 6 float32\n// right / offset \t\t\t\t: 1 uint32\n// splitAxis / isLeaf + count \t: 1 uint32 / 2 uint16\nexport function buildTree( bvh, primitiveBounds, offset, count, options, loadRange ) {\n\n\t// expand variables\n\tconst {\n\t\tmaxDepth,\n\t\tverbose,\n\t\ttargetLeafSize,\n\t\t_strictLeafSize = Infinity,\n\t\tstrategy,\n\t\tonProgress,\n\t\tuseSharedArrayBuffer = false,\n\t} = options;\n\n\tconst partitionBuffer = bvh.primitiveBuffer;\n\tconst partitionStride = bvh.primitiveBufferStride;\n\n\t// a binary tree with at least one primitive per leaf has at most 2n - 1 nodes. Group ranges that\n\t// don't line up with triangles give a fractional count.\n\tconst BufferConstructor = useSharedArrayBuffer ? SharedArrayBuffer : ArrayBuffer;\n\tconst buffer = new BufferConstructor( BYTES_PER_NODE * Math.max( 1, 2 * Math.ceil( count ) - 1 ) );\n\tconst float32Array = new Float32Array( buffer );\n\tconst uint32Array = new Uint32Array( buffer );\n\tconst uint16Array = new Uint16Array( buffer );\n\tlet nodeCount = 0;\n\tlet reachedMaxDepth = false;\n\n\tgetBounds( primitiveBounds, offset, count, _nodeBounds, _centroidBounds );\n\tsplitNode( offset, count, 0 );\n\treturn buffer.slice( 0, nodeCount * BYTES_PER_NODE );\n\n\tfunction triggerProgress( primitivesProcessed ) {\n\n\t\tif ( onProgress ) {\n\n\t\t\tonProgress( ( primitivesProcessed - loadRange.offset ) / loadRange.count );\n\n\t\t}\n\n\t}\n\n\tfunction writeLeaf( node32, offset, count ) {\n\n\t\tconst node16 = node32 * 2;\n\t\tuint32Array[ node32 + 6 ] = offset;\n\t\tuint16Array[ node16 + 14 ] = count;\n\t\tuint16Array[ node16 + 15 ] = IS_LEAFNODE_FLAG;\n\t\ttriggerProgress( offset + count );\n\n\t}\n\n\t// writes the node whose bounds are in \"_nodeBounds\" and either recursively splits it, creating left and right\n\t// subtrees for it, or makes it a leaf node, recording the offset and count of its primitives.\n\tfunction splitNode( offset, count, depth ) {\n\n\t\tconst nodeIndex = nodeCount ++;\n\t\tconst node32 = nodeIndex * UINT32_PER_NODE;\n\t\tfloat32Array.set( _nodeBounds, node32 );\n\n\t\tif ( ! reachedMaxDepth && depth >= maxDepth ) {\n\n\t\t\treachedMaxDepth = true;\n\t\t\tif ( verbose ) {\n\n\t\t\t\tconsole.warn( `BVH: Max depth of ${ maxDepth } reached when generating BVH. Consider increasing maxDepth.` );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// A hard guarantee that no leaf exceeds \"_strictLeafSize\" primitives. When this node is over\n\t\t// that limit it must keep splitting regardless of the heuristic.\n\t\tconst mustSplit = count > _strictLeafSize;\n\n\t\t// early out if we've met our capacity - unless the strict guarantee still requires a split\n\t\tif ( ( count <= targetLeafSize && ! mustSplit ) || depth >= maxDepth ) {\n\n\t\t\twriteLeaf( node32, offset, count );\n\t\t\treturn;\n\n\t\t}\n\n\t\t// Find where to split the volume\n\t\tconst split = getOptimalSplit( _nodeBounds, _centroidBounds, primitiveBounds, offset, count, strategy );\n\t\tlet splitOffset = split.axis === - 1 ? - 1 : partition( partitionBuffer, partitionStride, primitiveBounds, offset, count, split );\n\n\t\t// If the heuristic can't produce a usable split then make a leaf unless the strict guarantee requires the split -\n\t\t// in which case force an arbitrary median split. The axis comes from the node bounds so parallel and serial\n\t\t// builds produce identical trees.\n\t\tif ( split.axis === - 1 || splitOffset === offset || splitOffset === offset + count ) {\n\n\t\t\tif ( ! mustSplit ) {\n\n\t\t\t\twriteLeaf( node32, offset, count );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tsplit.axis = Math.max( 0, getLongestEdgeIndex( _nodeBounds ) );\n\t\t\tsplitOffset = offset + Math.max( 1, Math.floor( count / 2 ) );\n\n\t\t}\n\n\t\tuint32Array[ node32 + 7 ] = split.axis;\n\n\t\t// the left child directly follows this node\n\t\tconst leftCount = splitOffset - offset;\n\t\tgetBounds( primitiveBounds, offset, leftCount, _nodeBounds, _centroidBounds );\n\t\tsplitNode( offset, leftCount, depth + 1 );\n\n\t\t// the right child follows the left subtree, stored as an offset relative to this node\n\t\tconst relativeRightIndex = nodeCount - nodeIndex;\n\t\tif ( relativeRightIndex > MAX_POINTER ) {\n\n\t\t\tthrow new Error( 'MeshBVH: Cannot store relative child node offset greater than 32 bits.' );\n\n\t\t}\n\n\t\tuint32Array[ node32 + 6 ] = relativeRightIndex;\n\n\t\tconst rightCount = count - leftCount;\n\t\tgetBounds( primitiveBounds, splitOffset, rightCount, _nodeBounds, _centroidBounds );\n\t\tsplitNode( splitOffset, rightCount, depth + 1 );\n\n\t}\n\n}\n\nexport function buildPackedTree( bvh, options ) {\n\n\t// get the range of buffer data to construct / arrange\n\tconst rootRanges = bvh.getRootRanges( options.range );\n\tconst firstRange = rootRanges[ 0 ];\n\tconst lastRange = rootRanges[ rootRanges.length - 1 ];\n\tconst fullRange = {\n\t\toffset: firstRange.offset,\n\t\tcount: lastRange.offset + lastRange.count - firstRange.offset,\n\t};\n\n\t// construct the primitive bounds for sorting\n\tconst primitiveBounds = new Float32Array( 6 * fullRange.count );\n\tprimitiveBounds.offset = fullRange.offset;\n\tbvh.computePrimitiveBounds( fullRange.offset, fullRange.count, primitiveBounds );\n\n\t// Build BVH roots\n\tbvh._roots = rootRanges.map( range => {\n\n\t\treturn buildTree( bvh, primitiveBounds, range.offset, range.count, options, fullRange );\n\n\t} );\n\n}\n","export class PrimitivePool {\n\n\tconstructor( getNewPrimitive ) {\n\n\t\tthis._getNewPrimitive = getNewPrimitive;\n\t\tthis._primitives = [];\n\n\t}\n\n\tgetPrimitive() {\n\n\t\tconst primitives = this._primitives;\n\t\tif ( primitives.length === 0 ) {\n\n\t\t\treturn this._getNewPrimitive();\n\n\t\t} else {\n\n\t\t\treturn primitives.pop();\n\n\t\t}\n\n\t}\n\n\treleasePrimitive( primitive ) {\n\n\t\tthis._primitives.push( primitive );\n\n\t}\n\n}\n","class _BufferStack {\n\n\tconstructor() {\n\n\t\tthis.float32Array = null;\n\t\tthis.uint16Array = null;\n\t\tthis.uint32Array = null;\n\n\t\tconst stack = [];\n\t\tlet prevBuffer = null;\n\t\tthis.setBuffer = buffer => {\n\n\t\t\tif ( prevBuffer ) {\n\n\t\t\t\tstack.push( prevBuffer );\n\n\t\t\t}\n\n\t\t\tprevBuffer = buffer;\n\t\t\tthis.float32Array = new Float32Array( buffer );\n\t\t\tthis.uint16Array = new Uint16Array( buffer );\n\t\t\tthis.uint32Array = new Uint32Array( buffer );\n\n\t\t};\n\n\t\tthis.clearBuffer = () => {\n\n\t\t\tprevBuffer = null;\n\t\t\tthis.float32Array = null;\n\t\t\tthis.uint16Array = null;\n\t\t\tthis.uint32Array = null;\n\n\t\t\tif ( stack.length !== 0 ) {\n\n\t\t\t\tthis.setBuffer( stack.pop() );\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n}\n\nexport const BufferStack = /* @__PURE__ */ new _BufferStack();\n","import { Box3 } from 'three';\nimport { CONTAINED, UINT32_PER_NODE } from '../Constants.js';\nimport { arrayToBox } from '../../utils/ArrayBoxUtilities.js';\nimport { PrimitivePool } from '../../utils/PrimitivePool.js';\nimport { COUNT, OFFSET, LEFT_NODE, RIGHT_NODE, IS_LEAF, BOUNDING_DATA_INDEX } from '../utils/nodeBufferUtils.js';\nimport { BufferStack } from '../utils/BufferStack.js';\n\nlet _box1, _box2;\nconst boxStack = [];\nconst boxPool = /* @__PURE__ */ new PrimitivePool( () => new Box3() );\n\nexport function shapecast( bvh, root, intersectsBounds, intersectsRange, boundsTraverseOrder, nodeOffset ) {\n\n\t// setup\n\t_box1 = boxPool.getPrimitive();\n\t_box2 = boxPool.getPrimitive();\n\tboxStack.push( _box1, _box2 );\n\tBufferStack.setBuffer( bvh._roots[ root ] );\n\n\tconst result = shapecastTraverse( 0, bvh.geometry, intersectsBounds, intersectsRange, boundsTraverseOrder, nodeOffset );\n\n\t// cleanup\n\tBufferStack.clearBuffer();\n\tboxPool.releasePrimitive( _box1 );\n\tboxPool.releasePrimitive( _box2 );\n\tboxStack.pop();\n\tboxStack.pop();\n\n\tconst length = boxStack.length;\n\tif ( length > 0 ) {\n\n\t\t_box2 = boxStack[ length - 1 ];\n\t\t_box1 = boxStack[ length - 2 ];\n\n\t}\n\n\treturn result;\n\n}\n\nfunction shapecastTraverse(\n\tnodeIndex32,\n\tgeometry,\n\tintersectsBoundsFunc,\n\tintersectsRangeFunc,\n\tnodeScoreFunc = null,\n\tnodeIndexOffset = 0, // offset for unique node identifier\n\tdepth = 0\n) {\n\n\tconst { float32Array, uint16Array, uint32Array } = BufferStack;\n\tlet nodeIndex16 = nodeIndex32 * 2;\n\n\tconst isLeaf = IS_LEAF( nodeIndex16, uint16Array );\n\tif ( isLeaf ) {\n\n\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\n\t\tconst count = COUNT( nodeIndex16, uint16Array );\n\t\tarrayToBox( BOUNDING_DATA_INDEX( nodeIndex32 ), float32Array, _box1 );\n\t\treturn intersectsRangeFunc( offset, count, false, depth, nodeIndexOffset + nodeIndex32 / UINT32_PER_NODE, _box1 );\n\n\t} else {\n\n\t\tconst left = LEFT_NODE( nodeIndex32 );\n\t\tconst right = RIGHT_NODE( nodeIndex32, uint32Array );\n\t\tlet c1 = left;\n\t\tlet c2 = right;\n\n\t\tlet score1, score2;\n\t\tlet box1, box2;\n\t\tif ( nodeScoreFunc ) {\n\n\t\t\tbox1 = _box1;\n\t\t\tbox2 = _box2;\n\n\t\t\t// bounding data is not offset\n\t\t\tarrayToBox( BOUNDING_DATA_INDEX( c1 ), float32Array, box1 );\n\t\t\tarrayToBox( BOUNDING_DATA_INDEX( c2 ), float32Array, box2 );\n\n\t\t\tscore1 = nodeScoreFunc( box1 );\n\t\t\tscore2 = nodeScoreFunc( box2 );\n\n\t\t\tif ( score2 < score1 ) {\n\n\t\t\t\tc1 = right;\n\t\t\t\tc2 = left;\n\n\t\t\t\tconst temp = score1;\n\t\t\t\tscore1 = score2;\n\t\t\t\tscore2 = temp;\n\n\t\t\t\tbox1 = box2;\n\t\t\t\t// box2 is always set before use below\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Check box 1 intersection\n\t\tif ( ! box1 ) {\n\n\t\t\tbox1 = _box1;\n\t\t\tarrayToBox( BOUNDING_DATA_INDEX( c1 ), float32Array, box1 );\n\n\t\t}\n\n\t\tconst isC1Leaf = IS_LEAF( c1 * 2, uint16Array );\n\t\tconst c1Intersection = intersectsBoundsFunc( box1, isC1Leaf, score1, depth + 1, nodeIndexOffset + c1 / UINT32_PER_NODE );\n\n\t\tlet c1StopTraversal;\n\t\tif ( c1Intersection === CONTAINED ) {\n\n\t\t\tconst offset = getLeftOffset( c1 );\n\t\t\tconst end = getRightEndOffset( c1 );\n\t\t\tconst count = end - offset;\n\n\t\t\tc1StopTraversal = intersectsRangeFunc( offset, count, true, depth + 1, nodeIndexOffset + c1 / UINT32_PER_NODE, box1 );\n\n\t\t} else {\n\n\t\t\tc1StopTraversal =\n\t\t\t\tc1Intersection &&\n\t\t\t\tshapecastTraverse(\n\t\t\t\t\tc1,\n\t\t\t\t\tgeometry,\n\t\t\t\t\tintersectsBoundsFunc,\n\t\t\t\t\tintersectsRangeFunc,\n\t\t\t\t\tnodeScoreFunc,\n\t\t\t\t\tnodeIndexOffset,\n\t\t\t\t\tdepth + 1\n\t\t\t\t);\n\n\t\t}\n\n\t\tif ( c1StopTraversal ) return true;\n\n\t\t// Check box 2 intersection\n\t\t// cached box2 will have been overwritten by previous traversal\n\t\tbox2 = _box2;\n\t\tarrayToBox( BOUNDING_DATA_INDEX( c2 ), float32Array, box2 );\n\n\t\tconst isC2Leaf = IS_LEAF( c2 * 2, uint16Array );\n\t\tconst c2Intersection = intersectsBoundsFunc( box2, isC2Leaf, score2, depth + 1, nodeIndexOffset + c2 / UINT32_PER_NODE );\n\n\t\tlet c2StopTraversal;\n\t\tif ( c2Intersection === CONTAINED ) {\n\n\t\t\tconst offset = getLeftOffset( c2 );\n\t\t\tconst end = getRightEndOffset( c2 );\n\t\t\tconst count = end - offset;\n\n\t\t\tc2StopTraversal = intersectsRangeFunc( offset, count, true, depth + 1, nodeIndexOffset + c2 / UINT32_PER_NODE, box2 );\n\n\t\t} else {\n\n\t\t\tc2StopTraversal =\n\t\t\t\tc2Intersection &&\n\t\t\t\tshapecastTraverse(\n\t\t\t\t\tc2,\n\t\t\t\t\tgeometry,\n\t\t\t\t\tintersectsBoundsFunc,\n\t\t\t\t\tintersectsRangeFunc,\n\t\t\t\t\tnodeScoreFunc,\n\t\t\t\t\tnodeIndexOffset,\n\t\t\t\t\tdepth + 1\n\t\t\t\t);\n\n\t\t}\n\n\t\tif ( c2StopTraversal ) return true;\n\n\t\treturn false;\n\n\t\t// Define these inside the function so it has access to the local variables needed\n\t\t// when converting to the buffer equivalents\n\t\tfunction getLeftOffset( nodeIndex32 ) {\n\n\t\t\tconst { uint16Array, uint32Array } = BufferStack;\n\t\t\tlet nodeIndex16 = nodeIndex32 * 2;\n\n\t\t\t// traverse until we find a leaf\n\t\t\twhile ( ! IS_LEAF( nodeIndex16, uint16Array ) ) {\n\n\t\t\t\tnodeIndex32 = LEFT_NODE( nodeIndex32 );\n\t\t\t\tnodeIndex16 = nodeIndex32 * 2;\n\n\t\t\t}\n\n\t\t\treturn OFFSET( nodeIndex32, uint32Array );\n\n\t\t}\n\n\t\tfunction getRightEndOffset( nodeIndex32 ) {\n\n\t\t\tconst { uint16Array, uint32Array } = BufferStack;\n\t\t\tlet nodeIndex16 = nodeIndex32 * 2;\n\n\t\t\t// traverse until we find a leaf\n\t\t\twhile ( ! IS_LEAF( nodeIndex16, uint16Array ) ) {\n\n\t\t\t\t// adjust offset to point to the right node\n\t\t\t\tnodeIndex32 = RIGHT_NODE( nodeIndex32, uint32Array );\n\t\t\t\tnodeIndex16 = nodeIndex32 * 2;\n\n\t\t\t}\n\n\t\t\t// return the end offset of the triangle range\n\t\t\treturn OFFSET( nodeIndex32, uint32Array ) + COUNT( nodeIndex16, uint16Array );\n\n\t\t}\n\n\t}\n\n}\n","import { Box3, Matrix4 } from 'three';\nimport { BufferStack } from '../utils/BufferStack.js';\nimport { BOUNDING_DATA_INDEX, COUNT, IS_LEAF, LEFT_NODE, OFFSET, RIGHT_NODE } from '../utils/nodeBufferUtils.js';\nimport { arrayToBox } from '../../utils/ArrayBoxUtilities.js';\nimport { PrimitivePool } from '../../utils/PrimitivePool.js';\nimport { BYTES_PER_NODE, UINT32_PER_NODE } from '../Constants.js';\n\nconst _bufferStack1 = /* @__PURE__ */ new BufferStack.constructor();\nconst _bufferStack2 = /* @__PURE__ */ new BufferStack.constructor();\nconst _boxPool = /* @__PURE__ */ new PrimitivePool( () => new Box3() );\nconst _leftBox1 = /* @__PURE__ */ new Box3();\nconst _rightBox1 = /* @__PURE__ */ new Box3();\n\nconst _leftBox2 = /* @__PURE__ */ new Box3();\nconst _rightBox2 = /* @__PURE__ */ new Box3();\n\nlet _active = false;\n\nexport function bvhcast( bvh, otherBvh, matrixToLocal, intersectsRanges ) {\n\n\tif ( _active ) {\n\n\t\tthrow new Error( 'MeshBVH: Recursive calls to bvhcast not supported.' );\n\n\t}\n\n\t_active = true;\n\n\tconst roots = bvh._roots;\n\tconst otherRoots = otherBvh._roots;\n\tlet result;\n\tlet nodeOffset1 = 0;\n\tlet nodeOffset2 = 0;\n\tconst invMat = new Matrix4().copy( matrixToLocal ).invert();\n\n\t// iterate over the first set of roots\n\tfor ( let i = 0, il = roots.length; i < il; i ++ ) {\n\n\t\t_bufferStack1.setBuffer( roots[ i ] );\n\t\tnodeOffset2 = 0;\n\n\t\t// prep the initial root box\n\t\tconst localBox = _boxPool.getPrimitive();\n\t\tarrayToBox( BOUNDING_DATA_INDEX( 0 ), _bufferStack1.float32Array, localBox );\n\t\tlocalBox.applyMatrix4( invMat );\n\n\t\t// iterate over the second set of roots\n\t\tfor ( let j = 0, jl = otherRoots.length; j < jl; j ++ ) {\n\n\t\t\t_bufferStack2.setBuffer( otherRoots[ j ] );\n\n\t\t\tresult = _traverse(\n\t\t\t\t0, 0, matrixToLocal, invMat, intersectsRanges,\n\t\t\t\tnodeOffset1, nodeOffset2, 0, 0,\n\t\t\t\tlocalBox,\n\t\t\t);\n\n\t\t\t_bufferStack2.clearBuffer();\n\t\t\tnodeOffset2 += otherRoots[ j ].byteLength / BYTES_PER_NODE;\n\n\t\t\tif ( result ) {\n\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// release stack info\n\t\t_boxPool.releasePrimitive( localBox );\n\t\t_bufferStack1.clearBuffer();\n\t\tnodeOffset1 += roots[ i ].byteLength / BYTES_PER_NODE;\n\n\t\tif ( result ) {\n\n\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\t_active = false;\n\treturn result;\n\n}\n\nfunction _traverse(\n\tnode1Index32,\n\tnode2Index32,\n\tmatrix2to1,\n\tmatrix1to2,\n\tintersectsRangesFunc,\n\n\t// offsets for ids\n\tnode1IndexOffset = 0,\n\tnode2IndexOffset = 0,\n\n\t// tree depth\n\tdepth1 = 0,\n\tdepth2 = 0,\n\n\tcurrBox = null,\n\treversed = false,\n\n) {\n\n\t// get the buffer stacks associated with the current indices\n\tlet bufferStack1, bufferStack2;\n\tif ( reversed ) {\n\n\t\tbufferStack1 = _bufferStack2;\n\t\tbufferStack2 = _bufferStack1;\n\n\t} else {\n\n\t\tbufferStack1 = _bufferStack1;\n\t\tbufferStack2 = _bufferStack2;\n\n\t}\n\n\t// get the local instances of the typed buffers\n\tconst\n\t\tfloat32Array1 = bufferStack1.float32Array,\n\t\tuint32Array1 = bufferStack1.uint32Array,\n\t\tuint16Array1 = bufferStack1.uint16Array,\n\t\tfloat32Array2 = bufferStack2.float32Array,\n\t\tuint32Array2 = bufferStack2.uint32Array,\n\t\tuint16Array2 = bufferStack2.uint16Array;\n\n\tconst node1Index16 = node1Index32 * 2;\n\tconst node2Index16 = node2Index32 * 2;\n\tconst isLeaf1 = IS_LEAF( node1Index16, uint16Array1 );\n\tconst isLeaf2 = IS_LEAF( node2Index16, uint16Array2 );\n\tlet result = false;\n\tif ( isLeaf2 && isLeaf1 ) {\n\n\t\t// if both bounds are leaf nodes then fire the callback if the boxes intersect\n\t\t// Note the \"nodeIndex\" values are just intended to be used as unique identifiers in the tree and\n\t\t// not used for accessing data\n\t\tif ( reversed ) {\n\n\t\t\tresult = intersectsRangesFunc(\n\t\t\t\tOFFSET( node2Index32, uint32Array2 ), COUNT( node2Index32 * 2, uint16Array2 ),\n\t\t\t\tOFFSET( node1Index32, uint32Array1 ), COUNT( node1Index32 * 2, uint16Array1 ),\n\t\t\t\tdepth2, node2IndexOffset + node2Index32 / UINT32_PER_NODE,\n\t\t\t\tdepth1, node1IndexOffset + node1Index32 / UINT32_PER_NODE,\n\t\t\t);\n\n\t\t} else {\n\n\t\t\tresult = intersectsRangesFunc(\n\t\t\t\tOFFSET( node1Index32, uint32Array1 ), COUNT( node1Index32 * 2, uint16Array1 ),\n\t\t\t\tOFFSET( node2Index32, uint32Array2 ), COUNT( node2Index32 * 2, uint16Array2 ),\n\t\t\t\tdepth1, node1IndexOffset + node1Index32 / UINT32_PER_NODE,\n\t\t\t\tdepth2, node2IndexOffset + node2Index32 / UINT32_PER_NODE,\n\t\t\t);\n\n\t\t}\n\n\t} else if ( isLeaf2 ) {\n\n\t\t// SWAP\n\t\t// If we've traversed to the leaf node on the other bvh then we need to swap over\n\t\t// to traverse down the first one\n\n\t\t// get the new box to use\n\t\tconst newBox = _boxPool.getPrimitive();\n\t\tarrayToBox( BOUNDING_DATA_INDEX( node2Index32 ), float32Array2, newBox );\n\t\tnewBox.applyMatrix4( matrix2to1 );\n\n\t\t// get the child bounds to check before traversal\n\t\tconst cl1 = LEFT_NODE( node1Index32 );\n\t\tconst cr1 = RIGHT_NODE( node1Index32, uint32Array1 );\n\t\tarrayToBox( BOUNDING_DATA_INDEX( cl1 ), float32Array1, _leftBox1 );\n\t\tarrayToBox( BOUNDING_DATA_INDEX( cr1 ), float32Array1, _rightBox1 );\n\n\t\t// precompute the intersections otherwise the global boxes will be modified during traversal\n\t\tconst intersectCl1 = newBox.intersectsBox( _leftBox1 );\n\t\tconst intersectCr1 = newBox.intersectsBox( _rightBox1 );\n\t\tresult = (\n\t\t\tintersectCl1 && _traverse(\n\t\t\t\tnode2Index32, cl1, matrix1to2, matrix2to1, intersectsRangesFunc,\n\t\t\t\tnode2IndexOffset, node1IndexOffset, depth2, depth1 + 1,\n\t\t\t\tnewBox, ! reversed,\n\t\t\t)\n\t\t) || (\n\t\t\tintersectCr1 && _traverse(\n\t\t\t\tnode2Index32, cr1, matrix1to2, matrix2to1, intersectsRangesFunc,\n\t\t\t\tnode2IndexOffset, node1IndexOffset, depth2, depth1 + 1,\n\t\t\t\tnewBox, ! reversed,\n\t\t\t)\n\t\t);\n\n\t\t_boxPool.releasePrimitive( newBox );\n\n\t} else {\n\n\t\t// if neither are leaves then we should swap if one of the children does not\n\t\t// intersect with the current bounds\n\n\t\t// get the child bounds to check\n\t\tconst cl2 = LEFT_NODE( node2Index32 );\n\t\tconst cr2 = RIGHT_NODE( node2Index32, uint32Array2 );\n\t\tarrayToBox( BOUNDING_DATA_INDEX( cl2 ), float32Array2, _leftBox2 );\n\t\tarrayToBox( BOUNDING_DATA_INDEX( cr2 ), float32Array2, _rightBox2 );\n\n\t\tconst leftIntersects = currBox.intersectsBox( _leftBox2 );\n\t\tconst rightIntersects = currBox.intersectsBox( _rightBox2 );\n\t\tif ( leftIntersects && rightIntersects ) {\n\n\t\t\t// continue to traverse both children if they both intersect\n\t\t\tresult = _traverse(\n\t\t\t\tnode1Index32, cl2, matrix2to1, matrix1to2, intersectsRangesFunc,\n\t\t\t\tnode1IndexOffset, node2IndexOffset, depth1, depth2 + 1,\n\t\t\t\tcurrBox, reversed,\n\t\t\t) || _traverse(\n\t\t\t\tnode1Index32, cr2, matrix2to1, matrix1to2, intersectsRangesFunc,\n\t\t\t\tnode1IndexOffset, node2IndexOffset, depth1, depth2 + 1,\n\t\t\t\tcurrBox, reversed,\n\t\t\t);\n\n\t\t} else if ( leftIntersects ) {\n\n\t\t\tif ( isLeaf1 ) {\n\n\t\t\t\t// if the current box is a leaf then just continue\n\t\t\t\tresult = _traverse(\n\t\t\t\t\tnode1Index32, cl2, matrix2to1, matrix1to2, intersectsRangesFunc,\n\t\t\t\t\tnode1IndexOffset, node2IndexOffset, depth1, depth2 + 1,\n\t\t\t\t\tcurrBox, reversed,\n\t\t\t\t);\n\n\t\t\t} else {\n\n\t\t\t\t// SWAP\n\t\t\t\t// if only one box intersects then we have to swap to the other bvh to continue\n\t\t\t\tconst newBox = _boxPool.getPrimitive();\n\t\t\t\tnewBox.copy( _leftBox2 ).applyMatrix4( matrix2to1 );\n\n\t\t\t\tconst cl1 = LEFT_NODE( node1Index32 );\n\t\t\t\tconst cr1 = RIGHT_NODE( node1Index32, uint32Array1 );\n\t\t\t\tarrayToBox( BOUNDING_DATA_INDEX( cl1 ), float32Array1, _leftBox1 );\n\t\t\t\tarrayToBox( BOUNDING_DATA_INDEX( cr1 ), float32Array1, _rightBox1 );\n\n\t\t\t\t// precompute the intersections otherwise the global boxes will be modified during traversal\n\t\t\t\tconst intersectCl1 = newBox.intersectsBox( _leftBox1 );\n\t\t\t\tconst intersectCr1 = newBox.intersectsBox( _rightBox1 );\n\t\t\t\tresult = (\n\t\t\t\t\tintersectCl1 && _traverse(\n\t\t\t\t\t\tcl2, cl1, matrix1to2, matrix2to1, intersectsRangesFunc,\n\t\t\t\t\t\tnode2IndexOffset, node1IndexOffset, depth2, depth1 + 1,\n\t\t\t\t\t\tnewBox, ! reversed,\n\t\t\t\t\t)\n\t\t\t\t) || (\n\t\t\t\t\tintersectCr1 && _traverse(\n\t\t\t\t\t\tcl2, cr1, matrix1to2, matrix2to1, intersectsRangesFunc,\n\t\t\t\t\t\tnode2IndexOffset, node1IndexOffset, depth2, depth1 + 1,\n\t\t\t\t\t\tnewBox, ! reversed,\n\t\t\t\t\t)\n\t\t\t\t);\n\n\t\t\t\t_boxPool.releasePrimitive( newBox );\n\n\t\t\t}\n\n\t\t} else if ( rightIntersects ) {\n\n\t\t\tif ( isLeaf1 ) {\n\n\t\t\t\t// if the current box is a leaf then just continue\n\t\t\t\tresult = _traverse(\n\t\t\t\t\tnode1Index32, cr2, matrix2to1, matrix1to2, intersectsRangesFunc,\n\t\t\t\t\tnode1IndexOffset, node2IndexOffset, depth1, depth2 + 1,\n\t\t\t\t\tcurrBox, reversed,\n\t\t\t\t);\n\n\t\t\t} else {\n\n\t\t\t\t// SWAP\n\t\t\t\t// if only one box intersects then we have to swap to the other bvh to continue\n\t\t\t\tconst newBox = _boxPool.getPrimitive();\n\t\t\t\tnewBox.copy( _rightBox2 ).applyMatrix4( matrix2to1 );\n\n\t\t\t\tconst cl1 = LEFT_NODE( node1Index32 );\n\t\t\t\tconst cr1 = RIGHT_NODE( node1Index32, uint32Array1 );\n\t\t\t\tarrayToBox( BOUNDING_DATA_INDEX( cl1 ), float32Array1, _leftBox1 );\n\t\t\t\tarrayToBox( BOUNDING_DATA_INDEX( cr1 ), float32Array1, _rightBox1 );\n\n\t\t\t\t// precompute the intersections otherwise the global boxes will be modified during traversal\n\t\t\t\tconst intersectCl1 = newBox.intersectsBox( _leftBox1 );\n\t\t\t\tconst intersectCr1 = newBox.intersectsBox( _rightBox1 );\n\t\t\t\tresult = (\n\t\t\t\t\tintersectCl1 && _traverse(\n\t\t\t\t\t\tcr2, cl1, matrix1to2, matrix2to1, intersectsRangesFunc,\n\t\t\t\t\t\tnode2IndexOffset, node1IndexOffset, depth2, depth1 + 1,\n\t\t\t\t\t\tnewBox, ! reversed,\n\t\t\t\t\t)\n\t\t\t\t) || (\n\t\t\t\t\tintersectCr1 && _traverse(\n\t\t\t\t\t\tcr2, cr1, matrix1to2, matrix2to1, intersectsRangesFunc,\n\t\t\t\t\t\tnode2IndexOffset, node1IndexOffset, depth2, depth1 + 1,\n\t\t\t\t\t\tnewBox, ! reversed,\n\t\t\t\t\t)\n\t\t\t\t);\n\n\t\t\t\t_boxPool.releasePrimitive( newBox );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\treturn result;\n\n}\n\n","import { COUNT, IS_LEAF, LEFT_NODE, OFFSET, RIGHT_NODE, SPLIT_AXIS } from './utils/nodeBufferUtils.js';\n\nexport const BVHTraversalHelper = new ( class {\n\n\tconstructor() {\n\n\t\tlet buffer = null;\n\t\tlet uint32Array = null;\n\t\tlet uint16Array = null;\n\t\tlet traversing = false;\n\n\t\tthis.root = null;\n\t\tthis.buffer = null;\n\t\tthis.uint32Array = null;\n\t\tthis.uint16Array = null;\n\n\t\tthis.setBVH = ( bvh, root ) => {\n\n\t\t\tif ( traversing ) {\n\n\t\t\t\tthrow new Error( 'BVHTraversalHelper: cannot call setBVH during an active traversal.' );\n\n\t\t\t}\n\n\t\t\tthis.root = root;\n\t\t\tthis.buffer = buffer = bvh._roots[ root ];\n\t\t\tthis.uint16Array = uint16Array = new Uint16Array( buffer );\n\t\t\tthis.uint32Array = uint32Array = new Uint32Array( buffer );\n\n\t\t};\n\n\t\tthis.reset = () => {\n\n\t\t\tthis.root = null;\n\t\t\tthis.buffer = buffer = null;\n\t\t\tthis.uint16Array = uint16Array = null;\n\t\t\tthis.uint32Array = uint32Array = null;\n\n\t\t};\n\n\t\tthis.getRangeStart = node32Index => {\n\n\t\t\tlet node16Index = node32Index * 2;\n\t\t\twhile ( ! IS_LEAF( node16Index, uint16Array ) ) {\n\n\t\t\t\tnode32Index = LEFT_NODE( node32Index );\n\t\t\t\tnode16Index = node32Index * 2;\n\n\t\t\t}\n\n\t\t\treturn OFFSET( node32Index, uint32Array );\n\n\t\t};\n\n\t\tthis.getRangeEnd = node32Index => {\n\n\t\t\tlet node16Index = node32Index * 2;\n\t\t\twhile ( ! IS_LEAF( node16Index, uint16Array ) ) {\n\n\t\t\t\tnode32Index = RIGHT_NODE( node32Index, uint32Array );\n\t\t\t\tnode16Index = node32Index * 2;\n\n\t\t\t}\n\n\t\t\treturn OFFSET( node32Index, uint32Array ) + COUNT( node16Index, uint16Array );\n\n\t\t};\n\n\t\t// internal recursive walk - the public \"traverseBuffer\" wraps this with the re-entrancy guard\n\t\tconst walk = ( callback, node32Index, depth ) => {\n\n\t\t\tconst node16Index = node32Index * 2;\n\t\t\tconst isLeaf = IS_LEAF( node16Index, uint16Array );\n\t\t\tconst stopTraversal = callback( depth, isLeaf, node32Index );\n\t\t\tif ( ! stopTraversal && ! isLeaf ) {\n\n\t\t\t\tconst left = LEFT_NODE( node32Index );\n\t\t\t\tconst right = RIGHT_NODE( node32Index, uint32Array );\n\t\t\t\twalk( callback, left, depth + 1 );\n\t\t\t\twalk( callback, right, depth + 1 );\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.traverseBuffer = callback => {\n\n\t\t\tif ( traversing ) {\n\n\t\t\t\tthrow new Error( 'BVHTraversalHelper: cannot start a traversal during an active traversal.' );\n\n\t\t\t}\n\n\t\t\ttraversing = true;\n\t\t\ttry {\n\n\t\t\t\twalk( callback, 0, 0 );\n\n\t\t\t} finally {\n\n\t\t\t\ttraversing = false;\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.traverse = callback => {\n\n\t\t\tthis.traverseBuffer( ( depth, isLeaf, node32Index ) => {\n\n\t\t\t\tif ( isLeaf ) {\n\n\t\t\t\t\tconst node16Index = node32Index * 2;\n\t\t\t\t\tconst offset = uint32Array[ node32Index + 6 ];\n\t\t\t\t\tconst count = uint16Array[ node16Index + 14 ];\n\t\t\t\t\treturn callback( depth, isLeaf, new Float32Array( buffer, node32Index * 4, 6 ), offset, count );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconst splitAxis = SPLIT_AXIS( node32Index, uint32Array );\n\t\t\t\t\treturn callback( depth, isLeaf, new Float32Array( buffer, node32Index * 4, 6 ), splitAxis );\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t};\n\n\t}\n\n} )();\n","/** @import { Matrix4 } from 'three' */\nimport { Box3 } from 'three';\nimport { BYTES_PER_NODE, UINT32_PER_NODE, DEFAULT_OPTIONS, FLOAT32_EPSILON } from './Constants.js';\nimport { arrayToBox } from '../utils/ArrayBoxUtilities.js';\nimport { IS_LEAF, LEFT_NODE, RIGHT_NODE, COUNT, OFFSET } from './utils/nodeBufferUtils.js';\nimport { buildPackedTree } from './build/buildTree.js';\nimport { shapecast as shapecastFunc } from './cast/shapecast.js';\nimport { bvhcast } from './cast/bvhcast.js';\nimport { BVHTraversalHelper } from './BVHTraversalHelper.js';\n\nconst _tempBox = /* @__PURE__ */ new Box3();\nconst _tempBuffer = /* @__PURE__ */ new Float32Array( 6 );\n\n/**\n * @callback BoundsTraverseOrderCallback\n * @param {Box3} box\n * @returns {number}\n */\n\n/**\n * @callback IntersectsBoundsCallback\n * @param {Box3} box\n * @param {boolean} isLeaf\n * @param {number|undefined} score\n * @param {number} depth\n * @param {number} nodeIndex\n * @returns {number}\n */\n\n/**\n * @callback IntersectsRangeCallback\n * @param {number} offset\n * @param {number} count\n * @param {boolean} contained\n * @param {number} depth\n * @param {number} nodeIndex\n * @param {Box3} box\n * @returns {boolean}\n */\n\n/**\n * @callback IntersectsRangesCallback\n * @param {number} offset1\n * @param {number} count1\n * @param {number} offset2\n * @param {number} count2\n * @param {number} depth1\n * @param {number} nodeIndex1\n * @param {number} depth2\n * @param {number} nodeIndex2\n * @returns {boolean}\n */\n\n/**\n * Abstract base class for BVH implementations. Provides core tree traversal and spatial query\n * methods. Subclasses implement primitive-specific logic by overriding `writePrimitiveBounds`\n * and related internal methods.\n */\nexport class BVH {\n\n\tconstructor() {\n\n\t\tthis._roots = null;\n\t\tthis.primitiveBuffer = null;\n\t\tthis.primitiveBufferStride = null;\n\n\t}\n\n\tinit( options ) {\n\n\t\toptions = {\n\t\t\t...DEFAULT_OPTIONS,\n\t\t\t...options,\n\t\t};\n\n\t\tif ( 'maxLeafSize' in options ) {\n\n\t\t\tconsole.warn( 'BVH: \"maxLeafSize\" option has been deprecated. Use \"targetLeafSize\", instead.' );\n\t\t\toptions = {\n\t\t\t\t...options,\n\t\t\t\ttargetLeafSize: options.maxLeafSize,\n\t\t\t};\n\n\t\t}\n\n\t\tbuildPackedTree( this, options );\n\n\t}\n\n\tgetRootRanges( /* range */ ) {\n\n\t\t// TODO: can we avoid passing range in here?\n\t\tthrow new Error( 'BVH: getRootRanges() not implemented' );\n\n\t}\n\n\t// write the i-th primitive bounds in a 6-value min / max format to the buffer\n\t// starting at the given \"writeOffset\"\n\twritePrimitiveBounds( /* i, buffer, writeOffset */ ) {\n\n\t\tthrow new Error( 'BVH: writePrimitiveBounds() not implemented' );\n\n\t}\n\n\t// writes the union bounds of all primitives in the given range in a min / max format\n\t// to the buffer\n\twritePrimitiveRangeBounds( offset, count, targetBuffer, baseIndex ) {\n\n\t\t// Initialize bounds\n\t\tlet minX = Infinity;\n\t\tlet minY = Infinity;\n\t\tlet minZ = Infinity;\n\t\tlet maxX = - Infinity;\n\t\tlet maxY = - Infinity;\n\t\tlet maxZ = - Infinity;\n\n\t\t// compute union of all bounds\n\t\tfor ( let i = offset, end = offset + count; i < end; i ++ ) {\n\n\t\t\tthis.writePrimitiveBounds( i, _tempBuffer, 0 );\n\n\t\t\t// compute union\n\t\t\tconst [ lx, ly, lz, rx, ry, rz ] = _tempBuffer;\n\t\t\tif ( lx < minX ) minX = lx;\n\t\t\tif ( rx > maxX ) maxX = rx;\n\t\t\tif ( ly < minY ) minY = ly;\n\t\t\tif ( ry > maxY ) maxY = ry;\n\t\t\tif ( lz < minZ ) minZ = lz;\n\t\t\tif ( rz > maxZ ) maxZ = rz;\n\n\t\t}\n\n\t\t// write bounds\n\t\ttargetBuffer[ baseIndex + 0 ] = minX;\n\t\ttargetBuffer[ baseIndex + 1 ] = minY;\n\t\ttargetBuffer[ baseIndex + 2 ] = minZ;\n\t\ttargetBuffer[ baseIndex + 3 ] = maxX;\n\t\ttargetBuffer[ baseIndex + 4 ] = maxY;\n\t\ttargetBuffer[ baseIndex + 5 ] = maxZ;\n\n\t\treturn targetBuffer;\n\n\t}\n\n\tcomputePrimitiveBounds( offset, count, targetBuffer ) {\n\n\t\tconst boundsOffset = targetBuffer.offset || 0;\n\t\tfor ( let i = offset, end = offset + count; i < end; i ++ ) {\n\n\t\t\tthis.writePrimitiveBounds( i, _tempBuffer, 0 );\n\n\t\t\t// construction primitive bounds requires a center + half extents format\n\t\t\tconst [ lx, ly, lz, rx, ry, rz ] = _tempBuffer;\n\n\t\t\tconst cx = ( lx + rx ) / 2;\n\t\t\tconst cy = ( ly + ry ) / 2;\n\t\t\tconst cz = ( lz + rz ) / 2;\n\n\t\t\tconst hx = ( rx - lx ) / 2;\n\t\t\tconst hy = ( ry - ly ) / 2;\n\t\t\tconst hz = ( rz - lz ) / 2;\n\n\t\t\tconst baseIndex = ( i - boundsOffset ) * 6;\n\t\t\ttargetBuffer[ baseIndex + 0 ] = cx;\n\t\t\ttargetBuffer[ baseIndex + 1 ] = hx + ( Math.abs( cx ) + hx ) * FLOAT32_EPSILON;\n\t\t\ttargetBuffer[ baseIndex + 2 ] = cy;\n\t\t\ttargetBuffer[ baseIndex + 3 ] = hy + ( Math.abs( cy ) + hy ) * FLOAT32_EPSILON;\n\t\t\ttargetBuffer[ baseIndex + 4 ] = cz;\n\t\t\ttargetBuffer[ baseIndex + 5 ] = hz + ( Math.abs( cz ) + hz ) * FLOAT32_EPSILON;\n\n\t\t}\n\n\t\treturn targetBuffer;\n\n\t}\n\n\t/**\n\t * Adjusts all primitive offsets stored in the BVH leaf nodes by the given value. Useful when\n\t * geometry buffers have been shifted or compacted (e.g. when merging geometries).\n\t * @param {number} offset\n\t */\n\tshiftPrimitiveOffsets( offset ) {\n\n\t\tconst indirectBuffer = this._indirectBuffer;\n\t\tif ( indirectBuffer ) {\n\n\t\t\t// the offsets are embedded in the indirect buffer\n\t\t\tfor ( let i = 0, l = indirectBuffer.length; i < l; i ++ ) {\n\n\t\t\t\tindirectBuffer[ i ] += offset;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// offsets are embedded in the leaf nodes\n\t\t\tconst roots = this._roots;\n\t\t\tfor ( let rootIndex = 0; rootIndex < roots.length; rootIndex ++ ) {\n\n\t\t\t\tconst root = roots[ rootIndex ];\n\t\t\t\tconst uint32Array = new Uint32Array( root );\n\t\t\t\tconst uint16Array = new Uint16Array( root );\n\t\t\t\tconst totalNodes = root.byteLength / BYTES_PER_NODE;\n\t\t\t\tfor ( let node = 0; node < totalNodes; node ++ ) {\n\n\t\t\t\t\tconst node32Index = UINT32_PER_NODE * node;\n\t\t\t\t\tconst node16Index = 2 * node32Index;\n\t\t\t\t\tif ( IS_LEAF( node16Index, uint16Array ) ) {\n\n\t\t\t\t\t\t// offset value\n\t\t\t\t\t\tuint32Array[ node32Index + 6 ] += offset;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Traverses all nodes of the BVH, invoking a callback for each node.\n\t *\n\t * For leaf nodes the callback receives `( depth, isLeaf, boundingData, offset, count )`.\n\t * For internal nodes it receives `( depth, isLeaf, boundingData, splitAxis )` and may\n\t * return `true` to stop descending into that node's children.\n\t *\n\t * @param {Function} callback\n\t * @param {number} [rootIndex=0]\n\t */\n\ttraverse( callback, rootIndex = 0 ) {\n\n\t\tBVHTraversalHelper.setBVH( this, rootIndex );\n\t\tBVHTraversalHelper.traverse( callback );\n\t\tBVHTraversalHelper.reset();\n\n\t}\n\n\t/**\n\t * Refits all BVH node bounds to reflect the current primitive positions. Faster than\n\t * rebuilding the BVH but produces a less optimal tree after large vertex deformations.\n\t */\n\trefit( /* nodeIndices = null */ ) {\n\n\t\t// TODO: add support for \"nodeIndices\"\n\t\t// if ( nodeIndices && Array.isArray( nodeIndices ) ) {\n\n\t\t// \tnodeIndices = new Set( nodeIndices );\n\n\t\t// }\n\n\t\tconst roots = this._roots;\n\t\tfor ( let rootIndex = 0, rootCount = roots.length; rootIndex < rootCount; rootIndex ++ ) {\n\n\t\t\tconst buffer = roots[ rootIndex ];\n\t\t\tconst uint32Array = new Uint32Array( buffer );\n\t\t\tconst uint16Array = new Uint16Array( buffer );\n\t\t\tconst float32Array = new Float32Array( buffer );\n\t\t\tconst totalNodes = buffer.byteLength / BYTES_PER_NODE;\n\n\t\t\t// Traverse nodes from right to left so children are updated before parents\n\t\t\tfor ( let nodeIndex = totalNodes - 1; nodeIndex >= 0; nodeIndex -- ) {\n\n\t\t\t\tconst nodeIndex32 = nodeIndex * UINT32_PER_NODE;\n\t\t\t\tconst nodeIndex16 = nodeIndex32 * 2;\n\t\t\t\tconst isLeaf = IS_LEAF( nodeIndex16, uint16Array );\n\n\t\t\t\tif ( isLeaf ) {\n\n\t\t\t\t\t// get the bounds\n\t\t\t\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\n\t\t\t\t\tconst count = COUNT( nodeIndex16, uint16Array );\n\t\t\t\t\tthis.writePrimitiveRangeBounds( offset, count, _tempBuffer, 0 );\n\n\t\t\t\t\t// write directly to node bounds (already in min/max format)\n\t\t\t\t\tfloat32Array.set( _tempBuffer, nodeIndex32 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconst left = LEFT_NODE( nodeIndex32 );\n\t\t\t\t\tconst right = RIGHT_NODE( nodeIndex32, uint32Array );\n\n\t\t\t\t\t// Union the bounds of left and right children\n\t\t\t\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\t\t\t\tconst leftMin = float32Array[ left + i ];\n\t\t\t\t\t\tconst leftMax = float32Array[ left + i + 3 ];\n\t\t\t\t\t\tconst rightMin = float32Array[ right + i ];\n\t\t\t\t\t\tconst rightMax = float32Array[ right + i + 3 ];\n\n\t\t\t\t\t\tfloat32Array[ nodeIndex32 + i ] = leftMin < rightMin ? leftMin : rightMin;\n\t\t\t\t\t\tfloat32Array[ nodeIndex32 + i + 3 ] = leftMax > rightMax ? leftMax : rightMax;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Computes the axis-aligned bounding box of all primitives in the BVH.\n\t * @param {Box3} target - Target box to write the result into.\n\t * @returns {Box3}\n\t */\n\tgetBoundingBox( target ) {\n\n\t\ttarget.makeEmpty();\n\n\t\tconst roots = this._roots;\n\t\troots.forEach( buffer => {\n\n\t\t\tarrayToBox( 0, new Float32Array( buffer ), _tempBox );\n\t\t\ttarget.union( _tempBox );\n\n\t\t} );\n\n\t\treturn target;\n\n\t}\n\n\t/**\n\t * A generalized traversal function for performing spatial queries against the BVH. Returns\n\t * `true` as soon as a primitive has been reported as intersected. The tree is traversed\n\t * depth-first; `boundsTraverseOrder` controls which child is visited first. Returning\n\t * `CONTAINED` from `intersectsBounds` skips further child traversal and intersects all\n\t * primitives in that subtree immediately.\n\t *\n\t * @param {Object} callbacks\n\t * @param {IntersectsBoundsCallback} callbacks.intersectsBounds\n\t * @param {IntersectsRangeCallback} [callbacks.intersectsRange]\n\t * @param {BoundsTraverseOrderCallback} [callbacks.boundsTraverseOrder]\n\t * @returns {boolean}\n\t */\n\t// TODO: see if we can get rid of \"iterateFunc\" here as well as the primitive so the function\n\t// API aligns with the \"shapecast\" implementation\n\tshapecast( callbacks ) {\n\n\t\t// TODO: can we get rid of \"scratchPrimitive\" and / or \"iterate\"? Or merge them somehow\n\t\tlet {\n\t\t\tboundsTraverseOrder,\n\t\t\tintersectsBounds,\n\t\t\tintersectsRange,\n\t\t\tintersectsPrimitive,\n\t\t\tscratchPrimitive,\n\t\t\titerate,\n\t\t} = callbacks;\n\n\t\t// wrap the intersectsRange function\n\t\tif ( intersectsRange && intersectsPrimitive ) {\n\n\t\t\tconst originalIntersectsRange = intersectsRange;\n\t\t\tintersectsRange = ( offset, count, contained, depth, nodeIndex ) => {\n\n\t\t\t\tif ( ! originalIntersectsRange( offset, count, contained, depth, nodeIndex ) ) {\n\n\t\t\t\t\treturn iterate( offset, count, this, intersectsPrimitive, contained, depth, scratchPrimitive );\n\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\n\t\t\t};\n\n\t\t} else if ( ! intersectsRange ) {\n\n\t\t\tif ( intersectsPrimitive ) {\n\n\t\t\t\tintersectsRange = ( offset, count, contained, depth ) => {\n\n\t\t\t\t\treturn iterate( offset, count, this, intersectsPrimitive, contained, depth, scratchPrimitive );\n\n\t\t\t\t};\n\n\t\t\t} else {\n\n\t\t\t\tintersectsRange = ( offset, count, contained ) => {\n\n\t\t\t\t\treturn contained;\n\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t}\n\n\t\t// run shapecast\n\t\tlet result = false;\n\t\tlet nodeOffset = 0;\n\t\tconst roots = this._roots;\n\t\tfor ( let i = 0, l = roots.length; i < l; i ++ ) {\n\n\t\t\tconst root = roots[ i ];\n\t\t\tresult = shapecastFunc( this, i, intersectsBounds, intersectsRange, boundsTraverseOrder, nodeOffset );\n\n\t\t\tif ( result ) {\n\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tnodeOffset += root.byteLength / BYTES_PER_NODE;\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n\t/**\n\t * Simultaneously traverses two BVH structures to find intersecting primitive pairs. Returns\n\t * `true` as soon as any intersection is reported. Both trees are traversed depth-first with\n\t * alternating descent. `matrixToLocal` transforms `otherBvh` into the local space of this BVH.\n\t *\n\t * @param {BVH} otherBvh\n\t * @param {Matrix4} matrixToLocal\n\t * @param {Object} callbacks\n\t * @param {IntersectsRangesCallback} callbacks.intersectsRanges\n\t * @returns {boolean}\n\t */\n\tbvhcast( otherBvh, matrixToLocal, callbacks ) {\n\n\t\tlet { intersectsRanges } = callbacks;\n\t\treturn bvhcast( this, otherBvh, matrixToLocal, intersectsRanges );\n\n\n\t}\n\n}\n","export function isSharedArrayBufferSupported() {\n\n\treturn typeof SharedArrayBuffer !== 'undefined';\n\n}\n\nexport function convertToBufferType( array, BufferConstructor ) {\n\n\tif ( array === null ) {\n\n\t\treturn array;\n\n\t} else if ( array.buffer ) {\n\n\t\tconst buffer = array.buffer;\n\t\tif ( buffer.constructor === BufferConstructor ) {\n\n\t\t\treturn array;\n\n\t\t}\n\n\t\tconst ArrayConstructor = array.constructor;\n\t\tconst result = new ArrayConstructor( new BufferConstructor( buffer.byteLength ) );\n\t\tresult.set( array );\n\t\treturn result;\n\n\t} else {\n\n\t\tif ( array.constructor === BufferConstructor ) {\n\n\t\t\treturn array;\n\n\t\t}\n\n\t\tconst result = new BufferConstructor( array.byteLength );\n\t\tnew Uint8Array( result ).set( new Uint8Array( array ) );\n\t\treturn result;\n\n\t}\n\n}\n","import { BufferAttribute } from 'three';\n\nexport function getVertexCount( geo ) {\n\n\treturn geo.index ? geo.index.count : geo.attributes.position.count;\n\n}\n\nexport function getTriCount( geo ) {\n\n\treturn getVertexCount( geo ) / 3;\n\n}\n\nexport function getIndexArray( vertexCount, BufferConstructor = ArrayBuffer ) {\n\n\tif ( vertexCount > 65535 ) {\n\n\t\treturn new Uint32Array( new BufferConstructor( 4 * vertexCount ) );\n\n\t} else {\n\n\t\treturn new Uint16Array( new BufferConstructor( 2 * vertexCount ) );\n\n\t}\n\n}\n\n// ensures that an index is present on the geometry\nexport function ensureIndex( geo, options ) {\n\n\tif ( ! geo.index ) {\n\n\t\tconst vertexCount = geo.attributes.position.count;\n\t\tconst BufferConstructor = options.useSharedArrayBuffer ? SharedArrayBuffer : ArrayBuffer;\n\t\tconst index = getIndexArray( vertexCount, BufferConstructor );\n\t\tgeo.setIndex( new BufferAttribute( index, 1 ) );\n\n\t\tfor ( let i = 0; i < vertexCount; i ++ ) {\n\n\t\t\tindex[ i ] = i;\n\n\t\t}\n\n\t}\n\n}\n\n// Computes the set of { offset, count } ranges which need independent BVH roots. Each\n// region in the geometry index that belongs to a different set of material groups requires\n// a separate BVH root, so that triangles indices belonging to one group never get swapped\n// with triangle indices belongs to another group. For example, if the groups were like this:\n//\n// [-------------------------------------------------------------]\n// |__________________|\n//   g0 = [0, 20]  |______________________||_____________________|\n//                      g1 = [16, 40]           g2 = [41, 60]\n//\n// we would need four BVH roots: [0, 15], [16, 20], [21, 40], [41, 60].\nfunction getFullPrimitiveRange( geo, range, stride ) {\n\n\tconst primitiveCount = getVertexCount( geo ) / stride;\n\tconst drawRange = range ? range : geo.drawRange;\n\tconst start = drawRange.start / stride;\n\tconst end = ( drawRange.start + drawRange.count ) / stride;\n\n\tconst offset = Math.max( 0, start );\n\tconst count = Math.min( primitiveCount, end ) - offset;\n\treturn {\n\t\toffset: Math.floor( offset ),\n\t\tcount: Math.floor( count ),\n\t};\n\n}\n\nfunction getPrimitiveGroupRanges( geo, stride ) {\n\n\treturn geo.groups.map( group => ( {\n\t\toffset: group.start / stride,\n\t\tcount: group.count / stride,\n\t} ));\n\n}\n\n// Function that extracts a set of mutually exclusive ranges representing the primitives being\n// drawn as determined by the geometry groups, draw range, and user specified range\nexport function getRootPrimitiveRanges( geo, range, stride ) {\n\n\tconst drawRange = getFullPrimitiveRange( geo, range, stride );\n\tconst primitiveRanges = getPrimitiveGroupRanges( geo, stride );\n\tif ( ! primitiveRanges.length ) {\n\n\t\treturn [ drawRange ];\n\n\t}\n\n\tconst ranges = [];\n\tconst drawRangeStart = drawRange.offset;\n\tconst drawRangeEnd = drawRange.offset + drawRange.count;\n\n\t// Create events for group boundaries\n\tconst primitiveCount = getVertexCount( geo ) / stride;\n\tconst events = [];\n\tfor ( const group of primitiveRanges ) {\n\n\t\t// Account for cases where group size is set to Infinity\n\t\tconst { offset, count } = group;\n\t\tconst groupStart = offset;\n\t\tconst groupCount = isFinite( count ) ? count : ( primitiveCount - offset );\n\t\tconst groupEnd = ( offset + groupCount );\n\n\t\t// Only add events if the group intersects with the draw range\n\t\tif ( groupStart < drawRangeEnd && groupEnd > drawRangeStart ) {\n\n\t\t\tevents.push( { pos: Math.max( drawRangeStart, groupStart ), isStart: true } );\n\t\t\tevents.push( { pos: Math.min( drawRangeEnd, groupEnd ), isStart: false } );\n\n\t\t}\n\n\t}\n\n\t// Sort events by position, with 'end' events before 'start' events at the same position\n\tevents.sort( ( a, b ) => {\n\n\t\tif ( a.pos !== b.pos ) {\n\n\t\t\treturn a.pos - b.pos;\n\n\t\t} else {\n\n\t\t\treturn a.type === 'end' ? - 1 : 1;\n\n\t\t}\n\n\t} );\n\n\t// sweep through events and create ranges where activeGroups > 0\n\tlet activeGroups = 0;\n\tlet lastPos = null;\n\tfor ( const event of events ) {\n\n\t\tconst newPos = event.pos;\n\t\tif ( activeGroups !== 0 && newPos !== lastPos ) {\n\n\t\t\tranges.push( {\n\t\t\t\toffset: lastPos,\n\t\t\t\tcount: newPos - lastPos,\n\t\t\t} );\n\n\t\t}\n\n\t\tactiveGroups += event.isStart ? 1 : - 1;\n\t\tlastPos = newPos;\n\n\t}\n\n\treturn ranges;\n\n}\n","/** @import { BufferGeometry } from 'three' */\nimport { Box3 } from 'three';\nimport { SKIP_GENERATION, DEFAULT_OPTIONS } from './Constants.js';\nimport { isSharedArrayBufferSupported } from '../utils/BufferUtils.js';\nimport { ensureIndex, getRootPrimitiveRanges } from './build/geometryUtils.js';\nimport { BVH } from './BVH.js';\n\n// construct a new buffer that points to the set of triangles represented by the given ranges\nexport function generateIndirectBuffer( ranges, useSharedArrayBuffer ) {\n\n\tconst lastRange = ranges[ ranges.length - 1 ];\n\tconst useUint32 = lastRange.offset + lastRange.count > 2 ** 16;\n\n\t// use getRootIndexRanges which excludes gaps\n\tconst length = ranges.reduce( ( acc, val ) => acc + val.count, 0 );\n\tconst byteCount = useUint32 ? 4 : 2;\n\tconst buffer = useSharedArrayBuffer ? new SharedArrayBuffer( length * byteCount ) : new ArrayBuffer( length * byteCount );\n\tconst indirectBuffer = useUint32 ? new Uint32Array( buffer ) : new Uint16Array( buffer );\n\n\t// construct a compact form of the triangles in these ranges\n\tlet index = 0;\n\tfor ( let r = 0; r < ranges.length; r ++ ) {\n\n\t\tconst { offset, count } = ranges[ r ];\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\tindirectBuffer[ index + i ] = offset + i;\n\n\t\t}\n\n\t\tindex += count;\n\n\t}\n\n\treturn indirectBuffer;\n\n}\n\n/**\n * Abstract base class for geometry-backed BVH implementations. Handles geometry\n * indexing, indirect mode, and bounding box initialization. Subclasses implement\n * primitive-specific bounds computation and raycasting via `writePrimitiveBounds`\n * and `raycastObject3D`.\n *\n * @param {BufferGeometry} geometry\n * @param {Object} [options]\n * @param {number} [options.strategy=CENTER] - Split strategy: `CENTER`, `AVERAGE`, or `SAH`.\n * @param {number} [options.maxDepth=40] - Maximum tree depth. Note that this can cause the target leaf size to not\n * be met if the tree is truncated.\n * @param {number} [options.targetLeafSize=10] - The target number of primitives per leaf node. Note that this is\n * a soft limit and generation strategies like SAH will terminate early if the heuristic determines.\n * @param {boolean} [options.setBoundingBox=true] - Set `geometry.boundingBox` if not already present.\n * @param {boolean} [options.useSharedArrayBuffer=false] - Use `SharedArrayBuffer` for BVH root buffers.\n * @param {boolean} [options.indirect=false] - Build using an indirect buffer, leaving the original index unmodified.\n * @param {boolean} [options.verbose=true] - Log build progress to the console.\n * @param {Function|null} [options.onProgress=null] - Called with a progress value in [0, 1] during build.\n * @param {Object|null} [options.range=null] - Restrict the BVH to a specific geometry group range.\n * @extends BVH\n */\nexport class GeometryBVH extends BVH {\n\n\t/**\n\t * Whether the BVH was built in indirect mode.\n\t * @type {boolean}\n\t * @readonly\n\t */\n\tget indirect() {\n\n\t\treturn ! ! this._indirectBuffer;\n\n\t}\n\n\tget primitiveStride() {\n\n\t\treturn null;\n\n\t}\n\n\tget primitiveBufferStride() {\n\n\t\treturn this.indirect ? 1 : this.primitiveStride;\n\n\t}\n\tset primitiveBufferStride( v ) {}\n\n\tget primitiveBuffer() {\n\n\t\treturn this.indirect ? this._indirectBuffer : this.geometry.index.array;\n\n\t}\n\tset primitiveBuffer( v ) {}\n\n\tconstructor( geometry, options = {} ) {\n\n\t\tif ( ! geometry.isBufferGeometry ) {\n\n\t\t\tthrow new Error( 'BVH: Only BufferGeometries are supported.' );\n\n\t\t} else if ( geometry.index && geometry.index.isInterleavedBufferAttribute ) {\n\n\t\t\tthrow new Error( 'BVH: InterleavedBufferAttribute is not supported for the index attribute.' );\n\n\t\t}\n\n\t\tif ( options.useSharedArrayBuffer && ! isSharedArrayBufferSupported() ) {\n\n\t\t\tthrow new Error( 'BVH: SharedArrayBuffer is not available.' );\n\n\t\t}\n\n\t\tsuper();\n\n\t\t// retain references to the geometry so we can use them it without having to\n\t\t// take a geometry reference in every function.\n\n\t\t/**\n\t\t * The geometry this BVH was built from.\n\t\t * @type {BufferGeometry}\n\t\t * @readonly\n\t\t */\n\t\tthis.geometry = geometry;\n\t\tthis.resolvePrimitiveIndex = options.indirect ? i => this._indirectBuffer[ i ] : i => i;\n\t\tthis.primitiveBuffer = null;\n\t\tthis.primitiveBufferStride = null;\n\t\tthis._indirectBuffer = null;\n\n\t\toptions = {\n\t\t\t...DEFAULT_OPTIONS,\n\t\t\t...options,\n\t\t};\n\n\t\t// build the BVH unless we're deserializing\n\t\tif ( ! options[ SKIP_GENERATION ] ) {\n\n\t\t\tthis.init( options );\n\n\t\t}\n\n\t}\n\n\tinit( options ) {\n\n\t\tconst { geometry, primitiveStride } = this;\n\n\t\tif ( options.indirect ) {\n\n\t\t\t// construct an buffer that is indirectly sorts the triangles used for the BVH\n\t\t\tconst ranges = getRootPrimitiveRanges( geometry, options.range, primitiveStride );\n\t\t\tconst indirectBuffer = generateIndirectBuffer( ranges, options.useSharedArrayBuffer );\n\t\t\tthis._indirectBuffer = indirectBuffer;\n\n\t\t} else {\n\n\t\t\tensureIndex( geometry, options );\n\n\t\t}\n\n\t\tsuper.init( options );\n\n\t\tif ( ! geometry.boundingBox && options.setBoundingBox ) {\n\n\t\t\tgeometry.boundingBox = this.getBoundingBox( new Box3() );\n\n\t\t}\n\n\t}\n\n\t// Abstract methods to be implemented by subclasses\n\tgetRootRanges( range ) {\n\n\t\t// TODO: can we avoid passing options in here\n\t\tif ( this.indirect ) {\n\n\t\t\treturn [ { offset: 0, count: this._indirectBuffer.length } ];\n\n\n\t\t} else {\n\n\t\t\treturn getRootPrimitiveRanges( this.geometry, range, this.primitiveStride );\n\n\t\t}\n\n\t}\n\n\traycastObject3D( /* object, raycaster, intersects = [] */ ) {\n\n\t\tthrow new Error( 'BVH: raycastObject3D() not implemented' );\n\n\t}\n\n}\n","import { Vector3 } from 'three';\n\nexport class SeparatingAxisBounds {\n\n\tconstructor() {\n\n\t\tthis.min = Infinity;\n\t\tthis.max = - Infinity;\n\n\t}\n\n\tsetFromPointsField( points, field ) {\n\n\t\tlet min = Infinity;\n\t\tlet max = - Infinity;\n\t\tfor ( let i = 0, l = points.length; i < l; i ++ ) {\n\n\t\t\tconst p = points[ i ];\n\t\t\tconst val = p[ field ];\n\t\t\tmin = val < min ? val : min;\n\t\t\tmax = val > max ? val : max;\n\n\t\t}\n\n\t\tthis.min = min;\n\t\tthis.max = max;\n\n\t}\n\n\tsetFromPoints( axis, points ) {\n\n\t\tlet min = Infinity;\n\t\tlet max = - Infinity;\n\t\tfor ( let i = 0, l = points.length; i < l; i ++ ) {\n\n\t\t\tconst p = points[ i ];\n\t\t\tconst val = axis.dot( p );\n\t\t\tmin = val < min ? val : min;\n\t\t\tmax = val > max ? val : max;\n\n\t\t}\n\n\t\tthis.min = min;\n\t\tthis.max = max;\n\n\t}\n\n\tisSeparated( other ) {\n\n\t\treturn this.min > other.max || other.min > this.max;\n\n\t}\n\n}\n\nSeparatingAxisBounds.prototype.setFromBox = ( function () {\n\n\tconst p = /* @__PURE__ */ new Vector3();\n\treturn function setFromBox( axis, box ) {\n\n\t\tconst boxMin = box.min;\n\t\tconst boxMax = box.max;\n\t\tlet min = Infinity;\n\t\tlet max = - Infinity;\n\t\tfor ( let x = 0; x <= 1; x ++ ) {\n\n\t\t\tfor ( let y = 0; y <= 1; y ++ ) {\n\n\t\t\t\tfor ( let z = 0; z <= 1; z ++ ) {\n\n\t\t\t\t\tp.x = boxMin.x * x + boxMax.x * ( 1 - x );\n\t\t\t\t\tp.y = boxMin.y * y + boxMax.y * ( 1 - y );\n\t\t\t\t\tp.z = boxMin.z * z + boxMax.z * ( 1 - z );\n\n\t\t\t\t\tconst val = axis.dot( p );\n\t\t\t\t\tmin = Math.min( val, min );\n\t\t\t\t\tmax = Math.max( val, max );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.min = min;\n\t\tthis.max = max;\n\n\t};\n\n} )();\n\nexport const areIntersecting = ( function () {\n\n\tconst cacheSatBounds = /* @__PURE__ */ new SeparatingAxisBounds();\n\treturn function areIntersecting( shape1, shape2 ) {\n\n\t\tconst points1 = shape1.points;\n\t\tconst satAxes1 = shape1.satAxes;\n\t\tconst satBounds1 = shape1.satBounds;\n\n\t\tconst points2 = shape2.points;\n\t\tconst satAxes2 = shape2.satAxes;\n\t\tconst satBounds2 = shape2.satBounds;\n\n\t\t// check axes of the first shape\n\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\tconst sb = satBounds1[ i ];\n\t\t\tconst sa = satAxes1[ i ];\n\t\t\tcacheSatBounds.setFromPoints( sa, points2 );\n\t\t\tif ( sb.isSeparated( cacheSatBounds ) ) return false;\n\n\t\t}\n\n\t\t// check axes of the second shape\n\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\tconst sb = satBounds2[ i ];\n\t\t\tconst sa = satAxes2[ i ];\n\t\t\tcacheSatBounds.setFromPoints( sa, points1 );\n\t\t\tif ( sb.isSeparated( cacheSatBounds ) ) return false;\n\n\t\t}\n\n\t};\n\n} )();\n","import { Vector3, Vector2, Plane, Line3 } from 'three';\n\nexport const closestPointLineToLine = ( function () {\n\n\t// https://github.com/juj/MathGeoLib/blob/master/src/Geometry/Line.cpp#L56\n\tconst dir1 = /* @__PURE__ */ new Vector3();\n\tconst dir2 = /* @__PURE__ */ new Vector3();\n\tconst v02 = /* @__PURE__ */ new Vector3();\n\treturn function closestPointLineToLine( l1, l2, result ) {\n\n\t\tconst v0 = l1.start;\n\t\tconst v10 = dir1;\n\t\tconst v2 = l2.start;\n\t\tconst v32 = dir2;\n\n\t\tv02.subVectors( v0, v2 );\n\t\tdir1.subVectors( l1.end, l1.start );\n\t\tdir2.subVectors( l2.end, l2.start );\n\n\t\t// float d0232 = v02.Dot(v32);\n\t\tconst d0232 = v02.dot( v32 );\n\n\t\t// float d3210 = v32.Dot(v10);\n\t\tconst d3210 = v32.dot( v10 );\n\n\t\t// float d3232 = v32.Dot(v32);\n\t\tconst d3232 = v32.dot( v32 );\n\n\t\t// float d0210 = v02.Dot(v10);\n\t\tconst d0210 = v02.dot( v10 );\n\n\t\t// float d1010 = v10.Dot(v10);\n\t\tconst d1010 = v10.dot( v10 );\n\n\t\t// float denom = d1010*d3232 - d3210*d3210;\n\t\tconst denom = d1010 * d3232 - d3210 * d3210;\n\n\t\tlet d, d2;\n\t\tif ( denom !== 0 ) {\n\n\t\t\td = ( d0232 * d3210 - d0210 * d3232 ) / denom;\n\n\t\t} else {\n\n\t\t\td = 0;\n\n\t\t}\n\n\t\td2 = ( d0232 + d * d3210 ) / d3232;\n\n\t\tresult.x = d;\n\t\tresult.y = d2;\n\n\t};\n\n} )();\n\nexport const closestPointsSegmentToSegment = ( function () {\n\n\t// https://github.com/juj/MathGeoLib/blob/master/src/Geometry/LineSegment.cpp#L187\n\tconst paramResult = /* @__PURE__ */ new Vector2();\n\tconst temp1 = /* @__PURE__ */ new Vector3();\n\tconst temp2 = /* @__PURE__ */ new Vector3();\n\treturn function closestPointsSegmentToSegment( l1, l2, target1, target2 ) {\n\n\t\tclosestPointLineToLine( l1, l2, paramResult );\n\n\t\tlet d = paramResult.x;\n\t\tlet d2 = paramResult.y;\n\t\tif ( d >= 0 && d <= 1 && d2 >= 0 && d2 <= 1 ) {\n\n\t\t\tl1.at( d, target1 );\n\t\t\tl2.at( d2, target2 );\n\n\t\t\treturn;\n\n\t\t} else if ( d >= 0 && d <= 1 ) {\n\n\t\t\t// Only d2 is out of bounds.\n\t\t\tif ( d2 < 0 ) {\n\n\t\t\t\tl2.at( 0, target2 );\n\n\t\t\t} else {\n\n\t\t\t\tl2.at( 1, target2 );\n\n\t\t\t}\n\n\t\t\tl1.closestPointToPoint( target2, true, target1 );\n\t\t\treturn;\n\n\t\t} else if ( d2 >= 0 && d2 <= 1 ) {\n\n\t\t\t// Only d is out of bounds.\n\t\t\tif ( d < 0 ) {\n\n\t\t\t\tl1.at( 0, target1 );\n\n\t\t\t} else {\n\n\t\t\t\tl1.at( 1, target1 );\n\n\t\t\t}\n\n\t\t\tl2.closestPointToPoint( target1, true, target2 );\n\t\t\treturn;\n\n\t\t} else {\n\n\t\t\t// Both u and u2 are out of bounds.\n\t\t\tlet p;\n\t\t\tif ( d < 0 ) {\n\n\t\t\t\tp = l1.start;\n\n\t\t\t} else {\n\n\t\t\t\tp = l1.end;\n\n\t\t\t}\n\n\t\t\tlet p2;\n\t\t\tif ( d2 < 0 ) {\n\n\t\t\t\tp2 = l2.start;\n\n\t\t\t} else {\n\n\t\t\t\tp2 = l2.end;\n\n\t\t\t}\n\n\t\t\tconst closestPoint = temp1;\n\t\t\tconst closestPoint2 = temp2;\n\t\t\tl1.closestPointToPoint( p2, true, temp1 );\n\t\t\tl2.closestPointToPoint( p, true, temp2 );\n\n\t\t\tif ( closestPoint.distanceToSquared( p2 ) <= closestPoint2.distanceToSquared( p ) ) {\n\n\t\t\t\ttarget1.copy( closestPoint );\n\t\t\t\ttarget2.copy( p2 );\n\t\t\t\treturn;\n\n\t\t\t} else {\n\n\t\t\t\ttarget1.copy( p );\n\t\t\t\ttarget2.copy( closestPoint2 );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t}\n\n\t};\n\n} )();\n\n\nexport const sphereIntersectTriangle = ( function () {\n\n\t// https://stackoverflow.com/questions/34043955/detect-collision-between-sphere-and-triangle-in-three-js\n\tconst closestPointTemp = /* @__PURE__ */ new Vector3();\n\tconst projectedPointTemp = /* @__PURE__ */ new Vector3();\n\tconst planeTemp = /* @__PURE__ */ new Plane();\n\tconst lineTemp = /* @__PURE__ */ new Line3();\n\treturn function sphereIntersectTriangle( sphere, triangle ) {\n\n\t\tconst { radius, center } = sphere;\n\t\tconst { a, b, c } = triangle;\n\n\t\t// phase 1\n\t\tlineTemp.start = a;\n\t\tlineTemp.end = b;\n\t\tconst closestPoint1 = lineTemp.closestPointToPoint( center, true, closestPointTemp );\n\t\tif ( closestPoint1.distanceTo( center ) <= radius ) return true;\n\n\t\tlineTemp.start = a;\n\t\tlineTemp.end = c;\n\t\tconst closestPoint2 = lineTemp.closestPointToPoint( center, true, closestPointTemp );\n\t\tif ( closestPoint2.distanceTo( center ) <= radius ) return true;\n\n\t\tlineTemp.start = b;\n\t\tlineTemp.end = c;\n\t\tconst closestPoint3 = lineTemp.closestPointToPoint( center, true, closestPointTemp );\n\t\tif ( closestPoint3.distanceTo( center ) <= radius ) return true;\n\n\t\t// phase 2\n\t\tconst plane = triangle.getPlane( planeTemp );\n\t\tconst dp = Math.abs( plane.distanceToPoint( center ) );\n\t\tif ( dp <= radius ) {\n\n\t\t\tconst pp = plane.projectPoint( center, projectedPointTemp );\n\t\t\tconst cp = triangle.containsPoint( pp );\n\t\t\tif ( cp ) return true;\n\n\t\t}\n\n\t\treturn false;\n\n\t};\n\n} )();\n","/** @import { Sphere } from 'three' */\nimport { Triangle, Vector3, Vector2, Line3, Plane } from 'three';\nimport { SeparatingAxisBounds } from './SeparatingAxisBounds.js';\nimport { closestPointsSegmentToSegment, sphereIntersectTriangle } from './MathUtilities.js';\n\nconst componentKeys = [ 'x', 'y', 'z' ];\nconst ZERO_EPSILON = 1e-15;\nconst ZERO_EPSILON_SQR = ZERO_EPSILON * ZERO_EPSILON;\nfunction isNearZero( value ) {\n\n\treturn Math.abs( value ) < ZERO_EPSILON;\n\n}\n\n/**\n * An extended version of three.js' Triangle class. A variety of derivative values are cached on\n * the object to accelerate the intersection functions. `.needsUpdate` must be set to true when\n * modifying the triangle parameters.\n * @extends Triangle\n */\nexport class ExtendedTriangle extends Triangle {\n\n\tconstructor( ...args ) {\n\n\t\tsuper( ...args );\n\n\t\tthis.isExtendedTriangle = true;\n\t\tthis.satAxes = new Array( 4 ).fill().map( () => new Vector3() );\n\t\tthis.satBounds = new Array( 4 ).fill().map( () => new SeparatingAxisBounds() );\n\t\tthis.points = [ this.a, this.b, this.c ];\n\t\tthis.plane = new Plane();\n\t\tthis.isDegenerateIntoSegment = false;\n\t\tthis.isDegenerateIntoPoint = false;\n\t\tthis.degenerateSegment = new Line3();\n\n\t\t/**\n\t\t * Indicates that the triangle fields have changed so cached variables to accelerate other\n\t\t * function execution can be updated. Must be set to true after modifying the triangle\n\t\t * `a`, `b`, `c` fields.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis.needsUpdate = true;\n\n\t}\n\n\t/**\n\t * Returns whether the triangle intersects the given sphere.\n\t * @param {Sphere} sphere\n\t * @returns {boolean}\n\t */\n\tintersectsSphere( sphere ) {\n\n\t\treturn sphereIntersectTriangle( sphere, this );\n\n\t}\n\n\tupdate() {\n\n\t\tconst a = this.a;\n\t\tconst b = this.b;\n\t\tconst c = this.c;\n\t\tconst points = this.points;\n\n\t\tconst satAxes = this.satAxes;\n\t\tconst satBounds = this.satBounds;\n\n\t\tconst axis0 = satAxes[ 0 ];\n\t\tconst sab0 = satBounds[ 0 ];\n\t\tthis.getNormal( axis0 );\n\t\tsab0.setFromPoints( axis0, points );\n\n\t\tconst axis1 = satAxes[ 1 ];\n\t\tconst sab1 = satBounds[ 1 ];\n\t\taxis1.subVectors( a, b );\n\t\tsab1.setFromPoints( axis1, points );\n\n\t\tconst axis2 = satAxes[ 2 ];\n\t\tconst sab2 = satBounds[ 2 ];\n\t\taxis2.subVectors( b, c );\n\t\tsab2.setFromPoints( axis2, points );\n\n\t\tconst axis3 = satAxes[ 3 ];\n\t\tconst sab3 = satBounds[ 3 ];\n\t\taxis3.subVectors( c, a );\n\t\tsab3.setFromPoints( axis3, points );\n\n\t\tconst lengthAB = axis1.length();\n\t\tconst lengthBC = axis2.length();\n\t\tconst lengthCA = axis3.length();\n\n\t\tthis.isDegenerateIntoPoint = false;\n\t\tthis.isDegenerateIntoSegment = false;\n\n\t\tif ( lengthAB < ZERO_EPSILON ) {\n\n\t\t\tif ( lengthBC < ZERO_EPSILON || lengthCA < ZERO_EPSILON ) {\n\n\t\t\t\tthis.isDegenerateIntoPoint = true;\n\n\t\t\t} else {\n\n\t\t\t\tthis.isDegenerateIntoSegment = true;\n\t\t\t\tthis.degenerateSegment.start.copy( a );\n\t\t\t\tthis.degenerateSegment.end.copy( c );\n\n\t\t\t}\n\n\t\t} else if ( lengthBC < ZERO_EPSILON ) {\n\n\t\t\tif ( lengthCA < ZERO_EPSILON ) {\n\n\t\t\t\tthis.isDegenerateIntoPoint = true;\n\n\t\t\t} else {\n\n\t\t\t\tthis.isDegenerateIntoSegment = true;\n\t\t\t\tthis.degenerateSegment.start.copy( b );\n\t\t\t\tthis.degenerateSegment.end.copy( a );\n\n\t\t\t}\n\n\t\t} else if ( lengthCA < ZERO_EPSILON ) {\n\n\t\t\tthis.isDegenerateIntoSegment = true;\n\t\t\tthis.degenerateSegment.start.copy( c );\n\t\t\tthis.degenerateSegment.end.copy( b );\n\n\t\t}\n\n\t\tthis.plane.setFromNormalAndCoplanarPoint( axis0, a );\n\n\t\tthis.needsUpdate = false;\n\n\t}\n\n}\n\n/**\n * Returns the distance to the provided line segment. `target1` and `target2` are set to the\n * closest points on the triangle and segment respectively.\n * @function\n * @param {Line3} segment\n * @param {Vector3} [target1]\n * @param {Vector3} [target2]\n * @returns {number}\n */\nExtendedTriangle.prototype.closestPointToSegment = ( function () {\n\n\tconst point1 = /* @__PURE__ */ new Vector3();\n\tconst point2 = /* @__PURE__ */ new Vector3();\n\tconst edge = /* @__PURE__ */ new Line3();\n\n\treturn function distanceToSegment( segment, target1 = null, target2 = null ) {\n\n\t\tif ( this.needsUpdate ) {\n\n\t\t\tthis.update();\n\n\t\t}\n\n\t\tconst { start, end } = segment;\n\t\tconst points = this.points;\n\t\tlet distSq;\n\t\tlet closestDistanceSq = Infinity;\n\n\t\tconst startDist = this.plane.distanceToPoint( start );\n\t\tconst endDist = this.plane.distanceToPoint( end );\n\t\tif (\n\t\t\tstartDist * endDist < 0 &&\n\t\t\tthis.plane.intersectLine( segment, point1 ) !== null &&\n\t\t\tthis.containsPoint( point1 )\n\t\t) {\n\n\t\t\tif ( target1 ) target1.copy( point1 );\n\t\t\tif ( target2 ) target2.copy( point1 );\n\t\t\treturn 0;\n\n\t\t}\n\n\t\t// check the triangle edges\n\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\tconst nexti = ( i + 1 ) % 3;\n\t\t\tedge.start.copy( points[ i ] );\n\t\t\tedge.end.copy( points[ nexti ] );\n\n\t\t\tclosestPointsSegmentToSegment( edge, segment, point1, point2 );\n\n\t\t\tdistSq = point1.distanceToSquared( point2 );\n\t\t\tif ( distSq < closestDistanceSq ) {\n\n\t\t\t\tclosestDistanceSq = distSq;\n\t\t\t\tif ( target1 ) target1.copy( point1 );\n\t\t\t\tif ( target2 ) target2.copy( point2 );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// check end points\n\t\tthis.closestPointToPoint( start, point1 );\n\t\tdistSq = start.distanceToSquared( point1 );\n\t\tif ( distSq < closestDistanceSq ) {\n\n\t\t\tclosestDistanceSq = distSq;\n\t\t\tif ( target1 ) target1.copy( point1 );\n\t\t\tif ( target2 ) target2.copy( start );\n\n\t\t}\n\n\t\tthis.closestPointToPoint( end, point1 );\n\t\tdistSq = end.distanceToSquared( point1 );\n\t\tif ( distSq < closestDistanceSq ) {\n\n\t\t\tclosestDistanceSq = distSq;\n\t\t\tif ( target1 ) target1.copy( point1 );\n\t\t\tif ( target2 ) target2.copy( end );\n\n\t\t}\n\n\t\treturn Math.sqrt( closestDistanceSq );\n\n\t};\n\n} )();\n\n/**\n * Returns whether the triangles intersect. `target` is set to the line segment representing\n * the intersection.\n * @function\n * @param {Triangle} other\n * @param {Line3} [target]\n * @param {boolean} [suppressLog=false]\n * @returns {boolean}\n */\nExtendedTriangle.prototype.intersectsTriangle = ( function () {\n\n\tconst saTri2 = /* @__PURE__ */ new ExtendedTriangle();\n\tconst cachedSatBounds = /* @__PURE__ */ new SeparatingAxisBounds();\n\tconst cachedSatBounds2 = /* @__PURE__ */ new SeparatingAxisBounds();\n\tconst tmpVec = /* @__PURE__ */ new Vector3();\n\tconst dir1 = /* @__PURE__ */ new Vector3();\n\tconst dir2 = /* @__PURE__ */ new Vector3();\n\tconst tempDir = /* @__PURE__ */ new Vector3();\n\tconst edge1 = /* @__PURE__ */ new Line3();\n\tconst edge2 = /* @__PURE__ */ new Line3();\n\tconst tempPoint = /* @__PURE__ */ new Vector3();\n\tconst bounds1 = /* @__PURE__ */ new Vector2();\n\tconst bounds2 = /* @__PURE__ */ new Vector2();\n\n\tfunction coplanarIntersectsTriangle( self, other, target, suppressLog ) {\n\n\t\t// Perform separating axis intersection test only for coplanar triangles\n\t\t// There should be at least one non-degenerate triangle when calling this\n\t\t// Otherwise we won't know the plane normal\n\t\tconst planeNormal = tmpVec;\n\t\tif ( ! self.isDegenerateIntoPoint && ! self.isDegenerateIntoSegment ) {\n\n\t\t\tplaneNormal.copy( self.plane.normal );\n\n\t\t} else {\n\n\t\t\tplaneNormal.copy( other.plane.normal );\n\n\t\t}\n\n\t\tconst satBounds1 = self.satBounds;\n\t\tconst satAxes1 = self.satAxes;\n\t\tfor ( let i = 1; i < 4; i ++ ) {\n\n\t\t\tconst sb = satBounds1[ i ];\n\t\t\tconst sa = satAxes1[ i ];\n\t\t\tcachedSatBounds.setFromPoints( sa, other.points );\n\t\t\tif ( sb.isSeparated( cachedSatBounds ) ) return false;\n\n\t\t\ttempDir.copy( planeNormal ).cross( sa );\n\t\t\tcachedSatBounds.setFromPoints( tempDir, self.points );\n\t\t\tcachedSatBounds2.setFromPoints( tempDir, other.points );\n\t\t\tif ( cachedSatBounds.isSeparated( cachedSatBounds2 ) ) return false;\n\n\t\t}\n\n\t\tconst satBounds2 = other.satBounds;\n\t\tconst satAxes2 = other.satAxes;\n\t\tfor ( let i = 1; i < 4; i ++ ) {\n\n\t\t\tconst sb = satBounds2[ i ];\n\t\t\tconst sa = satAxes2[ i ];\n\t\t\tcachedSatBounds.setFromPoints( sa, self.points );\n\t\t\tif ( sb.isSeparated( cachedSatBounds ) ) return false;\n\n\t\t\ttempDir.crossVectors( planeNormal, sa );\n\t\t\tcachedSatBounds.setFromPoints( tempDir, self.points );\n\t\t\tcachedSatBounds2.setFromPoints( tempDir, other.points );\n\t\t\tif ( cachedSatBounds.isSeparated( cachedSatBounds2 ) ) return false;\n\n\t\t}\n\n\t\tif ( target ) {\n\n\t\t\t// TODO find two points that intersect on the edges and make that the result\n\t\t\tif ( ! suppressLog ) {\n\n\t\t\t\tconsole.warn( 'ExtendedTriangle.intersectsTriangle: Triangles are coplanar which does not support an output edge. Setting edge to 0, 0, 0.' );\n\n\t\t\t}\n\n\t\t\ttarget.start.set( 0, 0, 0 );\n\t\t\ttarget.end.set( 0, 0, 0 );\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tfunction findSingleBounds( a, b, c, aProj, bProj, cProj, aDist, bDist, cDist, bounds, edge ) {\n\n\t\tlet t = aDist / ( aDist - bDist );\n\t\tbounds.x = aProj + ( bProj - aProj ) * t;\n\t\tedge.start.subVectors( b, a ).multiplyScalar( t ).add( a );\n\n\t\tt = aDist / ( aDist - cDist );\n\t\tbounds.y = aProj + ( cProj - aProj ) * t;\n\t\tedge.end.subVectors( c, a ).multiplyScalar( t ).add( a );\n\n\t}\n\n\t/**\n\t * Calculates intersection segment of a triangle with intersection line.\n\t * Intersection line is snapped to its biggest component.\n\t * And triangle points are passed as a projection on that component.\n\t * @returns {boolean} whether this is a coplanar case or not\n\t */\n\tfunction findIntersectionLineBounds( self, aProj, bProj, cProj, abDist, acDist, aDist, bDist, cDist, bounds, edge ) {\n\n\t\tif ( abDist > 0 ) {\n\n\t\t\t// then bcDist < 0\n\t\t\tfindSingleBounds( self.c, self.a, self.b, cProj, aProj, bProj, cDist, aDist, bDist, bounds, edge );\n\n\t\t} else if ( acDist > 0 ) {\n\n\t\t\tfindSingleBounds( self.b, self.a, self.c, bProj, aProj, cProj, bDist, aDist, cDist, bounds, edge );\n\n\t\t} else if ( bDist * cDist > 0 || aDist != 0 ) {\n\n\t\t\tfindSingleBounds( self.a, self.b, self.c, aProj, bProj, cProj, aDist, bDist, cDist, bounds, edge );\n\n\t\t} else if ( bDist != 0 ) {\n\n\t\t\tfindSingleBounds( self.b, self.a, self.c, bProj, aProj, cProj, bDist, aDist, cDist, bounds, edge );\n\n\t\t} else if ( cDist != 0 ) {\n\n\t\t\tfindSingleBounds( self.c, self.a, self.b, cProj, aProj, bProj, cDist, aDist, bDist, bounds, edge );\n\n\t\t} else {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t\treturn false;\n\n\t}\n\n\tfunction intersectTriangleSegment( triangle, degenerateTriangle, target, suppressLog ) {\n\n\t\tconst segment = degenerateTriangle.degenerateSegment;\n\t\tconst startDist = triangle.plane.distanceToPoint( segment.start );\n\t\tconst endDist = triangle.plane.distanceToPoint( segment.end );\n\t\tif ( isNearZero( startDist ) ) {\n\n\t\t\tif ( isNearZero( endDist ) ) {\n\n\t\t\t\treturn coplanarIntersectsTriangle( triangle, degenerateTriangle, target, suppressLog );\n\n\t\t\t} else {\n\n\t\t\t\t// Is this fine to modify target even if there might be no intersection?\n\t\t\t\tif ( target ) {\n\n\t\t\t\t\ttarget.start.copy( segment.start );\n\t\t\t\t\ttarget.end.copy( segment.start );\n\n\t\t\t\t}\n\n\t\t\t\treturn triangle.containsPoint( segment.start );\n\n\t\t\t}\n\n\t\t} else if ( isNearZero( endDist ) ) {\n\n\t\t\tif ( target ) {\n\n\t\t\t\ttarget.start.copy( segment.end );\n\t\t\t\ttarget.end.copy( segment.end );\n\n\t\t\t}\n\n\t\t\treturn triangle.containsPoint( segment.end );\n\n\t\t} else {\n\n\t\t\tif ( triangle.plane.intersectLine( segment, tmpVec ) != null ) {\n\n\t\t\t\tif ( target ) {\n\n\t\t\t\t\ttarget.start.copy( tmpVec );\n\t\t\t\t\ttarget.end.copy( tmpVec );\n\n\t\t\t\t}\n\n\t\t\t\treturn triangle.containsPoint( tmpVec );\n\n\t\t\t} else {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction intersectTrianglePoint( triangle, degenerateTriangle, target ) {\n\n\t\tconst point = degenerateTriangle.a;\n\n\t\tif ( isNearZero( triangle.plane.distanceToPoint( point ) ) && triangle.containsPoint( point ) ) {\n\n\t\t\tif ( target ) {\n\n\t\t\t\ttarget.start.copy( point );\n\t\t\t\ttarget.end.copy( point );\n\n\t\t\t}\n\n\t\t\treturn true;\n\n\t\t} else {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t}\n\n\tfunction intersectSegmentPoint( segmentTri, pointTri, target ) {\n\n\t\tconst segment = segmentTri.degenerateSegment;\n\t\tconst point = pointTri.a;\n\n\t\tsegment.closestPointToPoint( point, true, tmpVec );\n\n\t\tif ( point.distanceToSquared( tmpVec ) < ZERO_EPSILON_SQR ) {\n\n\t\t\tif ( target ) {\n\n\t\t\t\ttarget.start.copy( point );\n\t\t\t\ttarget.end.copy( point );\n\n\t\t\t}\n\n\t\t\treturn true;\n\n\t\t} else {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t}\n\n\tfunction handleDegenerateCases( self, other, target, suppressLog ) {\n\n\t\tif ( self.isDegenerateIntoSegment ) {\n\n\t\t\tif ( other.isDegenerateIntoSegment ) {\n\n\t\t\t\t// TODO: replace with Line.distanceSqToLine3 after r179\n\t\t\t\tconst segment1 = self.degenerateSegment;\n\t\t\t\tconst segment2 = other.degenerateSegment;\n\t\t\t\tconst delta1 = dir1;\n\t\t\t\tconst delta2 = dir2;\n\t\t\t\tsegment1.delta( delta1 );\n\t\t\t\tsegment2.delta( delta2 );\n\t\t\t\tconst startDelta = tmpVec.subVectors( segment2.start, segment1.start );\n\n\t\t\t\tconst denom = delta1.x * delta2.y - delta1.y * delta2.x;\n\t\t\t\tif ( isNearZero( denom ) ) {\n\n\t\t\t\t\treturn false;\n\n\t\t\t\t}\n\n\t\t\t\tconst t = ( startDelta.x * delta2.y - startDelta.y * delta2.x ) / denom;\n\t\t\t\tconst u = - ( delta1.x * startDelta.y - delta1.y * startDelta.x ) / denom;\n\n\t\t\t\tif ( t < 0 || t > 1 || u < 0 || u > 1 ) {\n\n\t\t\t\t\treturn false;\n\n\t\t\t\t}\n\n\t\t\t\tconst z1 = segment1.start.z + delta1.z * t;\n\t\t\t\tconst z2 = segment2.start.z + delta2.z * u;\n\n\t\t\t\tif ( isNearZero( z1 - z2 ) ) {\n\n\t\t\t\t\tif ( target ) {\n\n\t\t\t\t\t\ttarget.start.copy( segment1.start ).addScaledVector( delta1, t );\n\t\t\t\t\t\ttarget.end.copy( segment1.start ).addScaledVector( delta1, t );\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn false;\n\n\t\t\t\t}\n\n\t\t\t} else if ( other.isDegenerateIntoPoint ) {\n\n\t\t\t\treturn intersectSegmentPoint( self, other, target );\n\n\t\t\t} else {\n\n\t\t\t\treturn intersectTriangleSegment( other, self, target, suppressLog );\n\n\t\t\t}\n\n\t\t} else if ( self.isDegenerateIntoPoint ) {\n\n\t\t\tif ( other.isDegenerateIntoPoint ) {\n\n\t\t\t\tif ( other.a.distanceToSquared( self.a ) < ZERO_EPSILON_SQR ) {\n\n\t\t\t\t\tif ( target ) {\n\n\t\t\t\t\t\ttarget.start.copy( self.a );\n\t\t\t\t\t\ttarget.end.copy( self.a );\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn false;\n\n\t\t\t\t}\n\n\t\t\t} else if ( other.isDegenerateIntoSegment ) {\n\n\t\t\t\treturn intersectSegmentPoint( other, self, target );\n\n\t\t\t} else {\n\n\t\t\t\treturn intersectTrianglePoint( other, self, target );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tif ( other.isDegenerateIntoPoint ) {\n\n\t\t\t\treturn intersectTrianglePoint( self, other, target );\n\n\t\t\t} else if ( other.isDegenerateIntoSegment ) {\n\n\t\t\t\treturn intersectTriangleSegment( self, other, target, suppressLog );\n\n\t\t\t} /* else this is a general triangle-traingle case, so return undefined */\n\n\t\t}\n\n\t}\n\n\t/* TODO: If the triangles are coplanar and intersecting the target is nonsensical. It should at least\n\t * be a line contained by both triangles if not a different special case somehow represented in the return result.\n\t *\n\t * General triangle intersection code is based on Moller's algorithm from here: https://web.stanford.edu/class/cs277/resources/papers/Moller1997b.pdf\n\t * Reference implementation from here: https://github.com/erich666/jgt-code/blob/master/Volume_08/Number_1/Shen2003/tri_tri_test/include/Moller97.c#L570\n\t * All degeneracies are handled before the general algorithm.\n\t * Coplanar check is different from Moller's and based on SAT tests.\n\t */\n\treturn function intersectsTriangle( other, target = null, suppressLog = false ) {\n\n\t\tif ( this.needsUpdate ) {\n\n\t\t\tthis.update();\n\n\t\t}\n\n\t\tif ( ! other.isExtendedTriangle ) {\n\n\t\t\tsaTri2.copy( other );\n\t\t\tsaTri2.update();\n\t\t\tother = saTri2;\n\n\t\t} else if ( other.needsUpdate ) {\n\n\t\t\tother.update();\n\n\t\t}\n\n\t\tconst res = handleDegenerateCases( this, other, target, suppressLog );\n\t\tif ( res !== undefined ) {\n\n\t\t\treturn res;\n\n\t\t}\n\n\t\tconst plane1 = this.plane;\n\t\tconst plane2 = other.plane;\n\n\t\tlet a1Dist = plane2.distanceToPoint( this.a );\n\t\tlet b1Dist = plane2.distanceToPoint( this.b );\n\t\tlet c1Dist = plane2.distanceToPoint( this.c );\n\n\t\tif ( isNearZero( a1Dist ) )\n\t\t\ta1Dist = 0;\n\n\t\tif ( isNearZero( b1Dist ) )\n\t\t\tb1Dist = 0;\n\n\t\tif ( isNearZero( c1Dist ) )\n\t\t\tc1Dist = 0;\n\n\t\tconst a1b1Dist = a1Dist * b1Dist;\n\t\tconst a1c1Dist = a1Dist * c1Dist;\n\t\tif ( a1b1Dist > 0 && a1c1Dist > 0 ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\tlet a2Dist = plane1.distanceToPoint( other.a );\n\t\tlet b2Dist = plane1.distanceToPoint( other.b );\n\t\tlet c2Dist = plane1.distanceToPoint( other.c );\n\n\t\tif ( isNearZero( a2Dist ) )\n\t\t\ta2Dist = 0;\n\n\t\tif ( isNearZero( b2Dist ) )\n\t\t\tb2Dist = 0;\n\n\t\tif ( isNearZero( c2Dist ) )\n\t\t\tc2Dist = 0;\n\n\t\tconst a2b2Dist = a2Dist * b2Dist;\n\t\tconst a2c2Dist = a2Dist * c2Dist;\n\t\tif ( a2b2Dist > 0 && a2c2Dist > 0 ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\tdir1.copy( plane1.normal );\n\t\tdir2.copy( plane2.normal );\n\t\tconst intersectionLine = dir1.cross( dir2 );\n\n\t\tlet componentIndex = 0;\n\t\tlet maxComponent = Math.abs( intersectionLine.x );\n\t\tconst comp1 = Math.abs( intersectionLine.y );\n\t\tif ( comp1 > maxComponent ) {\n\n\t\t\tmaxComponent = comp1;\n\t\t\tcomponentIndex = 1;\n\n\t\t}\n\n\t\tconst comp2 = Math.abs( intersectionLine.z );\n\t\tif ( comp2 > maxComponent ) {\n\n\t\t\tcomponentIndex = 2;\n\n\t\t}\n\n\t\tconst key = componentKeys[ componentIndex ];\n\t\tconst a1Proj = this.a[ key ];\n\t\tconst b1Proj = this.b[ key ];\n\t\tconst c1Proj = this.c[ key ];\n\n\t\tconst a2Proj = other.a[ key ];\n\t\tconst b2Proj = other.b[ key ];\n\t\tconst c2Proj = other.c[ key ];\n\n\t\tif ( findIntersectionLineBounds( this, a1Proj, b1Proj, c1Proj, a1b1Dist, a1c1Dist, a1Dist, b1Dist, c1Dist, bounds1, edge1 ) ) {\n\n\t\t\treturn coplanarIntersectsTriangle( this, other, target, suppressLog );\n\n\t\t}\n\n\t\tif ( findIntersectionLineBounds( other, a2Proj, b2Proj, c2Proj, a2b2Dist, a2c2Dist, a2Dist, b2Dist, c2Dist, bounds2, edge2 ) ) {\n\n\t\t\treturn coplanarIntersectsTriangle( this, other, target, suppressLog );\n\n\t\t}\n\n\t\tif ( bounds1.y < bounds1.x ) {\n\n\t\t\tconst tmp = bounds1.y;\n\t\t\tbounds1.y = bounds1.x;\n\t\t\tbounds1.x = tmp;\n\n\t\t\ttempPoint.copy( edge1.start );\n\t\t\tedge1.start.copy( edge1.end );\n\t\t\tedge1.end.copy( tempPoint );\n\n\t\t}\n\n\t\tif ( bounds2.y < bounds2.x ) {\n\n\t\t\tconst tmp = bounds2.y;\n\t\t\tbounds2.y = bounds2.x;\n\t\t\tbounds2.x = tmp;\n\n\t\t\ttempPoint.copy( edge2.start );\n\t\t\tedge2.start.copy( edge2.end );\n\t\t\tedge2.end.copy( tempPoint );\n\n\t\t}\n\n\t\tif ( bounds1.y < bounds2.x || bounds2.y < bounds1.x ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\tif ( target ) {\n\n\t\t\tif ( bounds2.x > bounds1.x ) {\n\n\t\t\t\ttarget.start.copy( edge2.start );\n\n\t\t\t} else {\n\n\t\t\t\ttarget.start.copy( edge1.start );\n\n\t\t\t}\n\n\t\t\tif ( bounds2.y < bounds1.y ) {\n\n\t\t\t\ttarget.end.copy( edge2.end );\n\n\t\t\t} else {\n\n\t\t\t\ttarget.end.copy( edge1.end );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t};\n\n} )();\n\n\n/**\n * Returns the distance to the provided point.\n * @function\n * @param {Vector3} point\n * @returns {number}\n */\nExtendedTriangle.prototype.distanceToPoint = ( function () {\n\n\tconst target = /* @__PURE__ */ new Vector3();\n\treturn function distanceToPoint( point ) {\n\n\t\tthis.closestPointToPoint( point, target );\n\t\treturn point.distanceTo( target );\n\n\t};\n\n} )();\n\n\n/**\n * Returns the distance to the provided triangle.\n * @function\n * @param {Triangle} other\n * @param {Vector3} [target1]\n * @param {Vector3} [target2]\n * @returns {number}\n */\nExtendedTriangle.prototype.distanceToTriangle = ( function () {\n\n\tconst point = /* @__PURE__ */ new Vector3();\n\tconst point2 = /* @__PURE__ */ new Vector3();\n\tconst cornerFields = [ 'a', 'b', 'c' ];\n\tconst line1 = /* @__PURE__ */ new Line3();\n\tconst line2 = /* @__PURE__ */ new Line3();\n\n\treturn function distanceToTriangle( other, target1 = null, target2 = null ) {\n\n\t\tconst lineTarget = target1 || target2 ? line1 : null;\n\t\t// `intersectsTriangle` returns a zero-length segment for coplanar\n\t\t// intersecting triangles, which is fine for our purposes here. We\n\t\t// don't need the segment itself in this function. So we can suppress\n\t\t// the warning about coplanar triangles.\n\t\tif ( this.intersectsTriangle( other, lineTarget, true ) ) {\n\n\t\t\tif ( target1 || target2 ) {\n\n\t\t\t\tif ( target1 ) lineTarget.getCenter( target1 );\n\t\t\t\tif ( target2 ) lineTarget.getCenter( target2 );\n\n\t\t\t}\n\n\t\t\treturn 0;\n\n\t\t}\n\n\t\tlet closestDistanceSq = Infinity;\n\n\t\t// check all point distances\n\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\tlet dist;\n\t\t\tconst field = cornerFields[ i ];\n\t\t\tconst otherVec = other[ field ];\n\t\t\tthis.closestPointToPoint( otherVec, point );\n\n\t\t\tdist = otherVec.distanceToSquared( point );\n\n\t\t\tif ( dist < closestDistanceSq ) {\n\n\t\t\t\tclosestDistanceSq = dist;\n\t\t\t\tif ( target1 ) target1.copy( point );\n\t\t\t\tif ( target2 ) target2.copy( otherVec );\n\n\t\t\t}\n\n\n\t\t\tconst thisVec = this[ field ];\n\t\t\tother.closestPointToPoint( thisVec, point );\n\n\t\t\tdist = thisVec.distanceToSquared( point );\n\n\t\t\tif ( dist < closestDistanceSq ) {\n\n\t\t\t\tclosestDistanceSq = dist;\n\t\t\t\tif ( target1 ) target1.copy( thisVec );\n\t\t\t\tif ( target2 ) target2.copy( point );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\tconst f11 = cornerFields[ i ];\n\t\t\tconst f12 = cornerFields[ ( i + 1 ) % 3 ];\n\t\t\tline1.set( this[ f11 ], this[ f12 ] );\n\t\t\tfor ( let i2 = 0; i2 < 3; i2 ++ ) {\n\n\t\t\t\tconst f21 = cornerFields[ i2 ];\n\t\t\t\tconst f22 = cornerFields[ ( i2 + 1 ) % 3 ];\n\t\t\t\tline2.set( other[ f21 ], other[ f22 ] );\n\n\t\t\t\tclosestPointsSegmentToSegment( line1, line2, point, point2 );\n\n\t\t\t\tconst dist = point.distanceToSquared( point2 );\n\t\t\t\tif ( dist < closestDistanceSq ) {\n\n\t\t\t\t\tclosestDistanceSq = dist;\n\t\t\t\t\tif ( target1 ) target1.copy( point );\n\t\t\t\t\tif ( target2 ) target2.copy( point2 );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn Math.sqrt( closestDistanceSq );\n\n\t};\n\n} )();\n","/** @import { Box3, Triangle } from 'three' */\nimport { Vector3, Matrix4, Line3 } from 'three';\nimport { SeparatingAxisBounds } from './SeparatingAxisBounds.js';\nimport { ExtendedTriangle } from './ExtendedTriangle.js';\nimport { closestPointsSegmentToSegment } from './MathUtilities.js';\n\n/**\n * An oriented version of three.js' Box3 class. A variety of derivative values are cached on the\n * object to accelerate the intersection functions. `.needsUpdate` must be set to true when\n * modifying the box parameters.\n *\n * @param {Vector3} [min]\n * @param {Vector3} [max]\n * @param {Matrix4} [matrix]\n */\nexport class OrientedBox {\n\n\tconstructor( min, max, matrix ) {\n\n\t\tthis.isOrientedBox = true;\n\n\t\t/** @type {Vector3} */\n\t\tthis.min = new Vector3();\n\n\t\t/** @type {Vector3} */\n\t\tthis.max = new Vector3();\n\n\t\t/**\n\t\t * Matrix transformation applied to the box.\n\t\t * @type {Matrix4}\n\t\t */\n\t\tthis.matrix = new Matrix4();\n\t\tthis.invMatrix = new Matrix4();\n\t\tthis.points = new Array( 8 ).fill().map( () => new Vector3() );\n\t\tthis.satAxes = new Array( 3 ).fill().map( () => new Vector3() );\n\t\tthis.satBounds = new Array( 3 ).fill().map( () => new SeparatingAxisBounds() );\n\t\tthis.alignedSatBounds = new Array( 3 ).fill().map( () => new SeparatingAxisBounds() );\n\t\t/**\n\t\t * Indicates that the bounding box fields have changed so cached variables to accelerate\n\t\t * other function execution can be updated. Must be set to true after modifying the\n\t\t * oriented box `min`, `max`, `matrix` fields.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis.needsUpdate = false;\n\n\t\tif ( min ) this.min.copy( min );\n\t\tif ( max ) this.max.copy( max );\n\t\tif ( matrix ) this.matrix.copy( matrix );\n\n\t}\n\n\t/**\n\t * Sets the oriented box parameters.\n\t * @param {Vector3} min\n\t * @param {Vector3} max\n\t * @param {Matrix4} matrix\n\t */\n\tset( min, max, matrix ) {\n\n\t\tthis.min.copy( min );\n\t\tthis.max.copy( max );\n\t\tthis.matrix.copy( matrix );\n\t\tthis.needsUpdate = true;\n\n\t}\n\n\tcopy( other ) {\n\n\t\tthis.min.copy( other.min );\n\t\tthis.max.copy( other.max );\n\t\tthis.matrix.copy( other.matrix );\n\t\tthis.needsUpdate = true;\n\n\t}\n\n}\n\nOrientedBox.prototype.update = ( function () {\n\n\treturn function update() {\n\n\t\tconst matrix = this.matrix;\n\t\tconst min = this.min;\n\t\tconst max = this.max;\n\n\t\tconst points = this.points;\n\t\tfor ( let x = 0; x <= 1; x ++ ) {\n\n\t\t\tfor ( let y = 0; y <= 1; y ++ ) {\n\n\t\t\t\tfor ( let z = 0; z <= 1; z ++ ) {\n\n\t\t\t\t\tconst i = ( ( 1 << 0 ) * x ) | ( ( 1 << 1 ) * y ) | ( ( 1 << 2 ) * z );\n\t\t\t\t\tconst v = points[ i ];\n\t\t\t\t\tv.x = x ? max.x : min.x;\n\t\t\t\t\tv.y = y ? max.y : min.y;\n\t\t\t\t\tv.z = z ? max.z : min.z;\n\n\t\t\t\t\tv.applyMatrix4( matrix );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst satBounds = this.satBounds;\n\t\tconst satAxes = this.satAxes;\n\t\tconst minVec = points[ 0 ];\n\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\tconst axis = satAxes[ i ];\n\t\t\tconst sb = satBounds[ i ];\n\t\t\tconst index = 1 << i;\n\t\t\tconst pi = points[ index ];\n\n\t\t\taxis.subVectors( minVec, pi );\n\t\t\tsb.setFromPoints( axis, points );\n\n\t\t}\n\n\t\tconst alignedSatBounds = this.alignedSatBounds;\n\t\talignedSatBounds[ 0 ].setFromPointsField( points, 'x' );\n\t\talignedSatBounds[ 1 ].setFromPointsField( points, 'y' );\n\t\talignedSatBounds[ 2 ].setFromPointsField( points, 'z' );\n\n\t\tthis.invMatrix.copy( this.matrix ).invert();\n\t\tthis.needsUpdate = false;\n\n\t};\n\n} )();\n\n/**\n * Returns true if intersecting with the provided box.\n * @function\n * @param {Box3} box\n * @returns {boolean}\n */\nOrientedBox.prototype.intersectsBox = ( function () {\n\n\tconst aabbBounds = /* @__PURE__ */ new SeparatingAxisBounds();\n\treturn function intersectsBox( box ) {\n\n\t\t// TODO: should this be doing SAT against the AABB?\n\t\tif ( this.needsUpdate ) {\n\n\t\t\tthis.update();\n\n\t\t}\n\n\t\tconst min = box.min;\n\t\tconst max = box.max;\n\t\tconst satBounds = this.satBounds;\n\t\tconst satAxes = this.satAxes;\n\t\tconst alignedSatBounds = this.alignedSatBounds;\n\n\t\taabbBounds.min = min.x;\n\t\taabbBounds.max = max.x;\n\t\tif ( alignedSatBounds[ 0 ].isSeparated( aabbBounds ) ) return false;\n\n\t\taabbBounds.min = min.y;\n\t\taabbBounds.max = max.y;\n\t\tif ( alignedSatBounds[ 1 ].isSeparated( aabbBounds ) ) return false;\n\n\t\taabbBounds.min = min.z;\n\t\taabbBounds.max = max.z;\n\t\tif ( alignedSatBounds[ 2 ].isSeparated( aabbBounds ) ) return false;\n\n\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\tconst axis = satAxes[ i ];\n\t\t\tconst sb = satBounds[ i ];\n\t\t\taabbBounds.setFromBox( axis, box );\n\t\t\tif ( sb.isSeparated( aabbBounds ) ) return false;\n\n\t\t}\n\n\t\treturn true;\n\n\t};\n\n} )();\n\n/**\n * Returns true if intersecting with the provided triangle.\n * @function\n * @param {Triangle} triangle\n * @returns {boolean}\n */\nOrientedBox.prototype.intersectsTriangle = ( function () {\n\n\tconst saTri = /* @__PURE__ */ new ExtendedTriangle();\n\tconst pointsArr = /* @__PURE__ */ new Array( 3 );\n\tconst cachedSatBounds = /* @__PURE__ */ new SeparatingAxisBounds();\n\tconst cachedSatBounds2 = /* @__PURE__ */ new SeparatingAxisBounds();\n\tconst cachedAxis = /* @__PURE__ */ new Vector3();\n\treturn function intersectsTriangle( triangle ) {\n\n\t\tif ( this.needsUpdate ) {\n\n\t\t\tthis.update();\n\n\t\t}\n\n\t\tif ( ! triangle.isExtendedTriangle ) {\n\n\t\t\tsaTri.copy( triangle );\n\t\t\tsaTri.update();\n\t\t\ttriangle = saTri;\n\n\t\t} else if ( triangle.needsUpdate ) {\n\n\t\t\ttriangle.update();\n\n\t\t}\n\n\t\tconst satBounds = this.satBounds;\n\t\tconst satAxes = this.satAxes;\n\n\t\tpointsArr[ 0 ] = triangle.a;\n\t\tpointsArr[ 1 ] = triangle.b;\n\t\tpointsArr[ 2 ] = triangle.c;\n\n\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\tconst sb = satBounds[ i ];\n\t\t\tconst sa = satAxes[ i ];\n\t\t\tcachedSatBounds.setFromPoints( sa, pointsArr );\n\t\t\tif ( sb.isSeparated( cachedSatBounds ) ) return false;\n\n\t\t}\n\n\t\tconst triSatBounds = triangle.satBounds;\n\t\tconst triSatAxes = triangle.satAxes;\n\t\tconst points = this.points;\n\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\tconst sb = triSatBounds[ i ];\n\t\t\tconst sa = triSatAxes[ i ];\n\t\t\tcachedSatBounds.setFromPoints( sa, points );\n\t\t\tif ( sb.isSeparated( cachedSatBounds ) ) return false;\n\n\t\t}\n\n\t\t// check crossed axes\n\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\tconst sa1 = satAxes[ i ];\n\t\t\tfor ( let i2 = 0; i2 < 4; i2 ++ ) {\n\n\t\t\t\tconst sa2 = triSatAxes[ i2 ];\n\t\t\t\tcachedAxis.crossVectors( sa1, sa2 );\n\t\t\t\tcachedSatBounds.setFromPoints( cachedAxis, pointsArr );\n\t\t\t\tcachedSatBounds2.setFromPoints( cachedAxis, points );\n\t\t\t\tif ( cachedSatBounds.isSeparated( cachedSatBounds2 ) ) return false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t};\n\n} )();\n\n/**\n * Returns the distance to the provided point. Sets `target` to the closest point on the surface\n * of the box if provided.\n * @function\n * @param {Vector3} point\n * @param {Vector3} target\n * @returns {number}\n */\nOrientedBox.prototype.closestPointToPoint = ( function () {\n\n\treturn function closestPointToPoint( point, target1 ) {\n\n\t\tif ( this.needsUpdate ) {\n\n\t\t\tthis.update();\n\n\t\t}\n\n\t\ttarget1\n\t\t\t.copy( point )\n\t\t\t.applyMatrix4( this.invMatrix )\n\t\t\t.clamp( this.min, this.max )\n\t\t\t.applyMatrix4( this.matrix );\n\n\t\treturn target1;\n\n\t};\n\n} )();\n\n/**\n * Returns the distance to the provided point.\n * @function\n * @param {Vector3} point\n * @returns {number}\n */\nOrientedBox.prototype.distanceToPoint = ( function () {\n\n\tconst target = new Vector3();\n\treturn function distanceToPoint( point ) {\n\n\t\tthis.closestPointToPoint( point, target );\n\t\treturn point.distanceTo( target );\n\n\t};\n\n} )();\n\n/**\n * Returns the distance to the provided box. `threshold` is an optional distance to return early\n * if the distance is found to be within it. `target1` and `target2` are set to the points on the\n * surface of this box and the `box` argument respectively.\n * @function\n * @param {Box3} box\n * @param {number} [threshold=0]\n * @param {Vector3} [target1]\n * @param {Vector3} [target2]\n * @returns {number}\n */\nOrientedBox.prototype.distanceToBox = ( function () {\n\n\tconst xyzFields = [ 'x', 'y', 'z' ];\n\tconst segments1 = /* @__PURE__ */ new Array( 12 ).fill().map( () => new Line3() );\n\tconst segments2 = /* @__PURE__ */ new Array( 12 ).fill().map( () => new Line3() );\n\n\tconst point1 = /* @__PURE__ */ new Vector3();\n\tconst point2 = /* @__PURE__ */ new Vector3();\n\n\t// early out if we find a value below threshold\n\treturn function distanceToBox( box, threshold = 0, target1 = null, target2 = null ) {\n\n\t\tif ( this.needsUpdate ) {\n\n\t\t\tthis.update();\n\n\t\t}\n\n\t\tif ( this.intersectsBox( box ) ) {\n\n\t\t\tif ( target1 || target2 ) {\n\n\t\t\t\tbox.getCenter( point2 );\n\t\t\t\tthis.closestPointToPoint( point2, point1 );\n\t\t\t\tbox.closestPointToPoint( point1, point2 );\n\n\t\t\t\tif ( target1 ) target1.copy( point1 );\n\t\t\t\tif ( target2 ) target2.copy( point2 );\n\n\t\t\t}\n\n\t\t\treturn 0;\n\n\t\t}\n\n\t\tconst threshold2 = threshold * threshold;\n\t\tconst min = box.min;\n\t\tconst max = box.max;\n\t\tconst points = this.points;\n\n\n\t\t// iterate over every edge and compare distances\n\t\tlet closestDistanceSq = Infinity;\n\n\t\t// check over all these points\n\t\tfor ( let i = 0; i < 8; i ++ ) {\n\n\t\t\tconst p = points[ i ];\n\t\t\tpoint2.copy( p ).clamp( min, max );\n\n\t\t\tconst dist = p.distanceToSquared( point2 );\n\t\t\tif ( dist < closestDistanceSq ) {\n\n\t\t\t\tclosestDistanceSq = dist;\n\t\t\t\tif ( target1 ) target1.copy( p );\n\t\t\t\tif ( target2 ) target2.copy( point2 );\n\n\t\t\t\tif ( dist < threshold2 ) return Math.sqrt( dist );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// generate and check all line segment distances\n\t\tlet count = 0;\n\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\tfor ( let i1 = 0; i1 <= 1; i1 ++ ) {\n\n\t\t\t\tfor ( let i2 = 0; i2 <= 1; i2 ++ ) {\n\n\t\t\t\t\tconst nextIndex = ( i + 1 ) % 3;\n\t\t\t\t\tconst nextIndex2 = ( i + 2 ) % 3;\n\n\t\t\t\t\t// get obb line segments\n\t\t\t\t\tconst index = i1 << nextIndex | i2 << nextIndex2;\n\t\t\t\t\tconst index2 = 1 << i | i1 << nextIndex | i2 << nextIndex2;\n\t\t\t\t\tconst p1 = points[ index ];\n\t\t\t\t\tconst p2 = points[ index2 ];\n\t\t\t\t\tconst line1 = segments1[ count ];\n\t\t\t\t\tline1.set( p1, p2 );\n\n\n\t\t\t\t\t// get aabb line segments\n\t\t\t\t\tconst f1 = xyzFields[ i ];\n\t\t\t\t\tconst f2 = xyzFields[ nextIndex ];\n\t\t\t\t\tconst f3 = xyzFields[ nextIndex2 ];\n\t\t\t\t\tconst line2 = segments2[ count ];\n\t\t\t\t\tconst start = line2.start;\n\t\t\t\t\tconst end = line2.end;\n\n\t\t\t\t\tstart[ f1 ] = min[ f1 ];\n\t\t\t\t\tstart[ f2 ] = i1 ? min[ f2 ] : max[ f2 ];\n\t\t\t\t\tstart[ f3 ] = i2 ? min[ f3 ] : max[ f3 ];\n\n\t\t\t\t\tend[ f1 ] = max[ f1 ];\n\t\t\t\t\tend[ f2 ] = i1 ? min[ f2 ] : max[ f2 ];\n\t\t\t\t\tend[ f3 ] = i2 ? min[ f3 ] : max[ f3 ];\n\n\t\t\t\t\tcount ++;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// check all the other boxes point\n\t\tfor ( let x = 0; x <= 1; x ++ ) {\n\n\t\t\tfor ( let y = 0; y <= 1; y ++ ) {\n\n\t\t\t\tfor ( let z = 0; z <= 1; z ++ ) {\n\n\t\t\t\t\tpoint2.x = x ? max.x : min.x;\n\t\t\t\t\tpoint2.y = y ? max.y : min.y;\n\t\t\t\t\tpoint2.z = z ? max.z : min.z;\n\n\t\t\t\t\tthis.closestPointToPoint( point2, point1 );\n\t\t\t\t\tconst dist = point2.distanceToSquared( point1 );\n\t\t\t\t\tif ( dist < closestDistanceSq ) {\n\n\t\t\t\t\t\tclosestDistanceSq = dist;\n\t\t\t\t\t\tif ( target1 ) target1.copy( point1 );\n\t\t\t\t\t\tif ( target2 ) target2.copy( point2 );\n\n\t\t\t\t\t\tif ( dist < threshold2 ) return Math.sqrt( dist );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( let i = 0; i < 12; i ++ ) {\n\n\t\t\tconst l1 = segments1[ i ];\n\t\t\tfor ( let i2 = 0; i2 < 12; i2 ++ ) {\n\n\t\t\t\tconst l2 = segments2[ i2 ];\n\t\t\t\tclosestPointsSegmentToSegment( l1, l2, point1, point2 );\n\t\t\t\tconst dist = point1.distanceToSquared( point2 );\n\t\t\t\tif ( dist < closestDistanceSq ) {\n\n\t\t\t\t\tclosestDistanceSq = dist;\n\t\t\t\t\tif ( target1 ) target1.copy( point1 );\n\t\t\t\t\tif ( target2 ) target2.copy( point2 );\n\n\t\t\t\t\tif ( dist < threshold2 ) return Math.sqrt( dist );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn Math.sqrt( closestDistanceSq );\n\n\t};\n\n} )();\n","import { ExtendedTriangle } from '../math/ExtendedTriangle.js';\nimport { PrimitivePool } from './PrimitivePool.js';\n\nclass ExtendedTrianglePoolBase extends PrimitivePool {\n\n\tconstructor() {\n\n\t\tsuper( () => new ExtendedTriangle() );\n\n\t}\n\n}\n\nexport const ExtendedTrianglePool = /* @__PURE__ */ new ExtendedTrianglePoolBase();\n","import { Vector3 } from 'three';\n\nconst temp = /* @__PURE__ */ new Vector3();\nconst temp1 = /* @__PURE__ */ new Vector3();\n\nexport function closestPointToPoint(\n\tbvh,\n\tpoint,\n\ttarget = { },\n\tminThreshold = 0,\n\tmaxThreshold = Infinity,\n) {\n\n\t// early out if under minThreshold\n\t// skip checking if over maxThreshold\n\t// set minThreshold = maxThreshold to quickly check if a point is within a threshold\n\t// returns Infinity if no value found\n\tconst minThresholdSq = minThreshold * minThreshold;\n\tconst maxThresholdSq = maxThreshold * maxThreshold;\n\tlet closestDistanceSq = Infinity;\n\tlet closestDistanceTriIndex = null;\n\tbvh.shapecast(\n\n\t\t{\n\n\t\t\tboundsTraverseOrder: box => {\n\n\t\t\t\ttemp.copy( point ).clamp( box.min, box.max );\n\t\t\t\treturn temp.distanceToSquared( point );\n\n\t\t\t},\n\n\t\t\tintersectsBounds: ( box, isLeaf, score ) => {\n\n\t\t\t\treturn score < closestDistanceSq && score < maxThresholdSq;\n\n\t\t\t},\n\n\t\t\tintersectsTriangle: ( tri, triIndex ) => {\n\n\t\t\t\ttri.closestPointToPoint( point, temp );\n\t\t\t\tconst distSq = point.distanceToSquared( temp );\n\t\t\t\tif ( distSq < closestDistanceSq ) {\n\n\t\t\t\t\ttemp1.copy( temp );\n\t\t\t\t\tclosestDistanceSq = distSq;\n\t\t\t\t\tclosestDistanceTriIndex = triIndex;\n\n\t\t\t\t}\n\n\t\t\t\tif ( distSq < minThresholdSq ) {\n\n\t\t\t\t\treturn true;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn false;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t}\n\n\t);\n\n\tif ( closestDistanceSq === Infinity ) return null;\n\n\tconst closestDistance = Math.sqrt( closestDistanceSq );\n\n\tif ( ! target.point ) target.point = temp1.clone();\n\telse target.point.copy( temp1 );\n\ttarget.distance = closestDistance,\n\ttarget.faceIndex = closestDistanceTriIndex;\n\n\treturn target;\n\n}\n","import { Vector3, Vector2, Triangle, DoubleSide, BackSide, REVISION } from 'three';\n\nconst IS_GT_REVISION_169 = parseInt( REVISION ) >= 169;\nconst IS_LT_REVISION_161 = parseInt( REVISION ) <= 161;\n\n// Ripped and modified From THREE.js Mesh raycast\n// https://github.com/mrdoob/three.js/blob/0aa87c999fe61e216c1133fba7a95772b503eddf/src/objects/Mesh.js#L115\nconst _vA = /* @__PURE__ */ new Vector3();\nconst _vB = /* @__PURE__ */ new Vector3();\nconst _vC = /* @__PURE__ */ new Vector3();\n\nconst _uvA = /* @__PURE__ */ new Vector2();\nconst _uvB = /* @__PURE__ */ new Vector2();\nconst _uvC = /* @__PURE__ */ new Vector2();\n\nconst _normalA = /* @__PURE__ */ new Vector3();\nconst _normalB = /* @__PURE__ */ new Vector3();\nconst _normalC = /* @__PURE__ */ new Vector3();\n\nconst _intersectionPoint = /* @__PURE__ */ new Vector3();\nfunction checkIntersection( ray, pA, pB, pC, point, side, near, far ) {\n\n\tlet intersect;\n\tif ( side === BackSide ) {\n\n\t\tintersect = ray.intersectTriangle( pC, pB, pA, true, point );\n\n\t} else {\n\n\t\tintersect = ray.intersectTriangle( pA, pB, pC, side !== DoubleSide, point );\n\n\t}\n\n\tif ( intersect === null ) return null;\n\n\tconst distance = ray.origin.distanceTo( point );\n\n\tif ( distance < near || distance > far ) return null;\n\n\treturn {\n\n\t\tdistance: distance,\n\t\tpoint: point.clone(),\n\n\t};\n\n}\n\nfunction checkBufferGeometryIntersection( ray, position, normal, uv, uv1, a, b, c, side, near, far ) {\n\n\t_vA.fromBufferAttribute( position, a );\n\t_vB.fromBufferAttribute( position, b );\n\t_vC.fromBufferAttribute( position, c );\n\n\tconst intersection = checkIntersection( ray, _vA, _vB, _vC, _intersectionPoint, side, near, far );\n\n\tif ( intersection ) {\n\n\t\tif ( uv ) {\n\n\t\t\t_uvA.fromBufferAttribute( uv, a );\n\t\t\t_uvB.fromBufferAttribute( uv, b );\n\t\t\t_uvC.fromBufferAttribute( uv, c );\n\n\t\t\tintersection.uv = new Vector2();\n\t\t\tconst res = Triangle.getInterpolation( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, intersection.uv );\n\t\t\tif ( ! IS_GT_REVISION_169 ) {\n\n\t\t\t\tintersection.uv = res;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( uv1 ) {\n\n\t\t\t_uvA.fromBufferAttribute( uv1, a );\n\t\t\t_uvB.fromBufferAttribute( uv1, b );\n\t\t\t_uvC.fromBufferAttribute( uv1, c );\n\n\t\t\tintersection.uv1 = new Vector2();\n\t\t\tconst res = Triangle.getInterpolation( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, intersection.uv1 );\n\t\t\tif ( ! IS_GT_REVISION_169 ) {\n\n\t\t\t\tintersection.uv1 = res;\n\n\t\t\t}\n\n\t\t\tif ( IS_LT_REVISION_161 ) {\n\n\t\t\t\tintersection.uv2 = intersection.uv1;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( normal ) {\n\n\t\t\t_normalA.fromBufferAttribute( normal, a );\n\t\t\t_normalB.fromBufferAttribute( normal, b );\n\t\t\t_normalC.fromBufferAttribute( normal, c );\n\n\t\t\tintersection.normal = new Vector3();\n\t\t\tconst res = Triangle.getInterpolation( _intersectionPoint, _vA, _vB, _vC, _normalA, _normalB, _normalC, intersection.normal );\n\t\t\tif ( intersection.normal.dot( ray.direction ) > 0 ) {\n\n\t\t\t\tintersection.normal.multiplyScalar( - 1 );\n\n\t\t\t}\n\n\t\t\tif ( ! IS_GT_REVISION_169 ) {\n\n\t\t\t\tintersection.normal = res;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst face = {\n\t\t\ta: a,\n\t\t\tb: b,\n\t\t\tc: c,\n\t\t\tnormal: new Vector3(),\n\t\t\tmaterialIndex: 0\n\t\t};\n\n\t\tTriangle.getNormal( _vA, _vB, _vC, face.normal );\n\n\t\tintersection.face = face;\n\t\tintersection.faceIndex = a;\n\n\t\tif ( IS_GT_REVISION_169 ) {\n\n\t\t\tconst barycoord = new Vector3();\n\t\t\tTriangle.getBarycoord( _intersectionPoint, _vA, _vB, _vC, barycoord );\n\n\t\t\tintersection.barycoord = barycoord;\n\n\t\t}\n\n\t}\n\n\treturn intersection;\n\n}\n\nfunction getSide( materialOrSide ) {\n\n\treturn materialOrSide && materialOrSide.isMaterial ? materialOrSide.side : materialOrSide;\n\n}\n\n// https://github.com/mrdoob/three.js/blob/0aa87c999fe61e216c1133fba7a95772b503eddf/src/objects/Mesh.js#L258\nexport function intersectTri( geometry, materialOrSide, ray, tri, intersections, near, far ) {\n\n\tconst triOffset = tri * 3;\n\tlet a = triOffset + 0;\n\tlet b = triOffset + 1;\n\tlet c = triOffset + 2;\n\n\tconst { index, groups } = geometry;\n\tif ( geometry.index ) {\n\n\t\ta = index.getX( a );\n\t\tb = index.getX( b );\n\t\tc = index.getX( c );\n\n\t}\n\n\tconst { position, normal, uv, uv1 } = geometry.attributes;\n\tif ( Array.isArray( materialOrSide ) ) {\n\n\t\t// check which groups a triangle is present in and run the intersections\n\t\t// TODO: we shouldn't need to run and intersection test multiple times\n\t\tconst firstIndex = tri * 3;\n\t\tfor ( let i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\tconst { start, count, materialIndex } = groups[ i ];\n\t\t\tif ( firstIndex >= start && firstIndex < start + count ) {\n\n\t\t\t\tconst side = getSide( materialOrSide[ materialIndex ] );\n\t\t\t\tconst intersection = checkBufferGeometryIntersection( ray, position, normal, uv, uv1, a, b, c, side, near, far );\n\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\tintersection.faceIndex = tri;\n\t\t\t\t\tintersection.face.materialIndex = materialIndex;\n\n\t\t\t\t\tif ( intersections ) {\n\n\t\t\t\t\t\tintersections.push( intersection );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\treturn intersection;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t} else {\n\n\t\t// run the intersection for the single material\n\t\tconst side = getSide( materialOrSide );\n\t\tconst intersection = checkBufferGeometryIntersection( ray, position, normal, uv, uv1, a, b, c, side, near, far );\n\t\tif ( intersection ) {\n\n\t\t\tintersection.faceIndex = tri;\n\t\t\tintersection.face.materialIndex = 0;\n\n\t\t\tif ( intersections ) {\n\n\t\t\t\tintersections.push( intersection );\n\n\t\t\t} else {\n\n\t\t\t\treturn intersection;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\treturn null;\n\n}\n","/** @import { BufferGeometry } from 'three' */\nimport { Vector2, Vector3, Triangle } from 'three';\n\n// sets the vertices of triangle `tri` with the 3 vertices after i\nexport function setTriangle( tri, i, index, pos ) {\n\n\tconst ta = tri.a;\n\tconst tb = tri.b;\n\tconst tc = tri.c;\n\n\tlet i0 = i;\n\tlet i1 = i + 1;\n\tlet i2 = i + 2;\n\tif ( index ) {\n\n\t\ti0 = index.getX( i0 );\n\t\ti1 = index.getX( i1 );\n\t\ti2 = index.getX( i2 );\n\n\t}\n\n\tta.x = pos.getX( i0 );\n\tta.y = pos.getY( i0 );\n\tta.z = pos.getZ( i0 );\n\n\ttb.x = pos.getX( i1 );\n\ttb.y = pos.getY( i1 );\n\ttb.z = pos.getZ( i1 );\n\n\ttc.x = pos.getX( i2 );\n\ttc.y = pos.getY( i2 );\n\ttc.z = pos.getZ( i2 );\n\n}\n\nconst tempV1 = /* @__PURE__ */ new Vector3();\nconst tempV2 = /* @__PURE__ */ new Vector3();\nconst tempV3 = /* @__PURE__ */ new Vector3();\nconst tempUV1 = /* @__PURE__ */ new Vector2();\nconst tempUV2 = /* @__PURE__ */ new Vector2();\nconst tempUV3 = /* @__PURE__ */ new Vector2();\n\n/**\n * @typedef {Object} HitTriangleInfo\n * @property {{ a: number, b: number, c: number, materialIndex: number, normal: Vector3 }} face\n *   Triangle vertex indices, material index, and face normal.\n * @property {Vector2|null} uv - UV coordinates at the hit point, or `null` if no UV attribute is present.\n * @property {Vector3} barycoord - Barycentric coordinates of the hit point within the triangle.\n */\n\n/**\n * Computes hit-point information for a point on a triangle within a `BufferGeometry`. Returns\n * the face vertex indices, face normal, material index, UV coordinates, and barycentric coordinates.\n * Useful for retrieving detailed hit data after a call to `MeshBVH.closestPointToPoint` or\n * `MeshBVH.closestPointToGeometry`.\n *\n * @section Functions\n * @param {Vector3} point - The point on the triangle surface (in the geometry's local space).\n * @param {BufferGeometry} geometry - The geometry containing the triangle.\n * @param {number} triangleIndex - The index of the triangle within the geometry.\n * @param {HitTriangleInfo} [target] - Optional object to write results into. Reuses existing\n *   `face`, `uv`, and `barycoord` sub-objects if present.\n * @returns {HitTriangleInfo}\n */\nexport function getTriangleHitPointInfo( point, geometry, triangleIndex, target ) {\n\n\tconst indices = geometry.getIndex().array;\n\tconst positions = geometry.getAttribute( 'position' );\n\tconst uvs = geometry.getAttribute( 'uv' );\n\n\tconst a = indices[ triangleIndex * 3 ];\n\tconst b = indices[ triangleIndex * 3 + 1 ];\n\tconst c = indices[ triangleIndex * 3 + 2 ];\n\n\ttempV1.fromBufferAttribute( positions, a );\n\ttempV2.fromBufferAttribute( positions, b );\n\ttempV3.fromBufferAttribute( positions, c );\n\n\t// find the associated material index\n\tlet materialIndex = 0;\n\tconst groups = geometry.groups;\n\tconst firstVertexIndex = triangleIndex * 3;\n\tfor ( let i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\tconst group = groups[ i ];\n\t\tconst { start, count } = group;\n\t\tif ( firstVertexIndex >= start && firstVertexIndex < start + count ) {\n\n\t\t\tmaterialIndex = group.materialIndex;\n\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\t// extract barycoord\n\tconst barycoord = target && target.barycoord ? target.barycoord : new Vector3();\n\tTriangle.getBarycoord( point, tempV1, tempV2, tempV3, barycoord );\n\n\t// extract uvs\n\tlet uv = null;\n\tif ( uvs ) {\n\n\t\ttempUV1.fromBufferAttribute( uvs, a );\n\t\ttempUV2.fromBufferAttribute( uvs, b );\n\t\ttempUV3.fromBufferAttribute( uvs, c );\n\n\t\tif ( target && target.uv ) uv = target.uv;\n\t\telse uv = new Vector2();\n\n\t\tTriangle.getInterpolation( point, tempV1, tempV2, tempV3, tempUV1, tempUV2, tempUV3, uv );\n\n\t}\n\n\t// adjust the provided target or create a new one\n\tif ( target ) {\n\n\t\tif ( ! target.face ) target.face = { };\n\t\ttarget.face.a = a;\n\t\ttarget.face.b = b;\n\t\ttarget.face.c = c;\n\t\ttarget.face.materialIndex = materialIndex;\n\t\tif ( ! target.face.normal ) target.face.normal = new Vector3();\n\t\tTriangle.getNormal( tempV1, tempV2, tempV3, target.face.normal );\n\n\t\tif ( uv ) target.uv = uv;\n\t\ttarget.barycoord = barycoord;\n\n\t\treturn target;\n\n\t} else {\n\n\t\treturn {\n\t\t\tface: {\n\t\t\t\ta: a,\n\t\t\t\tb: b,\n\t\t\t\tc: c,\n\t\t\t\tmaterialIndex: materialIndex,\n\t\t\t\tnormal: Triangle.getNormal( tempV1, tempV2, tempV3, new Vector3() )\n\t\t\t},\n\t\t\tuv: uv,\n\t\t\tbarycoord: barycoord,\n\t\t};\n\n\t}\n\n}\n","import { intersectTri } from '../../utils/ThreeRayIntersectUtilities.js';\nimport { setTriangle } from '../../utils/TriangleUtilities.js';\n\n/*************************************************************/\n/* This file is generated from \"iterationUtils.template.js\". */\n/*************************************************************/\n\nfunction intersectTris( bvh, materialOrSide, ray, offset, count, intersections, near, far ) {\n\n\tconst { geometry, _indirectBuffer } = bvh;\n\tfor ( let i = offset, end = offset + count; i < end; i ++ ) {\n\n\n\t\tintersectTri( geometry, materialOrSide, ray, i, intersections, near, far );\n\n\n\t}\n\n}\n\nfunction intersectClosestTri( bvh, materialOrSide, ray, offset, count, near, far ) {\n\n\tconst { geometry, _indirectBuffer } = bvh;\n\tlet dist = Infinity;\n\tlet res = null;\n\tfor ( let i = offset, end = offset + count; i < end; i ++ ) {\n\n\t\tlet intersection;\n\n\t\tintersection = intersectTri( geometry, materialOrSide, ray, i, null, near, far );\n\n\n\t\tif ( intersection && intersection.distance < dist ) {\n\n\t\t\tres = intersection;\n\t\t\tdist = intersection.distance;\n\n\t\t}\n\n\t}\n\n\treturn res;\n\n}\n\nfunction iterateOverTriangles(\n\toffset,\n\tcount,\n\tbvh,\n\tintersectsTriangleFunc,\n\tcontained,\n\tdepth,\n\ttriangle\n) {\n\n\tconst { geometry } = bvh;\n\tconst { index } = geometry;\n\tconst pos = geometry.attributes.position;\n\tfor ( let i = offset, l = count + offset; i < l; i ++ ) {\n\n\t\tlet tri;\n\n\t\ttri = i;\n\n\t\tsetTriangle( triangle, tri * 3, index, pos );\n\t\ttriangle.needsUpdate = true;\n\n\t\tif ( intersectsTriangleFunc( triangle, tri, contained, depth ) ) {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t}\n\n\treturn false;\n\n}\n\nexport { intersectClosestTri, intersectTris, iterateOverTriangles };\n","import { UINT32_PER_NODE, BYTES_PER_NODE } from '../Constants.js';\nimport { IS_LEAF, OFFSET, COUNT, LEFT_NODE, RIGHT_NODE } from '../utils/nodeBufferUtils.js';\n\n/****************************************************/\n/* This file is generated from \"refit.template.js\". */\n/****************************************************/\n\nfunction refit( bvh, nodeIndices = null ) {\n\n\tif ( nodeIndices && Array.isArray( nodeIndices ) ) {\n\n\t\tnodeIndices = new Set( nodeIndices );\n\n\t}\n\n\tconst geometry = bvh.geometry;\n\tconst indexArr = geometry.index ? geometry.index.array : null;\n\tconst posAttr = geometry.attributes.position;\n\n\tlet buffer, uint32Array, uint16Array, float32Array;\n\tlet byteOffset = 0;\n\tconst roots = bvh._roots;\n\tfor ( let i = 0, l = roots.length; i < l; i ++ ) {\n\n\t\tbuffer = roots[ i ];\n\t\tuint32Array = new Uint32Array( buffer );\n\t\tuint16Array = new Uint16Array( buffer );\n\t\tfloat32Array = new Float32Array( buffer );\n\n\t\t_traverse( 0, byteOffset );\n\t\tbyteOffset += buffer.byteLength;\n\n\t}\n\n\tfunction _traverse( nodeIndex32, byteOffset, force = false ) {\n\n\t\tconst nodeIndex16 = nodeIndex32 * 2;\n\t\tif ( IS_LEAF( nodeIndex16, uint16Array ) ) {\n\n\t\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\n\t\t\tconst count = COUNT( nodeIndex16, uint16Array );\n\n\t\t\tlet minx = Infinity;\n\t\t\tlet miny = Infinity;\n\t\t\tlet minz = Infinity;\n\t\t\tlet maxx = - Infinity;\n\t\t\tlet maxy = - Infinity;\n\t\t\tlet maxz = - Infinity;\n\n\n\t\t\tfor ( let i = 3 * offset, l = 3 * ( offset + count ); i < l; i ++ ) {\n\n\t\t\t\tlet index = indexArr[ i ];\n\t\t\t\tconst x = posAttr.getX( index );\n\t\t\t\tconst y = posAttr.getY( index );\n\t\t\t\tconst z = posAttr.getZ( index );\n\n\t\t\t\tif ( x < minx ) minx = x;\n\t\t\t\tif ( x > maxx ) maxx = x;\n\n\t\t\t\tif ( y < miny ) miny = y;\n\t\t\t\tif ( y > maxy ) maxy = y;\n\n\t\t\t\tif ( z < minz ) minz = z;\n\t\t\t\tif ( z > maxz ) maxz = z;\n\n\t\t\t}\n\n\n\t\t\tif (\n\t\t\t\tfloat32Array[ nodeIndex32 + 0 ] !== minx ||\n\t\t\t\tfloat32Array[ nodeIndex32 + 1 ] !== miny ||\n\t\t\t\tfloat32Array[ nodeIndex32 + 2 ] !== minz ||\n\n\t\t\t\tfloat32Array[ nodeIndex32 + 3 ] !== maxx ||\n\t\t\t\tfloat32Array[ nodeIndex32 + 4 ] !== maxy ||\n\t\t\t\tfloat32Array[ nodeIndex32 + 5 ] !== maxz\n\t\t\t) {\n\n\t\t\t\tfloat32Array[ nodeIndex32 + 0 ] = minx;\n\t\t\t\tfloat32Array[ nodeIndex32 + 1 ] = miny;\n\t\t\t\tfloat32Array[ nodeIndex32 + 2 ] = minz;\n\n\t\t\t\tfloat32Array[ nodeIndex32 + 3 ] = maxx;\n\t\t\t\tfloat32Array[ nodeIndex32 + 4 ] = maxy;\n\t\t\t\tfloat32Array[ nodeIndex32 + 5 ] = maxz;\n\n\t\t\t\treturn true;\n\n\t\t\t} else {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconst left = LEFT_NODE( nodeIndex32 );\n\t\t\tconst right = RIGHT_NODE( nodeIndex32, uint32Array );\n\n\t\t\t// the identifying node indices provided by the shapecast function include offsets of all\n\t\t\t// root buffers to guarantee they're unique between roots so offset left and right indices here.\n\t\t\tlet forceChildren = force;\n\t\t\tlet includesLeft = false;\n\t\t\tlet includesRight = false;\n\n\t\t\tif ( nodeIndices ) {\n\n\t\t\t\t// if we see that neither the left or right child are included in the set that need to be updated\n\t\t\t\t// then we assume that all children need to be updated.\n\t\t\t\tif ( ! forceChildren ) {\n\n\t\t\t\t\tconst leftNodeId = left / UINT32_PER_NODE + byteOffset / BYTES_PER_NODE;\n\t\t\t\t\tconst rightNodeId = right / UINT32_PER_NODE + byteOffset / BYTES_PER_NODE;\n\t\t\t\t\tincludesLeft = nodeIndices.has( leftNodeId );\n\t\t\t\t\tincludesRight = nodeIndices.has( rightNodeId );\n\t\t\t\t\tforceChildren = ! includesLeft && ! includesRight;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tincludesLeft = true;\n\t\t\t\tincludesRight = true;\n\n\t\t\t}\n\n\t\t\tconst traverseLeft = forceChildren || includesLeft;\n\t\t\tconst traverseRight = forceChildren || includesRight;\n\n\t\t\tlet leftChange = false;\n\t\t\tif ( traverseLeft ) {\n\n\t\t\t\tleftChange = _traverse( left, byteOffset, forceChildren );\n\n\t\t\t}\n\n\t\t\tlet rightChange = false;\n\t\t\tif ( traverseRight ) {\n\n\t\t\t\trightChange = _traverse( right, byteOffset, forceChildren );\n\n\t\t\t}\n\n\t\t\tconst didChange = leftChange || rightChange;\n\t\t\tif ( didChange ) {\n\n\t\t\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\t\t\tconst left_i = left + i;\n\t\t\t\t\tconst right_i = right + i;\n\t\t\t\t\tconst minLeftValue = float32Array[ left_i ];\n\t\t\t\t\tconst maxLeftValue = float32Array[ left_i + 3 ];\n\t\t\t\t\tconst minRightValue = float32Array[ right_i ];\n\t\t\t\t\tconst maxRightValue = float32Array[ right_i + 3 ];\n\n\t\t\t\t\tfloat32Array[ nodeIndex32 + i ] = minLeftValue < minRightValue ? minLeftValue : minRightValue;\n\t\t\t\t\tfloat32Array[ nodeIndex32 + i + 3 ] = maxLeftValue > maxRightValue ? maxLeftValue : maxRightValue;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn didChange;\n\n\t\t}\n\n\t}\n\n}\n\nexport { refit };\n","\nexport function intersectsNodeBounds( nodeIndex32, array, ray, near, far ) {\n\n\t// This function performs intersection tests similar to Ray.intersectBox in three.js,\n\t// with the difference that the box values are read from an array to improve performance.\n\n\tlet tmin, tmax, tymin, tymax, tzmin, tzmax;\n\n\tconst invdirx = 1 / ray.direction.x,\n\t\tinvdiry = 1 / ray.direction.y,\n\t\tinvdirz = 1 / ray.direction.z;\n\n\tconst ox = ray.origin.x;\n\tconst oy = ray.origin.y;\n\tconst oz = ray.origin.z;\n\n\tlet minx = array[ nodeIndex32 ];\n\tlet maxx = array[ nodeIndex32 + 3 ];\n\n\tlet miny = array[ nodeIndex32 + 1 ];\n\tlet maxy = array[ nodeIndex32 + 3 + 1 ];\n\n\tlet minz = array[ nodeIndex32 + 2 ];\n\tlet maxz = array[ nodeIndex32 + 3 + 2 ];\n\n\tif ( invdirx >= 0 ) {\n\n\t\ttmin = ( minx - ox ) * invdirx;\n\t\ttmax = ( maxx - ox ) * invdirx;\n\n\t} else {\n\n\t\ttmin = ( maxx - ox ) * invdirx;\n\t\ttmax = ( minx - ox ) * invdirx;\n\n\t}\n\n\tif ( invdiry >= 0 ) {\n\n\t\ttymin = ( miny - oy ) * invdiry;\n\t\ttymax = ( maxy - oy ) * invdiry;\n\n\t} else {\n\n\t\ttymin = ( maxy - oy ) * invdiry;\n\t\ttymax = ( miny - oy ) * invdiry;\n\n\t}\n\n\tif ( ( tmin > tymax ) || ( tymin > tmax ) ) return false;\n\n\tif ( tymin > tmin || isNaN( tmin ) ) tmin = tymin;\n\n\tif ( tymax < tmax || isNaN( tmax ) ) tmax = tymax;\n\n\tif ( invdirz >= 0 ) {\n\n\t\ttzmin = ( minz - oz ) * invdirz;\n\t\ttzmax = ( maxz - oz ) * invdirz;\n\n\t} else {\n\n\t\ttzmin = ( maxz - oz ) * invdirz;\n\t\ttzmax = ( minz - oz ) * invdirz;\n\n\t}\n\n\tif ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return false;\n\n\tif ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;\n\n\tif ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;\n\n\t//return point closest to the ray (positive side)\n\n\treturn tmin <= far && tmax >= near;\n\n}\n","import { intersectTri } from '../../utils/ThreeRayIntersectUtilities.js';\nimport { setTriangle } from '../../utils/TriangleUtilities.js';\n\n/*************************************************************/\n/* This file is generated from \"iterationUtils.template.js\". */\n/*************************************************************/\n\nfunction intersectTris_indirect( bvh, materialOrSide, ray, offset, count, intersections, near, far ) {\n\n\tconst { geometry, _indirectBuffer } = bvh;\n\tfor ( let i = offset, end = offset + count; i < end; i ++ ) {\n\n\t\tlet vi = _indirectBuffer ? _indirectBuffer[ i ] : i;\n\t\tintersectTri( geometry, materialOrSide, ray, vi, intersections, near, far );\n\n\n\t}\n\n}\n\nfunction intersectClosestTri_indirect( bvh, materialOrSide, ray, offset, count, near, far ) {\n\n\tconst { geometry, _indirectBuffer } = bvh;\n\tlet dist = Infinity;\n\tlet res = null;\n\tfor ( let i = offset, end = offset + count; i < end; i ++ ) {\n\n\t\tlet intersection;\n\t\tintersection = intersectTri( geometry, materialOrSide, ray, _indirectBuffer ? _indirectBuffer[ i ] : i, null, near, far );\n\n\n\t\tif ( intersection && intersection.distance < dist ) {\n\n\t\t\tres = intersection;\n\t\t\tdist = intersection.distance;\n\n\t\t}\n\n\t}\n\n\treturn res;\n\n}\n\nfunction iterateOverTriangles_indirect(\n\toffset,\n\tcount,\n\tbvh,\n\tintersectsTriangleFunc,\n\tcontained,\n\tdepth,\n\ttriangle\n) {\n\n\tconst { geometry } = bvh;\n\tconst { index } = geometry;\n\tconst pos = geometry.attributes.position;\n\tfor ( let i = offset, l = count + offset; i < l; i ++ ) {\n\n\t\tlet tri;\n\t\ttri = bvh.resolveTriangleIndex( i );\n\n\t\tsetTriangle( triangle, tri * 3, index, pos );\n\t\ttriangle.needsUpdate = true;\n\n\t\tif ( intersectsTriangleFunc( triangle, tri, contained, depth ) ) {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t}\n\n\treturn false;\n\n}\n\nexport { intersectClosestTri_indirect, intersectTris_indirect, iterateOverTriangles_indirect };\n","import { intersectsNodeBounds } from '../utils/intersectUtils.js';\nimport { IS_LEAF, OFFSET, COUNT, LEFT_NODE, RIGHT_NODE } from '../utils/nodeBufferUtils.js';\nimport { BufferStack } from '../utils/BufferStack.js';\nimport { intersectTris } from '../utils/iterationUtils.generated.js';\nimport '../utils/iterationUtils_indirect.generated.js';\n\n/******************************************************/\n/* This file is generated from \"raycast.template.js\". */\n/******************************************************/\n\nfunction raycast( bvh, root, materialOrSide, ray, intersects, near, far ) {\n\n\tBufferStack.setBuffer( bvh._roots[ root ] );\n\tif ( intersectsNodeBounds( 0, BufferStack.float32Array, ray, near, far ) ) {\n\n\t\t_raycast( 0, bvh, materialOrSide, ray, intersects, near, far );\n\n\t}\n\n\tBufferStack.clearBuffer();\n\n}\n\nfunction _raycast( nodeIndex32, bvh, materialOrSide, ray, intersects, near, far ) {\n\n\tconst { float32Array, uint16Array, uint32Array } = BufferStack;\n\tconst nodeIndex16 = nodeIndex32 * 2;\n\tconst isLeaf = IS_LEAF( nodeIndex16, uint16Array );\n\tif ( isLeaf ) {\n\n\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\n\t\tconst count = COUNT( nodeIndex16, uint16Array );\n\n\n\t\tintersectTris( bvh, materialOrSide, ray, offset, count, intersects, near, far );\n\n\n\t} else {\n\n\t\tconst leftIndex = LEFT_NODE( nodeIndex32 );\n\t\tif ( intersectsNodeBounds( leftIndex, float32Array, ray, near, far ) ) {\n\n\t\t\t_raycast( leftIndex, bvh, materialOrSide, ray, intersects, near, far );\n\n\t\t}\n\n\t\tconst rightIndex = RIGHT_NODE( nodeIndex32, uint32Array );\n\t\tif ( intersectsNodeBounds( rightIndex, float32Array, ray, near, far ) ) {\n\n\t\t\t_raycast( rightIndex, bvh, materialOrSide, ray, intersects, near, far );\n\n\t\t}\n\n\t}\n\n}\n\nexport { raycast };\n","import { IS_LEAF, OFFSET, COUNT, SPLIT_AXIS, LEFT_NODE, RIGHT_NODE } from '../utils/nodeBufferUtils.js';\nimport { BufferStack } from '../utils/BufferStack.js';\nimport { intersectsNodeBounds } from '../utils/intersectUtils.js';\nimport { intersectClosestTri } from '../utils/iterationUtils.generated.js';\nimport '../utils/iterationUtils_indirect.generated.js';\n\n/***********************************************************/\n/* This file is generated from \"raycastFirst.template.js\". */\n/***********************************************************/\n\nconst _xyzFields = [ 'x', 'y', 'z' ];\n\nfunction raycastFirst( bvh, root, materialOrSide, ray, near, far ) {\n\n\tBufferStack.setBuffer( bvh._roots[ root ] );\n\n\tlet result = null;\n\tif ( intersectsNodeBounds( 0, BufferStack.float32Array, ray, near, far ) ) {\n\n\t\tresult = _raycastFirst( 0, bvh, materialOrSide, ray, near, far );\n\n\t}\n\n\tBufferStack.clearBuffer();\n\n\treturn result;\n\n}\n\nfunction _raycastFirst( nodeIndex32, bvh, materialOrSide, ray, near, far ) {\n\n\tconst { float32Array, uint16Array, uint32Array } = BufferStack;\n\tlet nodeIndex16 = nodeIndex32 * 2;\n\n\tconst isLeaf = IS_LEAF( nodeIndex16, uint16Array );\n\tif ( isLeaf ) {\n\n\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\n\t\tconst count = COUNT( nodeIndex16, uint16Array );\n\n\n\t\t// eslint-disable-next-line no-unreachable\n\t\treturn intersectClosestTri( bvh, materialOrSide, ray, offset, count, near, far );\n\n\n\t} else {\n\n\t\t// consider the position of the split plane with respect to the oncoming ray; whichever direction\n\t\t// the ray is coming from, look for an intersection among that side of the tree first\n\t\tconst splitAxis = SPLIT_AXIS( nodeIndex32, uint32Array );\n\t\tconst xyzAxis = _xyzFields[ splitAxis ];\n\t\tconst rayDir = ray.direction[ xyzAxis ];\n\t\tconst leftToRight = rayDir >= 0;\n\n\t\t// c1 is the child to check first\n\t\tlet c1, c2;\n\t\tif ( leftToRight ) {\n\n\t\t\tc1 = LEFT_NODE( nodeIndex32 );\n\t\t\tc2 = RIGHT_NODE( nodeIndex32, uint32Array );\n\n\t\t} else {\n\n\t\t\tc1 = RIGHT_NODE( nodeIndex32, uint32Array );\n\t\t\tc2 = LEFT_NODE( nodeIndex32 );\n\n\t\t}\n\n\t\tconst c1Intersection = intersectsNodeBounds( c1, float32Array, ray, near, far );\n\t\tconst c1Result = c1Intersection ? _raycastFirst( c1, bvh, materialOrSide, ray, near, far ) : null;\n\n\t\t// if we got an intersection in the first node and it's closer than the second node's bounding\n\t\t// box, we don't need to consider the second node because it couldn't possibly be a better result\n\t\tif ( c1Result ) {\n\n\t\t\t// check if the point is within the second bounds\n\t\t\t// \"point\" is in the local frame of the bvh\n\t\t\tconst point = c1Result.point[ xyzAxis ];\n\t\t\tconst isOutside = leftToRight ?\n\t\t\t\tpoint <= float32Array[ c2 + splitAxis ] : // min bounding data\n\t\t\t\tpoint >= float32Array[ c2 + splitAxis + 3 ]; // max bounding data\n\n\t\t\tif ( isOutside ) {\n\n\t\t\t\treturn c1Result;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// either there was no intersection in the first node, or there could still be a closer\n\t\t// intersection in the second, so check the second node and then take the better of the two\n\t\tconst c2Intersection = intersectsNodeBounds( c2, float32Array, ray, near, far );\n\t\tconst c2Result = c2Intersection ? _raycastFirst( c2, bvh, materialOrSide, ray, near, far ) : null;\n\n\t\tif ( c1Result && c2Result ) {\n\n\t\t\treturn c1Result.distance <= c2Result.distance ? c1Result : c2Result;\n\n\t\t} else {\n\n\t\t\treturn c1Result || c2Result || null;\n\n\t\t}\n\n\t}\n\n}\n\nexport { raycastFirst };\n","import { Box3, Matrix4 } from 'three';\nimport { OrientedBox } from '../../math/OrientedBox.js';\nimport { ExtendedTriangle } from '../../math/ExtendedTriangle.js';\nimport { setTriangle } from '../../utils/TriangleUtilities.js';\nimport { arrayToBox } from '../../utils/ArrayBoxUtilities.js';\nimport { IS_LEAF, OFFSET, COUNT, BOUNDING_DATA_INDEX, LEFT_NODE, RIGHT_NODE } from '../utils/nodeBufferUtils.js';\nimport { BufferStack } from '../utils/BufferStack.js';\nimport { getTriCount } from '../build/geometryUtils.js';\n\n/*****************************************************************/\n/* This file is generated from \"intersectsGeometry.template.js\". */\n/*****************************************************************/\n/* eslint-disable indent */\n\nconst boundingBox = /* @__PURE__ */ new Box3();\nconst triangle = /* @__PURE__ */ new ExtendedTriangle();\nconst triangle2 = /* @__PURE__ */ new ExtendedTriangle();\nconst invertedMat = /* @__PURE__ */ new Matrix4();\n\nconst obb = /* @__PURE__ */ new OrientedBox();\nconst obb2 = /* @__PURE__ */ new OrientedBox();\n\nfunction intersectsGeometry( bvh, root, otherGeometry, geometryToBvh ) {\n\n\tBufferStack.setBuffer( bvh._roots[ root ] );\n\tconst result = _intersectsGeometry( 0, bvh, otherGeometry, geometryToBvh );\n\tBufferStack.clearBuffer();\n\n\treturn result;\n\n}\n\nfunction _intersectsGeometry( nodeIndex32, bvh, otherGeometry, geometryToBvh, cachedObb = null ) {\n\n\tconst { float32Array, uint16Array, uint32Array } = BufferStack;\n\tlet nodeIndex16 = nodeIndex32 * 2;\n\n\tif ( cachedObb === null ) {\n\n\t\tif ( ! otherGeometry.boundingBox ) {\n\n\t\t\totherGeometry.computeBoundingBox();\n\n\t\t}\n\n\t\tobb.set( otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh );\n\t\tcachedObb = obb;\n\n\t}\n\n\tconst isLeaf = IS_LEAF( nodeIndex16, uint16Array );\n\tif ( isLeaf ) {\n\n\t\tconst thisGeometry = bvh.geometry;\n\t\tconst thisIndex = thisGeometry.index;\n\t\tconst thisPos = thisGeometry.attributes.position;\n\n\t\tconst otherIndex = otherGeometry.index;\n\t\tconst otherPos = otherGeometry.attributes.position;\n\n\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\n\t\tconst count = COUNT( nodeIndex16, uint16Array );\n\n\t\t// get the inverse of the geometry matrix so we can transform our triangles into the\n\t\t// geometry space we're trying to test. We assume there are fewer triangles being checked\n\t\t// here.\n\t\tinvertedMat.copy( geometryToBvh ).invert();\n\n\t\tif ( otherGeometry.boundsTree ) {\n\n\t\t\t// if there's a bounds tree\n\t\t\tarrayToBox( BOUNDING_DATA_INDEX( nodeIndex32 ), float32Array, obb2 );\n\t\t\tobb2.matrix.copy( invertedMat );\n\t\t\tobb2.needsUpdate = true;\n\n\t\t\t// TODO: use a triangle iteration function here\n\t\t\tconst res = otherGeometry.boundsTree.shapecast( {\n\n\t\t\t\tintersectsBounds: box => obb2.intersectsBox( box ),\n\n\t\t\t\tintersectsTriangle: tri => {\n\n\t\t\t\t\ttri.a.applyMatrix4( geometryToBvh );\n\t\t\t\t\ttri.b.applyMatrix4( geometryToBvh );\n\t\t\t\t\ttri.c.applyMatrix4( geometryToBvh );\n\t\t\t\t\ttri.needsUpdate = true;\n\n\n\t\t\t\t\tfor ( let i = offset * 3, l = ( count + offset ) * 3; i < l; i += 3 ) {\n\n\t\t\t\t\t\t// this triangle needs to be transformed into the current BVH coordinate frame\n\t\t\t\t\t\tsetTriangle( triangle2, i, thisIndex, thisPos );\n\t\t\t\t\t\ttriangle2.needsUpdate = true;\n\t\t\t\t\t\tif ( tri.intersectsTriangle( triangle2 ) ) {\n\n\t\t\t\t\t\t\treturn true;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\n\t\t\t\t\treturn false;\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t\treturn res;\n\n\t\t} else {\n\n\t\t\t// if we're just dealing with raw geometry\n\t\t\tconst otherTriangleCount = getTriCount( otherGeometry );\n\n\n\t\t\tfor ( let i = offset * 3, l = ( count + offset ) * 3; i < l; i += 3 ) {\n\n\t\t\t\t// this triangle needs to be transformed into the current BVH coordinate frame\n\t\t\t\tsetTriangle( triangle, i, thisIndex, thisPos );\n\n\n\t\t\t\ttriangle.a.applyMatrix4( invertedMat );\n\t\t\t\ttriangle.b.applyMatrix4( invertedMat );\n\t\t\t\ttriangle.c.applyMatrix4( invertedMat );\n\t\t\t\ttriangle.needsUpdate = true;\n\n\t\t\t\tfor ( let i2 = 0, l2 = otherTriangleCount * 3; i2 < l2; i2 += 3 ) {\n\n\t\t\t\t\tsetTriangle( triangle2, i2, otherIndex, otherPos );\n\t\t\t\t\ttriangle2.needsUpdate = true;\n\n\t\t\t\t\tif ( triangle.intersectsTriangle( triangle2 ) ) {\n\n\t\t\t\t\t\treturn true;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\n\t\t\t}\n\n\n\t\t}\n\n\t} else {\n\n\t\tconst left = LEFT_NODE( nodeIndex32 );\n\t\tconst right = RIGHT_NODE( nodeIndex32, uint32Array );\n\n\t\tarrayToBox( BOUNDING_DATA_INDEX( left ), float32Array, boundingBox );\n\t\tconst leftIntersection =\n\t\t\tcachedObb.intersectsBox( boundingBox ) &&\n\t\t\t_intersectsGeometry( left, bvh, otherGeometry, geometryToBvh, cachedObb );\n\n\t\tif ( leftIntersection ) return true;\n\n\t\tarrayToBox( BOUNDING_DATA_INDEX( right ), float32Array, boundingBox );\n\t\tconst rightIntersection =\n\t\t\tcachedObb.intersectsBox( boundingBox ) &&\n\t\t\t_intersectsGeometry( right, bvh, otherGeometry, geometryToBvh, cachedObb );\n\n\t\tif ( rightIntersection ) return true;\n\n\t\treturn false;\n\n\t}\n\n}\n\nexport { intersectsGeometry };\n","import { Matrix4, Vector3 } from 'three';\nimport { OrientedBox } from '../../math/OrientedBox.js';\nimport { setTriangle } from '../../utils/TriangleUtilities.js';\nimport { getTriCount } from '../build/geometryUtils.js';\nimport { ExtendedTrianglePool } from '../../utils/ExtendedTrianglePool.js';\n\n/*********************************************************************/\n/* This file is generated from \"closestPointToGeometry.template.js\". */\n/*********************************************************************/\n\nconst tempMatrix = /* @__PURE__ */ new Matrix4();\nconst obb = /* @__PURE__ */ new OrientedBox();\nconst obb2 = /* @__PURE__ */ new OrientedBox();\nconst temp1 = /* @__PURE__ */ new Vector3();\nconst temp2 = /* @__PURE__ */ new Vector3();\nconst temp3 = /* @__PURE__ */ new Vector3();\nconst temp4 = /* @__PURE__ */ new Vector3();\n\nfunction closestPointToGeometry(\n\tbvh,\n\totherGeometry,\n\tgeometryToBvh,\n\ttarget1 = { },\n\ttarget2 = { },\n\tminThreshold = 0,\n\tmaxThreshold = Infinity,\n) {\n\n\tif ( ! otherGeometry.boundingBox ) {\n\n\t\totherGeometry.computeBoundingBox();\n\n\t}\n\n\tobb.set( otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh );\n\tobb.needsUpdate = true;\n\n\tconst geometry = bvh.geometry;\n\tconst pos = geometry.attributes.position;\n\tconst index = geometry.index;\n\tconst otherPos = otherGeometry.attributes.position;\n\tconst otherIndex = otherGeometry.index;\n\tconst triangle = ExtendedTrianglePool.getPrimitive();\n\tconst triangle2 = ExtendedTrianglePool.getPrimitive();\n\n\tlet tempTarget1 = temp1;\n\tlet tempTargetDest1 = temp2;\n\tlet tempTarget2 = null;\n\tlet tempTargetDest2 = null;\n\n\tif ( target2 ) {\n\n\t\ttempTarget2 = temp3;\n\t\ttempTargetDest2 = temp4;\n\n\t}\n\n\tlet closestDistance = Infinity;\n\tlet closestDistanceTriIndex = null;\n\tlet closestDistanceOtherTriIndex = null;\n\ttempMatrix.copy( geometryToBvh ).invert();\n\tobb2.matrix.copy( tempMatrix );\n\tbvh.shapecast(\n\t\t{\n\n\t\t\tboundsTraverseOrder: box => {\n\n\t\t\t\treturn obb.distanceToBox( box );\n\n\t\t\t},\n\n\t\t\tintersectsBounds: ( box, isLeaf, score ) => {\n\n\t\t\t\tif ( score < closestDistance && score < maxThreshold ) {\n\n\t\t\t\t\t// if we know the triangles of this bounds will be intersected next then\n\t\t\t\t\t// save the bounds to use during triangle checks.\n\t\t\t\t\tif ( isLeaf ) {\n\n\t\t\t\t\t\tobb2.min.copy( box.min );\n\t\t\t\t\t\tobb2.max.copy( box.max );\n\t\t\t\t\t\tobb2.needsUpdate = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\n\t\t\t},\n\n\t\t\tintersectsRange: ( offset, count ) => {\n\n\t\t\t\tif ( otherGeometry.boundsTree ) {\n\n\t\t\t\t\t// if the other geometry has a bvh then use the accelerated path where we use shapecast to find\n\t\t\t\t\t// the closest bounds in the other geometry to check.\n\t\t\t\t\tconst otherBvh = otherGeometry.boundsTree;\n\t\t\t\t\treturn otherBvh.shapecast( {\n\t\t\t\t\t\tboundsTraverseOrder: box => {\n\n\t\t\t\t\t\t\treturn obb2.distanceToBox( box );\n\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tintersectsBounds: ( box, isLeaf, score ) => {\n\n\t\t\t\t\t\t\treturn score < closestDistance && score < maxThreshold;\n\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tintersectsRange: ( otherOffset, otherCount ) => {\n\n\t\t\t\t\t\t\tfor ( let i2 = otherOffset, l2 = otherOffset + otherCount; i2 < l2; i2 ++ ) {\n\n\n\t\t\t\t\t\t\t\tsetTriangle( triangle2, 3 * i2, otherIndex, otherPos );\n\n\t\t\t\t\t\t\t\ttriangle2.a.applyMatrix4( geometryToBvh );\n\t\t\t\t\t\t\t\ttriangle2.b.applyMatrix4( geometryToBvh );\n\t\t\t\t\t\t\t\ttriangle2.c.applyMatrix4( geometryToBvh );\n\t\t\t\t\t\t\t\ttriangle2.needsUpdate = true;\n\n\t\t\t\t\t\t\t\tfor ( let i = offset, l = offset + count; i < l; i ++ ) {\n\n\n\t\t\t\t\t\t\t\t\tsetTriangle( triangle, 3 * i, index, pos );\n\n\t\t\t\t\t\t\t\t\ttriangle.needsUpdate = true;\n\n\t\t\t\t\t\t\t\t\tconst dist = triangle.distanceToTriangle( triangle2, tempTarget1, tempTarget2 );\n\t\t\t\t\t\t\t\t\tif ( dist < closestDistance ) {\n\n\t\t\t\t\t\t\t\t\t\ttempTargetDest1.copy( tempTarget1 );\n\n\t\t\t\t\t\t\t\t\t\tif ( tempTargetDest2 ) {\n\n\t\t\t\t\t\t\t\t\t\t\ttempTargetDest2.copy( tempTarget2 );\n\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tclosestDistance = dist;\n\t\t\t\t\t\t\t\t\t\tclosestDistanceTriIndex = i;\n\t\t\t\t\t\t\t\t\t\tclosestDistanceOtherTriIndex = i2;\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// stop traversal if we find a point that's under the given threshold\n\t\t\t\t\t\t\t\t\tif ( dist < minThreshold ) {\n\n\t\t\t\t\t\t\t\t\t\treturn true;\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t},\n\t\t\t\t\t} );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// If no bounds tree then we'll just check every triangle.\n\t\t\t\t\tconst triCount = getTriCount( otherGeometry );\n\t\t\t\t\tfor ( let i2 = 0, l2 = triCount; i2 < l2; i2 ++ ) {\n\n\t\t\t\t\t\tsetTriangle( triangle2, 3 * i2, otherIndex, otherPos );\n\t\t\t\t\t\ttriangle2.a.applyMatrix4( geometryToBvh );\n\t\t\t\t\t\ttriangle2.b.applyMatrix4( geometryToBvh );\n\t\t\t\t\t\ttriangle2.c.applyMatrix4( geometryToBvh );\n\t\t\t\t\t\ttriangle2.needsUpdate = true;\n\n\t\t\t\t\t\tfor ( let i = offset, l = offset + count; i < l; i ++ ) {\n\n\n\t\t\t\t\t\t\tsetTriangle( triangle, 3 * i, index, pos );\n\n\t\t\t\t\t\t\ttriangle.needsUpdate = true;\n\n\t\t\t\t\t\t\tconst dist = triangle.distanceToTriangle( triangle2, tempTarget1, tempTarget2 );\n\t\t\t\t\t\t\tif ( dist < closestDistance ) {\n\n\t\t\t\t\t\t\t\ttempTargetDest1.copy( tempTarget1 );\n\n\t\t\t\t\t\t\t\tif ( tempTargetDest2 ) {\n\n\t\t\t\t\t\t\t\t\ttempTargetDest2.copy( tempTarget2 );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tclosestDistance = dist;\n\t\t\t\t\t\t\t\tclosestDistanceTriIndex = i;\n\t\t\t\t\t\t\t\tclosestDistanceOtherTriIndex = i2;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// stop traversal if we find a point that's under the given threshold\n\t\t\t\t\t\t\tif ( dist < minThreshold ) {\n\n\t\t\t\t\t\t\t\treturn true;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t}\n\n\t);\n\n\tExtendedTrianglePool.releasePrimitive( triangle );\n\tExtendedTrianglePool.releasePrimitive( triangle2 );\n\n\tif ( closestDistance === Infinity ) {\n\n\t\treturn null;\n\n\t}\n\n\tif ( ! target1.point ) {\n\n\t\ttarget1.point = tempTargetDest1.clone();\n\n\t} else {\n\n\t\ttarget1.point.copy( tempTargetDest1 );\n\n\t}\n\n\ttarget1.distance = closestDistance,\n\ttarget1.faceIndex = closestDistanceTriIndex;\n\n\tif ( target2 ) {\n\n\t\tif ( ! target2.point ) target2.point = tempTargetDest2.clone();\n\t\telse target2.point.copy( tempTargetDest2 );\n\t\ttarget2.point.applyMatrix4( tempMatrix );\n\t\ttempTargetDest1.applyMatrix4( tempMatrix );\n\t\ttarget2.distance = tempTargetDest1.sub( target2.point ).length();\n\t\ttarget2.faceIndex = closestDistanceOtherTriIndex;\n\n\t}\n\n\treturn target1;\n\n}\n\nexport { closestPointToGeometry };\n","import { UINT32_PER_NODE, BYTES_PER_NODE } from '../Constants.js';\nimport { IS_LEAF, OFFSET, COUNT, LEFT_NODE, RIGHT_NODE } from '../utils/nodeBufferUtils.js';\n\n/****************************************************/\n/* This file is generated from \"refit.template.js\". */\n/****************************************************/\n\nfunction refit_indirect( bvh, nodeIndices = null ) {\n\n\tif ( nodeIndices && Array.isArray( nodeIndices ) ) {\n\n\t\tnodeIndices = new Set( nodeIndices );\n\n\t}\n\n\tconst geometry = bvh.geometry;\n\tconst indexArr = geometry.index ? geometry.index.array : null;\n\tconst posAttr = geometry.attributes.position;\n\n\tlet buffer, uint32Array, uint16Array, float32Array;\n\tlet byteOffset = 0;\n\tconst roots = bvh._roots;\n\tfor ( let i = 0, l = roots.length; i < l; i ++ ) {\n\n\t\tbuffer = roots[ i ];\n\t\tuint32Array = new Uint32Array( buffer );\n\t\tuint16Array = new Uint16Array( buffer );\n\t\tfloat32Array = new Float32Array( buffer );\n\n\t\t_traverse( 0, byteOffset );\n\t\tbyteOffset += buffer.byteLength;\n\n\t}\n\n\tfunction _traverse( nodeIndex32, byteOffset, force = false ) {\n\n\t\tconst nodeIndex16 = nodeIndex32 * 2;\n\t\tif ( IS_LEAF( nodeIndex16, uint16Array ) ) {\n\n\t\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\n\t\t\tconst count = COUNT( nodeIndex16, uint16Array );\n\n\t\t\tlet minx = Infinity;\n\t\t\tlet miny = Infinity;\n\t\t\tlet minz = Infinity;\n\t\t\tlet maxx = - Infinity;\n\t\t\tlet maxy = - Infinity;\n\t\t\tlet maxz = - Infinity;\n\n\t\t\tfor ( let i = offset, l = offset + count; i < l; i ++ ) {\n\n\t\t\t\tconst t = 3 * bvh.resolveTriangleIndex( i );\n\t\t\t\tfor ( let j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\tlet index = t + j;\n\t\t\t\t\tindex = indexArr ? indexArr[ index ] : index;\n\n\t\t\t\t\tconst x = posAttr.getX( index );\n\t\t\t\t\tconst y = posAttr.getY( index );\n\t\t\t\t\tconst z = posAttr.getZ( index );\n\n\t\t\t\t\tif ( x < minx ) minx = x;\n\t\t\t\t\tif ( x > maxx ) maxx = x;\n\n\t\t\t\t\tif ( y < miny ) miny = y;\n\t\t\t\t\tif ( y > maxy ) maxy = y;\n\n\t\t\t\t\tif ( z < minz ) minz = z;\n\t\t\t\t\tif ( z > maxz ) maxz = z;\n\n\n\t\t\t\t}\n\n\t\t\t}\n\n\n\t\t\tif (\n\t\t\t\tfloat32Array[ nodeIndex32 + 0 ] !== minx ||\n\t\t\t\tfloat32Array[ nodeIndex32 + 1 ] !== miny ||\n\t\t\t\tfloat32Array[ nodeIndex32 + 2 ] !== minz ||\n\n\t\t\t\tfloat32Array[ nodeIndex32 + 3 ] !== maxx ||\n\t\t\t\tfloat32Array[ nodeIndex32 + 4 ] !== maxy ||\n\t\t\t\tfloat32Array[ nodeIndex32 + 5 ] !== maxz\n\t\t\t) {\n\n\t\t\t\tfloat32Array[ nodeIndex32 + 0 ] = minx;\n\t\t\t\tfloat32Array[ nodeIndex32 + 1 ] = miny;\n\t\t\t\tfloat32Array[ nodeIndex32 + 2 ] = minz;\n\n\t\t\t\tfloat32Array[ nodeIndex32 + 3 ] = maxx;\n\t\t\t\tfloat32Array[ nodeIndex32 + 4 ] = maxy;\n\t\t\t\tfloat32Array[ nodeIndex32 + 5 ] = maxz;\n\n\t\t\t\treturn true;\n\n\t\t\t} else {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconst left = LEFT_NODE( nodeIndex32 );\n\t\t\tconst right = RIGHT_NODE( nodeIndex32, uint32Array );\n\n\t\t\t// the identifying node indices provided by the shapecast function include offsets of all\n\t\t\t// root buffers to guarantee they're unique between roots so offset left and right indices here.\n\t\t\tlet forceChildren = force;\n\t\t\tlet includesLeft = false;\n\t\t\tlet includesRight = false;\n\n\t\t\tif ( nodeIndices ) {\n\n\t\t\t\t// if we see that neither the left or right child are included in the set that need to be updated\n\t\t\t\t// then we assume that all children need to be updated.\n\t\t\t\tif ( ! forceChildren ) {\n\n\t\t\t\t\tconst leftNodeId = left / UINT32_PER_NODE + byteOffset / BYTES_PER_NODE;\n\t\t\t\t\tconst rightNodeId = right / UINT32_PER_NODE + byteOffset / BYTES_PER_NODE;\n\t\t\t\t\tincludesLeft = nodeIndices.has( leftNodeId );\n\t\t\t\t\tincludesRight = nodeIndices.has( rightNodeId );\n\t\t\t\t\tforceChildren = ! includesLeft && ! includesRight;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tincludesLeft = true;\n\t\t\t\tincludesRight = true;\n\n\t\t\t}\n\n\t\t\tconst traverseLeft = forceChildren || includesLeft;\n\t\t\tconst traverseRight = forceChildren || includesRight;\n\n\t\t\tlet leftChange = false;\n\t\t\tif ( traverseLeft ) {\n\n\t\t\t\tleftChange = _traverse( left, byteOffset, forceChildren );\n\n\t\t\t}\n\n\t\t\tlet rightChange = false;\n\t\t\tif ( traverseRight ) {\n\n\t\t\t\trightChange = _traverse( right, byteOffset, forceChildren );\n\n\t\t\t}\n\n\t\t\tconst didChange = leftChange || rightChange;\n\t\t\tif ( didChange ) {\n\n\t\t\t\tfor ( let i = 0; i < 3; i ++ ) {\n\n\t\t\t\t\tconst left_i = left + i;\n\t\t\t\t\tconst right_i = right + i;\n\t\t\t\t\tconst minLeftValue = float32Array[ left_i ];\n\t\t\t\t\tconst maxLeftValue = float32Array[ left_i + 3 ];\n\t\t\t\t\tconst minRightValue = float32Array[ right_i ];\n\t\t\t\t\tconst maxRightValue = float32Array[ right_i + 3 ];\n\n\t\t\t\t\tfloat32Array[ nodeIndex32 + i ] = minLeftValue < minRightValue ? minLeftValue : minRightValue;\n\t\t\t\t\tfloat32Array[ nodeIndex32 + i + 3 ] = maxLeftValue > maxRightValue ? maxLeftValue : maxRightValue;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn didChange;\n\n\t\t}\n\n\t}\n\n}\n\nexport { refit_indirect };\n","import { intersectsNodeBounds } from '../utils/intersectUtils.js';\nimport { IS_LEAF, OFFSET, COUNT, LEFT_NODE, RIGHT_NODE } from '../utils/nodeBufferUtils.js';\nimport { BufferStack } from '../utils/BufferStack.js';\nimport '../utils/iterationUtils.generated.js';\nimport { intersectTris_indirect } from '../utils/iterationUtils_indirect.generated.js';\n\n/******************************************************/\n/* This file is generated from \"raycast.template.js\". */\n/******************************************************/\n\nfunction raycast_indirect( bvh, root, materialOrSide, ray, intersects, near, far ) {\n\n\tBufferStack.setBuffer( bvh._roots[ root ] );\n\tif ( intersectsNodeBounds( 0, BufferStack.float32Array, ray, near, far ) ) {\n\n\t\t_raycast( 0, bvh, materialOrSide, ray, intersects, near, far );\n\n\t}\n\n\tBufferStack.clearBuffer();\n\n}\n\nfunction _raycast( nodeIndex32, bvh, materialOrSide, ray, intersects, near, far ) {\n\n\tconst { float32Array, uint16Array, uint32Array } = BufferStack;\n\tconst nodeIndex16 = nodeIndex32 * 2;\n\tconst isLeaf = IS_LEAF( nodeIndex16, uint16Array );\n\tif ( isLeaf ) {\n\n\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\n\t\tconst count = COUNT( nodeIndex16, uint16Array );\n\n\t\tintersectTris_indirect( bvh, materialOrSide, ray, offset, count, intersects, near, far );\n\n\n\t} else {\n\n\t\tconst leftIndex = LEFT_NODE( nodeIndex32 );\n\t\tif ( intersectsNodeBounds( leftIndex, float32Array, ray, near, far ) ) {\n\n\t\t\t_raycast( leftIndex, bvh, materialOrSide, ray, intersects, near, far );\n\n\t\t}\n\n\t\tconst rightIndex = RIGHT_NODE( nodeIndex32, uint32Array );\n\t\tif ( intersectsNodeBounds( rightIndex, float32Array, ray, near, far ) ) {\n\n\t\t\t_raycast( rightIndex, bvh, materialOrSide, ray, intersects, near, far );\n\n\t\t}\n\n\t}\n\n}\n\nexport { raycast_indirect };\n","import { IS_LEAF, OFFSET, COUNT, SPLIT_AXIS, LEFT_NODE, RIGHT_NODE } from '../utils/nodeBufferUtils.js';\nimport { BufferStack } from '../utils/BufferStack.js';\nimport { intersectsNodeBounds } from '../utils/intersectUtils.js';\nimport '../utils/iterationUtils.generated.js';\nimport { intersectClosestTri_indirect } from '../utils/iterationUtils_indirect.generated.js';\n\n/***********************************************************/\n/* This file is generated from \"raycastFirst.template.js\". */\n/***********************************************************/\n\nconst _xyzFields = [ 'x', 'y', 'z' ];\n\nfunction raycastFirst_indirect( bvh, root, materialOrSide, ray, near, far ) {\n\n\tBufferStack.setBuffer( bvh._roots[ root ] );\n\n\tlet result = null;\n\tif ( intersectsNodeBounds( 0, BufferStack.float32Array, ray, near, far ) ) {\n\n\t\tresult = _raycastFirst( 0, bvh, materialOrSide, ray, near, far );\n\n\t}\n\n\tBufferStack.clearBuffer();\n\n\treturn result;\n\n}\n\nfunction _raycastFirst( nodeIndex32, bvh, materialOrSide, ray, near, far ) {\n\n\tconst { float32Array, uint16Array, uint32Array } = BufferStack;\n\tlet nodeIndex16 = nodeIndex32 * 2;\n\n\tconst isLeaf = IS_LEAF( nodeIndex16, uint16Array );\n\tif ( isLeaf ) {\n\n\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\n\t\tconst count = COUNT( nodeIndex16, uint16Array );\n\n\t\treturn intersectClosestTri_indirect( bvh, materialOrSide, ray, offset, count, near, far );\n\n\n\t} else {\n\n\t\t// consider the position of the split plane with respect to the oncoming ray; whichever direction\n\t\t// the ray is coming from, look for an intersection among that side of the tree first\n\t\tconst splitAxis = SPLIT_AXIS( nodeIndex32, uint32Array );\n\t\tconst xyzAxis = _xyzFields[ splitAxis ];\n\t\tconst rayDir = ray.direction[ xyzAxis ];\n\t\tconst leftToRight = rayDir >= 0;\n\n\t\t// c1 is the child to check first\n\t\tlet c1, c2;\n\t\tif ( leftToRight ) {\n\n\t\t\tc1 = LEFT_NODE( nodeIndex32 );\n\t\t\tc2 = RIGHT_NODE( nodeIndex32, uint32Array );\n\n\t\t} else {\n\n\t\t\tc1 = RIGHT_NODE( nodeIndex32, uint32Array );\n\t\t\tc2 = LEFT_NODE( nodeIndex32 );\n\n\t\t}\n\n\t\tconst c1Intersection = intersectsNodeBounds( c1, float32Array, ray, near, far );\n\t\tconst c1Result = c1Intersection ? _raycastFirst( c1, bvh, materialOrSide, ray, near, far ) : null;\n\n\t\t// if we got an intersection in the first node and it's closer than the second node's bounding\n\t\t// box, we don't need to consider the second node because it couldn't possibly be a better result\n\t\tif ( c1Result ) {\n\n\t\t\t// check if the point is within the second bounds\n\t\t\t// \"point\" is in the local frame of the bvh\n\t\t\tconst point = c1Result.point[ xyzAxis ];\n\t\t\tconst isOutside = leftToRight ?\n\t\t\t\tpoint <= float32Array[ c2 + splitAxis ] : // min bounding data\n\t\t\t\tpoint >= float32Array[ c2 + splitAxis + 3 ]; // max bounding data\n\n\t\t\tif ( isOutside ) {\n\n\t\t\t\treturn c1Result;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// either there was no intersection in the first node, or there could still be a closer\n\t\t// intersection in the second, so check the second node and then take the better of the two\n\t\tconst c2Intersection = intersectsNodeBounds( c2, float32Array, ray, near, far );\n\t\tconst c2Result = c2Intersection ? _raycastFirst( c2, bvh, materialOrSide, ray, near, far ) : null;\n\n\t\tif ( c1Result && c2Result ) {\n\n\t\t\treturn c1Result.distance <= c2Result.distance ? c1Result : c2Result;\n\n\t\t} else {\n\n\t\t\treturn c1Result || c2Result || null;\n\n\t\t}\n\n\t}\n\n}\n\nexport { raycastFirst_indirect };\n","import { Box3, Matrix4 } from 'three';\nimport { OrientedBox } from '../../math/OrientedBox.js';\nimport { ExtendedTriangle } from '../../math/ExtendedTriangle.js';\nimport { setTriangle } from '../../utils/TriangleUtilities.js';\nimport { arrayToBox } from '../../utils/ArrayBoxUtilities.js';\nimport { IS_LEAF, OFFSET, COUNT, BOUNDING_DATA_INDEX, LEFT_NODE, RIGHT_NODE } from '../utils/nodeBufferUtils.js';\nimport { BufferStack } from '../utils/BufferStack.js';\nimport { getTriCount } from '../build/geometryUtils.js';\n\n/*****************************************************************/\n/* This file is generated from \"intersectsGeometry.template.js\". */\n/*****************************************************************/\n/* eslint-disable indent */\n\nconst boundingBox = /* @__PURE__ */ new Box3();\nconst triangle = /* @__PURE__ */ new ExtendedTriangle();\nconst triangle2 = /* @__PURE__ */ new ExtendedTriangle();\nconst invertedMat = /* @__PURE__ */ new Matrix4();\n\nconst obb = /* @__PURE__ */ new OrientedBox();\nconst obb2 = /* @__PURE__ */ new OrientedBox();\n\nfunction intersectsGeometry_indirect( bvh, root, otherGeometry, geometryToBvh ) {\n\n\tBufferStack.setBuffer( bvh._roots[ root ] );\n\tconst result = _intersectsGeometry( 0, bvh, otherGeometry, geometryToBvh );\n\tBufferStack.clearBuffer();\n\n\treturn result;\n\n}\n\nfunction _intersectsGeometry( nodeIndex32, bvh, otherGeometry, geometryToBvh, cachedObb = null ) {\n\n\tconst { float32Array, uint16Array, uint32Array } = BufferStack;\n\tlet nodeIndex16 = nodeIndex32 * 2;\n\n\tif ( cachedObb === null ) {\n\n\t\tif ( ! otherGeometry.boundingBox ) {\n\n\t\t\totherGeometry.computeBoundingBox();\n\n\t\t}\n\n\t\tobb.set( otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh );\n\t\tcachedObb = obb;\n\n\t}\n\n\tconst isLeaf = IS_LEAF( nodeIndex16, uint16Array );\n\tif ( isLeaf ) {\n\n\t\tconst thisGeometry = bvh.geometry;\n\t\tconst thisIndex = thisGeometry.index;\n\t\tconst thisPos = thisGeometry.attributes.position;\n\n\t\tconst otherIndex = otherGeometry.index;\n\t\tconst otherPos = otherGeometry.attributes.position;\n\n\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\n\t\tconst count = COUNT( nodeIndex16, uint16Array );\n\n\t\t// get the inverse of the geometry matrix so we can transform our triangles into the\n\t\t// geometry space we're trying to test. We assume there are fewer triangles being checked\n\t\t// here.\n\t\tinvertedMat.copy( geometryToBvh ).invert();\n\n\t\tif ( otherGeometry.boundsTree ) {\n\n\t\t\t// if there's a bounds tree\n\t\t\tarrayToBox( BOUNDING_DATA_INDEX( nodeIndex32 ), float32Array, obb2 );\n\t\t\tobb2.matrix.copy( invertedMat );\n\t\t\tobb2.needsUpdate = true;\n\n\t\t\t// TODO: use a triangle iteration function here\n\t\t\tconst res = otherGeometry.boundsTree.shapecast( {\n\n\t\t\t\tintersectsBounds: box => obb2.intersectsBox( box ),\n\n\t\t\t\tintersectsTriangle: tri => {\n\n\t\t\t\t\ttri.a.applyMatrix4( geometryToBvh );\n\t\t\t\t\ttri.b.applyMatrix4( geometryToBvh );\n\t\t\t\t\ttri.c.applyMatrix4( geometryToBvh );\n\t\t\t\t\ttri.needsUpdate = true;\n\n\t\t\t\t\tfor ( let i = offset, l = count + offset; i < l; i ++ ) {\n\n\t\t\t\t\t\t// this triangle needs to be transformed into the current BVH coordinate frame\n\t\t\t\t\t\tsetTriangle( triangle2, 3 * bvh.resolveTriangleIndex( i ), thisIndex, thisPos );\n\t\t\t\t\t\ttriangle2.needsUpdate = true;\n\t\t\t\t\t\tif ( tri.intersectsTriangle( triangle2 ) ) {\n\n\t\t\t\t\t\t\treturn true;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\n\t\t\t\t\treturn false;\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t\treturn res;\n\n\t\t} else {\n\n\t\t\t// if we're just dealing with raw geometry\n\t\t\tconst otherTriangleCount = getTriCount( otherGeometry );\n\n\t\t\tfor ( let i = offset, l = count + offset; i < l; i ++ ) {\n\n\t\t\t\t// this triangle needs to be transformed into the current BVH coordinate frame\n\t\t\t\tconst ti = bvh.resolveTriangleIndex( i );\n\t\t\t\tsetTriangle( triangle, 3 * ti, thisIndex, thisPos );\n\n\n\t\t\t\ttriangle.a.applyMatrix4( invertedMat );\n\t\t\t\ttriangle.b.applyMatrix4( invertedMat );\n\t\t\t\ttriangle.c.applyMatrix4( invertedMat );\n\t\t\t\ttriangle.needsUpdate = true;\n\n\t\t\t\tfor ( let i2 = 0, l2 = otherTriangleCount * 3; i2 < l2; i2 += 3 ) {\n\n\t\t\t\t\tsetTriangle( triangle2, i2, otherIndex, otherPos );\n\t\t\t\t\ttriangle2.needsUpdate = true;\n\n\t\t\t\t\tif ( triangle.intersectsTriangle( triangle2 ) ) {\n\n\t\t\t\t\t\treturn true;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\n\t\t}\n\n\t} else {\n\n\t\tconst left = LEFT_NODE( nodeIndex32 );\n\t\tconst right = RIGHT_NODE( nodeIndex32, uint32Array );\n\n\t\tarrayToBox( BOUNDING_DATA_INDEX( left ), float32Array, boundingBox );\n\t\tconst leftIntersection =\n\t\t\tcachedObb.intersectsBox( boundingBox ) &&\n\t\t\t_intersectsGeometry( left, bvh, otherGeometry, geometryToBvh, cachedObb );\n\n\t\tif ( leftIntersection ) return true;\n\n\t\tarrayToBox( BOUNDING_DATA_INDEX( right ), float32Array, boundingBox );\n\t\tconst rightIntersection =\n\t\t\tcachedObb.intersectsBox( boundingBox ) &&\n\t\t\t_intersectsGeometry( right, bvh, otherGeometry, geometryToBvh, cachedObb );\n\n\t\tif ( rightIntersection ) return true;\n\n\t\treturn false;\n\n\t}\n\n}\n\nexport { intersectsGeometry_indirect };\n","import { Matrix4, Vector3 } from 'three';\nimport { OrientedBox } from '../../math/OrientedBox.js';\nimport { setTriangle } from '../../utils/TriangleUtilities.js';\nimport { getTriCount } from '../build/geometryUtils.js';\nimport { ExtendedTrianglePool } from '../../utils/ExtendedTrianglePool.js';\n\n/*********************************************************************/\n/* This file is generated from \"closestPointToGeometry.template.js\". */\n/*********************************************************************/\n\nconst tempMatrix = /* @__PURE__ */ new Matrix4();\nconst obb = /* @__PURE__ */ new OrientedBox();\nconst obb2 = /* @__PURE__ */ new OrientedBox();\nconst temp1 = /* @__PURE__ */ new Vector3();\nconst temp2 = /* @__PURE__ */ new Vector3();\nconst temp3 = /* @__PURE__ */ new Vector3();\nconst temp4 = /* @__PURE__ */ new Vector3();\n\nfunction closestPointToGeometry_indirect(\n\tbvh,\n\totherGeometry,\n\tgeometryToBvh,\n\ttarget1 = { },\n\ttarget2 = { },\n\tminThreshold = 0,\n\tmaxThreshold = Infinity,\n) {\n\n\tif ( ! otherGeometry.boundingBox ) {\n\n\t\totherGeometry.computeBoundingBox();\n\n\t}\n\n\tobb.set( otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh );\n\tobb.needsUpdate = true;\n\n\tconst geometry = bvh.geometry;\n\tconst pos = geometry.attributes.position;\n\tconst index = geometry.index;\n\tconst otherPos = otherGeometry.attributes.position;\n\tconst otherIndex = otherGeometry.index;\n\tconst triangle = ExtendedTrianglePool.getPrimitive();\n\tconst triangle2 = ExtendedTrianglePool.getPrimitive();\n\n\tlet tempTarget1 = temp1;\n\tlet tempTargetDest1 = temp2;\n\tlet tempTarget2 = null;\n\tlet tempTargetDest2 = null;\n\n\tif ( target2 ) {\n\n\t\ttempTarget2 = temp3;\n\t\ttempTargetDest2 = temp4;\n\n\t}\n\n\tlet closestDistance = Infinity;\n\tlet closestDistanceTriIndex = null;\n\tlet closestDistanceOtherTriIndex = null;\n\ttempMatrix.copy( geometryToBvh ).invert();\n\tobb2.matrix.copy( tempMatrix );\n\tbvh.shapecast(\n\t\t{\n\n\t\t\tboundsTraverseOrder: box => {\n\n\t\t\t\treturn obb.distanceToBox( box );\n\n\t\t\t},\n\n\t\t\tintersectsBounds: ( box, isLeaf, score ) => {\n\n\t\t\t\tif ( score < closestDistance && score < maxThreshold ) {\n\n\t\t\t\t\t// if we know the triangles of this bounds will be intersected next then\n\t\t\t\t\t// save the bounds to use during triangle checks.\n\t\t\t\t\tif ( isLeaf ) {\n\n\t\t\t\t\t\tobb2.min.copy( box.min );\n\t\t\t\t\t\tobb2.max.copy( box.max );\n\t\t\t\t\t\tobb2.needsUpdate = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\n\t\t\t},\n\n\t\t\tintersectsRange: ( offset, count ) => {\n\n\t\t\t\tif ( otherGeometry.boundsTree ) {\n\n\t\t\t\t\t// if the other geometry has a bvh then use the accelerated path where we use shapecast to find\n\t\t\t\t\t// the closest bounds in the other geometry to check.\n\t\t\t\t\tconst otherBvh = otherGeometry.boundsTree;\n\t\t\t\t\treturn otherBvh.shapecast( {\n\t\t\t\t\t\tboundsTraverseOrder: box => {\n\n\t\t\t\t\t\t\treturn obb2.distanceToBox( box );\n\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tintersectsBounds: ( box, isLeaf, score ) => {\n\n\t\t\t\t\t\t\treturn score < closestDistance && score < maxThreshold;\n\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tintersectsRange: ( otherOffset, otherCount ) => {\n\n\t\t\t\t\t\t\tfor ( let i2 = otherOffset, l2 = otherOffset + otherCount; i2 < l2; i2 ++ ) {\n\n\t\t\t\t\t\t\t\tconst ti2 = otherBvh.resolveTriangleIndex( i2 );\n\t\t\t\t\t\t\t\tsetTriangle( triangle2, 3 * ti2, otherIndex, otherPos );\n\n\t\t\t\t\t\t\t\ttriangle2.a.applyMatrix4( geometryToBvh );\n\t\t\t\t\t\t\t\ttriangle2.b.applyMatrix4( geometryToBvh );\n\t\t\t\t\t\t\t\ttriangle2.c.applyMatrix4( geometryToBvh );\n\t\t\t\t\t\t\t\ttriangle2.needsUpdate = true;\n\n\t\t\t\t\t\t\t\tfor ( let i = offset, l = offset + count; i < l; i ++ ) {\n\n\t\t\t\t\t\t\t\t\tconst ti = bvh.resolveTriangleIndex( i );\n\t\t\t\t\t\t\t\t\tsetTriangle( triangle, 3 * ti, index, pos );\n\n\t\t\t\t\t\t\t\t\ttriangle.needsUpdate = true;\n\n\t\t\t\t\t\t\t\t\tconst dist = triangle.distanceToTriangle( triangle2, tempTarget1, tempTarget2 );\n\t\t\t\t\t\t\t\t\tif ( dist < closestDistance ) {\n\n\t\t\t\t\t\t\t\t\t\ttempTargetDest1.copy( tempTarget1 );\n\n\t\t\t\t\t\t\t\t\t\tif ( tempTargetDest2 ) {\n\n\t\t\t\t\t\t\t\t\t\t\ttempTargetDest2.copy( tempTarget2 );\n\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tclosestDistance = dist;\n\t\t\t\t\t\t\t\t\t\tclosestDistanceTriIndex = i;\n\t\t\t\t\t\t\t\t\t\tclosestDistanceOtherTriIndex = i2;\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// stop traversal if we find a point that's under the given threshold\n\t\t\t\t\t\t\t\t\tif ( dist < minThreshold ) {\n\n\t\t\t\t\t\t\t\t\t\treturn true;\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t},\n\t\t\t\t\t} );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// If no bounds tree then we'll just check every triangle.\n\t\t\t\t\tconst triCount = getTriCount( otherGeometry );\n\t\t\t\t\tfor ( let i2 = 0, l2 = triCount; i2 < l2; i2 ++ ) {\n\n\t\t\t\t\t\tsetTriangle( triangle2, 3 * i2, otherIndex, otherPos );\n\t\t\t\t\t\ttriangle2.a.applyMatrix4( geometryToBvh );\n\t\t\t\t\t\ttriangle2.b.applyMatrix4( geometryToBvh );\n\t\t\t\t\t\ttriangle2.c.applyMatrix4( geometryToBvh );\n\t\t\t\t\t\ttriangle2.needsUpdate = true;\n\n\t\t\t\t\t\tfor ( let i = offset, l = offset + count; i < l; i ++ ) {\n\n\t\t\t\t\t\t\tconst ti = bvh.resolveTriangleIndex( i );\n\t\t\t\t\t\t\tsetTriangle( triangle, 3 * ti, index, pos );\n\n\t\t\t\t\t\t\ttriangle.needsUpdate = true;\n\n\t\t\t\t\t\t\tconst dist = triangle.distanceToTriangle( triangle2, tempTarget1, tempTarget2 );\n\t\t\t\t\t\t\tif ( dist < closestDistance ) {\n\n\t\t\t\t\t\t\t\ttempTargetDest1.copy( tempTarget1 );\n\n\t\t\t\t\t\t\t\tif ( tempTargetDest2 ) {\n\n\t\t\t\t\t\t\t\t\ttempTargetDest2.copy( tempTarget2 );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tclosestDistance = dist;\n\t\t\t\t\t\t\t\tclosestDistanceTriIndex = i;\n\t\t\t\t\t\t\t\tclosestDistanceOtherTriIndex = i2;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// stop traversal if we find a point that's under the given threshold\n\t\t\t\t\t\t\tif ( dist < minThreshold ) {\n\n\t\t\t\t\t\t\t\treturn true;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t}\n\n\t);\n\n\tExtendedTrianglePool.releasePrimitive( triangle );\n\tExtendedTrianglePool.releasePrimitive( triangle2 );\n\n\tif ( closestDistance === Infinity ) {\n\n\t\treturn null;\n\n\t}\n\n\tif ( ! target1.point ) {\n\n\t\ttarget1.point = tempTargetDest1.clone();\n\n\t} else {\n\n\t\ttarget1.point.copy( tempTargetDest1 );\n\n\t}\n\n\ttarget1.distance = closestDistance,\n\ttarget1.faceIndex = closestDistanceTriIndex;\n\n\tif ( target2 ) {\n\n\t\tif ( ! target2.point ) target2.point = tempTargetDest2.clone();\n\t\telse target2.point.copy( tempTargetDest2 );\n\t\ttarget2.point.applyMatrix4( tempMatrix );\n\t\ttempTargetDest1.applyMatrix4( tempMatrix );\n\t\ttarget2.distance = tempTargetDest1.sub( target2.point ).length();\n\t\ttarget2.faceIndex = closestDistanceOtherTriIndex;\n\n\t}\n\n\treturn target1;\n\n}\n\nexport { closestPointToGeometry_indirect };\n","// converts the given BVH raycast intersection to align with the three.js raycast\n// structure (include object, world space distance and point).\nexport function convertRaycastIntersect( hit, object, raycaster ) {\n\n\tif ( hit === null ) {\n\n\t\treturn null;\n\n\t}\n\n\thit.point.applyMatrix4( object.matrixWorld );\n\thit.distance = hit.point.distanceTo( raycaster.ray.origin );\n\thit.object = object;\n\n\treturn hit;\n\n}\n","/** @import { BufferGeometry, Sphere, Box3, Intersection, Material, Object3D, Raycaster } from 'three' */\n/** @import { ExtendedTriangle } from '../math/ExtendedTriangle.js' */\n/** @import { IntersectsBoundsCallback, IntersectsRangeCallback, BoundsTraverseOrderCallback, IntersectsRangesCallback } from './BVH.js' */\nimport { BufferAttribute, FrontSide, Ray, Vector3, Matrix4 } from 'three';\nimport { SKIP_GENERATION, BYTES_PER_NODE, UINT32_PER_NODE, FLOAT32_EPSILON } from './Constants.js';\nimport { OrientedBox } from '../math/OrientedBox.js';\nimport { ExtendedTrianglePool } from '../utils/ExtendedTrianglePool.js';\nimport { closestPointToPoint } from './cast/closestPointToPoint.js';\nimport { IS_LEAF } from './utils/nodeBufferUtils.js';\n\nimport { iterateOverTriangles } from './utils/iterationUtils.generated.js';\nimport { refit } from './cast/refit.generated.js';\nimport { raycast } from './cast/raycast.generated.js';\nimport { raycastFirst } from './cast/raycastFirst.generated.js';\nimport { intersectsGeometry } from './cast/intersectsGeometry.generated.js';\nimport { closestPointToGeometry } from './cast/closestPointToGeometry.generated.js';\n\nimport { iterateOverTriangles_indirect } from './utils/iterationUtils_indirect.generated.js';\nimport { refit_indirect } from './cast/refit_indirect.generated.js';\nimport { raycast_indirect } from './cast/raycast_indirect.generated.js';\nimport { raycastFirst_indirect } from './cast/raycastFirst_indirect.generated.js';\nimport { intersectsGeometry_indirect } from './cast/intersectsGeometry_indirect.generated.js';\nimport { closestPointToGeometry_indirect } from './cast/closestPointToGeometry_indirect.generated.js';\nimport { setTriangle } from '../utils/TriangleUtilities.js';\nimport { convertRaycastIntersect } from '../utils/GeometryRayIntersectUtilities.js';\nimport { GeometryBVH } from './GeometryBVH.js';\n\nconst _obb = /* @__PURE__ */ new OrientedBox();\nconst _ray = /* @__PURE__ */ new Ray();\nconst _direction = /* @__PURE__ */ new Vector3();\nconst _inverseMatrix = /* @__PURE__ */ new Matrix4();\nconst _worldScale = /* @__PURE__ */ new Vector3();\nconst _getters = [ 'getX', 'getY', 'getZ' ];\n\n/**\n * @callback IntersectsTriangleCallback\n * @param {ExtendedTriangle} triangle - The triangle primitive in local space.\n * @param {number} triangleIndex - The index of the triangle in the geometry.\n * @param {boolean} contained - Whether the node bounds are fully contained by the query shape.\n * @param {number} depth - The depth of the node in the tree.\n * @returns {boolean} Return `true` to stop traversal.\n */\n\n/**\n * @callback IntersectsTrianglesCallback\n * @param {ExtendedTriangle} triangle1 - Triangle from this BVH in local space.\n * @param {ExtendedTriangle} triangle2 - Triangle from `otherBvh`, transformed into local space.\n * @param {number} triangleIndex1 - Triangle index in the first geometry.\n * @param {number} triangleIndex2 - Triangle index in the second geometry.\n * @param {number} depth1 - Depth of the node in the first BVH.\n * @param {number} nodeIndex1 - Node index in the first BVH.\n * @param {number} depth2 - Depth of the node in the second BVH.\n * @param {number} nodeIndex2 - Node index in the second BVH.\n * @returns {boolean} Return `true` to stop traversal.\n */\n\n/**\n * Plain-object representation of a `MeshBVH` produced by `MeshBVH.serialize` and\n * consumed by `MeshBVH.deserialize`. Suitable for transfer across WebWorker boundaries\n * or storage, with optional buffer sharing via `SharedArrayBuffer`.\n *\n * @typedef {Object} SerializedBVH\n * @property {Array<ArrayBuffer>} roots - BVH root node buffers.\n * @property {Int32Array|Uint32Array|Uint16Array|null} index - Serialized geometry index buffer.\n * @property {Uint32Array|Uint16Array|null} indirectBuffer - Indirect primitive index buffer, or `null`\n *   if the BVH was not built in indirect mode.\n */\n\n/**\n * @typedef {Object} HitPointInfo\n * @property {Vector3} point - The closest point on the mesh surface.\n * @property {number} distance - Distance from the query point to the closest point.\n * @property {number} faceIndex - Index of the triangle containing the closest point. Can be\n *   passed to `getTriangleHitPointInfo` to retrieve UV, normal, and material index.\n */\n\n/**\n * The MeshBVH generation process modifies the geometry's index bufferAttribute in place to save\n * memory. The BVH construction will use the geometry's boundingBox if it exists or set it if it\n * does not. The BVH will no longer work correctly if the index buffer is modified.\n *\n * Only triangles within the geometry's draw range (or provided `range` option) are included in the\n * BVH. When a geometry has multiple groups, only triangles within the defined group ranges are\n * included. Triangles in gaps between groups are excluded.\n *\n * Note that all query functions expect arguments in local space of the BVH and return results in\n * local space, as well. If world space results are needed they must be transformed into world space\n * using `object.matrixWorld`.\n *\n * @param {BufferGeometry} geometry\n * @param {Object} [options] - Same options as {@link GeometryBVH}.\n * @extends GeometryBVH\n */\nexport class MeshBVH extends GeometryBVH {\n\n\t/**\n\t * Generates a representation of the complete bounds tree and the geometry index buffer which\n\t * can be used to recreate a bounds tree using the `deserialize` function. The `serialize` and\n\t * `deserialize` functions can be used to generate a MeshBVH asynchronously in a background web\n\t * worker to prevent the main thread from stuttering. The BVH roots buffer stored in the\n\t * serialized representation are the same as the ones used by the original BVH so they should\n\t * not be modified. If `SharedArrayBuffers` are used then the same BVH memory can be used for\n\t * multiple BVH in multiple WebWorkers.\n\t *\n\t * @static\n\t * @param {MeshBVH} bvh - The BVH to serialize.\n\t * @param {Object} [options]\n\t * @param {boolean} [options.cloneBuffers=true] - If `true`, the index and BVH root buffers\n\t *   are cloned so the serialized data is independent of the live BVH.\n\t * @returns {SerializedBVH}\n\t */\n\tstatic serialize( bvh, options = {} ) {\n\n\t\toptions = {\n\t\t\tcloneBuffers: true,\n\t\t\t...options,\n\t\t};\n\n\t\tconst geometry = bvh.geometry;\n\t\tconst rootData = bvh._roots;\n\t\tconst indirectBuffer = bvh._indirectBuffer;\n\t\tconst indexAttribute = geometry.getIndex();\n\t\tconst result = {\n\t\t\tversion: 1,\n\t\t\troots: null,\n\t\t\tindex: null,\n\t\t\tindirectBuffer: null,\n\t\t};\n\t\tif ( options.cloneBuffers ) {\n\n\t\t\tresult.roots = rootData.map( root => root.slice() );\n\t\t\tresult.index = indexAttribute ? indexAttribute.array.slice() : null;\n\t\t\tresult.indirectBuffer = indirectBuffer ? indirectBuffer.slice() : null;\n\n\t\t} else {\n\n\t\t\tresult.roots = rootData;\n\t\t\tresult.index = indexAttribute ? indexAttribute.array : null;\n\t\t\tresult.indirectBuffer = indirectBuffer;\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n\t/**\n\t * Returns a new MeshBVH instance from the serialized data. `geometry` is the geometry used\n\t * to generate the original BVH `data` was derived from. The root buffers stored in `data`\n\t * are set directly on the new BVH so the memory is shared.\n\t *\n\t * @static\n\t * @param {SerializedBVH} data - Serialized BVH data.\n\t * @param {BufferGeometry} geometry - The geometry the BVH was originally built from.\n\t * @param {Object} [options]\n\t * @param {boolean} [options.setIndex=true] - If `true`, sets `geometry.index` from the\n\t *   serialized index buffer (creating one if none exists).\n\t * @returns {MeshBVH}\n\t */\n\tstatic deserialize( data, geometry, options = {} ) {\n\n\t\toptions = {\n\t\t\tsetIndex: true,\n\t\t\tindirect: Boolean( data.indirectBuffer ),\n\t\t\t...options,\n\t\t};\n\n\t\tconst { index, roots, indirectBuffer } = data;\n\n\t\t// handle backwards compatibility by fixing up the buffer roots\n\t\t// see issue gkjohnson/three-mesh-bvh#759\n\t\tif ( ! data.version ) {\n\n\t\t\tconsole.warn(\n\t\t\t\t'MeshBVH.deserialize: Serialization format has been changed and will be fixed up. ' +\n\t\t\t\t'It is recommended to regenerate any stored serialized data.'\n\t\t\t);\n\t\t\tfixupVersion0( roots );\n\n\t\t}\n\n\t\tconst bvh = new MeshBVH( geometry, { ...options, [ SKIP_GENERATION ]: true } );\n\t\tbvh._roots = roots;\n\t\tbvh._indirectBuffer = indirectBuffer || null;\n\n\t\tif ( options.setIndex ) {\n\n\t\t\tconst indexAttribute = geometry.getIndex();\n\t\t\tif ( indexAttribute === null ) {\n\n\t\t\t\tconst newIndex = new BufferAttribute( data.index, 1, false );\n\t\t\t\tgeometry.setIndex( newIndex );\n\n\t\t\t} else if ( indexAttribute.array !== index ) {\n\n\t\t\t\tindexAttribute.array.set( index );\n\t\t\t\tindexAttribute.needsUpdate = true;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn bvh;\n\n\t\t// convert version 0 serialized data (uint32 indices) to version 1 (node indices)\n\t\tfunction fixupVersion0( roots ) {\n\n\t\t\tfor ( let rootIndex = 0; rootIndex < roots.length; rootIndex ++ ) {\n\n\t\t\t\tconst root = roots[ rootIndex ];\n\t\t\t\tconst uint32Array = new Uint32Array( root );\n\t\t\t\tconst uint16Array = new Uint16Array( root );\n\n\t\t\t\t// iterate over nodes and convert right child offsets\n\t\t\t\tfor ( let node = 0, l = root.byteLength / BYTES_PER_NODE; node < l; node ++ ) {\n\n\t\t\t\t\tconst node32Index = UINT32_PER_NODE * node;\n\t\t\t\t\tconst node16Index = 2 * node32Index;\n\t\t\t\t\tif ( ! IS_LEAF( node16Index, uint16Array ) ) {\n\n\t\t\t\t\t\t// convert absolute right child offset to relative offset\n\t\t\t\t\t\tuint32Array[ node32Index + 6 ] = uint32Array[ node32Index + 6 ] / UINT32_PER_NODE - node;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tget primitiveStride() {\n\n\t\treturn 3;\n\n\t}\n\n\t/**\n\t * Helper function for use when `indirect` is set to true. This function takes a triangle\n\t * index in the BVH layout and returns the associated triangle index in the geometry index\n\t * buffer or position attribute.\n\t * @type {function(number): number}\n\t * @readonly\n\t */\n\tget resolveTriangleIndex() {\n\n\t\treturn this.resolvePrimitiveIndex;\n\n\t}\n\n\tconstructor( geometry, options = {} ) {\n\n\t\tif ( options.maxLeafTris ) {\n\n\t\t\tconsole.warn( 'MeshBVH: \"maxLeafTris\" option has been deprecated. Use \"targetLeafSize\", instead.' );\n\t\t\toptions = {\n\t\t\t\t...options,\n\t\t\t\ttargetLeafSize: options.maxLeafTris,\n\t\t\t};\n\n\t\t}\n\n\t\tsuper( geometry, options );\n\n\t}\n\n\t/**\n\t * Adjusts all triangle offsets stored in the BVH by the given offset. This is useful when the\n\t * triangle data has been compacted or shifted in the geometry buffers (e.g. in `BatchedMesh`\n\t * when geometries are compacted using the 'optimize' function or constructing a 'merged' BVH).\n\t * This function only adjusts the BVH to point to different triangles in the geometry. The\n\t * geometry's index buffer and/or position attributes must be updated separately to match.\n\t *\n\t * @param {number} offset\n\t * @returns {void}\n\t */\n\t// implement abstract methods from BVH base class\n\tshiftTriangleOffsets( offset ) {\n\n\t\treturn super.shiftPrimitiveOffsets( offset );\n\n\t}\n\n\t// write primitive bounds to the buffer - used only for validateBounds at the moment\n\twritePrimitiveBounds( i, targetBuffer, baseIndex ) {\n\n\t\tconst geometry = this.geometry;\n\t\tconst indirectBuffer = this._indirectBuffer;\n\t\tconst posAttr = geometry.attributes.position;\n\t\tconst index = geometry.index ? geometry.index.array : null;\n\n\t\tconst tri = indirectBuffer ? indirectBuffer[ i ] : i;\n\t\tconst tri3 = tri * 3;\n\n\t\tlet ai = tri3 + 0;\n\t\tlet bi = tri3 + 1;\n\t\tlet ci = tri3 + 2;\n\n\t\tif ( index ) {\n\n\t\t\tai = index[ ai ];\n\t\t\tbi = index[ bi ];\n\t\t\tci = index[ ci ];\n\n\t\t}\n\n\t\tfor ( let el = 0; el < 3; el ++ ) {\n\n\t\t\tconst a = posAttr[ _getters[ el ] ]( ai );\n\t\t\tconst b = posAttr[ _getters[ el ] ]( bi );\n\t\t\tconst c = posAttr[ _getters[ el ] ]( ci );\n\n\t\t\tlet min = a;\n\t\t\tif ( b < min ) min = b;\n\t\t\tif ( c < min ) min = c;\n\n\t\t\tlet max = a;\n\t\t\tif ( b > max ) max = b;\n\t\t\tif ( c > max ) max = c;\n\n\t\t\t// Write in min/max format [minx, miny, minz, maxx, maxy, maxz]\n\t\t\ttargetBuffer[ baseIndex + el ] = min;\n\t\t\ttargetBuffer[ baseIndex + el + 3 ] = max;\n\n\t\t}\n\n\t\treturn targetBuffer;\n\n\t}\n\n\t// precomputes the bounding box for each triangle; required for quickly calculating tree splits.\n\t// result is an array of size count * 6 where triangle i maps to a\n\t// [x_center, x_delta, y_center, y_delta, z_center, z_delta] tuple starting at index (i - offset) * 6,\n\t// representing the center and half-extent in each dimension of triangle i\n\tcomputePrimitiveBounds( offset, count, targetBuffer ) {\n\n\t\tconst geometry = this.geometry;\n\t\tconst indirectBuffer = this._indirectBuffer;\n\t\tconst posAttr = geometry.attributes.position;\n\t\tconst index = geometry.index ? geometry.index.array : null;\n\t\tconst normalized = posAttr.normalized;\n\n\t\tif ( offset < 0 || count + offset - targetBuffer.offset > targetBuffer.length / 6 ) {\n\n\t\t\tthrow new Error( 'MeshBVH: compute triangle bounds range is invalid.' );\n\n\t\t}\n\n\t\t// used for non-normalized positions\n\t\tconst posArr = posAttr.array;\n\n\t\t// support for an interleaved position buffer\n\t\tconst bufferOffset = posAttr.offset || 0;\n\t\tlet stride = 3;\n\t\tif ( posAttr.isInterleavedBufferAttribute ) {\n\n\t\t\tstride = posAttr.data.stride;\n\n\t\t}\n\n\t\t// used for normalized positions\n\t\tconst getters = [ 'getX', 'getY', 'getZ' ];\n\t\tconst writeOffset = targetBuffer.offset;\n\n\t\t// iterate over the triangle range\n\t\tfor ( let i = offset, l = offset + count; i < l; i ++ ) {\n\n\t\t\tconst tri = indirectBuffer ? indirectBuffer[ i ] : i;\n\t\t\tconst tri3 = tri * 3;\n\t\t\tconst boundsIndexOffset = ( i - writeOffset ) * 6;\n\n\t\t\tlet ai = tri3 + 0;\n\t\t\tlet bi = tri3 + 1;\n\t\t\tlet ci = tri3 + 2;\n\n\t\t\tif ( index ) {\n\n\t\t\t\tai = index[ ai ];\n\t\t\t\tbi = index[ bi ];\n\t\t\t\tci = index[ ci ];\n\n\t\t\t}\n\n\t\t\t// we add the stride and offset here since we access the array directly\n\t\t\t// below for the sake of performance\n\t\t\tif ( ! normalized ) {\n\n\t\t\t\tai = ai * stride + bufferOffset;\n\t\t\t\tbi = bi * stride + bufferOffset;\n\t\t\t\tci = ci * stride + bufferOffset;\n\n\t\t\t}\n\n\t\t\tfor ( let el = 0; el < 3; el ++ ) {\n\n\t\t\t\tlet a, b, c;\n\n\t\t\t\tif ( normalized ) {\n\n\t\t\t\t\ta = posAttr[ getters[ el ] ]( ai );\n\t\t\t\t\tb = posAttr[ getters[ el ] ]( bi );\n\t\t\t\t\tc = posAttr[ getters[ el ] ]( ci );\n\n\t\t\t\t} else {\n\n\t\t\t\t\ta = posArr[ ai + el ];\n\t\t\t\t\tb = posArr[ bi + el ];\n\t\t\t\t\tc = posArr[ ci + el ];\n\n\t\t\t\t}\n\n\t\t\t\tlet min = a;\n\t\t\t\tif ( b < min ) min = b;\n\t\t\t\tif ( c < min ) min = c;\n\n\t\t\t\tlet max = a;\n\t\t\t\tif ( b > max ) max = b;\n\t\t\t\tif ( c > max ) max = c;\n\n\t\t\t\t// Increase the bounds size by float32 epsilon to avoid precision errors when\n\t\t\t\t// converting to 32 bit float. Scale the epsilon by the size of the numbers being\n\t\t\t\t// worked with.\n\t\t\t\tconst halfExtents = ( max - min ) / 2;\n\t\t\t\tconst el2 = el * 2;\n\t\t\t\ttargetBuffer[ boundsIndexOffset + el2 + 0 ] = min + halfExtents;\n\t\t\t\ttargetBuffer[ boundsIndexOffset + el2 + 1 ] = halfExtents + ( Math.abs( min ) + halfExtents ) * FLOAT32_EPSILON;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn targetBuffer;\n\n\t}\n\n\t/**\n\t * A convenience function for performing a raycast based on a mesh. Results are formed like\n\t * three.js raycast results in world frame.\n\t *\n\t * @param {Object3D} object\n\t * @param {Raycaster} raycaster\n\t * @param {Array<Intersection>} [intersects=[]]\n\t * @returns {Array<Intersection>}\n\t */\n\traycastObject3D( object, raycaster, intersects = [] ) {\n\n\t\tconst { material } = object;\n\t\tif ( material === undefined ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\t_inverseMatrix.copy( object.matrixWorld ).invert();\n\t\t_ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );\n\n\t\t_worldScale.setFromMatrixScale( object.matrixWorld );\n\t\t_direction.copy( _ray.direction ).multiply( _worldScale );\n\n\t\tconst scaleFactor = _direction.length();\n\t\tconst near = raycaster.near / scaleFactor;\n\t\tconst far = raycaster.far / scaleFactor;\n\n\t\tif ( raycaster.firstHitOnly === true ) {\n\n\t\t\tlet hit = this.raycastFirst( _ray, material, near, far );\n\t\t\thit = convertRaycastIntersect( hit, object, raycaster );\n\t\t\tif ( hit ) {\n\n\t\t\t\tintersects.push( hit );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconst hits = this.raycast( _ray, material, near, far );\n\t\t\tfor ( let i = 0, l = hits.length; i < l; i ++ ) {\n\n\t\t\t\tconst hit = convertRaycastIntersect( hits[ i ], object, raycaster );\n\t\t\t\tif ( hit ) {\n\n\t\t\t\t\tintersects.push( hit );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn intersects;\n\n\t}\n\n\t/**\n\t * Refit the node bounds to the current triangle positions. This is quicker than regenerating\n\t * a new BVH but will not be optimal after significant changes to the vertices. `nodeIndices`\n\t * is a set of node indices (provided by the `shapecast` function) that need to be refit\n\t * including all internal nodes.\n\t *\n\t * @param {Set<number>|Array<number>|null} [nodeIndices=null]\n\t */\n\trefit( nodeIndices = null ) {\n\n\t\tconst refitFunc = this.indirect ? refit_indirect : refit;\n\t\treturn refitFunc( this, nodeIndices );\n\n\t}\n\n\t/* Core Cast Functions */\n\n\t/**\n\t * Returns all raycast triangle hits in unsorted order. It is expected that `ray` is in the\n\t * frame of the BVH already. Likewise the returned results are also provided in the local\n\t * frame of the BVH. The `side` identifier is used to determine the side to check when\n\t * raycasting or a material with the given side field can be passed. If an array of materials\n\t * is provided then it is expected that the geometry has groups and the appropriate material\n\t * side is used per group.\n\t *\n\t * Note that unlike three.js' Raycaster results the points and distances in the intersections\n\t * returned from this function are relative to the local frame of the MeshBVH. When using the\n\t * `acceleratedRaycast` function as an override for `Mesh.raycast` they are transformed into\n\t * world space to be consistent with three's results.\n\t *\n\t * @param {Ray} ray\n\t * @param {number|Material|Array<Material>} [materialOrSide=FrontSide]\n\t * @param {number} [near=0]\n\t * @param {number} [far=Infinity]\n\t * @returns {Array<Intersection>}\n\t */\n\traycast( ray, materialOrSide = FrontSide, near = 0, far = Infinity ) {\n\n\t\tconst roots = this._roots;\n\t\tconst intersects = [];\n\t\tconst raycastFunc = this.indirect ? raycast_indirect : raycast;\n\t\tfor ( let i = 0, l = roots.length; i < l; i ++ ) {\n\n\t\t\traycastFunc( this, i, materialOrSide, ray, intersects, near, far );\n\n\t\t}\n\n\t\treturn intersects;\n\n\t}\n\n\t/**\n\t * Returns the first raycast hit in the model. This is typically much faster than returning\n\t * all hits. See `raycast` for information on the side and material options as well as the\n\t * frame of the returned intersections.\n\t *\n\t * @param {Ray} ray\n\t * @param {number|Material|Array<Material>} [materialOrSide=FrontSide]\n\t * @param {number} [near=0]\n\t * @param {number} [far=Infinity]\n\t * @returns {Intersection|null}\n\t */\n\traycastFirst( ray, materialOrSide = FrontSide, near = 0, far = Infinity ) {\n\n\t\tconst roots = this._roots;\n\t\tlet closestResult = null;\n\n\t\tconst raycastFirstFunc = this.indirect ? raycastFirst_indirect : raycastFirst;\n\t\tfor ( let i = 0, l = roots.length; i < l; i ++ ) {\n\n\t\t\tconst result = raycastFirstFunc( this, i, materialOrSide, ray, near, far );\n\t\t\tif ( result != null && ( closestResult == null || result.distance < closestResult.distance ) ) {\n\n\t\t\t\tclosestResult = result;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn closestResult;\n\n\t}\n\n\t/**\n\t * Returns whether or not the mesh intersects the given geometry.\n\t *\n\t * The `geometryToBvh` parameter is the transform of the geometry in the BVH's local frame.\n\t *\n\t * Performance improves considerably if the provided geometry also has a `boundsTree`.\n\t *\n\t * @param {BufferGeometry} otherGeometry\n\t * @param {Matrix4} geometryToBvh - Transform of `otherGeometry` into the local space of\n\t *   this BVH.\n\t * @returns {boolean}\n\t */\n\tintersectsGeometry( otherGeometry, geomToMesh ) {\n\n\t\tlet result = false;\n\t\tconst roots = this._roots;\n\t\tconst intersectsGeometryFunc = this.indirect ? intersectsGeometry_indirect : intersectsGeometry;\n\t\tfor ( let i = 0, l = roots.length; i < l; i ++ ) {\n\n\t\t\tresult = intersectsGeometryFunc( this, i, otherGeometry, geomToMesh );\n\n\t\t\tif ( result ) {\n\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n\t/**\n\t * A generalized cast function that can be used to implement intersection logic for custom\n\t * shapes. This is used internally for `intersectsBox`, `intersectsSphere`, and more. The\n\t * function returns as soon as a triangle has been reported as intersected and returns `true`\n\t * if a triangle has been intersected.\n\t *\n\t * @param {Object} callbacks\n\t * @param {IntersectsBoundsCallback} callbacks.intersectsBounds\n\t * @param {IntersectsTriangleCallback} [callbacks.intersectsTriangle]\n\t * @param {IntersectsRangeCallback} [callbacks.intersectsRange]\n\t * @param {BoundsTraverseOrderCallback} [callbacks.boundsTraverseOrder]\n\t * @returns {boolean}\n\t */\n\tshapecast( callbacks ) {\n\n\t\tconst triangle = ExtendedTrianglePool.getPrimitive();\n\t\tconst result = super.shapecast(\n\t\t\t{\n\t\t\t\t...callbacks,\n\t\t\t\tintersectsPrimitive: callbacks.intersectsTriangle,\n\t\t\t\tscratchPrimitive: triangle,\n\n\t\t\t\t// TODO: is the performance significant enough for the added complexity here?\n\t\t\t\t// can we just use one function?\n\t\t\t\titerate: this.indirect ? iterateOverTriangles_indirect : iterateOverTriangles,\n\t\t\t}\n\t\t);\n\t\tExtendedTrianglePool.releasePrimitive( triangle );\n\n\t\treturn result;\n\n\t}\n\n\t/**\n\t * A generalized cast function that traverses two BVH structures simultaneously to perform\n\t * intersection tests between them. This is used internally by `intersectsGeometry`. The\n\t * function returns `true` as soon as a triangle pair has been reported as intersected by\n\t * the callbacks.\n\t *\n\t * `matrixToLocal` is a Matrix4 that transforms `otherBvh` into the local space of this BVH.\n\t * The other BVH's triangles are transformed by this matrix before intersection tests.\n\t *\n\t * @param {MeshBVH} otherBvh\n\t * @param {Matrix4} matrixToLocal - Transforms `otherBvh` into the local space of this BVH.\n\t * @param {Object} callbacks\n\t * @param {IntersectsRangesCallback} [callbacks.intersectsRanges]\n\t * @param {IntersectsTrianglesCallback} [callbacks.intersectsTriangles]\n\t * @returns {boolean}\n\t */\n\tbvhcast( otherBvh, matrixToLocal, callbacks ) {\n\n\t\tlet {\n\t\t\tintersectsRanges,\n\t\t\tintersectsTriangles,\n\t\t} = callbacks;\n\n\t\tconst triangle1 = ExtendedTrianglePool.getPrimitive();\n\t\tconst indexAttr1 = this.geometry.index;\n\t\tconst positionAttr1 = this.geometry.attributes.position;\n\t\tconst assignTriangle1 = this.indirect ?\n\t\t\ti1 => {\n\n\n\t\t\t\tconst ti = this.resolveTriangleIndex( i1 );\n\t\t\t\tsetTriangle( triangle1, ti * 3, indexAttr1, positionAttr1 );\n\n\t\t\t} :\n\t\t\ti1 => {\n\n\t\t\t\tsetTriangle( triangle1, i1 * 3, indexAttr1, positionAttr1 );\n\n\t\t\t};\n\n\t\tconst triangle2 = ExtendedTrianglePool.getPrimitive();\n\t\tconst indexAttr2 = otherBvh.geometry.index;\n\t\tconst positionAttr2 = otherBvh.geometry.attributes.position;\n\t\tconst assignTriangle2 = otherBvh.indirect ?\n\t\t\ti2 => {\n\n\t\t\t\tconst ti2 = otherBvh.resolveTriangleIndex( i2 );\n\t\t\t\tsetTriangle( triangle2, ti2 * 3, indexAttr2, positionAttr2 );\n\n\t\t\t} :\n\t\t\ti2 => {\n\n\t\t\t\tsetTriangle( triangle2, i2 * 3, indexAttr2, positionAttr2 );\n\n\t\t\t};\n\n\t\t// generate triangle callback if needed\n\t\tif ( intersectsTriangles ) {\n\n\t\t\tif ( ! ( otherBvh instanceof MeshBVH ) ) {\n\n\t\t\t\tthrow new Error( 'MeshBVH: \"intersectsTriangles\" callback can only be used with another MeshBVH.' );\n\n\t\t\t}\n\n\t\t\tconst iterateOverDoubleTriangles = ( offset1, count1, offset2, count2, depth1, nodeIndex1, depth2, nodeIndex2 ) => {\n\n\t\t\t\tfor ( let i2 = offset2, l2 = offset2 + count2; i2 < l2; i2 ++ ) {\n\n\t\t\t\t\tassignTriangle2( i2 );\n\n\t\t\t\t\ttriangle2.a.applyMatrix4( matrixToLocal );\n\t\t\t\t\ttriangle2.b.applyMatrix4( matrixToLocal );\n\t\t\t\t\ttriangle2.c.applyMatrix4( matrixToLocal );\n\t\t\t\t\ttriangle2.needsUpdate = true;\n\n\t\t\t\t\tfor ( let i1 = offset1, l1 = offset1 + count1; i1 < l1; i1 ++ ) {\n\n\t\t\t\t\t\tassignTriangle1( i1 );\n\n\t\t\t\t\t\ttriangle1.needsUpdate = true;\n\n\t\t\t\t\t\tif ( intersectsTriangles( triangle1, triangle2, i1, i2, depth1, nodeIndex1, depth2, nodeIndex2 ) ) {\n\n\t\t\t\t\t\t\treturn true;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\n\t\t\t};\n\n\t\t\tif ( intersectsRanges ) {\n\n\t\t\t\tconst originalIntersectsRanges = intersectsRanges;\n\t\t\t\tintersectsRanges = function ( offset1, count1, offset2, count2, depth1, nodeIndex1, depth2, nodeIndex2 ) {\n\n\t\t\t\t\tif ( ! originalIntersectsRanges( offset1, count1, offset2, count2, depth1, nodeIndex1, depth2, nodeIndex2 ) ) {\n\n\t\t\t\t\t\treturn iterateOverDoubleTriangles( offset1, count1, offset2, count2, depth1, nodeIndex1, depth2, nodeIndex2 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\n\t\t\t\t};\n\n\t\t\t} else {\n\n\t\t\t\tintersectsRanges = iterateOverDoubleTriangles;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn super.bvhcast( otherBvh, matrixToLocal, { intersectsRanges } );\n\n\t}\n\n\n\t/* Derived Cast Functions */\n\n\t/**\n\t * Returns whether or not the mesh intersects the given box.\n\t *\n\t * The `boxToBvh` parameter is the transform of the box in the meshes frame.\n\t *\n\t * @param {Box3} box\n\t * @param {Matrix4} boxToBvh - Transform of the box in the local space of this BVH.\n\t * @returns {boolean}\n\t */\n\tintersectsBox( box, boxToMesh ) {\n\n\t\t_obb.set( box.min, box.max, boxToMesh );\n\t\t_obb.needsUpdate = true;\n\n\t\treturn this.shapecast(\n\t\t\t{\n\t\t\t\tintersectsBounds: box => _obb.intersectsBox( box ),\n\t\t\t\tintersectsTriangle: tri => _obb.intersectsTriangle( tri )\n\t\t\t}\n\t\t);\n\n\t}\n\n\t/**\n\t * Returns whether or not the mesh intersects the given sphere.\n\t *\n\t * @param {Sphere} sphere\n\t * @returns {boolean}\n\t */\n\tintersectsSphere( sphere ) {\n\n\t\treturn this.shapecast(\n\t\t\t{\n\t\t\t\tintersectsBounds: box => sphere.intersectsBox( box ),\n\t\t\t\tintersectsTriangle: tri => tri.intersectsSphere( sphere )\n\t\t\t}\n\t\t);\n\n\t}\n\n\t/**\n\t * Computes the closest distance from the geometry to the mesh and puts the closest point on\n\t * the mesh in `target1` (in the frame of the BVH) and the closest point on the other\n\t * geometry in `target2` (in the geometry frame). If `target1` is not provided a new Object\n\t * is created and returned from the function.\n\t *\n\t * The `geometryToBvh` parameter is the transform of the geometry in the BVH's local frame.\n\t *\n\t * If a point is found that is closer than `minThreshold` then the function will return that\n\t * result early. Any triangles or points outside of `maxThreshold` are ignored. If no point\n\t * is found within the min / max thresholds then `null` is returned and the target objects\n\t * are not modified.\n\t *\n\t * The returned faceIndex in `target1` and `target2` can be used with the standalone function\n\t * `getTriangleHitPointInfo` to obtain more information like UV coordinates, triangle normal\n\t * and materialIndex.\n\t *\n\t * @note This function can be very slow if `geometry` does not have a `geometry.boundsTree`\n\t * computed.\n\t *\n\t * @param {BufferGeometry} otherGeometry\n\t * @param {Matrix4} geometryToBvh - Transform of `otherGeometry` into the local space of\n\t *   this BVH.\n\t * @param {HitPointInfo} [target1={}]\n\t * @param {HitPointInfo} [target2={}]\n\t * @param {number} [minThreshold=0]\n\t * @param {number} [maxThreshold=Infinity]\n\t * @returns {HitPointInfo|null}\n\t */\n\tclosestPointToGeometry( otherGeometry, geometryToBvh, target1 = { }, target2 = { }, minThreshold = 0, maxThreshold = Infinity ) {\n\n\t\tconst closestPointToGeometryFunc = this.indirect ? closestPointToGeometry_indirect : closestPointToGeometry;\n\t\treturn closestPointToGeometryFunc(\n\t\t\tthis,\n\t\t\totherGeometry,\n\t\t\tgeometryToBvh,\n\t\t\ttarget1,\n\t\t\ttarget2,\n\t\t\tminThreshold,\n\t\t\tmaxThreshold,\n\t\t);\n\n\t}\n\n\t/**\n\t * Computes the closest distance from the point to the mesh and gives additional information\n\t * in `target`. The target can be left undefined to default to a new object which is\n\t * ultimately returned by the function.\n\t *\n\t * If a point is found that is closer than `minThreshold` then the function will return that\n\t * result early. Any triangles or points outside of `maxThreshold` are ignored. If no point\n\t * is found within the min / max thresholds then `null` is returned and the `target` object\n\t * is not modified.\n\t *\n\t * The returned faceIndex can be used with the standalone function `getTriangleHitPointInfo`\n\t * to obtain more information like UV coordinates, triangle normal and materialIndex.\n\t *\n\t * @param {Vector3} point\n\t * @param {HitPointInfo} [target={}]\n\t * @param {number} [minThreshold=0]\n\t * @param {number} [maxThreshold=Infinity]\n\t * @returns {HitPointInfo|null}\n\t */\n\tclosestPointToPoint( point, target = { }, minThreshold = 0, maxThreshold = Infinity ) {\n\n\t\treturn closestPointToPoint(\n\t\t\tthis,\n\t\t\tpoint,\n\t\t\ttarget,\n\t\t\tminThreshold,\n\t\t\tmaxThreshold,\n\t\t);\n\n\t}\n\n}\n","/** @import { BufferGeometry } from 'three' */\n/** @import { IntersectsBoundsCallback, IntersectsRangeCallback, BoundsTraverseOrderCallback } from './BVH.js' */\nimport { Matrix4, Line3, Vector3, Ray, Box3 } from 'three';\nimport { PrimitivePool } from '../utils/PrimitivePool.js';\nimport { INTERSECTED, NOT_INTERSECTED } from './Constants.js';\nimport { GeometryBVH } from './GeometryBVH.js';\n\nconst _inverseMatrix = /* @__PURE__ */ new Matrix4();\nconst _ray = /* @__PURE__ */ new Ray();\nconst _linePool = /* @__PURE__ */ new PrimitivePool( () => new Line3() );\nconst _intersectPointOnRay = /*@__PURE__*/ new Vector3();\nconst _intersectPointOnSegment = /*@__PURE__*/ new Vector3();\nconst _box = /* @__PURE__ */ new Box3();\nconst _vec = /* @__PURE__ */ new Vector3();\nconst _getters = [ 'getX', 'getY', 'getZ' ];\n\n/**\n * @callback IntersectsLineCallback\n * @param {Line3} line - The line segment primitive in local space.\n * @param {number} index - The primitive index within the BVH buffer.\n * @param {boolean} contained - Whether the node bounds are fully contained by the query shape.\n * @param {number} depth - The depth of the node in the tree.\n * @returns {boolean} Return `true` to stop traversal.\n */\n\n/**\n * BVH for `THREE.LineSegments` geometries. Each BVH primitive represents one line segment\n * (two consecutive vertices).\n * @extends GeometryBVH\n */\nexport class LineSegmentsBVH extends GeometryBVH {\n\n\tget primitiveStride() {\n\n\t\treturn 2;\n\n\t}\n\n\twritePrimitiveBounds( i, targetBuffer, baseIndex ) {\n\n\t\tconst indirectBuffer = this._indirectBuffer;\n\t\tconst { geometry, primitiveStride } = this;\n\n\t\tconst posAttr = geometry.attributes.position;\n\t\tconst indexAttr = geometry.index;\n\n\t\t// TODO: this may not be right for a LineLoop with a limited draw range / groups\n\t\tconst vertCount = indexAttr ? indexAttr.count : posAttr.count;\n\n\t\tconst prim = indirectBuffer ? indirectBuffer[ i ] : i;\n\t\tlet i0 = prim * primitiveStride;\n\t\tlet i1 = ( i0 + 1 ) % vertCount;\n\t\tif ( indexAttr ) {\n\n\t\t\ti0 = indexAttr.getX( i0 );\n\t\t\ti1 = indexAttr.getX( i1 );\n\n\t\t}\n\n\t\tfor ( let el = 0; el < 3; el ++ ) {\n\n\t\t\tconst v0 = posAttr[ _getters[ el ] ]( i0 );\n\t\t\tconst v1 = posAttr[ _getters[ el ] ]( i1 );\n\t\t\tconst min = v0 < v1 ? v0 : v1;\n\t\t\tconst max = v0 > v1 ? v0 : v1;\n\n\t\t\t// Write in min/max format [minx, miny, minz, maxx, maxy, maxz]\n\t\t\ttargetBuffer[ baseIndex + el ] = min;\n\t\t\ttargetBuffer[ baseIndex + el + 3 ] = max;\n\n\t\t}\n\n\t\treturn targetBuffer;\n\n\t}\n\n\t/**\n\t * Performs a spatial query against the BVH. Extends the base `shapecast` with an\n\t * `intersectsLine` callback that is called once per line segment primitive in leaf nodes.\n\t *\n\t * @param {Object} callbacks\n\t * @param {IntersectsBoundsCallback} callbacks.intersectsBounds\n\t * @param {IntersectsLineCallback} [callbacks.intersectsLine]\n\t * @param {IntersectsRangeCallback} [callbacks.intersectsRange]\n\t * @param {BoundsTraverseOrderCallback} [callbacks.boundsTraverseOrder]\n\t * @returns {boolean}\n\t */\n\tshapecast( callbacks ) {\n\n\t\tconst line = _linePool.getPrimitive();\n\t\tconst result = super.shapecast( {\n\t\t\t...callbacks,\n\t\t\tintersectsPrimitive: callbacks.intersectsLine,\n\t\t\tscratchPrimitive: line,\n\t\t\titerate: iterateOverLines,\n\t\t} );\n\t\t_linePool.releasePrimitive( line );\n\n\t\treturn result;\n\n\t}\n\n\traycastObject3D( object, raycaster, intersects = [] ) {\n\n\t\tconst { matrixWorld } = object;\n\t\tconst { firstHitOnly } = raycaster;\n\n\t\t_inverseMatrix.copy( matrixWorld ).invert();\n\t\t_ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );\n\n\t\tconst threshold = raycaster.params.Line.threshold;\n\t\tconst localThreshold = threshold / ( ( object.scale.x + object.scale.y + object.scale.z ) / 3 );\n\t\tconst localThresholdSq = localThreshold * localThreshold;\n\n\t\tlet closestHit = null;\n\t\tlet closestDistance = Infinity;\n\t\tthis.shapecast( {\n\t\t\tboundsTraverseOrder: box => {\n\n\t\t\t\treturn box.distanceToPoint( _ray.origin );\n\n\t\t\t},\n\t\t\tintersectsBounds: box => {\n\n\t\t\t\t_box.copy( box ).expandByScalar( localThreshold );\n\n\t\t\t\tif ( firstHitOnly ) {\n\n\t\t\t\t\tif ( ! _ray.intersectBox( _box, _vec ) ) {\n\n\t\t\t\t\t\treturn NOT_INTERSECTED;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlet dist;\n\t\t\t\t\tif ( _box.containsPoint( _ray.origin ) ) {\n\n\t\t\t\t\t\tdist = 0;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t_vec.applyMatrix4( matrixWorld );\n\t\t\t\t\t\tdist = raycaster.ray.origin.distanceTo( _vec );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// early out if the box is further than the closest raycast\n\t\t\t\t\treturn dist < closestDistance ? INTERSECTED : NOT_INTERSECTED;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn _ray.intersectsBox( _box ) ? INTERSECTED : NOT_INTERSECTED;\n\n\t\t\t\t}\n\n\t\t\t},\n\t\t\tintersectsLine: ( line, index ) => {\n\n\t\t\t\tconst distSq = _ray.distanceSqToSegment( line.start, line.end, _intersectPointOnRay, _intersectPointOnSegment );\n\n\t\t\t\tif ( distSq > localThresholdSq ) return;\n\n\t\t\t\t_intersectPointOnRay.applyMatrix4( object.matrixWorld );\n\n\t\t\t\tconst distance = raycaster.ray.origin.distanceTo( _intersectPointOnRay );\n\n\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) return;\n\n\t\t\t\tif ( firstHitOnly && distance >= closestDistance ) return;\n\t\t\t\tclosestDistance = distance;\n\n\t\t\t\tindex = this.resolvePrimitiveIndex( index );\n\n\t\t\t\tclosestHit = {\n\t\t\t\t\tdistance,\n\t\t\t\t\tpoint: _intersectPointOnSegment.clone().applyMatrix4( matrixWorld ),\n\t\t\t\t\tindex: index * this.primitiveStride,\n\t\t\t\t\tface: null,\n\t\t\t\t\tfaceIndex: null,\n\t\t\t\t\tbarycoord: null,\n\t\t\t\t\tobject,\n\t\t\t\t};\n\n\t\t\t\tif ( ! firstHitOnly ) {\n\n\t\t\t\t\tintersects.push( closestHit );\n\n\t\t\t\t}\n\n\t\t\t},\n\t\t} );\n\n\t\tif ( firstHitOnly && closestHit ) {\n\n\t\t\tintersects.push( closestHit );\n\n\t\t}\n\n\t\treturn intersects;\n\n\t}\n\n}\n\n/**\n * BVH for `THREE.LineLoop` geometries. Forces indirect mode since the loop structure\n * requires that the index buffer remain unmodified.\n * @param {BufferGeometry} geometry\n * @param {Object} [options] - Same options as {@link GeometryBVH}. `indirect` is always forced to `true`.\n * @extends LineSegmentsBVH\n */\nexport class LineLoopBVH extends LineSegmentsBVH {\n\n\tget primitiveStride() {\n\n\t\treturn 1;\n\n\t}\n\n\tconstructor( geometry, options = {} ) {\n\n\t\t// \"Line\" and \"LineLoop\" BVH must be indirect since we cannot rearrange the index\n\t\t// buffer without breaking the lines\n\t\toptions = {\n\t\t\t...options,\n\t\t\tindirect: true,\n\t\t};\n\n\t\tsuper( geometry, options );\n\n\t}\n\n}\n\n/**\n * BVH for `THREE.Line` geometries. Like `LineLoopBVH` but excludes the final closing\n * segment so the open line is accurately represented.\n * @param {BufferGeometry} geometry\n * @param {Object} [options] - Same options as {@link GeometryBVH}. `indirect` is always forced to `true`.\n * @extends LineLoopBVH\n */\nexport class LineBVH extends LineLoopBVH {\n\n\tgetRootRanges( ...args ) {\n\n\t\tconst res = super.getRootRanges( ...args );\n\t\tres.forEach( group => group.count -- );\n\t\treturn res;\n\n\t}\n\n}\n\nfunction iterateOverLines(\n\toffset,\n\tcount,\n\tbvh,\n\tintersectsPointFunc,\n\tcontained,\n\tdepth,\n\tline\n) {\n\n\tconst { geometry, primitiveStride } = bvh;\n\tconst { index } = geometry;\n\tconst posAttr = geometry.attributes.position;\n\tconst vertCount = index ? index.count : posAttr.count;\n\n\tfor ( let i = offset, l = count + offset; i < l; i ++ ) {\n\n\t\tconst prim = bvh.resolvePrimitiveIndex( i );\n\t\tlet i0 = prim * primitiveStride;\n\t\tlet i1 = ( i0 + 1 ) % vertCount;\n\t\tif ( index ) {\n\n\t\t\ti0 = index.getX( i0 );\n\t\t\ti1 = index.getX( i1 );\n\n\t\t}\n\n\t\tline.start.fromBufferAttribute( posAttr, i0 );\n\t\tline.end.fromBufferAttribute( posAttr, i1 );\n\n\t\tif ( intersectsPointFunc( line, i, contained, depth ) ) {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t}\n\n\treturn false;\n\n}\n","/** @import { IntersectsBoundsCallback, IntersectsRangeCallback, BoundsTraverseOrderCallback } from './BVH.js' */\nimport { Vector3, Matrix4, Ray, Box3 } from 'three';\nimport { INTERSECTED, NOT_INTERSECTED } from './Constants.js';\nimport { PrimitivePool } from '../utils/PrimitivePool.js';\nimport { GeometryBVH } from './GeometryBVH.js';\n\nconst _inverseMatrix = /* @__PURE__ */ new Matrix4();\nconst _ray = /* @__PURE__ */ new Ray();\nconst _pointPool = /* @__PURE__ */ new PrimitivePool( () => new Vector3() );\nconst _box = /* @__PURE__ */ new Box3();\nconst _vec = /* @__PURE__ */ new Vector3();\n\n/**\n * @callback IntersectsPointCallback\n * @param {Vector3} point - The point primitive in local space.\n * @param {number} index - The primitive index within the BVH buffer.\n * @param {boolean} contained - Whether the node bounds are fully contained by the query shape.\n * @param {number} depth - The depth of the node in the tree.\n * @returns {boolean} Return `true` to stop traversal.\n */\n\n/**\n * BVH for `THREE.Points` geometries. Each BVH primitive represents a single point.\n * @extends GeometryBVH\n */\nexport class PointsBVH extends GeometryBVH {\n\n\tget primitiveStride() {\n\n\t\treturn 1;\n\n\t}\n\n\twritePrimitiveBounds( i, targetBuffer, baseIndex ) {\n\n\t\tconst indirectBuffer = this._indirectBuffer;\n\t\tconst { geometry } = this;\n\t\tconst posAttr = geometry.attributes.position;\n\t\tconst indexAttr = geometry.index;\n\t\tlet pointIndex = indirectBuffer ? indirectBuffer[ i ] : i;\n\t\tif ( indexAttr ) {\n\n\t\t\tpointIndex = indexAttr.getX( pointIndex );\n\n\t\t}\n\n\t\tconst px = posAttr.getX( pointIndex );\n\t\tconst py = posAttr.getY( pointIndex );\n\t\tconst pz = posAttr.getZ( pointIndex );\n\n\t\t// Write in min/max format [minx, miny, minz, maxx, maxy, maxz]\n\t\t// For points, min equals max (epsilon padding is applied in computePrimitiveBounds)\n\t\ttargetBuffer[ baseIndex + 0 ] = px;\n\t\ttargetBuffer[ baseIndex + 1 ] = py;\n\t\ttargetBuffer[ baseIndex + 2 ] = pz;\n\t\ttargetBuffer[ baseIndex + 3 ] = px;\n\t\ttargetBuffer[ baseIndex + 4 ] = py;\n\t\ttargetBuffer[ baseIndex + 5 ] = pz;\n\n\t\treturn targetBuffer;\n\n\t}\n\n\t/**\n\t * Performs a spatial query against the BVH. Extends the base `shapecast` with an\n\t * `intersectsPoint` callback that is called once per point primitive in leaf nodes.\n\t *\n\t * @param {Object} callbacks\n\t * @param {IntersectsBoundsCallback} callbacks.intersectsBounds\n\t * @param {IntersectsPointCallback} [callbacks.intersectsPoint]\n\t * @param {IntersectsRangeCallback} [callbacks.intersectsRange]\n\t * @param {BoundsTraverseOrderCallback} [callbacks.boundsTraverseOrder]\n\t * @returns {boolean}\n\t */\n\tshapecast( callbacks ) {\n\n\t\t// TODO: avoid unnecessary \"iterate over points\" function\n\t\tconst point = _pointPool.getPrimitive();\n\t\tconst result = super.shapecast(\n\t\t\t{\n\t\t\t\t...callbacks,\n\t\t\t\tintersectsPrimitive: callbacks.intersectsPoint,\n\t\t\t\tscratchPrimitive: point,\n\t\t\t\titerate: iterateOverPoints,\n\t\t\t},\n\t\t);\n\n\t\t_pointPool.releasePrimitive( point );\n\t\treturn result;\n\n\t}\n\n\traycastObject3D( object, raycaster, intersects = [] ) {\n\n\t\tconst { geometry } = this;\n\t\tconst { matrixWorld } = object;\n\t\tconst { firstHitOnly } = raycaster;\n\n\t\t_inverseMatrix.copy( matrixWorld ).invert();\n\t\t_ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );\n\n\t\tconst threshold = raycaster.params.Points.threshold;\n\t\tconst localThreshold = threshold / ( ( object.scale.x + object.scale.y + object.scale.z ) / 3 );\n\t\tconst localThresholdSq = localThreshold * localThreshold;\n\n\t\tlet closestHit = null;\n\t\tlet closestDistance = Infinity;\n\t\tthis.shapecast( {\n\t\t\tboundsTraverseOrder: box => {\n\n\t\t\t\treturn box.distanceToPoint( _ray.origin );\n\n\t\t\t},\n\t\t\tintersectsBounds: box => {\n\n\t\t\t\t_box.copy( box ).expandByScalar( localThreshold );\n\n\t\t\t\tif ( firstHitOnly ) {\n\n\t\t\t\t\tif ( ! _ray.intersectBox( _box, _vec ) ) {\n\n\t\t\t\t\t\treturn NOT_INTERSECTED;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlet dist;\n\t\t\t\t\tif ( _box.containsPoint( _ray.origin ) ) {\n\n\t\t\t\t\t\tdist = 0;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t_vec.applyMatrix4( matrixWorld );\n\t\t\t\t\t\tdist = raycaster.ray.origin.distanceTo( _vec );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// early out if the box is further than the closest raycast\n\t\t\t\t\treturn dist < closestDistance ? INTERSECTED : NOT_INTERSECTED;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn _ray.intersectsBox( _box ) ? INTERSECTED : NOT_INTERSECTED;\n\n\t\t\t\t}\n\n\t\t\t},\n\t\t\tintersectsPoint: ( point, index ) => {\n\n\t\t\t\tconst rayPointDistanceSq = _ray.distanceSqToPoint( point );\n\n\t\t\t\tif ( rayPointDistanceSq < localThresholdSq ) {\n\n\t\t\t\t\tconst intersectPoint = new Vector3();\n\n\t\t\t\t\t_ray.closestPointToPoint( point, intersectPoint );\n\t\t\t\t\tintersectPoint.applyMatrix4( matrixWorld );\n\n\t\t\t\t\tconst distance = raycaster.ray.origin.distanceTo( intersectPoint );\n\n\t\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) return;\n\n\t\t\t\t\tif ( firstHitOnly && distance >= closestDistance ) return;\n\t\t\t\t\tclosestDistance = distance;\n\n\t\t\t\t\tindex = this.resolvePrimitiveIndex( index );\n\n\t\t\t\t\tclosestHit = {\n\t\t\t\t\t\tdistance,\n\t\t\t\t\t\t// TODO: this doesn't seem right?\n\t\t\t\t\t\tdistanceToRay: Math.sqrt( rayPointDistanceSq ),\n\t\t\t\t\t\tpoint: intersectPoint,\n\t\t\t\t\t\tindex: geometry.index ? geometry.index.getX( index ) : index,\n\t\t\t\t\t\tface: null,\n\t\t\t\t\t\tfaceIndex: null,\n\t\t\t\t\t\tbarycoord: null,\n\t\t\t\t\t\tobject,\n\t\t\t\t\t};\n\n\t\t\t\t\tif ( ! firstHitOnly ) {\n\n\t\t\t\t\t\tintersects.push( closestHit );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t},\n\t\t} );\n\n\t\tif ( firstHitOnly && closestHit ) {\n\n\t\t\tintersects.push( closestHit );\n\n\t\t}\n\n\t\treturn intersects;\n\n\t}\n\n}\n\nfunction iterateOverPoints(\n\toffset,\n\tcount,\n\tbvh,\n\tintersectsPointFunc,\n\tcontained,\n\tdepth,\n\tpoint\n) {\n\n\tconst { geometry } = bvh;\n\tconst { index } = geometry;\n\tconst pos = geometry.attributes.position;\n\n\tfor ( let i = offset, l = count + offset; i < l; i ++ ) {\n\n\t\tconst prim = bvh.resolvePrimitiveIndex( i );\n\t\tconst vertexIndex = index ? index.array[ prim ] : prim;\n\t\tpoint.fromBufferAttribute( pos, vertexIndex );\n\n\t\tif ( intersectsPointFunc( point, i, contained, depth ) ) {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t}\n\n\treturn false;\n\n}\n","/** @import { Object3D } from 'three' */\n/** @import { IntersectsBoundsCallback, IntersectsRangeCallback, BoundsTraverseOrderCallback } from './BVH.js' */\nimport { Box3, BufferGeometry, Matrix4, Mesh, Vector3, Ray, Sphere } from 'three';\nimport { BVH } from './BVH.js';\nimport { INTERSECTED, NOT_INTERSECTED } from './Constants.js';\n\nconst _geometry = /* @__PURE__ */ new BufferGeometry();\nconst _matrix = /* @__PURE__ */ new Matrix4();\nconst _inverseMatrix = /* @__PURE__ */ new Matrix4();\nconst _box = /* @__PURE__ */ new Box3();\nconst _sphere = /* @__PURE__ */ new Sphere();\nconst _vec = /* @__PURE__ */ new Vector3();\nconst _ray = /* @__PURE__ */ new Ray();\nconst _mesh = /* @__PURE__ */ new Mesh();\nconst _geometryRange = {};\n\n/**\n * @callback IntersectsObjectCallback\n * @param {Object3D} object - The scene object whose bounds were intersected.\n * @param {number} instanceId - Instance index for InstancedMesh/BatchedMesh, or 0 for regular objects.\n * @param {boolean} contained - Whether the node bounds are fully contained by the query shape.\n * @param {number} depth - The depth of the node in the tree.\n * @returns {boolean} Return `true` to stop traversal.\n */\n\n/**\n * BVH built from a scene hierarchy rather than a single geometry. Each leaf holds\n * one Object3D (or one instance of an InstancedMesh/BatchedMesh), enabling\n * accelerated raycasting and spatial queries across many objects at once.\n *\n * @param {Object3D | Array<Object3D>} root - Root object or array of objects.\n * @param {Object} [options] - Accepts all standard BVH options plus:\n * @param {boolean} [options.precise=false] - Use vertex-level bounds instead of cached bounding boxes.\n * @param {boolean} [options.includeInstances=true] - Treat each instance of InstancedMesh/BatchedMesh as a separate primitive.\n * @extends BVH\n */\nexport class ObjectBVH extends BVH {\n\n\tconstructor( root, options = {} ) {\n\n\t\toptions = {\n\t\t\tprecise: false,\n\t\t\tincludeInstances: true,\n\t\t\tmatrixWorld: Array.isArray( root ) ? new Matrix4() : root.matrixWorld,\n\t\t\ttargetLeafSize: 1,\n\t\t\t...options,\n\t\t};\n\n\t\tsuper();\n\n\t\t// collect all the leaf node objects in the geometries\n\t\tconst objectSet = new Set();\n\t\tcollectObjects( root, objectSet );\n\n\t\t// calculate the number of bits required for the primary id, leaving the remainder\n\t\t// for the instanceId count\n\t\tconst objects = Array.from( objectSet );\n\t\tconst idBits = Math.ceil( Math.log2( objects.length ) );\n\t\tconst idMask = ( 1 << idBits ) - 1;\n\n\t\tthis.objects = objects;\n\t\tthis.idBits = idBits;\n\t\tthis.idMask = idMask;\n\t\tthis.primitiveBuffer = null;\n\t\tthis.primitiveBufferStride = 1;\n\n\t\t// settings\n\t\tthis.precise = options.precise;\n\t\tthis.includeInstances = options.includeInstances;\n\t\tthis.matrixWorld = options.matrixWorld;\n\n\t\tthis.init( options );\n\n\t}\n\n\t/**\n\t * Returns the `Object3D` associated with a composite id as provided to `intersectsObject`.\n\t * @param {number} compositeId\n\t * @returns {Object3D}\n\t */\n\tgetObjectFromId( compositeId ) {\n\n\t\tconst { idMask, objects } = this;\n\t\tconst id = getObjectId( compositeId, idMask );\n\t\treturn objects[ id ];\n\n\t}\n\n\t/**\n\t * Returns the instance index associated with a composite id as provided to `intersectsObject`.\n\t * @param {number} compositeId\n\t * @returns {number}\n\t */\n\tgetInstanceFromId( compositeId ) {\n\n\t\tconst { idMask, idBits } = this;\n\t\treturn getInstanceId( compositeId, idBits, idMask );\n\n\t}\n\n\tinit( options ) {\n\n\t\tconst { objects, idBits, matrixWorld } = this;\n\n\t\t// pre-cache the inverse matrix for use in the \"getPrimitiveBoundingBox\" function\n\t\t_inverseMatrix.copy( matrixWorld ).invert();\n\n\t\tthis.primitiveBuffer = new Uint32Array( this._countPrimitives( objects ) );\n\t\tthis._fillPrimitiveBuffer( objects, idBits, this.primitiveBuffer );\n\n\t\tsuper.init( options );\n\n\t}\n\n\trefit( ...args ) {\n\n\t\t// pre-cache the inverse matrix for use in the \"getPrimitiveBoundingBox\" function\n\t\t_inverseMatrix.copy( this.matrixWorld ).invert();\n\n\t\tsuper.refit( ...args );\n\n\t}\n\n\twritePrimitiveBounds( i, targetBuffer, writeOffset ) {\n\n\t\tconst { primitiveBuffer } = this;\n\t\tthis._getPrimitiveBoundingBox( primitiveBuffer[ i ], _inverseMatrix, _box );\n\n\t\tconst { min, max } = _box;\n\t\ttargetBuffer[ writeOffset + 0 ] = min.x;\n\t\ttargetBuffer[ writeOffset + 1 ] = min.y;\n\t\ttargetBuffer[ writeOffset + 2 ] = min.z;\n\t\ttargetBuffer[ writeOffset + 3 ] = max.x;\n\t\ttargetBuffer[ writeOffset + 4 ] = max.y;\n\t\ttargetBuffer[ writeOffset + 5 ] = max.z;\n\n\t}\n\n\tgetRootRanges() {\n\n\t\treturn [ { offset: 0, count: this.primitiveBuffer.length } ];\n\n\t}\n\n\t/**\n\t * Performs a spatial query against the BVH. Extends the base `shapecast` with an\n\t * `intersectsObject` callback that is called once per object primitive in leaf nodes.\n\t *\n\t * @param {Object} callbacks\n\t * @param {IntersectsBoundsCallback} callbacks.intersectsBounds\n\t * @param {IntersectsObjectCallback} [callbacks.intersectsObject]\n\t * @param {IntersectsRangeCallback} [callbacks.intersectsRange]\n\t * @param {BoundsTraverseOrderCallback} [callbacks.boundsTraverseOrder]\n\t * @returns {boolean}\n\t */\n\tshapecast( callbacks ) {\n\n\t\treturn super.shapecast( {\n\t\t\t...callbacks,\n\n\t\t\tintersectsPrimitive: callbacks.intersectsObject,\n\t\t\tscratchPrimitive: null,\n\t\t\titerate: iterateOverObjects,\n\t\t} );\n\n\t}\n\n\t// TODO: this is out of sync with the MeshBVH raycast signature.\n\t// Change this to \"raycastObject3D\"? Or add an equivalent?\n\traycast( raycaster, intersects = [] ) {\n\n\t\tconst { matrixWorld, includeInstances } = this;\n\t\tconst { firstHitOnly } = raycaster;\n\t\tconst localIntersects = [];\n\n\t\t// transform the ray into the local bvh frame\n\t\t_inverseMatrix.copy( matrixWorld ).invert();\n\t\t_ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );\n\n\t\tlet closestDistance = Infinity;\n\t\tlet closestHit = null;\n\n\t\tthis.shapecast( {\n\t\t\tboundsTraverseOrder: box => {\n\n\t\t\t\treturn box.distanceToPoint( _ray.origin );\n\n\t\t\t},\n\t\t\tintersectsBounds: box => {\n\n\t\t\t\tif ( firstHitOnly ) {\n\n\t\t\t\t\tif ( ! _ray.intersectBox( box, _vec ) ) {\n\n\t\t\t\t\t\treturn NOT_INTERSECTED;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlet dist;\n\t\t\t\t\tif ( box.containsPoint( _ray.origin ) ) {\n\n\t\t\t\t\t\tdist = 0;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t_vec.applyMatrix4( matrixWorld );\n\t\t\t\t\t\tdist = raycaster.ray.origin.distanceTo( _vec );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// early out if the box is further than the closest raycast\n\t\t\t\t\treturn dist < closestDistance ? INTERSECTED : NOT_INTERSECTED;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn _ray.intersectsBox( box ) ? INTERSECTED : NOT_INTERSECTED;\n\n\t\t\t\t}\n\n\t\t\t},\n\t\t\tintersectsObject( object, instanceId ) {\n\n\t\t\t\t// skip non visible objects\n\t\t\t\tif ( ! object.visible ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tlocalIntersects.length = 0;\n\n\t\t\t\tif ( object.isInstancedMesh && includeInstances ) {\n\n\t\t\t\t\t// raycast the instance\n\t\t\t\t\t_mesh.geometry = object.geometry;\n\t\t\t\t\t_mesh.material = object.material;\n\n\t\t\t\t\tobject.getMatrixAt( instanceId, _mesh.matrixWorld );\n\t\t\t\t\t_mesh.matrixWorld.premultiply( object.matrixWorld );\n\t\t\t\t\t_mesh.raycast( raycaster, localIntersects );\n\n\t\t\t\t\tlocalIntersects.forEach( hit => {\n\n\t\t\t\t\t\thit.object = object;\n\t\t\t\t\t\thit.instanceId = instanceId;\n\n\t\t\t\t\t} );\n\n\t\t\t\t\t_mesh.material = null;\n\n\t\t\t\t} else if ( object.isBatchedMesh && includeInstances ) {\n\n\t\t\t\t\tif ( ! object.getVisibleAt( instanceId ) ) {\n\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// extract the geometry & material\n\t\t\t\t\tconst geometryId = object.getGeometryIdAt( instanceId );\n\t\t\t\t\tconst geometryRange = object.getGeometryRangeAt( geometryId, _geometryRange );\n\n\t\t\t\t\t_geometry.index = object.geometry.index;\n\t\t\t\t\t_geometry.attributes = object.geometry.attributes;\n\t\t\t\t\t_geometry.setDrawRange( geometryRange.start, geometryRange.count );\n\n\t\t\t\t\t_mesh.geometry = _geometry;\n\t\t\t\t\t_mesh.material = object.material;\n\n\t\t\t\t\t// perform a raycast against the proxy mesh\n\t\t\t\t\tobject.getMatrixAt( instanceId, _mesh.matrixWorld );\n\t\t\t\t\t_mesh.matrixWorld.premultiply( object.matrixWorld );\n\t\t\t\t\t_mesh.raycast( raycaster, localIntersects );\n\n\t\t\t\t\t// fix up the fields\n\t\t\t\t\tlocalIntersects.forEach( hit => {\n\n\t\t\t\t\t\thit.object = object;\n\t\t\t\t\t\thit.batchId = instanceId;\n\n\t\t\t\t\t} );\n\n\t\t\t\t\t_mesh.material = null;\n\t\t\t\t\t_geometry.index = null;\n\t\t\t\t\t_geometry.attributes = null;\n\t\t\t\t\t_geometry.setDrawRange( 0, Infinity );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tobject.raycast( raycaster, localIntersects );\n\n\t\t\t\t}\n\n\t\t\t\t// find the closest hit to track\n\t\t\t\tif ( firstHitOnly ) {\n\n\t\t\t\t\tlocalIntersects.forEach( hit => {\n\n\t\t\t\t\t\tif ( hit.distance < closestDistance ) {\n\n\t\t\t\t\t\t\tclosestDistance = hit.distance;\n\t\t\t\t\t\t\tclosestHit = hit;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tintersects.push( ...localIntersects );\n\n\t\t\t\t}\n\n\t\t\t},\n\t\t} );\n\n\t\t// save the closest hit only if firstHitOnly = true\n\t\tif ( firstHitOnly && closestHit ) {\n\n\t\t\tintersects.push( closestHit );\n\n\t\t}\n\n\t\treturn intersects;\n\n\t}\n\n\t// get the bounding box of a primitive node accounting for the bvh options\n\t_getPrimitiveBoundingBox( compositeId, inverseMatrixWorld, target ) {\n\n\t\tconst { objects, idMask, idBits, precise, includeInstances } = this;\n\t\tconst id = getObjectId( compositeId, idMask );\n\t\tconst instanceId = getInstanceId( compositeId, idBits, idMask );\n\t\tconst object = objects[ id ];\n\n\t\tif ( ! includeInstances && ( object.isInstancedMesh || object.isBatchedMesh ) ) {\n\n\t\t\t// if we're not using instances then just account for the overall bounds of the BatchedMesh and InstancedMesh\n\t\t\tif ( ! object.boundingBox ) {\n\n\t\t\t\tobject.computeBoundingBox();\n\n\t\t\t}\n\n\t\t\tif ( ! object.boundingSphere ) {\n\n\t\t\t\tobject.computeBoundingSphere();\n\n\t\t\t}\n\n\t\t\t_matrix\n\t\t\t\t.copy( object.matrixWorld )\n\t\t\t\t.premultiply( inverseMatrixWorld );\n\n\t\t\t_sphere\n\t\t\t\t.copy( object.boundingSphere )\n\t\t\t\t.applyMatrix4( _matrix );\n\n\t\t\ttarget\n\t\t\t\t.copy( object.boundingBox )\n\t\t\t\t.applyMatrix4( _matrix );\n\n\t\t\tshrinkToSphere( target, _sphere );\n\n\t\t} else if ( precise ) {\n\n\t\t\t// calculate precise bounds if necessary by calculating the bounds of all vertices\n\t\t\t// in the bvh frame\n\t\t\tif ( object.isInstancedMesh ) {\n\n\t\t\t\tobject\n\t\t\t\t\t.getMatrixAt( instanceId, _matrix );\n\n\t\t\t\t_matrix\n\t\t\t\t\t.premultiply( object.matrixWorld )\n\t\t\t\t\t.premultiply( inverseMatrixWorld );\n\n\t\t\t\tgetPreciseBounds( object.geometry, _matrix, target );\n\n\t\t\t} else if ( object.isBatchedMesh ) {\n\n\t\t\t\tconst geometryId = object.getGeometryIdAt( instanceId );\n\t\t\t\tconst geometryRange = object.getGeometryRangeAt( geometryId, _geometryRange );\n\n\t\t\t\t_geometry.index = object.geometry.index;\n\t\t\t\t_geometry.attributes = object.geometry.attributes;\n\t\t\t\t_geometry.setDrawRange( geometryRange.start, geometryRange.count );\n\n\t\t\t\tobject\n\t\t\t\t\t.getMatrixAt( instanceId, _matrix );\n\n\t\t\t\t_matrix\n\t\t\t\t\t.premultiply( object.matrixWorld )\n\t\t\t\t\t.premultiply( inverseMatrixWorld );\n\n\t\t\t\tgetPreciseBounds( _geometry, _matrix, target );\n\n\t\t\t\t_geometry.attributes = null;\n\n\t\t\t} else {\n\n\t\t\t\t_matrix\n\t\t\t\t\t.copy( object.matrixWorld )\n\t\t\t\t\t.premultiply( inverseMatrixWorld );\n\n\t\t\t\ttarget.setFromObject( object, true ).applyMatrix4( inverseMatrixWorld );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// otherwise use the fast path of extracting the cached, AABB bounds and transforming them\n\t\t\t// into the local BVH frame\n\t\t\tif ( object.isInstancedMesh ) {\n\n\t\t\t\tif ( ! object.geometry.boundingBox ) {\n\n\t\t\t\t\tobject.geometry.computeBoundingBox();\n\n\t\t\t\t}\n\n\t\t\t\tif ( ! object.geometry.boundingSphere ) {\n\n\t\t\t\t\tobject.geometry.computeBoundingSphere();\n\n\t\t\t\t}\n\n\t\t\t\tobject\n\t\t\t\t\t.getMatrixAt( instanceId, _matrix );\n\n\t\t\t\t_matrix\n\t\t\t\t\t.premultiply( object.matrixWorld )\n\t\t\t\t\t.premultiply( inverseMatrixWorld );\n\n\t\t\t\t_sphere\n\t\t\t\t\t.copy( object.geometry.boundingSphere )\n\t\t\t\t\t.applyMatrix4( _matrix );\n\n\t\t\t\ttarget\n\t\t\t\t\t.copy( object.geometry.boundingBox )\n\t\t\t\t\t.applyMatrix4( _matrix );\n\n\t\t\t\tshrinkToSphere( target, _sphere );\n\n\t\t\t} else if ( object.isBatchedMesh ) {\n\n\t\t\t\tconst geometryId = object.getGeometryIdAt( instanceId );\n\n\t\t\t\tobject\n\t\t\t\t\t.getMatrixAt( instanceId, _matrix );\n\n\t\t\t\t_matrix\n\t\t\t\t\t.premultiply( object.matrixWorld )\n\t\t\t\t\t.premultiply( inverseMatrixWorld );\n\n\t\t\t\tobject\n\t\t\t\t\t.getBoundingSphereAt( geometryId, _sphere )\n\t\t\t\t\t.applyMatrix4( _matrix );\n\n\t\t\t\tobject\n\t\t\t\t\t.getBoundingBoxAt( geometryId, target )\n\t\t\t\t\t.applyMatrix4( _matrix );\n\n\t\t\t\tshrinkToSphere( target, _sphere );\n\n\t\t\t} else {\n\n\t\t\t\ttarget\n\t\t\t\t\t.setFromObject( object, false )\n\t\t\t\t\t.applyMatrix4( inverseMatrixWorld );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t// counts the total number of primitives required by the objects in given array of objects\n\t_countPrimitives( objects ) {\n\n\t\tconst { includeInstances } = this;\n\t\tlet total = 0;\n\t\tobjects.forEach( object => {\n\n\t\t\tif ( object.isInstancedMesh && includeInstances ) {\n\n\t\t\t\ttotal += object.count;\n\n\t\t\t} else if ( object.isBatchedMesh && includeInstances ) {\n\n\t\t\t\tif ( ! ( 'instanceCount' in object ) ) {\n\n\t\t\t\t\tthrow new Error( 'ObjectBVH: Three.js revision >= r169 is required to use BatchedMesh.' );\n\n\t\t\t\t}\n\n\t\t\t\ttotal += object.instanceCount;\n\n\t\t\t} else {\n\n\t\t\t\ttotal ++;\n\n\t\t\t}\n\n\t\t} );\n\n\t\treturn total;\n\n\t}\n\n\t_fillPrimitiveBuffer( objects, idBits, target ) {\n\n\t\tconst { includeInstances } = this;\n\t\tlet index = 0;\n\t\tobjects.forEach( ( object, i ) => {\n\n\t\t\tif ( object.isInstancedMesh && includeInstances ) {\n\n\t\t\t\tconst count = object.count;\n\t\t\t\tfor ( let c = 0; c < count; c ++ ) {\n\n\t\t\t\t\ttarget[ index ] = ( c << idBits ) | i;\n\t\t\t\t\tindex ++;\n\n\t\t\t\t}\n\n\t\t\t} else if ( object.isBatchedMesh && includeInstances ) {\n\n\t\t\t\tconst { instanceCount, maxInstanceCount } = object;\n\t\t\t\tlet foundInstances = 0;\n\t\t\t\tlet iter = 0;\n\n\t\t\t\twhile ( foundInstances < instanceCount && iter < maxInstanceCount ) {\n\n\t\t\t\t\t// TODO: it would be better to have a consistent way of querying whether an\n\t\t\t\t\t// instance were active\n\t\t\t\t\ttry {\n\n\t\t\t\t\t\tobject.getVisibleAt( iter );\n\n\t\t\t\t\t\ttarget[ index ] = ( iter << idBits ) | i;\n\t\t\t\t\t\tfoundInstances ++;\n\t\t\t\t\t\tindex ++;\n\n\t\t\t\t\t} catch {\n\n\t\t\t\t\t\t//\n\n\t\t\t\t\t}\n\n\t\t\t\t\titer ++;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\ttarget[ index ] = i;\n\t\t\t\tindex ++;\n\n\t\t\t}\n\n\t\t} );\n\n\t}\n\n}\n\n// id functions\n// extract the primary object id given the provided mask\nfunction getObjectId( id, idMask ) {\n\n\treturn id & idMask;\n\n}\n\n// extract the instance id given the mask and number of bits to shift\nfunction getInstanceId( id, idBits, idMask ) {\n\n\treturn ( id & ( ~ idMask ) ) >>> idBits;\n\n}\n\n// traverse the full scene and collect all leaves\nfunction collectObjects( root, objectSet = new Set() ) {\n\n\tif ( Array.isArray( root ) ) {\n\n\t\troot.forEach( object => collectObjects( object, objectSet ) );\n\n\t} else {\n\n\t\troot.traverse( child => {\n\n\t\t\tif ( child.isMesh || child.isLine || child.isPoints ) {\n\n\t\t\t\tobjectSet.add( child );\n\n\t\t\t}\n\n\t\t} );\n\n\t}\n\n}\n\n// calculate precise box bounds of the given geometry in the given frame\nfunction getPreciseBounds( geometry, matrix, target ) {\n\n\ttarget.makeEmpty();\n\n\tconst drawRange = geometry.drawRange;\n\tconst indexAttr = geometry.index;\n\tconst posAttr = geometry.attributes.position;\n\tconst start = drawRange.start;\n\tconst vertCount = indexAttr ? indexAttr.count : posAttr.count;\n\tconst count = Math.min( vertCount - start, drawRange.count );\n\tfor ( let i = start, l = start + count; i < l; i ++ ) {\n\n\t\tlet vi = i;\n\t\tif ( indexAttr ) {\n\n\t\t\tvi = indexAttr.getX( vi );\n\n\t\t}\n\n\t\t_vec.fromBufferAttribute( posAttr, vi ).applyMatrix4( matrix );\n\t\ttarget.expandByPoint( _vec );\n\n\t}\n\n\treturn target;\n\n}\n\n// iterator helper for raycasting\nfunction iterateOverObjects( offset, count, bvh, callback, contained, depth, /* scratch */ ) {\n\n\tconst { primitiveBuffer, objects, idMask, idBits } = bvh;\n\tfor ( let i = offset, l = count + offset; i < l; i ++ ) {\n\n\t\tconst compositeId = primitiveBuffer[ i ];\n\t\tconst id = getObjectId( compositeId, idMask );\n\t\tconst instanceId = getInstanceId( compositeId, idBits, idMask );\n\t\tconst object = objects[ id ];\n\t\tif ( callback( object, instanceId, contained, depth ) ) {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t}\n\n\treturn false;\n\n}\n\nfunction shrinkToSphere( box, sphere ) {\n\n\t_vec.copy( sphere.center ).addScalar( - sphere.radius );\n\tbox.min.max( _vec );\n\n\t_vec.copy( sphere.center ).addScalar( sphere.radius );\n\tbox.max.min( _vec );\n\n}\n","/** @import { SkinnedMesh } from 'three' */\n/** @import { IntersectsBoundsCallback, IntersectsRangeCallback, BoundsTraverseOrderCallback } from './BVH.js' */\nimport { Vector3, Vector2, Ray, Matrix4, FrontSide, BackSide, Triangle, REVISION } from 'three';\nimport { GeometryBVH } from './GeometryBVH.js';\nimport { ExtendedTriangle } from '../math/ExtendedTriangle.js';\nimport { INTERSECTED, NOT_INTERSECTED, SKIP_GENERATION } from './Constants.js';\n\nconst _v0 = /* @__PURE__ */ new Vector3();\nconst _v1 = /* @__PURE__ */ new Vector3();\nconst _v2 = /* @__PURE__ */ new Vector3();\nconst _ray = /* @__PURE__ */ new Ray();\nconst _inverseMatrix = /* @__PURE__ */ new Matrix4();\nconst _localPoint = /* @__PURE__ */ new Vector3();\nconst _vec = /* @__PURE__ */ new Vector3();\nconst _axes = [ 'x', 'y', 'z' ];\n\nconst IS_GT_REVISION_169 = parseInt( REVISION ) >= 169;\nconst IS_LT_REVISION_161 = parseInt( REVISION ) <= 161;\n\nconst _uvA = /* @__PURE__ */ new Vector2();\nconst _uvB = /* @__PURE__ */ new Vector2();\nconst _uvC = /* @__PURE__ */ new Vector2();\nconst _normalA = /* @__PURE__ */ new Vector3();\nconst _normalB = /* @__PURE__ */ new Vector3();\nconst _normalC = /* @__PURE__ */ new Vector3();\n\n/**\n * @callback IntersectsTriangleCallback\n * @param {ExtendedTriangle} triangle - The triangle primitive in local space.\n * @param {number} index - The primitive index within the BVH buffer.\n * @param {boolean} contained - Whether the node bounds are fully contained by the query shape.\n * @param {number} depth - The depth of the node in the tree.\n * @returns {boolean} Return `true` to stop traversal.\n */\n\n/**\n * BVH for `SkinnedMesh` objects. Computes primitive bounds using\n * `SkinnedMesh.getVertexPosition` so the tree reflects the current posed state\n * of the mesh. Call `refit()` after updating the skeleton to keep bounds accurate.\n *\n * @param {SkinnedMesh} mesh\n * @param {Object} [options] - Same options as {@link GeometryBVH}.\n * @extends GeometryBVH\n */\nexport class SkinnedMeshBVH extends GeometryBVH {\n\n\tget primitiveStride() {\n\n\t\treturn 3;\n\n\t}\n\n\tconstructor( mesh, options = {} ) {\n\n\t\tif ( ! mesh.isMesh ) {\n\n\t\t\tthrow new Error( 'SkinnedMeshBVH: First argument must be a Mesh.' );\n\n\t\t}\n\n\t\t// skip generation initially so we can add our local fields\n\t\t// TODO: is there a more clean way to handle this? Update all subclasses to be\n\t\t// responsible for calling \"init\" themselves?\n\t\tsuper( mesh.geometry, {\n\t\t\t...options,\n\t\t\t[ SKIP_GENERATION ]: true,\n\t\t} );\n\t\tthis.mesh = mesh;\n\n\t\tif ( ! options[ SKIP_GENERATION ] ) {\n\n\t\t\tthis.init( options );\n\n\t\t}\n\n\t}\n\n\twritePrimitiveBounds( i, targetBuffer, baseIndex ) {\n\n\t\tconst { mesh, geometry } = this;\n\t\tconst indirectBuffer = this._indirectBuffer;\n\t\tconst index = geometry.index ? geometry.index.array : null;\n\n\t\tconst tri = indirectBuffer ? indirectBuffer[ i ] : i;\n\t\tconst tri3 = tri * 3;\n\n\t\tlet ai = tri3 + 0;\n\t\tlet bi = tri3 + 1;\n\t\tlet ci = tri3 + 2;\n\n\t\tif ( index ) {\n\n\t\t\tai = index[ ai ];\n\t\t\tbi = index[ bi ];\n\t\t\tci = index[ ci ];\n\n\t\t}\n\n\t\t// Get skinned vertex positions\n\t\tmesh.getVertexPosition( ai, _v0 );\n\t\tmesh.getVertexPosition( bi, _v1 );\n\t\tmesh.getVertexPosition( ci, _v2 );\n\n\t\t// Compute bounds for each axis\n\t\tfor ( let el = 0; el < 3; el ++ ) {\n\n\t\t\tconst axis = _axes[ el ];\n\t\t\tconst a = _v0[ axis ];\n\t\t\tconst b = _v1[ axis ];\n\t\t\tconst c = _v2[ axis ];\n\n\t\t\tlet min = a;\n\t\t\tif ( b < min ) min = b;\n\t\t\tif ( c < min ) min = c;\n\n\t\t\tlet max = a;\n\t\t\tif ( b > max ) max = b;\n\t\t\tif ( c > max ) max = c;\n\n\t\t\t// Write in min/max format [minx, miny, minz, maxx, maxy, maxz]\n\t\t\ttargetBuffer[ baseIndex + el ] = min;\n\t\t\ttargetBuffer[ baseIndex + el + 3 ] = max;\n\n\t\t}\n\n\t\treturn targetBuffer;\n\n\t}\n\n\t/**\n\t * Performs a spatial query against the BVH. Extends the base `shapecast` with an\n\t * `intersectsTriangle` callback that is called once per triangle primitive in leaf nodes.\n\t *\n\t * @param {Object} callbacks\n\t * @param {IntersectsBoundsCallback} callbacks.intersectsBounds\n\t * @param {IntersectsTriangleCallback} [callbacks.intersectsTriangle]\n\t * @param {IntersectsRangeCallback} [callbacks.intersectsRange]\n\t * @param {BoundsTraverseOrderCallback} [callbacks.boundsTraverseOrder]\n\t * @returns {boolean}\n\t */\n\tshapecast( callbacks ) {\n\n\t\tconst triangle = new ExtendedTriangle();\n\t\treturn super.shapecast(\n\t\t\t{\n\t\t\t\t...callbacks,\n\t\t\t\tintersectsPrimitive: callbacks.intersectsTriangle,\n\t\t\t\tscratchPrimitive: triangle,\n\t\t\t\titerate: iterateOverTriangles,\n\t\t\t},\n\t\t);\n\n\t}\n\n\traycastObject3D( object, raycaster, intersects = [] ) {\n\n\t\tconst { material } = object;\n\t\tif ( material === undefined ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tconst { matrixWorld } = object;\n\t\tconst { firstHitOnly } = raycaster;\n\n\t\t_inverseMatrix.copy( matrixWorld ).invert();\n\t\t_ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );\n\n\t\tlet closestHit = null;\n\t\tlet closestDistance = Infinity;\n\n\t\tthis.shapecast( {\n\t\t\tboundsTraverseOrder: box => {\n\n\t\t\t\treturn box.distanceToPoint( _ray.origin );\n\n\t\t\t},\n\t\t\tintersectsBounds: box => {\n\n\t\t\t\tif ( firstHitOnly ) {\n\n\t\t\t\t\tif ( ! _ray.intersectBox( box, _vec ) ) {\n\n\t\t\t\t\t\treturn NOT_INTERSECTED;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlet dist;\n\t\t\t\t\tif ( box.containsPoint( _ray.origin ) ) {\n\n\t\t\t\t\t\tdist = 0;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t_vec.applyMatrix4( matrixWorld );\n\t\t\t\t\t\tdist = raycaster.ray.origin.distanceTo( _vec );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// early out if the box is further than the closest raycast\n\t\t\t\t\treturn dist < closestDistance ? INTERSECTED : NOT_INTERSECTED;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn _ray.intersectsBox( box ) ? INTERSECTED : NOT_INTERSECTED;\n\n\t\t\t\t}\n\n\t\t\t},\n\t\t\tintersectsTriangle: ( tri, triIndex ) => {\n\n\t\t\t\t// get the intersection\n\t\t\t\tlet point = null;\n\t\t\t\tif ( material.side === FrontSide ) {\n\n\t\t\t\t\tpoint = _ray.intersectTriangle( tri.a, tri.b, tri.c, true, _localPoint );\n\n\t\t\t\t} else if ( material.side === BackSide ) {\n\n\t\t\t\t\tpoint = _ray.intersectTriangle( tri.c, tri.b, tri.a, true, _localPoint );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tpoint = _ray.intersectTriangle( tri.a, tri.b, tri.c, false, _localPoint );\n\n\t\t\t\t}\n\n\t\t\t\tif ( ! point ) {\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\t// transform it into world space\n\t\t\t\tpoint = point.clone().applyMatrix4( matrixWorld );\n\n\t\t\t\t// check distance to ray\n\t\t\t\tconst dist = raycaster.ray.origin.distanceTo( point );\n\t\t\t\tif ( dist >= raycaster.near && dist <= raycaster.far ) {\n\n\t\t\t\t\tif ( firstHitOnly && dist >= closestDistance ) {\n\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// get the vertex indices\n\t\t\t\t\tconst { geometry } = this;\n\t\t\t\t\tconst { index } = geometry;\n\t\t\t\t\tconst actualTri = this.resolvePrimitiveIndex( triIndex );\n\t\t\t\t\tconst triOffset = actualTri * 3;\n\n\t\t\t\t\tlet ai = triOffset + 0;\n\t\t\t\t\tlet bi = triOffset + 1;\n\t\t\t\t\tlet ci = triOffset + 2;\n\n\t\t\t\t\tif ( index ) {\n\n\t\t\t\t\t\tai = index.array[ ai ];\n\t\t\t\t\t\tbi = index.array[ bi ];\n\t\t\t\t\t\tci = index.array[ ci ];\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// build the intersection result\n\t\t\t\t\tconst hit = {\n\t\t\t\t\t\tdistance: dist,\n\t\t\t\t\t\tpoint: point.clone(),\n\t\t\t\t\t\tobject,\n\t\t\t\t\t\tuv: null,\n\t\t\t\t\t\tuv1: null,\n\t\t\t\t\t\tnormal: null,\n\t\t\t\t\t\tface: {\n\t\t\t\t\t\t\ta: ai,\n\t\t\t\t\t\t\tb: bi,\n\t\t\t\t\t\t\tc: ci,\n\t\t\t\t\t\t\tnormal: Triangle.getNormal( tri.a, tri.b, tri.c, new Vector3() ),\n\t\t\t\t\t\t\tmaterialIndex: 0\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfaceIndex: actualTri,\n\t\t\t\t\t};\n\n\t\t\t\t\tif ( IS_GT_REVISION_169 ) {\n\n\t\t\t\t\t\tconst barycoord = new Vector3();\n\t\t\t\t\t\tTriangle.getBarycoord( _localPoint, tri.a, tri.b, tri.c, barycoord );\n\t\t\t\t\t\thit.barycoord = barycoord;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// add attribute fields if available\n\t\t\t\t\tconst uv = geometry.attributes.uv;\n\t\t\t\t\tconst uv1 = geometry.attributes.uv1;\n\t\t\t\t\tconst normal = geometry.attributes.normal;\n\n\t\t\t\t\tif ( uv ) {\n\n\t\t\t\t\t\t_uvA.fromBufferAttribute( uv, ai );\n\t\t\t\t\t\t_uvB.fromBufferAttribute( uv, bi );\n\t\t\t\t\t\t_uvC.fromBufferAttribute( uv, ci );\n\n\t\t\t\t\t\thit.uv = new Vector2();\n\t\t\t\t\t\tconst resUv = Triangle.getInterpolation( _localPoint, tri.a, tri.b, tri.c, _uvA, _uvB, _uvC, hit.uv );\n\t\t\t\t\t\tif ( ! IS_GT_REVISION_169 ) hit.uv = resUv;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( uv1 ) {\n\n\t\t\t\t\t\t_uvA.fromBufferAttribute( uv1, ai );\n\t\t\t\t\t\t_uvB.fromBufferAttribute( uv1, bi );\n\t\t\t\t\t\t_uvC.fromBufferAttribute( uv1, ci );\n\n\t\t\t\t\t\thit.uv1 = new Vector2();\n\t\t\t\t\t\tconst resUv1 = Triangle.getInterpolation( _localPoint, tri.a, tri.b, tri.c, _uvA, _uvB, _uvC, hit.uv1 );\n\t\t\t\t\t\tif ( ! IS_GT_REVISION_169 ) hit.uv1 = resUv1;\n\t\t\t\t\t\tif ( IS_LT_REVISION_161 ) hit.uv2 = hit.uv1;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( normal ) {\n\n\t\t\t\t\t\t_normalA.fromBufferAttribute( normal, ai );\n\t\t\t\t\t\t_normalB.fromBufferAttribute( normal, bi );\n\t\t\t\t\t\t_normalC.fromBufferAttribute( normal, ci );\n\n\t\t\t\t\t\thit.normal = new Vector3();\n\t\t\t\t\t\tconst resNormal = Triangle.getInterpolation( _localPoint, tri.a, tri.b, tri.c, _normalA, _normalB, _normalC, hit.normal );\n\t\t\t\t\t\tif ( hit.normal.dot( _ray.direction ) > 0 ) {\n\n\t\t\t\t\t\t\thit.normal.multiplyScalar( - 1 );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( ! IS_GT_REVISION_169 ) hit.normal = resNormal;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// first hit only settings\n\t\t\t\t\tclosestDistance = hit.distance;\n\t\t\t\t\tclosestHit = hit;\n\n\t\t\t\t\tif ( ! firstHitOnly ) {\n\n\t\t\t\t\t\tintersects.push( hit );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t} );\n\n\t\tif ( firstHitOnly && closestHit ) {\n\n\t\t\tintersects.push( closestHit );\n\n\t\t}\n\n\t\treturn intersects;\n\n\t}\n\n}\n\nfunction iterateOverTriangles(\n\toffset,\n\tcount,\n\tbvh,\n\tintersectsTriangleFunc,\n\tcontained,\n\tdepth,\n\ttriangle\n) {\n\n\tconst { mesh, geometry } = bvh;\n\tconst index = geometry.index ? geometry.index.array : null;\n\n\tfor ( let i = offset, l = count + offset; i < l; i ++ ) {\n\n\t\tconst tri = bvh.resolvePrimitiveIndex( i );\n\n\t\tlet i0 = 3 * tri + 0;\n\t\tlet i1 = 3 * tri + 1;\n\t\tlet i2 = 3 * tri + 2;\n\n\t\tif ( index ) {\n\n\t\t\ti0 = index[ i0 ];\n\t\t\ti1 = index[ i1 ];\n\t\t\ti2 = index[ i2 ];\n\n\t\t}\n\n\t\tmesh.getVertexPosition( i0, triangle.a );\n\t\tmesh.getVertexPosition( i1, triangle.b );\n\t\tmesh.getVertexPosition( i2, triangle.c );\n\t\ttriangle.needsUpdate = true;\n\n\t\tif ( intersectsTriangleFunc( triangle, i, contained, depth ) ) {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t}\n\n\treturn false;\n\n}\n","/** @import { Color } from 'three' */\n/** @import { GeometryBVH } from '../core/GeometryBVH.js' */\nimport { LineBasicMaterial, BufferAttribute, Box3, Group, MeshBasicMaterial, Object3D, BufferGeometry, Mesh, Matrix4, Vector3 } from 'three';\nimport { arrayToBox } from '../utils/ArrayBoxUtilities.js';\nimport { MeshBVH } from '../core/MeshBVH.js';\n\nconst boundingBox = /* @__PURE__ */ new Box3();\nconst matrix = /* @__PURE__ */ new Matrix4();\nconst vec = /* @__PURE__ */ new Vector3();\n\nclass BVHRootHelper extends Object3D {\n\n\tget isMesh() {\n\n\t\treturn ! this.displayEdges;\n\n\t}\n\n\tget isLineSegments() {\n\n\t\treturn this.displayEdges;\n\n\t}\n\n\tget isLine() {\n\n\t\treturn this.displayEdges;\n\n\t}\n\n\tgetVertexPosition( ...args ) {\n\n\t\t// implement this function so it works with Box3.setFromObject\n\t\treturn Mesh.prototype.getVertexPosition.call( this, ...args );\n\n\t}\n\n\tconstructor( bvh, material, depth = 10, group = 0 ) {\n\n\t\tsuper();\n\n\t\tthis.material = material;\n\t\tthis.geometry = new BufferGeometry();\n\t\tthis.name = 'BVHRootHelper';\n\t\tthis.depth = depth;\n\t\tthis.displayParents = false;\n\t\tthis.bvh = bvh;\n\t\tthis.displayEdges = true;\n\t\tthis._group = group;\n\n\t}\n\n\traycast() {}\n\n\tintersectsFrustum( frustum ) {\n\n\t\t// three r186+ frustum culls through this method, so forward it like Mesh / Line / Points do\n\t\treturn frustum.intersectsObject( this );\n\n\t}\n\n\tupdate() {\n\n\t\tconst boundsTree = this.bvh;\n\t\tthis.geometry.dispose();\n\t\tthis.visible = false;\n\t\tif ( boundsTree ) {\n\n\t\t\tthis.geometry = this.getGeometry( boundsTree );\n\t\t\tthis.visible = true;\n\n\t\t}\n\n\t}\n\n\tgetGeometry( boundsTree ) {\n\n\t\tconst group = this._group;\n\n\t\t// fill in the position buffer with the bounds corners\n\t\tlet positionArray = null;\n\t\tif ( group !== - 1 ) {\n\n\t\t\tpositionArray = this.getBVHBoundPositions( boundsTree, group );\n\n\t\t} else {\n\n\t\t\tconst positionArrays = boundsTree._roots.map( ( r, i ) => this.getBVHBoundPositions( boundsTree, i ) );\n\t\t\tconst total = positionArrays.reduce( ( v, arr ) => v + arr.length, 0 );\n\t\t\tpositionArray = new Float32Array( total );\n\n\t\t\tlet offset = 0;\n\t\t\tpositionArrays.forEach( arr => {\n\n\t\t\t\tpositionArray.set( arr, offset );\n\t\t\t\toffset += arr.length;\n\n\t\t\t} );\n\n\t\t}\n\n\t\tconst indexArray = this.getBVHBoundIndices( positionArray );\n\n\t\t// update the geometry\n\t\tconst geometry = new BufferGeometry();\n\t\tgeometry.setIndex( new BufferAttribute( indexArray, 1, false ) );\n\t\tgeometry.setAttribute( 'position', new BufferAttribute( positionArray, 3, false ) );\n\t\treturn geometry;\n\n\t}\n\n\tgetBVHBoundIndices( positionArray ) {\n\n\t\tconst boundsCount = positionArray.length / ( 8 * 3 );\n\t\tlet indexArray;\n\t\tlet indices;\n\t\tif ( this.displayEdges ) {\n\n\t\t\t// fill in the index buffer to point to the corner points\n\t\t\tindices = new Uint8Array( [\n\t\t\t\t// x axis\n\t\t\t\t0, 4,\n\t\t\t\t1, 5,\n\t\t\t\t2, 6,\n\t\t\t\t3, 7,\n\n\t\t\t\t// y axis\n\t\t\t\t0, 2,\n\t\t\t\t1, 3,\n\t\t\t\t4, 6,\n\t\t\t\t5, 7,\n\n\t\t\t\t// z axis\n\t\t\t\t0, 1,\n\t\t\t\t2, 3,\n\t\t\t\t4, 5,\n\t\t\t\t6, 7,\n\t\t\t] );\n\n\t\t} else {\n\n\t\t\tindices = new Uint8Array( [\n\n\t\t\t\t// X-, X+\n\t\t\t\t0, 1, 2,\n\t\t\t\t2, 1, 3,\n\n\t\t\t\t4, 6, 5,\n\t\t\t\t6, 7, 5,\n\n\t\t\t\t// Y-, Y+\n\t\t\t\t1, 4, 5,\n\t\t\t\t0, 4, 1,\n\n\t\t\t\t2, 3, 6,\n\t\t\t\t3, 7, 6,\n\n\t\t\t\t// Z-, Z+\n\t\t\t\t0, 2, 4,\n\t\t\t\t2, 6, 4,\n\n\t\t\t\t1, 5, 3,\n\t\t\t\t3, 5, 7,\n\n\t\t\t] );\n\n\t\t}\n\n\t\tif ( positionArray.length > 65535 ) {\n\n\t\t\tindexArray = new Uint32Array( indices.length * boundsCount );\n\n\t\t} else {\n\n\t\t\tindexArray = new Uint16Array( indices.length * boundsCount );\n\n\t\t}\n\n\t\tconst indexLength = indices.length;\n\t\tfor ( let i = 0; i < boundsCount; i ++ ) {\n\n\t\t\tconst posOffset = i * 8;\n\t\t\tconst indexOffset = i * indexLength;\n\t\t\tfor ( let j = 0; j < indexLength; j ++ ) {\n\n\t\t\t\tindexArray[ indexOffset + j ] = posOffset + indices[ j ];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn indexArray;\n\n\t}\n\n\tgetBVHBoundPositions( bvh, group = 0, matrix = null ) {\n\n\t\t// count the number of bounds required\n\t\tconst targetDepth = this.depth - 1;\n\t\tconst displayParents = this.displayParents;\n\t\tlet boundsCount = 0;\n\t\tbvh.traverse( ( depth, isLeaf ) => {\n\n\t\t\tif ( depth >= targetDepth || isLeaf ) {\n\n\t\t\t\tboundsCount ++;\n\t\t\t\treturn true;\n\n\t\t\t} else if ( displayParents ) {\n\n\t\t\t\tboundsCount ++;\n\n\t\t\t}\n\n\t\t}, group );\n\n\t\t// fill in the position buffer with the bounds corners\n\t\tlet posIndex = 0;\n\t\tconst positionArray = new Float32Array( 8 * 3 * boundsCount );\n\t\tbvh.traverse( ( depth, isLeaf, boundingData ) => {\n\n\t\t\tconst terminate = depth >= targetDepth || isLeaf;\n\t\t\tif ( terminate || displayParents ) {\n\n\t\t\t\tarrayToBox( 0, boundingData, boundingBox );\n\n\t\t\t\tconst { min, max } = boundingBox;\n\t\t\t\tfor ( let x = - 1; x <= 1; x += 2 ) {\n\n\t\t\t\t\tconst xVal = x < 0 ? min.x : max.x;\n\t\t\t\t\tfor ( let y = - 1; y <= 1; y += 2 ) {\n\n\t\t\t\t\t\tconst yVal = y < 0 ? min.y : max.y;\n\t\t\t\t\t\tfor ( let z = - 1; z <= 1; z += 2 ) {\n\n\t\t\t\t\t\t\tconst zVal = z < 0 ? min.z : max.z;\n\t\t\t\t\t\t\tvec.set( xVal, yVal, zVal );\n\t\t\t\t\t\t\tif ( matrix ) {\n\n\t\t\t\t\t\t\t\tvec.applyMatrix4( matrix );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tvec.toArray( positionArray, posIndex );\n\t\t\t\t\t\t\tposIndex += 3;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn terminate;\n\n\t\t\t}\n\n\t\t}, group );\n\n\t\treturn positionArray;\n\n\t}\n\n}\n\n/**\n * A `THREE.Group` that visualizes a BVH as wireframe bounding boxes or solid\n * face overlays. Attach it as a sibling of the mesh in the scene graph and\n * call `update()` whenever the mesh's BVH or world transform changes.\n *\n * @param {Object3D | GeometryBVH | null} [mesh=null] - The mesh whose `geometry.boundsTree`\n *   should be displayed, or a `GeometryBVH` to display directly.\n * @param {GeometryBVH | number | null} [bvh=null] - The BVH to visualize. When the first\n *   argument is a `GeometryBVH`, this argument is interpreted as `depth`.\n * @param {number} [depth=10] - Maximum tree depth to display.\n * @extends Group\n */\nexport class BVHHelper extends Group {\n\n\t/**\n\t * Shortcut to `edgeMaterial.color`.\n\t * @type {Color}\n\t * @readonly\n\t */\n\tget color() {\n\n\t\treturn this.edgeMaterial.color;\n\n\t}\n\n\t/**\n\t * Opacity applied to both edge and mesh materials.\n\t * @type {number}\n\t */\n\tget opacity() {\n\n\t\treturn this.edgeMaterial.opacity;\n\n\t}\n\n\tset opacity( v ) {\n\n\t\tthis.edgeMaterial.opacity = v;\n\t\tthis.meshMaterial.opacity = v;\n\n\t}\n\n\tget objectIndex() {\n\n\t\tconsole.warn( 'BVHHelper: \"objectIndex\" has been renamed \"instanceId\".' );\n\t\treturn this.instanceId;\n\n\t}\n\n\tset objectIndex( v ) {\n\n\t\tconsole.warn( 'BVHHelper: \"objectIndex\" has been renamed \"instanceId\".' );\n\t\tthis.instanceId = v;\n\n\t}\n\n\tconstructor( mesh = null, bvh = null, depth = 10 ) {\n\n\t\t// handle bvh, depth signature\n\t\tif ( mesh instanceof MeshBVH ) {\n\n\t\t\tdepth = bvh || 10;\n\t\t\tbvh = mesh;\n\t\t\tmesh = null;\n\n\t\t}\n\n\t\t// handle mesh, depth signature\n\t\tif ( typeof bvh === 'number' ) {\n\n\t\t\tdepth = bvh;\n\t\t\tbvh = null;\n\n\t\t}\n\n\t\tsuper();\n\n\t\tthis.name = 'BVHHelper';\n\n\t\t/** @type {number} */\n\t\tthis.depth = depth;\n\n\t\t/** @type {Object3D | null} */\n\t\tthis.mesh = mesh;\n\n\t\t/** @type {GeometryBVH | null} */\n\t\tthis.bvh = bvh;\n\n\t\t/** @type {boolean} */\n\t\tthis.displayParents = false;\n\n\t\t/** @type {boolean} */\n\t\tthis.displayEdges = true;\n\n\t\t/** @type {number} */\n\t\tthis.instanceId = 0;\n\n\t\tthis._roots = [];\n\n\t\tconst edgeMaterial = new LineBasicMaterial( {\n\t\t\tcolor: 0x00FF88,\n\t\t\ttransparent: true,\n\t\t\topacity: 0.3,\n\t\t\tdepthWrite: false,\n\t\t} );\n\n\t\tconst meshMaterial = new MeshBasicMaterial( {\n\t\t\tcolor: 0x00FF88,\n\t\t\ttransparent: true,\n\t\t\topacity: 0.3,\n\t\t\tdepthWrite: false,\n\t\t} );\n\n\t\tmeshMaterial.color = edgeMaterial.color;\n\n\t\t/**\n\t\t * Material used when rendering in wireframe edge mode.\n\t\t * @type {LineBasicMaterial}\n\t\t */\n\t\tthis.edgeMaterial = edgeMaterial;\n\n\t\t/**\n\t\t * Material used when rendering in solid face mode.\n\t\t * @type {MeshBasicMaterial}\n\t\t */\n\t\tthis.meshMaterial = meshMaterial;\n\n\t\tthis.update();\n\n\t}\n\n\t/**\n\t * Rebuilds the helper's display geometry from the current BVH state. Must\n\t * be called after changes to the BVH, `depth`, `displayParents`, or\n\t * `displayEdges`.\n\t */\n\tupdate() {\n\n\t\tconst mesh = this.mesh;\n\t\tconst instanceId = this.instanceId;\n\t\tlet bvh = this.bvh || mesh.boundsTree || mesh.geometry && mesh.geometry.boundsTree || null;\n\t\tif ( mesh && mesh.isBatchedMesh && mesh.boundsTrees && ! bvh && instanceId >= 0 ) {\n\n\t\t\t// get the bvh from a batchedMesh if not provided\n\t\t\t// TODO: we should have an official way to get the geometry index cleanly\n\t\t\tconst drawInfo = mesh._drawInfo[ instanceId ];\n\t\t\tif ( drawInfo ) {\n\n\t\t\t\tbvh = mesh.boundsTrees[ drawInfo.geometryIndex ] || bvh;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst totalRoots = bvh ? bvh._roots.length : 0;\n\t\twhile ( this._roots.length > totalRoots ) {\n\n\t\t\tconst root = this._roots.pop();\n\t\t\troot.geometry.dispose();\n\t\t\tthis.remove( root );\n\n\t\t}\n\n\t\tfor ( let i = 0; i < totalRoots; i ++ ) {\n\n\t\t\tconst { depth, edgeMaterial, meshMaterial, displayParents, displayEdges } = this;\n\n\t\t\tif ( i >= this._roots.length ) {\n\n\t\t\t\tconst root = new BVHRootHelper( bvh, edgeMaterial, depth, i );\n\t\t\t\tthis.add( root );\n\t\t\t\tthis._roots.push( root );\n\n\t\t\t}\n\n\t\t\tconst root = this._roots[ i ];\n\t\t\troot.bvh = bvh;\n\t\t\troot.depth = depth;\n\t\t\troot.displayParents = displayParents;\n\t\t\troot.displayEdges = displayEdges;\n\t\t\troot.material = displayEdges ? edgeMaterial : meshMaterial;\n\t\t\troot.update();\n\n\t\t}\n\n\t}\n\n\tupdateMatrixWorld( ...args ) {\n\n\t\tconst mesh = this.mesh;\n\t\tconst parent = this.parent;\n\t\tconst instanceId = this.instanceId;\n\n\t\tif ( mesh !== null ) {\n\n\t\t\tmesh.updateWorldMatrix( true, false );\n\n\t\t\tif ( parent ) {\n\n\t\t\t\tthis.matrix\n\t\t\t\t\t.copy( parent.matrixWorld )\n\t\t\t\t\t.invert()\n\t\t\t\t\t.multiply( mesh.matrixWorld );\n\n\t\t\t} else {\n\n\t\t\t\tthis.matrix\n\t\t\t\t\t.copy( mesh.matrixWorld );\n\n\t\t\t}\n\n\t\t\t// handle batched and instanced mesh bvhs\n\t\t\tif ( ( mesh.isInstancedMesh || mesh.isBatchedMesh ) && instanceId >= 0 ) {\n\n\t\t\t\tmesh.getMatrixAt( instanceId, matrix );\n\t\t\t\tthis.matrix.multiply( matrix );\n\n\t\t\t}\n\n\t\t\tthis.matrix.decompose(\n\t\t\t\tthis.position,\n\t\t\t\tthis.quaternion,\n\t\t\t\tthis.scale,\n\t\t\t);\n\n\t\t}\n\n\t\tsuper.updateMatrixWorld( ...args );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.depth = source.depth;\n\t\tthis.mesh = source.mesh;\n\t\tthis.bvh = source.bvh;\n\t\tthis.opacity = source.opacity;\n\t\tthis.color.copy( source.color );\n\n\t}\n\n\tclone() {\n\n\t\treturn new BVHHelper().copy( this );\n\n\t}\n\n\t/**\n\t * Disposes of the materials and geometries used by the helper.\n\t */\n\tdispose() {\n\n\t\tthis.edgeMaterial.dispose();\n\t\tthis.meshMaterial.dispose();\n\n\t\tconst children = this.children;\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tchildren[ i ].geometry.dispose();\n\n\t\t}\n\n\t}\n\n}\n\nexport class MeshBVHHelper extends BVHHelper {\n\n\tconstructor( ...args ) {\n\n\t\tconsole.warn( 'MeshBVHHelper: Class has been deprecated. Use BVHHelper instead.' );\n\t\tsuper( ...args );\n\n\t}\n\n}\n","/** @import { MeshBVH } from '../core/MeshBVH.js' */\n/** @import { BVH } from '../core/BVH.js' */\nimport { Box3 } from 'three';\nimport { PRIMITIVE_INTERSECT_COST, TRAVERSAL_COST } from '../core/Constants.js';\nimport { arrayToBox } from '../utils/ArrayBoxUtilities.js';\nimport { isSharedArrayBufferSupported } from '../utils/BufferUtils.js';\n\nconst _box1 = /* @__PURE__ */ new Box3();\nconst _box2 = /* @__PURE__ */ new Box3();\n\n// https://stackoverflow.com/questions/1248302/how-to-get-the-size-of-a-javascript-object\nfunction getElementSize( el ) {\n\n\tswitch ( typeof el ) {\n\n\t\tcase 'number':\n\t\t\treturn 8;\n\t\tcase 'string':\n\t\t\treturn el.length * 2;\n\t\tcase 'boolean':\n\t\t\treturn 4;\n\t\tdefault:\n\t\t\treturn 0;\n\n\t}\n\n}\n\nfunction isTypedArray( arr ) {\n\n\tconst regex = /(Uint|Int|Float)(8|16|32)Array/;\n\treturn regex.test( arr.constructor.name );\n\n}\n\nfunction getRootExtremes( bvh, group ) {\n\n\tconst result = {\n\t\tnodeCount: 0,\n\t\tleafNodeCount: 0,\n\n\t\tdepth: {\n\t\t\tmin: Infinity, max: - Infinity\n\t\t},\n\t\tprimitives: {\n\t\t\tmin: Infinity, max: - Infinity\n\t\t},\n\t\tsplits: [ 0, 0, 0 ],\n\t\tsurfaceAreaScore: 0,\n\t};\n\n\tbvh.traverse( ( depth, isLeaf, boundingData, offsetOrSplit, count ) => {\n\n\t\tconst l0 = boundingData[ 0 + 3 ] - boundingData[ 0 ];\n\t\tconst l1 = boundingData[ 1 + 3 ] - boundingData[ 1 ];\n\t\tconst l2 = boundingData[ 2 + 3 ] - boundingData[ 2 ];\n\n\t\tconst surfaceArea = 2 * ( l0 * l1 + l1 * l2 + l2 * l0 );\n\n\t\tresult.nodeCount ++;\n\t\tif ( isLeaf ) {\n\n\t\t\tresult.leafNodeCount ++;\n\n\t\t\tresult.depth.min = Math.min( depth, result.depth.min );\n\t\t\tresult.depth.max = Math.max( depth, result.depth.max );\n\n\t\t\tresult.primitives.min = Math.min( count, result.primitives.min );\n\t\t\tresult.primitives.max = Math.max( count, result.primitives.max );\n\n\t\t\tresult.surfaceAreaScore += surfaceArea * PRIMITIVE_INTERSECT_COST * count;\n\n\t\t} else {\n\n\t\t\tresult.splits[ offsetOrSplit ] ++;\n\n\t\t\tresult.surfaceAreaScore += surfaceArea * TRAVERSAL_COST;\n\n\t\t}\n\n\t}, group );\n\n\t// If there are no leaf nodes because the tree hasn't finished generating yet.\n\tif ( result.primitives.min === Infinity ) {\n\n\t\tresult.primitives.min = 0;\n\t\tresult.primitives.max = 0;\n\n\t}\n\n\tif ( result.depth.min === Infinity ) {\n\n\t\tresult.depth.min = 0;\n\t\tresult.depth.max = 0;\n\n\t}\n\n\treturn result;\n\n}\n\n/**\n * @section Debug Functions\n * @typedef {Object} BVHExtremes\n * @property {number} nodeCount Total number of nodes in the tree including leaf nodes.\n * @property {number} leafNodeCount Total number of leaf nodes in the tree.\n * @property {number} surfaceAreaScore Total tree score based on the surface area heuristic.\n * Lower is better. Useful for comparing tree quality and performance, and for detecting\n * degradation after `MeshBVH.refit` calls.\n * @property {{ min: number, max: number }} depth Min and max depth of leaf nodes.\n * @property {{ min: number, max: number }} tris Min and max triangle count in leaf nodes.\n * @property {Array<number>} splits Number of splits on each axis as a three-element array `[X, Y, Z]`.\n */\n\n/**\n * Measures the min and max extremes of the BVH tree structure, including node\n * depth, leaf primitive count, split axis distribution, and a surface-area\n * heuristic score. Returns one entry per root group in the BVH.\n * @section Debug Functions\n * @param {MeshBVH} bvh\n * @returns {Array<BVHExtremes>}\n */\nfunction getBVHExtremes( bvh ) {\n\n\treturn bvh._roots.map( ( root, i ) => getRootExtremes( bvh, i ) );\n\n}\n\n/**\n * Roughly estimates the amount of memory in bytes used by a BVH by walking\n * its object graph and summing typed-array byte lengths and primitive sizes.\n * @section Debug Functions\n * @param {BVH} bvh\n * @returns {number}\n */\nfunction estimateMemoryInBytes( obj ) {\n\n\tconst traversed = new Set();\n\tconst stack = [ obj ];\n\tlet bytes = 0;\n\n\twhile ( stack.length ) {\n\n\t\tconst curr = stack.pop();\n\t\tif ( traversed.has( curr ) ) {\n\n\t\t\tcontinue;\n\n\t\t}\n\n\t\ttraversed.add( curr );\n\n\t\tfor ( let key in curr ) {\n\n\t\t\tif ( ! Object.hasOwn( curr, key ) ) {\n\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tbytes += getElementSize( key );\n\n\t\t\tconst value = curr[ key ];\n\t\t\tif ( value && ( typeof value === 'object' || typeof value === 'function' ) ) {\n\n\t\t\t\tif ( isTypedArray( value ) ) {\n\n\t\t\t\t\tbytes += value.byteLength;\n\n\t\t\t\t} else if ( isSharedArrayBufferSupported() && value instanceof SharedArrayBuffer ) {\n\n\t\t\t\t\tbytes += value.byteLength;\n\n\t\t\t\t} else if ( value instanceof ArrayBuffer ) {\n\n\t\t\t\t\tbytes += value.byteLength;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tstack.push( value );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tbytes += getElementSize( value );\n\n\t\t\t}\n\n\n\t\t}\n\n\t}\n\n\treturn bytes;\n\n}\n\n/**\n * Validates that every node's bounding box fully contains its children and,\n * for leaf nodes, fully contains all of its primitives. Uses `console.assert`\n * to log failures and returns `false` if any check fails.\n * @section Debug Functions\n * @param {MeshBVH} bvh\n * @returns {boolean}\n */\nfunction validateBounds( bvh ) {\n\n\tconst depthStack = [];\n\tconst tempBuffer = new Float32Array( 6 );\n\tlet passes = true;\n\n\tbvh.traverse( ( depth, isLeaf, boundingData, offset, count ) => {\n\n\t\tconst info = {\n\t\t\tdepth,\n\t\t\tisLeaf,\n\t\t\tboundingData,\n\t\t\toffset,\n\t\t\tcount,\n\t\t};\n\t\tdepthStack[ depth ] = info;\n\n\t\tarrayToBox( 0, boundingData, _box1 );\n\t\tconst parent = depthStack[ depth - 1 ];\n\n\t\tif ( isLeaf ) {\n\n\t\t\t// Compute the actual bounds of the primitives in this leaf\n\t\t\tbvh.writePrimitiveRangeBounds( offset, count, tempBuffer, 0 );\n\n\t\t\t// tempBuffer is in min/max format [minx, miny, minz, maxx, maxy, maxz]\n\t\t\t_box2.min.set( tempBuffer[ 0 ], tempBuffer[ 1 ], tempBuffer[ 2 ] );\n\t\t\t_box2.max.set( tempBuffer[ 3 ], tempBuffer[ 4 ], tempBuffer[ 5 ] );\n\n\t\t\t// Check if the stored bounds contain the actual primitive bounds\n\t\t\tconst isContained = _box1.containsBox( _box2 );\n\t\t\tconsole.assert( isContained, 'Leaf bounds does not fully contain primitives.' );\n\t\t\tpasses = passes && isContained;\n\n\t\t}\n\n\t\tif ( parent ) {\n\n\t\t\t// check if my bounds fit in my parents\n\t\t\tarrayToBox( 0, parent.boundingData, _box2 );\n\n\t\t\tconst isContained = _box2.containsBox( _box1 );\n\t\t\tconsole.assert( isContained, 'Parent bounds does not fully contain child.' );\n\t\t\tpasses = passes && isContained;\n\n\t\t}\n\n\t} );\n\n\treturn passes;\n\n}\n\n/**\n * Returns a plain-object tree that mirrors the BVH hierarchy, useful for\n * inspecting or serialising the structure for debugging. Each node has a\n * `bounds` (`Box3`) and either `{ count, offset }` (leaf) or `{ left, right }`\n * (internal) fields.\n * @section Debug Functions\n * @param {BVH} bvh\n * @returns {Object}\n */\nfunction getJSONStructure( bvh ) {\n\n\tconst depthStack = [];\n\n\tbvh.traverse( ( depth, isLeaf, boundingData, offset, count ) => {\n\n\t\tconst info = {\n\t\t\tbounds: arrayToBox( 0, boundingData, new Box3() ),\n\t\t};\n\n\t\tif ( isLeaf ) {\n\n\t\t\tinfo.count = count;\n\t\t\tinfo.offset = offset;\n\n\t\t} else {\n\n\t\t\tinfo.left = null;\n\t\t\tinfo.right = null;\n\n\t\t}\n\n\t\tdepthStack[ depth ] = info;\n\n\t\t// traversal hits the left then right node\n\t\tconst parent = depthStack[ depth - 1 ];\n\t\tif ( parent ) {\n\n\t\t\tif ( parent.left === null ) {\n\n\t\t\t\tparent.left = info;\n\n\t\t\t} else {\n\n\t\t\t\tparent.right = info;\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\treturn depthStack[ 0 ];\n\n}\n\nexport { estimateMemoryInBytes, getBVHExtremes, validateBounds, getJSONStructure };\n","/** @import { Raycaster, Intersection } from 'three' */\n/** @import { GeometryBVH } from '../core/GeometryBVH.js' */\nimport { Mesh, Points, Line, LineLoop, LineSegments, Sphere, BatchedMesh, REVISION } from 'three';\nimport { MeshBVH } from '../core/MeshBVH.js';\n\nconst IS_REVISION_166 = parseInt( REVISION ) >= 166;\n\n// TODO: how can we expand these raycast functions?\nconst _raycastFunctions = {\n\t'Mesh': Mesh.prototype.raycast,\n\t'Line': Line.prototype.raycast,\n\t'LineSegments': LineSegments.prototype.raycast,\n\t'LineLoop': LineLoop.prototype.raycast,\n\t'Points': Points.prototype.raycast,\n\t'BatchedMesh': BatchedMesh.prototype.raycast,\n};\n\nconst _mesh = /* @__PURE__ */ new Mesh();\nconst _batchIntersects = [];\n\n/**\n * An accelerated raycast function with the same signature as `THREE.Mesh.raycast`. Uses the BVH\n * for raycasting if it's available otherwise it falls back to the built-in approach. The results\n * of the function are designed to be identical to the results of the conventional\n * `THREE.Mesh.raycast` results.\n *\n * If the raycaster object being used has a property `firstHitOnly` set to `true`, then the\n * raycasting will terminate as soon as it finds the closest intersection to the ray's origin and\n * return only that intersection. This is typically several times faster than searching for all\n * intersections.\n *\n * @section Extension Utilities\n * @param {Raycaster} raycaster\n * @param {Array<Intersection>} intersects\n * @returns {void}\n */\nexport function acceleratedRaycast( raycaster, intersects ) {\n\n\tif ( this.isBatchedMesh ) {\n\n\t\tacceleratedBatchedMeshRaycast.call( this, raycaster, intersects );\n\n\t} else {\n\n\t\tconst { geometry } = this;\n\t\tif ( geometry.boundsTree ) {\n\n\t\t\tgeometry.boundsTree.raycastObject3D( this, raycaster, intersects );\n\n\t\t} else {\n\n\t\t\tlet raycastFunction;\n\t\t\tif ( this instanceof Mesh ) {\n\n\t\t\t\traycastFunction = _raycastFunctions.Mesh;\n\n\t\t\t} else if ( this instanceof LineSegments ) {\n\n\t\t\t\traycastFunction = _raycastFunctions.LineSegments;\n\n\t\t\t} else if ( this instanceof LineLoop ) {\n\n\t\t\t\traycastFunction = _raycastFunctions.LineLoop;\n\n\t\t\t} else if ( this instanceof Line ) {\n\n\t\t\t\traycastFunction = _raycastFunctions.Line;\n\n\t\t\t} else if ( this instanceof Points ) {\n\n\t\t\t\traycastFunction = _raycastFunctions.Points;\n\n\t\t\t} else {\n\n\t\t\t\tthrow new Error( 'BVH: Fallback raycast function not found.' );\n\n\t\t\t}\n\n\t\t\traycastFunction.call( this, raycaster, intersects );\n\n\t\t}\n\n\t}\n\n}\n\nfunction acceleratedBatchedMeshRaycast( raycaster, intersects ) {\n\n\tif ( this.boundsTrees ) {\n\n\t\t// TODO: remove use of geometry info, instance info when r170 is minimum version\n\t\tconst boundsTrees = this.boundsTrees;\n\t\tconst drawInfo = this._drawInfo || this._instanceInfo;\n\t\tconst drawRanges = this._drawRanges || this._geometryInfo;\n\t\tconst matrixWorld = this.matrixWorld;\n\n\t\t_mesh.material = this.material;\n\t\t_mesh.geometry = this.geometry;\n\n\t\tconst oldBoundsTree = _mesh.geometry.boundsTree;\n\t\tconst oldDrawRange = _mesh.geometry.drawRange;\n\n\t\tif ( _mesh.geometry.boundingSphere === null ) {\n\n\t\t\t_mesh.geometry.boundingSphere = new Sphere();\n\n\t\t}\n\n\t\t// TODO: provide new method to get instances count instead of 'drawInfo.length'\n\t\tfor ( let i = 0, l = drawInfo.length; i < l; i ++ ) {\n\n\t\t\tif ( ! this.getVisibleAt( i ) ) {\n\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\t// TODO: use getGeometryIndex\n\t\t\tconst geometryId = drawInfo[ i ].geometryIndex;\n\n\t\t\t_mesh.geometry.boundsTree = boundsTrees[ geometryId ];\n\n\t\t\tthis.getMatrixAt( i, _mesh.matrixWorld ).premultiply( matrixWorld );\n\n\t\t\tif ( ! _mesh.geometry.boundsTree ) {\n\n\t\t\t\tthis.getBoundingBoxAt( geometryId, _mesh.geometry.boundingBox );\n\t\t\t\tthis.getBoundingSphereAt( geometryId, _mesh.geometry.boundingSphere );\n\n\t\t\t\tconst drawRange = drawRanges[ geometryId ];\n\t\t\t\t_mesh.geometry.setDrawRange( drawRange.start, drawRange.count );\n\n\t\t\t}\n\n\t\t\t_mesh.raycast( raycaster, _batchIntersects );\n\n\t\t\tfor ( let j = 0, l = _batchIntersects.length; j < l; j ++ ) {\n\n\t\t\t\tconst intersect = _batchIntersects[ j ];\n\t\t\t\tintersect.object = this;\n\t\t\t\tintersect.batchId = i;\n\t\t\t\tintersects.push( intersect );\n\n\t\t\t}\n\n\t\t\t_batchIntersects.length = 0;\n\n\t\t}\n\n\t\t_mesh.geometry.boundsTree = oldBoundsTree;\n\t\t_mesh.geometry.drawRange = oldDrawRange;\n\t\t_mesh.material = null;\n\t\t_mesh.geometry = null;\n\n\t} else {\n\n\t\t_raycastFunctions.BatchedMesh.call( this, raycaster, intersects );\n\n\t}\n\n}\n\n/**\n * A pre-made BufferGeometry extension function that builds a new BVH, assigns it to `boundsTree`\n * for BufferGeometry, and applies the new index buffer to the geometry. Comparable to\n * `computeBoundingBox` and `computeBoundingSphere`.\n *\n * ```js\n * THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;\n * ```\n *\n * @section Extension Utilities\n * @param {Object} [options]\n * @returns {GeometryBVH}\n */\nexport function computeBoundsTree( options = {} ) {\n\n\tconst { type = MeshBVH } = options;\n\tthis.boundsTree = new type( this, options );\n\treturn this.boundsTree;\n\n}\n\n/**\n * A BufferGeometry extension function that disposes of the BVH.\n *\n * ```js\n * THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;\n * ```\n *\n * @section Extension Utilities\n * @returns {void}\n */\nexport function disposeBoundsTree() {\n\n\tthis.boundsTree = null;\n\n}\n\n/**\n * Equivalent of `computeBoundsTree` for `BatchedMesh`. Creates the\n * `BatchedMesh.boundsTrees` array if it does not exist. If `index` is `-1`\n * BVHs for all available geometries are generated and the full array is\n * returned; otherwise only the BVH at that geometry index is generated and\n * returned.\n *\n * ```js\n * THREE.BatchedMesh.prototype.computeBoundsTree = computeBatchedBoundsTree;\n * ```\n *\n * @section Extension Utilities\n * @param {number} [index=-1]\n * @param {Object} [options]\n * @returns {GeometryBVH | Array<GeometryBVH> | null}\n */\nexport function computeBatchedBoundsTree( index = - 1, options = {} ) {\n\n\tif ( ! IS_REVISION_166 ) {\n\n\t\tthrow new Error( 'BatchedMesh: Three r166+ is required to compute bounds trees.' );\n\n\t}\n\n\toptions = {\n\t\t...options,\n\t\trange: null\n\t};\n\n\tconst drawRanges = this._drawRanges || this._geometryInfo;\n\tconst geometryCount = this._geometryCount;\n\tif ( ! this.boundsTrees ) {\n\n\t\tthis.boundsTrees = new Array( geometryCount ).fill( null );\n\n\t}\n\n\tconst boundsTrees = this.boundsTrees;\n\twhile ( boundsTrees.length < geometryCount ) {\n\n\t\tboundsTrees.push( null );\n\n\t}\n\n\tif ( index < 0 ) {\n\n\t\tfor ( let i = 0; i < geometryCount; i ++ ) {\n\n\t\t\toptions.range = drawRanges[ i ];\n\t\t\tboundsTrees[ i ] = new MeshBVH( this.geometry, options );\n\n\t\t}\n\n\t\treturn boundsTrees;\n\n\t} else {\n\n\t\tif ( index < drawRanges.length ) {\n\n\t\t\toptions.range = drawRanges[ index ];\n\t\t\tboundsTrees[ index ] = new MeshBVH( this.geometry, options );\n\n\t\t}\n\n\t\treturn boundsTrees[ index ] || null;\n\n\t}\n\n}\n\n/**\n * Equivalent of `disposeBoundsTree` for `BatchedMesh`. Sets entries in\n * `BatchedMesh.boundsTrees` to `null`. If `index` is `-1` all BVHs are\n * disposed; otherwise only the BVH at that geometry index is disposed.\n *\n * ```js\n * THREE.BatchedMesh.prototype.disposeBoundsTree = disposeBatchedBoundsTree;\n * ```\n *\n * @section Extension Utilities\n * @param {number} [index=-1]\n * @returns {void}\n */\nexport function disposeBatchedBoundsTree( index = - 1 ) {\n\n\tif ( index < 0 ) {\n\n\t\tthis.boundsTrees.fill( null );\n\n\t} else {\n\n\t\tif ( index < this.boundsTrees.length ) {\n\n\t\t\tthis.boundsTrees[ index ] = null;\n\n\t\t}\n\n\t}\n\n}\n","/** @import { BufferAttribute } from 'three' */\nimport {\n\tDataTexture,\n\tFloatType,\n\tIntType,\n\tUnsignedIntType,\n\tByteType,\n\tUnsignedByteType,\n\tShortType,\n\tUnsignedShortType,\n\n\tRedFormat,\n\tRGFormat,\n\tRGBAFormat,\n\n\tRedIntegerFormat,\n\tRGIntegerFormat,\n\tRGBAIntegerFormat,\n\n\tNearestFilter,\n} from 'three';\n\nfunction countToStringFormat( count ) {\n\n\tswitch ( count ) {\n\n\t\tcase 1: return 'R';\n\t\tcase 2: return 'RG';\n\t\tcase 3: return 'RGBA';\n\t\tcase 4: return 'RGBA';\n\n\t}\n\n\tthrow new Error();\n\n}\n\nfunction countToFormat( count ) {\n\n\tswitch ( count ) {\n\n\t\tcase 1: return RedFormat;\n\t\tcase 2: return RGFormat;\n\t\tcase 3: return RGBAFormat;\n\t\tcase 4: return RGBAFormat;\n\n\t}\n\n}\n\nfunction countToIntFormat( count ) {\n\n\tswitch ( count ) {\n\n\t\tcase 1: return RedIntegerFormat;\n\t\tcase 2: return RGIntegerFormat;\n\t\tcase 3: return RGBAIntegerFormat;\n\t\tcase 4: return RGBAIntegerFormat;\n\n\t}\n\n}\n\n/**\n * Float, Uint, and Int VertexAttributeTexture implementations are designed to simplify the\n * efficient packing of a three.js BufferAttribute into a texture. An instance can be treated as a\n * texture and when passing as a uniform to a shader they should be used as a `sampler2d`,\n * `usampler2d`, and `isampler2d` when using the Float, Uint, and Int texture types respectively.\n *\n * _extends THREE.DataTexture_\n *\n * @section Shader and Texture Packing API\n */\nexport class VertexAttributeTexture extends DataTexture {\n\n\tconstructor() {\n\n\t\tsuper();\n\t\tthis.minFilter = NearestFilter;\n\t\tthis.magFilter = NearestFilter;\n\t\tthis.generateMipmaps = false;\n\n\t\t/**\n\t\t * Treats `BufferAttribute.itemSize` as though it were set to this value when packing the\n\t\t * buffer attribute texture. Throws an error if the value does not divide evenly into the\n\t\t * length of the BufferAttribute buffer (`count * itemSize % overrideItemSize`).\n\t\t *\n\t\t * Specifically used to pack geometry indices into an RGB texture rather than an Red texture.\n\t\t * @type {number}\n\t\t */\n\t\tthis.overrideItemSize = null;\n\t\tthis._forcedType = null;\n\n\t}\n\n\t/**\n\t * Updates the texture to have the data contained in the passed BufferAttribute using the\n\t * BufferAttribute `itemSize` field, `normalized` field, and TypedArray layout to determine\n\t * the appropriate texture layout, format, and type. The texture dimensions will always be\n\t * square. Because these are intended to be sampled as 1D arrays the width of the texture must\n\t * be taken into account to derive a sampling uv. See `texelFetch1D` in shaderFunctions.\n\t *\n\t * @param {BufferAttribute} attribute\n\t * @returns {void}\n\t */\n\tupdateFrom( attr ) {\n\n\t\tconst overrideItemSize = this.overrideItemSize;\n\t\tconst originalItemSize = attr.itemSize;\n\t\tconst originalCount = attr.count;\n\t\tif ( overrideItemSize !== null ) {\n\n\t\t\tif ( ( originalItemSize * originalCount ) % overrideItemSize !== 0.0 ) {\n\n\t\t\t\tthrow new Error( 'VertexAttributeTexture: overrideItemSize must divide evenly into buffer length.' );\n\n\t\t\t}\n\n\t\t\tattr.itemSize = overrideItemSize;\n\t\t\tattr.count = originalCount * originalItemSize / overrideItemSize;\n\n\t\t}\n\n\t\tconst itemSize = attr.itemSize;\n\t\tconst count = attr.count;\n\t\tconst normalized = attr.normalized;\n\t\tconst originalBufferCons = attr.array.constructor;\n\t\tconst byteCount = originalBufferCons.BYTES_PER_ELEMENT;\n\t\tlet targetType = this._forcedType;\n\t\tlet finalStride = itemSize;\n\n\t\t// derive the type of texture this should be in the shader\n\t\tif ( targetType === null ) {\n\n\t\t\tswitch ( originalBufferCons ) {\n\n\t\t\t\tcase Float32Array:\n\t\t\t\t\ttargetType = FloatType;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Uint8Array:\n\t\t\t\tcase Uint16Array:\n\t\t\t\tcase Uint32Array:\n\t\t\t\t\ttargetType = UnsignedIntType;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase Int8Array:\n\t\t\t\tcase Int16Array:\n\t\t\t\tcase Int32Array:\n\t\t\t\t\ttargetType = IntType;\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// get the target format to store the texture as\n\t\tlet type, format, normalizeValue, targetBufferCons;\n\t\tlet internalFormat = countToStringFormat( itemSize );\n\t\tswitch ( targetType ) {\n\n\t\t\tcase FloatType:\n\t\t\t\tnormalizeValue = 1.0;\n\t\t\t\tformat = countToFormat( itemSize );\n\n\t\t\t\tif ( normalized && byteCount === 1 ) {\n\n\t\t\t\t\ttargetBufferCons = originalBufferCons;\n\t\t\t\t\tinternalFormat += '8';\n\n\t\t\t\t\tif ( originalBufferCons === Uint8Array ) {\n\n\t\t\t\t\t\ttype = UnsignedByteType;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ttype = ByteType;\n\t\t\t\t\t\tinternalFormat += '_SNORM';\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\ttargetBufferCons = Float32Array;\n\t\t\t\t\tinternalFormat += '32F';\n\t\t\t\t\ttype = FloatType;\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase IntType:\n\t\t\t\tinternalFormat += byteCount * 8 + 'I';\n\t\t\t\tnormalizeValue = normalized ? Math.pow( 2, originalBufferCons.BYTES_PER_ELEMENT * 8 - 1 ) : 1.0;\n\t\t\t\tformat = countToIntFormat( itemSize );\n\n\t\t\t\tif ( byteCount === 1 ) {\n\n\t\t\t\t\ttargetBufferCons = Int8Array;\n\t\t\t\t\ttype = ByteType;\n\n\t\t\t\t} else if ( byteCount === 2 ) {\n\n\t\t\t\t\ttargetBufferCons = Int16Array;\n\t\t\t\t\ttype = ShortType;\n\n\t\t\t\t} else {\n\n\t\t\t\t\ttargetBufferCons = Int32Array;\n\t\t\t\t\ttype = IntType;\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase UnsignedIntType:\n\t\t\t\tinternalFormat += byteCount * 8 + 'UI';\n\t\t\t\tnormalizeValue = normalized ? Math.pow( 2, originalBufferCons.BYTES_PER_ELEMENT * 8 - 1 ) : 1.0;\n\t\t\t\tformat = countToIntFormat( itemSize );\n\n\t\t\t\tif ( byteCount === 1 ) {\n\n\t\t\t\t\ttargetBufferCons = Uint8Array;\n\t\t\t\t\ttype = UnsignedByteType;\n\n\t\t\t\t} else if ( byteCount === 2 ) {\n\n\t\t\t\t\ttargetBufferCons = Uint16Array;\n\t\t\t\t\ttype = UnsignedShortType;\n\n\t\t\t\t} else {\n\n\t\t\t\t\ttargetBufferCons = Uint32Array;\n\t\t\t\t\ttype = UnsignedIntType;\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t}\n\n\t\t// there will be a mismatch between format length and final length because\n\t\t// RGBFormat and RGBIntegerFormat was removed\n\t\tif ( finalStride === 3 && ( format === RGBAFormat || format === RGBAIntegerFormat ) ) {\n\n\t\t\tfinalStride = 4;\n\n\t\t}\n\n\t\t// copy the data over to the new texture array\n\t\tconst dimension = Math.ceil( Math.sqrt( count ) ) || 1;\n\t\tconst length = finalStride * dimension * dimension;\n\t\tconst dataArray = new targetBufferCons( length );\n\n\t\t// temporarily set the normalized state to false since we have custom normalization logic\n\t\tconst originalNormalized = attr.normalized;\n\t\tattr.normalized = false;\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\tconst ii = finalStride * i;\n\t\t\tdataArray[ ii ] = attr.getX( i ) / normalizeValue;\n\n\t\t\tif ( itemSize >= 2 ) {\n\n\t\t\t\tdataArray[ ii + 1 ] = attr.getY( i ) / normalizeValue;\n\n\t\t\t}\n\n\t\t\tif ( itemSize >= 3 ) {\n\n\t\t\t\tdataArray[ ii + 2 ] = attr.getZ( i ) / normalizeValue;\n\n\t\t\t\tif ( finalStride === 4 ) {\n\n\t\t\t\t\tdataArray[ ii + 3 ] = 1.0;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( itemSize >= 4 ) {\n\n\t\t\t\tdataArray[ ii + 3 ] = attr.getW( i ) / normalizeValue;\n\n\t\t\t}\n\n\t\t}\n\n\t\tattr.normalized = originalNormalized;\n\n\t\tthis.internalFormat = internalFormat;\n\t\tthis.format = format;\n\t\tthis.type = type;\n\t\tthis.image.width = dimension;\n\t\tthis.image.height = dimension;\n\t\tthis.image.data = dataArray;\n\t\tthis.needsUpdate = true;\n\t\tthis.dispose();\n\n\t\tattr.itemSize = originalItemSize;\n\t\tattr.count = originalCount;\n\n\t}\n\n}\n\n/**\n * A VertexAttributeTexture that forces the unsigned integer texture type.\n * @extends VertexAttributeTexture\n * @section Shader and Texture Packing API\n */\nexport class UIntVertexAttributeTexture extends VertexAttributeTexture {\n\n\tconstructor() {\n\n\t\tsuper();\n\t\tthis._forcedType = UnsignedIntType;\n\n\t}\n\n}\n\n/**\n * A VertexAttributeTexture that forces the signed integer texture type.\n * @extends VertexAttributeTexture\n * @section Shader and Texture Packing API\n */\nexport class IntVertexAttributeTexture extends VertexAttributeTexture {\n\n\tconstructor() {\n\n\t\tsuper();\n\t\tthis._forcedType = IntType;\n\n\t}\n\n\n}\n\n/**\n * A VertexAttributeTexture that forces the float texture type.\n * @extends VertexAttributeTexture\n * @section Shader and Texture Packing API\n */\nexport class FloatVertexAttributeTexture extends VertexAttributeTexture {\n\n\tconstructor() {\n\n\t\tsuper();\n\t\tthis._forcedType = FloatType;\n\n\t}\n\n}\n","/** @import { MeshBVH } from '../core/MeshBVH.js' */\nimport {\n\tDataTexture,\n\tFloatType,\n\tUnsignedIntType,\n\tRGBAFormat,\n\tRGIntegerFormat,\n\tNearestFilter,\n\tBufferAttribute,\n} from 'three';\nimport {\n\tFloatVertexAttributeTexture,\n\tUIntVertexAttributeTexture,\n} from './VertexAttributeTexture.js';\nimport { BYTES_PER_NODE, LEAFNODE_MASK_32 } from '../core/Constants.js';\nimport {\n\tBOUNDING_DATA_INDEX,\n\tCOUNT,\n\tIS_LEAF,\n\tOFFSET,\n\tSPLIT_AXIS,\n} from '../core/utils/nodeBufferUtils.js';\nimport { getIndexArray, getVertexCount } from '../core/build/geometryUtils.js';\n\n/**\n * A shader uniform object corresponding to the `BVH` shader struct defined in shaderStructs. The\n * object contains four textures containing information about the BVH and geometry so it can be\n * queried in a shader using the bvh intersection functions defined in shaderFunctions. This object\n * is intended to be used as a shader uniform and read in the shader as a `BVH` struct.\n *\n * @section Shader and Texture Packing API\n */\nexport class MeshBVHUniformStruct {\n\n\tconstructor() {\n\n\t\tthis.index = new UIntVertexAttributeTexture();\n\t\tthis.position = new FloatVertexAttributeTexture();\n\t\tthis.bvhBounds = new DataTexture();\n\t\tthis.bvhContents = new DataTexture();\n\t\tthis._cachedIndexAttr = null;\n\n\t\tthis.index.overrideItemSize = 3;\n\n\t}\n\n\t/**\n\t * Updates the object and associated textures with data from the provided BVH.\n\t *\n\t * @param {MeshBVH} bvh\n\t * @returns {void}\n\t */\n\tupdateFrom( bvh ) {\n\n\t\tconst { geometry } = bvh;\n\t\tbvhToTextures( bvh, this.bvhBounds, this.bvhContents );\n\n\t\tthis.position.updateFrom( geometry.attributes.position );\n\n\t\t// dereference a new index attribute if we're using indirect storage\n\t\tif ( bvh.indirect ) {\n\n\t\t\tconst indirectBuffer = bvh._indirectBuffer;\n\t\t\tif (\n\t\t\t\tthis._cachedIndexAttr === null ||\n\t\t\t\tthis._cachedIndexAttr.count !== indirectBuffer.length\n\t\t\t) {\n\n\t\t\t\tif ( geometry.index ) {\n\n\t\t\t\t\tthis._cachedIndexAttr = geometry.index.clone();\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconst array = getIndexArray( getVertexCount( geometry ) );\n\t\t\t\t\tthis._cachedIndexAttr = new BufferAttribute( array, 1, false );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tdereferenceIndex( geometry, indirectBuffer, this._cachedIndexAttr );\n\t\t\tthis.index.updateFrom( this._cachedIndexAttr );\n\n\t\t} else {\n\n\t\t\tthis.index.updateFrom( geometry.index );\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Dispose of the associated textures.\n\t *\n\t * @returns {void}\n\t */\n\tdispose() {\n\n\t\tconst { index, position, bvhBounds, bvhContents } = this;\n\n\t\tif ( index ) index.dispose();\n\t\tif ( position ) position.dispose();\n\t\tif ( bvhBounds ) bvhBounds.dispose();\n\t\tif ( bvhContents ) bvhContents.dispose();\n\n\t}\n\n}\n\nfunction dereferenceIndex( geometry, indirectBuffer, target ) {\n\n\tconst unpacked = target.array;\n\tconst indexArray = geometry.index ? geometry.index.array : null;\n\tfor ( let i = 0, l = indirectBuffer.length; i < l; i ++ ) {\n\n\t\tconst i3 = 3 * i;\n\t\tconst v3 = 3 * indirectBuffer[ i ];\n\t\tfor ( let c = 0; c < 3; c ++ ) {\n\n\t\t\tunpacked[ i3 + c ] = indexArray ? indexArray[ v3 + c ] : v3 + c;\n\n\t\t}\n\n\t}\n\n}\n\nfunction bvhToTextures( bvh, boundsTexture, contentsTexture ) {\n\n\tconst roots = bvh._roots;\n\n\tif ( roots.length !== 1 ) {\n\n\t\tthrow new Error( 'MeshBVHUniformStruct: Multi-root BVHs not supported.' );\n\n\t}\n\n\tconst root = roots[ 0 ];\n\tconst uint16Array = new Uint16Array( root );\n\tconst uint32Array = new Uint32Array( root );\n\tconst float32Array = new Float32Array( root );\n\n\t// Both bounds need two elements per node so compute the height so it's twice as long as\n\t// the width so we can expand the row by two and still have a square texture\n\tconst nodeCount = root.byteLength / BYTES_PER_NODE;\n\tconst boundsDimension = 2 * Math.ceil( Math.sqrt( nodeCount / 2 ) );\n\tconst boundsArray = new Float32Array( 4 * boundsDimension * boundsDimension );\n\n\tconst contentsDimension = Math.ceil( Math.sqrt( nodeCount ) );\n\tconst contentsArray = new Uint32Array( 2 * contentsDimension * contentsDimension );\n\n\tfor ( let i = 0; i < nodeCount; i ++ ) {\n\n\t\tconst nodeIndex32 = i * BYTES_PER_NODE / 4;\n\t\tconst nodeIndex16 = nodeIndex32 * 2;\n\t\tconst boundsIndex = BOUNDING_DATA_INDEX( nodeIndex32 );\n\t\tfor ( let b = 0; b < 3; b ++ ) {\n\n\t\t\tboundsArray[ 8 * i + 0 + b ] = float32Array[ boundsIndex + 0 + b ];\n\t\t\tboundsArray[ 8 * i + 4 + b ] = float32Array[ boundsIndex + 3 + b ];\n\n\t\t}\n\n\t\tif ( IS_LEAF( nodeIndex16, uint16Array ) ) {\n\n\t\t\tconst count = COUNT( nodeIndex16, uint16Array );\n\t\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\n\n\t\t\tconst mergedLeafCount = LEAFNODE_MASK_32 | count;\n\t\t\tcontentsArray[ i * 2 + 0 ] = mergedLeafCount;\n\t\t\tcontentsArray[ i * 2 + 1 ] = offset;\n\n\t\t} else {\n\n\t\t\tconst rightNodeIndex = uint32Array[ nodeIndex32 + 6 ];\n\t\t\tconst splitAxis = SPLIT_AXIS( nodeIndex32, uint32Array );\n\n\t\t\tcontentsArray[ i * 2 + 0 ] = splitAxis;\n\t\t\tcontentsArray[ i * 2 + 1 ] = rightNodeIndex;\n\n\t\t}\n\n\t}\n\n\tboundsTexture.image.data = boundsArray;\n\tboundsTexture.image.width = boundsDimension;\n\tboundsTexture.image.height = boundsDimension;\n\tboundsTexture.format = RGBAFormat;\n\tboundsTexture.type = FloatType;\n\tboundsTexture.internalFormat = 'RGBA32F';\n\tboundsTexture.minFilter = NearestFilter;\n\tboundsTexture.magFilter = NearestFilter;\n\tboundsTexture.generateMipmaps = false;\n\tboundsTexture.needsUpdate = true;\n\tboundsTexture.dispose();\n\n\tcontentsTexture.image.data = contentsArray;\n\tcontentsTexture.image.width = contentsDimension;\n\tcontentsTexture.image.height = contentsDimension;\n\tcontentsTexture.format = RGIntegerFormat;\n\tcontentsTexture.type = UnsignedIntType;\n\tcontentsTexture.internalFormat = 'RG32UI';\n\tcontentsTexture.minFilter = NearestFilter;\n\tcontentsTexture.magFilter = NearestFilter;\n\tcontentsTexture.generateMipmaps = false;\n\tcontentsTexture.needsUpdate = true;\n\tcontentsTexture.dispose();\n\n}\n","/** @import { Mesh, Material, Object3D } from 'three' */\nimport { BufferAttribute, BufferGeometry, Vector3, Vector4, Matrix4, Matrix3 } from 'three';\n\nconst _positionVector = /*@__PURE__*/ new Vector3();\nconst _normalVector = /*@__PURE__*/ new Vector3();\nconst _tangentVector = /*@__PURE__*/ new Vector3();\nconst _tangentVector4 = /*@__PURE__*/ new Vector4();\n\nconst _morphVector = /*@__PURE__*/ new Vector3();\nconst _temp = /*@__PURE__*/ new Vector3();\n\nconst _skinIndex = /*@__PURE__*/ new Vector4();\nconst _skinWeight = /*@__PURE__*/ new Vector4();\nconst _matrix = /*@__PURE__*/ new Matrix4();\nconst _boneMatrix = /*@__PURE__*/ new Matrix4();\n\n// Confirms that the two provided attributes are compatible\nfunction validateAttributes( attr1, attr2 ) {\n\n\tif ( ! attr1 && ! attr2 ) {\n\n\t\treturn;\n\n\t}\n\n\tconst sameCount = attr1.count === attr2.count;\n\tconst sameNormalized = attr1.normalized === attr2.normalized;\n\tconst sameType = attr1.array.constructor === attr2.array.constructor;\n\tconst sameItemSize = attr1.itemSize === attr2.itemSize;\n\n\tif ( ! sameCount || ! sameNormalized || ! sameType || ! sameItemSize ) {\n\n\t\tthrow new Error();\n\n\t}\n\n}\n\n// Clones the given attribute with a new compatible buffer attribute but no data\nfunction createAttributeClone( attr, countOverride = null ) {\n\n\tconst cons = attr.array.constructor;\n\tconst normalized = attr.normalized;\n\tconst itemSize = attr.itemSize;\n\tconst count = countOverride === null ? attr.count : countOverride;\n\n\treturn new BufferAttribute( new cons( itemSize * count ), itemSize, normalized );\n\n}\n\n// target offset is the number of elements in the target buffer stride to skip before copying the\n// attributes contents in to.\nfunction copyAttributeContents( attr, target, targetOffset = 0 ) {\n\n\tif ( attr.isInterleavedBufferAttribute ) {\n\n\t\tconst itemSize = attr.itemSize;\n\t\tfor ( let i = 0, l = attr.count; i < l; i ++ ) {\n\n\t\t\tconst io = i + targetOffset;\n\t\t\ttarget.setX( io, attr.getX( i ) );\n\t\t\tif ( itemSize >= 2 ) target.setY( io, attr.getY( i ) );\n\t\t\tif ( itemSize >= 3 ) target.setZ( io, attr.getZ( i ) );\n\t\t\tif ( itemSize >= 4 ) target.setW( io, attr.getW( i ) );\n\n\t\t}\n\n\t} else {\n\n\t\tconst array = target.array;\n\t\tconst cons = array.constructor;\n\t\tconst byteOffset = array.BYTES_PER_ELEMENT * attr.itemSize * targetOffset;\n\t\tconst temp = new cons( array.buffer, byteOffset, attr.array.length );\n\t\ttemp.set( attr.array );\n\n\t}\n\n}\n\n// Adds the \"matrix\" multiplied by \"scale\" to \"target\"\nfunction addScaledMatrix( target, matrix, scale ) {\n\n\tconst targetArray = target.elements;\n\tconst matrixArray = matrix.elements;\n\tfor ( let i = 0, l = matrixArray.length; i < l; i ++ ) {\n\n\t\ttargetArray[ i ] += matrixArray[ i ] * scale;\n\n\t}\n\n}\n\n// A version of \"SkinnedMesh.boneTransform\" for normals\nfunction boneNormalTransform( mesh, index, target ) {\n\n\tconst skeleton = mesh.skeleton;\n\tconst geometry = mesh.geometry;\n\tconst bones = skeleton.bones;\n\tconst boneInverses = skeleton.boneInverses;\n\n\t_skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );\n\t_skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );\n\n\t_matrix.elements.fill( 0 );\n\n\tfor ( let i = 0; i < 4; i ++ ) {\n\n\t\tconst weight = _skinWeight.getComponent( i );\n\n\t\tif ( weight !== 0 ) {\n\n\t\t\tconst boneIndex = _skinIndex.getComponent( i );\n\t\t\t_boneMatrix.multiplyMatrices( bones[ boneIndex ].matrixWorld, boneInverses[ boneIndex ] );\n\n\t\t\taddScaledMatrix( _matrix, _boneMatrix, weight );\n\n\t\t}\n\n\t}\n\n\t_matrix.multiply( mesh.bindMatrix ).premultiply( mesh.bindMatrixInverse );\n\ttarget.transformDirection( _matrix );\n\n\treturn target;\n\n}\n\n// Applies the morph target data to the target vector\nfunction applyMorphTarget( morphData, morphInfluences, morphTargetsRelative, i, target ) {\n\n\t_morphVector.set( 0, 0, 0 );\n\tfor ( let j = 0, jl = morphData.length; j < jl; j ++ ) {\n\n\t\tconst influence = morphInfluences[ j ];\n\t\tconst morphAttribute = morphData[ j ];\n\n\t\tif ( influence === 0 ) continue;\n\n\t\t_temp.fromBufferAttribute( morphAttribute, i );\n\n\t\tif ( morphTargetsRelative ) {\n\n\t\t\t_morphVector.addScaledVector( _temp, influence );\n\n\t\t} else {\n\n\t\t\t_morphVector.addScaledVector( _temp.sub( target ), influence );\n\n\t\t}\n\n\t}\n\n\ttarget.add( _morphVector );\n\n}\n\n// Modified version of BufferGeometryUtils.mergeBufferGeometries that ignores morph targets and updates a attributes in place\nfunction mergeBufferGeometries( geometries, options = { useGroups: false, updateIndex: false, skipAttributes: [] }, targetGeometry = new BufferGeometry() ) {\n\n\tconst isIndexed = geometries[ 0 ].index !== null;\n\tconst { useGroups = false, updateIndex = false, skipAttributes = [] } = options;\n\n\tconst attributesUsed = new Set( Object.keys( geometries[ 0 ].attributes ) );\n\tconst attributes = {};\n\n\tlet offset = 0;\n\n\ttargetGeometry.clearGroups();\n\tfor ( let i = 0; i < geometries.length; ++ i ) {\n\n\t\tconst geometry = geometries[ i ];\n\t\tlet attributesCount = 0;\n\n\t\t// ensure that all geometries are indexed, or none\n\t\tif ( isIndexed !== ( geometry.index !== null ) ) {\n\n\t\t\tthrow new Error( 'StaticGeometryGenerator: All geometries must have compatible attributes; make sure index attribute exists among all geometries, or in none of them.' );\n\n\t\t}\n\n\t\t// gather attributes, exit early if they're different\n\t\tfor ( const name in geometry.attributes ) {\n\n\t\t\tif ( ! attributesUsed.has( name ) ) {\n\n\t\t\t\tthrow new Error( 'StaticGeometryGenerator: All geometries must have compatible attributes; make sure \"' + name + '\" attribute exists among all geometries, or in none of them.' );\n\n\t\t\t}\n\n\t\t\tif ( attributes[ name ] === undefined ) {\n\n\t\t\t\tattributes[ name ] = [];\n\n\t\t\t}\n\n\t\t\tattributes[ name ].push( geometry.attributes[ name ] );\n\t\t\tattributesCount ++;\n\n\t\t}\n\n\t\t// ensure geometries have the same number of attributes\n\t\tif ( attributesCount !== attributesUsed.size ) {\n\n\t\t\tthrow new Error( 'StaticGeometryGenerator: Make sure all geometries have the same number of attributes.' );\n\n\t\t}\n\n\t\tif ( useGroups ) {\n\n\t\t\tlet count;\n\t\t\tif ( isIndexed ) {\n\n\t\t\t\tcount = geometry.index.count;\n\n\t\t\t} else if ( geometry.attributes.position !== undefined ) {\n\n\t\t\t\tcount = geometry.attributes.position.count;\n\n\t\t\t} else {\n\n\t\t\t\tthrow new Error( 'StaticGeometryGenerator: The geometry must have either an index or a position attribute' );\n\n\t\t\t}\n\n\t\t\ttargetGeometry.addGroup( offset, count, i );\n\t\t\toffset += count;\n\n\t\t}\n\n\t}\n\n\t// merge indices\n\tif ( isIndexed ) {\n\n\t\tlet forceUpdateIndex = false;\n\t\tif ( ! targetGeometry.index ) {\n\n\t\t\tlet indexCount = 0;\n\t\t\tfor ( let i = 0; i < geometries.length; ++ i ) {\n\n\t\t\t\tindexCount += geometries[ i ].index.count;\n\n\t\t\t}\n\n\t\t\ttargetGeometry.setIndex( new BufferAttribute( new Uint32Array( indexCount ), 1, false ) );\n\t\t\tforceUpdateIndex = true;\n\n\t\t}\n\n\t\tif ( updateIndex || forceUpdateIndex ) {\n\n\t\t\tconst targetIndex = targetGeometry.index;\n\t\t\tlet targetOffset = 0;\n\t\t\tlet indexOffset = 0;\n\t\t\tfor ( let i = 0; i < geometries.length; ++ i ) {\n\n\t\t\t\tconst geometry = geometries[ i ];\n\t\t\t\tconst index = geometry.index;\n\t\t\t\tif ( skipAttributes[ i ] !== true ) {\n\n\t\t\t\t\tfor ( let j = 0; j < index.count; ++ j ) {\n\n\t\t\t\t\t\ttargetIndex.setX( targetOffset, index.getX( j ) + indexOffset );\n\t\t\t\t\t\ttargetOffset ++;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tindexOffset += geometry.attributes.position.count;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t// merge attributes\n\tfor ( const name in attributes ) {\n\n\t\tconst attrList = attributes[ name ];\n\t\tif ( ! ( name in targetGeometry.attributes ) ) {\n\n\t\t\tlet count = 0;\n\t\t\tfor ( const key in attrList ) {\n\n\t\t\t\tcount += attrList[ key ].count;\n\n\t\t\t}\n\n\t\t\ttargetGeometry.setAttribute( name, createAttributeClone( attributes[ name ][ 0 ], count ) );\n\n\t\t}\n\n\t\tconst targetAttribute = targetGeometry.attributes[ name ];\n\t\tlet offset = 0;\n\t\tfor ( let i = 0, l = attrList.length; i < l; i ++ ) {\n\n\t\t\tconst attr = attrList[ i ];\n\t\t\tif ( skipAttributes[ i ] !== true ) {\n\n\t\t\t\tcopyAttributeContents( attr, targetAttribute, offset );\n\n\t\t\t}\n\n\t\t\toffset += attr.count;\n\n\t\t}\n\n\t}\n\n\treturn targetGeometry;\n\n}\n\nfunction checkTypedArrayEquality( a, b ) {\n\n\tif ( a === null || b === null ) {\n\n\t\treturn a === b;\n\n\t}\n\n\tif ( a.length !== b.length ) {\n\n\t\treturn false;\n\n\t}\n\n\tfor ( let i = 0, l = a.length; i < l; i ++ ) {\n\n\t\tif ( a[ i ] !== b[ i ] ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t}\n\n\treturn true;\n\n}\n\nfunction invertGeometry( geometry ) {\n\n\tconst { index, attributes } = geometry;\n\tif ( index ) {\n\n\t\tfor ( let i = 0, l = index.count; i < l; i += 3 ) {\n\n\t\t\tconst v0 = index.getX( i );\n\t\t\tconst v2 = index.getX( i + 2 );\n\t\t\tindex.setX( i, v2 );\n\t\t\tindex.setX( i + 2, v0 );\n\n\t\t}\n\n\t} else {\n\n\t\tfor ( const key in attributes ) {\n\n\t\t\tconst attr = attributes[ key ];\n\t\t\tconst itemSize = attr.itemSize;\n\t\t\tfor ( let i = 0, l = attr.count; i < l; i += 3 ) {\n\n\t\t\t\tfor ( let j = 0; j < itemSize; j ++ ) {\n\n\t\t\t\t\tconst v0 = attr.getComponent( i, j );\n\t\t\t\t\tconst v2 = attr.getComponent( i + 2, j );\n\t\t\t\t\tattr.setComponent( i, j, v2 );\n\t\t\t\t\tattr.setComponent( i + 2, j, v0 );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\treturn geometry;\n\n\n}\n\n// Checks whether the geometry changed between this and last evaluation\nclass GeometryDiff {\n\n\tconstructor( mesh ) {\n\n\t\tthis.matrixWorld = new Matrix4();\n\t\tthis.geometryHash = null;\n\t\tthis.boneMatrices = null;\n\t\tthis.primitiveCount = - 1;\n\t\tthis.mesh = mesh;\n\n\t\tthis.update();\n\n\t}\n\n\tupdate() {\n\n\t\tconst mesh = this.mesh;\n\t\tconst geometry = mesh.geometry;\n\t\tconst skeleton = mesh.skeleton;\n\t\tconst primitiveCount = ( geometry.index ? geometry.index.count : geometry.attributes.position.count ) / 3;\n\t\tthis.matrixWorld.copy( mesh.matrixWorld );\n\t\tthis.geometryHash = geometry.attributes.position.version;\n\t\tthis.primitiveCount = primitiveCount;\n\n\t\tif ( skeleton ) {\n\n\t\t\t// ensure the bone matrix array is updated to the appropriate length\n\t\t\tif ( ! skeleton.boneTexture ) {\n\n\t\t\t\tskeleton.computeBoneTexture();\n\n\t\t\t}\n\n\t\t\tskeleton.update();\n\n\t\t\t// copy data if possible otherwise clone it\n\t\t\tconst boneMatrices = skeleton.boneMatrices;\n\t\t\tif ( ! this.boneMatrices || this.boneMatrices.length !== boneMatrices.length ) {\n\n\t\t\t\tthis.boneMatrices = boneMatrices.slice();\n\n\t\t\t} else {\n\n\t\t\t\tthis.boneMatrices.set( boneMatrices );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tthis.boneMatrices = null;\n\n\t\t}\n\n\t}\n\n\tdidChange() {\n\n\t\tconst mesh = this.mesh;\n\t\tconst geometry = mesh.geometry;\n\t\tconst primitiveCount = ( geometry.index ? geometry.index.count : geometry.attributes.position.count ) / 3;\n\t\tconst identical =\n\t\t\tthis.matrixWorld.equals( mesh.matrixWorld ) &&\n\t\t\tthis.geometryHash === geometry.attributes.position.version &&\n\t\t\tcheckTypedArrayEquality( mesh.skeleton && mesh.skeleton.boneMatrices || null, this.boneMatrices ) &&\n\t\t\tthis.primitiveCount === primitiveCount;\n\n\t\treturn ! identical;\n\n\t}\n\n}\n\n/**\n * A utility class for taking a set of SkinnedMeshes or morph target geometry and baking it into\n * a single, static geometry that a BVH can be generated for.\n */\nexport class StaticGeometryGenerator {\n\n\t/**\n\t * Takes an array of object hierarchies to bake into a single static geometry.\n\t *\n\t * @param {Object3D|Array<Object3D>} meshes\n\t */\n\tconstructor( meshes ) {\n\n\t\tif ( ! Array.isArray( meshes ) ) {\n\n\t\t\tmeshes = [ meshes ];\n\n\t\t}\n\n\t\tconst finalMeshes = [];\n\t\tmeshes.forEach( object => {\n\n\t\t\tobject.traverseVisible( c => {\n\n\t\t\t\tif ( c.isMesh ) {\n\n\t\t\t\t\tfinalMeshes.push( c );\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t} );\n\n\t\t/**\n\t\t * @type {Array<Mesh>}\n\t\t */\n\t\tthis.meshes = finalMeshes;\n\n\t\t/**\n\t\t * If true then groups are used to support an array of materials on the mesh.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis.useGroups = true;\n\n\t\t/**\n\t\t * Whether to transform the vertices of the geometry by the world transforms of each mesh when generating.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis.applyWorldTransforms = true;\n\n\t\t/**\n\t\t * The set of attributes to copy onto the static geometry.\n\t\t * @type {Array<string>}\n\t\t */\n\t\tthis.attributes = [ 'position', 'normal', 'color', 'tangent', 'uv', 'uv2' ];\n\t\tthis._intermediateGeometry = new Array( finalMeshes.length ).fill().map( () => new BufferGeometry() );\n\t\tthis._diffMap = new WeakMap();\n\n\t}\n\n\t/**\n\t * Returns an array of materials for the meshes to be merged. These can be used alongside the\n\t * generated geometry when creating a mesh: `new Mesh( geometry, generator.getMaterials() )`.\n\t *\n\t * @returns {Array<Material>}\n\t */\n\tgetMaterials() {\n\n\t\tconst materials = [];\n\t\tthis.meshes.forEach( mesh => {\n\n\t\t\tif ( Array.isArray( mesh.material ) ) {\n\n\t\t\t\tmaterials.push( ...mesh.material );\n\n\t\t\t} else {\n\n\t\t\t\tmaterials.push( mesh.material );\n\n\t\t\t}\n\n\t\t} );\n\t\treturn materials;\n\n\t}\n\n\t/**\n\t * Generates a single, static geometry for the passed meshes. When generating for the first\n\t * time an empty target geometry is expected. The same generated geometry can be passed into\n\t * the function on subsequent calls to update the geometry in place to save memory. An error\n\t * will be thrown if the attributes or geometry on the meshes to bake has been changed and\n\t * are incompatible lengths, types, etc.\n\t *\n\t * On subsequent calls the \"index\" buffer will not be modified so any BVH generated for the\n\t * geometry is unaffected. Once the geometry is updated the `MeshBVH.refit` function can be\n\t * called to update the BVH.\n\t *\n\t * @param {BufferGeometry} [targetGeometry]\n\t * @returns {BufferGeometry}\n\t */\n\tgenerate( targetGeometry = new BufferGeometry() ) {\n\n\t\t// track which attributes have been updated and which to skip to avoid unnecessary attribute copies\n\t\tlet skipAttributes = [];\n\t\tconst { meshes, useGroups, _intermediateGeometry, _diffMap } = this;\n\t\tfor ( let i = 0, l = meshes.length; i < l; i ++ ) {\n\n\t\t\tconst mesh = meshes[ i ];\n\t\t\tconst geom = _intermediateGeometry[ i ];\n\t\t\tconst diff = _diffMap.get( mesh );\n\t\t\tif ( ! diff || diff.didChange( mesh ) ) {\n\n\t\t\t\tthis._convertToStaticGeometry( mesh, geom );\n\t\t\t\tskipAttributes.push( false );\n\n\t\t\t\tif ( ! diff ) {\n\n\t\t\t\t\t_diffMap.set( mesh, new GeometryDiff( mesh ) );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tdiff.update();\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tskipAttributes.push( true );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( _intermediateGeometry.length === 0 ) {\n\n\t\t\t// if there are no geometries then just create a fake empty geometry to provide\n\t\t\ttargetGeometry.setIndex( null );\n\n\t\t\t// remove all geometry\n\t\t\tconst attrs = targetGeometry.attributes;\n\t\t\tfor ( const key in attrs ) {\n\n\t\t\t\ttargetGeometry.deleteAttribute( key );\n\n\t\t\t}\n\n\t\t\t// create dummy attributes\n\t\t\tfor ( const key in this.attributes ) {\n\n\t\t\t\ttargetGeometry.setAttribute( this.attributes[ key ], new BufferAttribute( new Float32Array( 0 ), 4, false ) );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tmergeBufferGeometries( _intermediateGeometry, { useGroups, skipAttributes }, targetGeometry );\n\n\t\t}\n\n\t\tfor ( const key in targetGeometry.attributes ) {\n\n\t\t\ttargetGeometry.attributes[ key ].needsUpdate = true;\n\n\t\t}\n\n\t\treturn targetGeometry;\n\n\t}\n\n\t_convertToStaticGeometry( mesh, targetGeometry = new BufferGeometry() ) {\n\n\t\tconst geometry = mesh.geometry;\n\t\tconst applyWorldTransforms = this.applyWorldTransforms;\n\t\tconst includeNormal = this.attributes.includes( 'normal' );\n\t\tconst includeTangent = this.attributes.includes( 'tangent' );\n\t\tconst attributes = geometry.attributes;\n\t\tconst targetAttributes = targetGeometry.attributes;\n\n\t\t// initialize the attributes if they don't exist\n\t\tif ( ! targetGeometry.index && geometry.index ) {\n\n\t\t\ttargetGeometry.index = geometry.index.clone();\n\n\t\t}\n\n\t\tif ( ! targetAttributes.position ) {\n\n\t\t\ttargetGeometry.setAttribute( 'position', createAttributeClone( attributes.position ) );\n\n\t\t}\n\n\t\tif ( includeNormal && ! targetAttributes.normal && attributes.normal ) {\n\n\t\t\ttargetGeometry.setAttribute( 'normal', createAttributeClone( attributes.normal ) );\n\n\t\t}\n\n\t\tif ( includeTangent && ! targetAttributes.tangent && attributes.tangent ) {\n\n\t\t\ttargetGeometry.setAttribute( 'tangent', createAttributeClone( attributes.tangent ) );\n\n\t\t}\n\n\t\t// ensure the attributes are consistent\n\t\tvalidateAttributes( geometry.index, targetGeometry.index );\n\t\tvalidateAttributes( attributes.position, targetAttributes.position );\n\n\t\tif ( includeNormal ) {\n\n\t\t\tvalidateAttributes( attributes.normal, targetAttributes.normal );\n\n\t\t}\n\n\t\tif ( includeTangent ) {\n\n\t\t\tvalidateAttributes( attributes.tangent, targetAttributes.tangent );\n\n\t\t}\n\n\t\t// generate transformed vertex attribute data\n\t\tconst position = attributes.position;\n\t\tconst normal = includeNormal ? attributes.normal : null;\n\t\tconst tangent = includeTangent ? attributes.tangent : null;\n\t\tconst morphPosition = geometry.morphAttributes.position;\n\t\tconst morphNormal = geometry.morphAttributes.normal;\n\t\tconst morphTangent = geometry.morphAttributes.tangent;\n\t\tconst morphTargetsRelative = geometry.morphTargetsRelative;\n\t\tconst morphInfluences = mesh.morphTargetInfluences;\n\t\tconst normalMatrix = new Matrix3();\n\t\tnormalMatrix.getNormalMatrix( mesh.matrixWorld );\n\n\t\t// copy the index\n\t\tif ( geometry.index ) {\n\n\t\t\ttargetGeometry.index.array.set( geometry.index.array );\n\n\t\t}\n\n\t\t// copy and apply other attributes\n\t\tfor ( let i = 0, l = attributes.position.count; i < l; i ++ ) {\n\n\t\t\t_positionVector.fromBufferAttribute( position, i );\n\t\t\tif ( normal ) {\n\n\t\t\t\t_normalVector.fromBufferAttribute( normal, i );\n\n\t\t\t}\n\n\t\t\tif ( tangent ) {\n\n\t\t\t\t_tangentVector4.fromBufferAttribute( tangent, i );\n\t\t\t\t_tangentVector.fromBufferAttribute( tangent, i );\n\n\t\t\t}\n\n\t\t\t// apply morph target transform\n\t\t\tif ( morphInfluences ) {\n\n\t\t\t\tif ( morphPosition ) {\n\n\t\t\t\t\tapplyMorphTarget( morphPosition, morphInfluences, morphTargetsRelative, i, _positionVector );\n\n\t\t\t\t}\n\n\t\t\t\tif ( morphNormal ) {\n\n\t\t\t\t\tapplyMorphTarget( morphNormal, morphInfluences, morphTargetsRelative, i, _normalVector );\n\n\t\t\t\t}\n\n\t\t\t\tif ( morphTangent ) {\n\n\t\t\t\t\tapplyMorphTarget( morphTangent, morphInfluences, morphTargetsRelative, i, _tangentVector );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// apply bone transform\n\t\t\tif ( mesh.isSkinnedMesh ) {\n\n\t\t\t\tmesh.applyBoneTransform( i, _positionVector );\n\t\t\t\tif ( normal ) {\n\n\t\t\t\t\tboneNormalTransform( mesh, i, _normalVector );\n\n\t\t\t\t}\n\n\t\t\t\tif ( tangent ) {\n\n\t\t\t\t\tboneNormalTransform( mesh, i, _tangentVector );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// update the vectors of the attributes\n\t\t\tif ( applyWorldTransforms ) {\n\n\t\t\t\t_positionVector.applyMatrix4( mesh.matrixWorld );\n\n\t\t\t}\n\n\t\t\ttargetAttributes.position.setXYZ( i, _positionVector.x, _positionVector.y, _positionVector.z );\n\n\t\t\tif ( normal ) {\n\n\t\t\t\tif ( applyWorldTransforms ) {\n\n\t\t\t\t\t_normalVector.applyNormalMatrix( normalMatrix );\n\n\t\t\t\t}\n\n\t\t\t\ttargetAttributes.normal.setXYZ( i, _normalVector.x, _normalVector.y, _normalVector.z );\n\n\t\t\t}\n\n\t\t\tif ( tangent ) {\n\n\t\t\t\tif ( applyWorldTransforms ) {\n\n\t\t\t\t\t_tangentVector.transformDirection( mesh.matrixWorld );\n\n\t\t\t\t}\n\n\t\t\t\ttargetAttributes.tangent.setXYZW( i, _tangentVector.x, _tangentVector.y, _tangentVector.z, _tangentVector4.w );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// copy other attributes over\n\t\tfor ( const i in this.attributes ) {\n\n\t\t\tconst key = this.attributes[ i ];\n\t\t\tif ( key === 'position' || key === 'tangent' || key === 'normal' || ! ( key in attributes ) ) {\n\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tif ( ! targetAttributes[ key ] ) {\n\n\t\t\t\ttargetGeometry.setAttribute( key, createAttributeClone( attributes[ key ] ) );\n\n\t\t\t}\n\n\t\t\tvalidateAttributes( attributes[ key ], targetAttributes[ key ] );\n\t\t\tcopyAttributeContents( attributes[ key ], targetAttributes[ key ] );\n\n\t\t}\n\n\t\tif ( mesh.matrixWorld.determinant() < 0 ) {\n\n\t\t\tinvertGeometry( targetGeometry );\n\n\t\t}\n\n\t\treturn targetGeometry;\n\n\t}\n\n}\n","/**\n * Set of shader functions used for interacting with the packed BVH in a shader and sampling\n * VertexAttributeTextures. Provides common utility functions including `texelFetch1D`. See\n * [src/webgl/glsl](https://github.com/gkjohnson/three-mesh-bvh/tree/master/src/webgl/glsl)\n * for full implementations and declarations.\n *\n * Accessed as `BVHShaderGLSL.common_functions`.\n *\n * @section Shader and Texture Packing API\n * @type {string}\n */\nexport const common_functions = /* glsl */`\n\n// A stack of uint32 indices can can store the indices for\n// a perfectly balanced tree with a depth up to 31. Lower stack\n// depth gets higher performance.\n//\n// However not all trees are balanced. Best value to set this to\n// is the trees max depth.\n#ifndef BVH_STACK_DEPTH\n#define BVH_STACK_DEPTH 60\n#endif\n\n#ifndef INFINITY\n#define INFINITY 1e20\n#endif\n\n// Utilities\nuvec4 uTexelFetch1D( usampler2D tex, uint index ) {\n\n\tuint width = uint( textureSize( tex, 0 ).x );\n\tuvec2 uv;\n\tuv.x = index % width;\n\tuv.y = index / width;\n\n\treturn texelFetch( tex, ivec2( uv ), 0 );\n\n}\n\nivec4 iTexelFetch1D( isampler2D tex, uint index ) {\n\n\tuint width = uint( textureSize( tex, 0 ).x );\n\tuvec2 uv;\n\tuv.x = index % width;\n\tuv.y = index / width;\n\n\treturn texelFetch( tex, ivec2( uv ), 0 );\n\n}\n\nvec4 texelFetch1D( sampler2D tex, uint index ) {\n\n\tuint width = uint( textureSize( tex, 0 ).x );\n\tuvec2 uv;\n\tuv.x = index % width;\n\tuv.y = index / width;\n\n\treturn texelFetch( tex, ivec2( uv ), 0 );\n\n}\n\nvec4 textureSampleBarycoord( sampler2D tex, vec3 barycoord, uvec3 faceIndices ) {\n\n\treturn\n\t\tbarycoord.x * texelFetch1D( tex, faceIndices.x ) +\n\t\tbarycoord.y * texelFetch1D( tex, faceIndices.y ) +\n\t\tbarycoord.z * texelFetch1D( tex, faceIndices.z );\n\n}\n\nvoid ndcToCameraRay(\n\tvec2 coord, mat4 cameraWorld, mat4 invProjectionMatrix,\n\tout vec3 rayOrigin, out vec3 rayDirection\n) {\n\n\t// get camera look direction and near plane for camera clipping\n\tvec4 lookDirection = cameraWorld * vec4( 0.0, 0.0, - 1.0, 0.0 );\n\tvec4 nearVector = invProjectionMatrix * vec4( 0.0, 0.0, - 1.0, 1.0 );\n\tfloat near = abs( nearVector.z / nearVector.w );\n\n\t// get the camera direction and position from camera matrices\n\tvec4 origin = cameraWorld * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec4 direction = invProjectionMatrix * vec4( coord, 0.5, 1.0 );\n\tdirection /= direction.w;\n\tdirection = cameraWorld * direction - origin;\n\n\t// slide the origin along the ray until it sits at the near clip plane position\n\torigin.xyz += direction.xyz * near / dot( direction, lookDirection );\n\n\trayOrigin = origin.xyz;\n\trayDirection = direction.xyz;\n\n}\n`;\n","// Distance to Point\n\n/**\n * Set of shader functions used for interacting with the packed BVH in a shader and sampling\n * VertexAttributeTextures. Provides distance query functions. See\n * [src/webgl/glsl](https://github.com/gkjohnson/three-mesh-bvh/tree/master/src/webgl/glsl)\n * for full implementations and declarations.\n *\n * Accessed as `BVHShaderGLSL.bvh_distance_functions`.\n *\n * @section Shader and Texture Packing API\n * @type {string}\n */\nexport const bvh_distance_functions = /* glsl */`\n\nfloat dot2( vec3 v ) {\n\n\treturn dot( v, v );\n\n}\n\n// implementation from https://www.shadertoy.com/view/ttfGWl, though method 2 has been removed\n// and is now available at this fork: https://www.shadertoy.com/view/WlB3zW\nvec3 closestPointToTriangle( vec3 p, vec3 v0, vec3 v1, vec3 v2, out vec3 barycoord ) {\n\n    vec3 v10 = v1 - v0;\n    vec3 v21 = v2 - v1;\n    vec3 v02 = v0 - v2;\n\n\tvec3 p0 = p - v0;\n\tvec3 p1 = p - v1;\n\tvec3 p2 = p - v2;\n\n    vec3 nor = cross( v10, v02 );\n\n    // method 2, in barycentric space\n    vec3  q = cross( nor, p0 );\n    float d = 1.0 / dot2( nor );\n    float u = d * dot( q, v02 );\n    float v = d * dot( q, v10 );\n    float w = 1.0 - u - v;\n\n\tif( u < 0.0 ) {\n\n\t\tw = clamp( dot( p2, v02 ) / dot2( v02 ), 0.0, 1.0 );\n\t\tu = 0.0;\n\t\tv = 1.0 - w;\n\n\t} else if( v < 0.0 ) {\n\n\t\tu = clamp( dot( p0, v10 ) / dot2( v10 ), 0.0, 1.0 );\n\t\tv = 0.0;\n\t\tw = 1.0 - u;\n\n\t} else if( w < 0.0 ) {\n\n\t\tv = clamp( dot( p1, v21 ) / dot2( v21 ), 0.0, 1.0 );\n\t\tw = 0.0;\n\t\tu = 1.0 - v;\n\n\t}\n\n\t// output the barycoord in v0, v1, v2 weight order\n\tbarycoord = vec3( w, u, v );\n    return u * v1 + v * v2 + w * v0;\n\n}\n\nfloat distanceToTriangles(\n\t// geometry info and triangle range\n\tsampler2D positionAttr, usampler2D indexAttr, uint offset, uint count,\n\n\t// point and cut off range\n\tvec3 point, float closestDistanceSquared,\n\n\t// outputs\n\tinout uvec4 faceIndices, inout vec3 faceNormal, inout vec3 barycoord, inout float side, inout vec3 outPoint\n) {\n\n\tbool found = false;\n\tvec3 localBarycoord;\n\tfor ( uint i = offset, l = offset + count; i < l; i ++ ) {\n\n\t\tuvec3 indices = uTexelFetch1D( indexAttr, i ).xyz;\n\t\tvec3 a = texelFetch1D( positionAttr, indices.x ).rgb;\n\t\tvec3 b = texelFetch1D( positionAttr, indices.y ).rgb;\n\t\tvec3 c = texelFetch1D( positionAttr, indices.z ).rgb;\n\n\t\t// get the closest point and barycoord\n\t\tvec3 closestPoint = closestPointToTriangle( point, a, b, c, localBarycoord );\n\t\tvec3 delta = point - closestPoint;\n\t\tfloat sqDist = dot2( delta );\n\t\tif ( sqDist < closestDistanceSquared ) {\n\n\t\t\t// set the output results\n\t\t\tclosestDistanceSquared = sqDist;\n\t\t\tfaceIndices = uvec4( indices.xyz, i );\n\t\t\tfaceNormal = normalize( cross( a - b, b - c ) );\n\t\t\tbarycoord = localBarycoord;\n\t\t\toutPoint = closestPoint;\n\t\t\tside = sign( dot( faceNormal, delta ) );\n\n\t\t}\n\n\t}\n\n\treturn closestDistanceSquared;\n\n}\n\nfloat distanceSqToBounds( vec3 point, vec3 boundsMin, vec3 boundsMax ) {\n\n\tvec3 clampedPoint = clamp( point, boundsMin, boundsMax );\n\tvec3 delta = point - clampedPoint;\n\treturn dot( delta, delta );\n\n}\n\nfloat distanceSqToBVHNodeBoundsPoint( vec3 point, sampler2D bvhBounds, uint currNodeIndex ) {\n\n\tuint cni2 = currNodeIndex * 2u;\n\tvec3 boundsMin = texelFetch1D( bvhBounds, cni2 ).xyz;\n\tvec3 boundsMax = texelFetch1D( bvhBounds, cni2 + 1u ).xyz;\n\treturn distanceSqToBounds( point, boundsMin, boundsMax );\n\n}\n\n// use a macro to hide the fact that we need to expand the struct into separate fields\n#define\\\n\tbvhClosestPointToPoint(\\\n\t\tbvh,\\\n\t\tpoint, maxDistance, faceIndices, faceNormal, barycoord, side, outPoint\\\n\t)\\\n\t_bvhClosestPointToPoint(\\\n\t\tbvh.position, bvh.index, bvh.bvhBounds, bvh.bvhContents,\\\n\t\tpoint, maxDistance, faceIndices, faceNormal, barycoord, side, outPoint\\\n\t)\n\nfloat _bvhClosestPointToPoint(\n\t// bvh info\n\tsampler2D bvh_position, usampler2D bvh_index, sampler2D bvh_bvhBounds, usampler2D bvh_bvhContents,\n\n\t// point to check\n\tvec3 point, float maxDistance,\n\n\t// output variables\n\tinout uvec4 faceIndices, inout vec3 faceNormal, inout vec3 barycoord,\n\tinout float side, inout vec3 outPoint\n ) {\n\n\t// stack needs to be twice as long as the deepest tree we expect because\n\t// we push both the left and right child onto the stack every traversal\n\tint pointer = 0;\n\tuint stack[ BVH_STACK_DEPTH ];\n\tstack[ 0 ] = 0u;\n\n\tfloat closestDistanceSquared = maxDistance * maxDistance;\n\tbool found = false;\n\twhile ( pointer > - 1 && pointer < BVH_STACK_DEPTH ) {\n\n\t\tuint currNodeIndex = stack[ pointer ];\n\t\tpointer --;\n\n\t\t// check if we intersect the current bounds\n\t\tfloat boundsHitDistance = distanceSqToBVHNodeBoundsPoint( point, bvh_bvhBounds, currNodeIndex );\n\t\tif ( boundsHitDistance > closestDistanceSquared ) {\n\n\t\t\tcontinue;\n\n\t\t}\n\n\t\tuvec2 boundsInfo = uTexelFetch1D( bvh_bvhContents, currNodeIndex ).xy;\n\t\tbool isLeaf = bool( boundsInfo.x & 0xffff0000u );\n\t\tif ( isLeaf ) {\n\n\t\t\tuint count = boundsInfo.x & 0x0000ffffu;\n\t\t\tuint offset = boundsInfo.y;\n\t\t\tclosestDistanceSquared = distanceToTriangles(\n\t\t\t\tbvh_position, bvh_index, offset, count, point, closestDistanceSquared,\n\n\t\t\t\t// outputs\n\t\t\t\tfaceIndices, faceNormal, barycoord, side, outPoint\n\t\t\t);\n\n\t\t} else {\n\n\t\t\tuint leftIndex = currNodeIndex + 1u;\n\t\t\tuint splitAxis = boundsInfo.x & 0x0000ffffu;\n\t\t\tuint rightIndex = currNodeIndex + boundsInfo.y;\n\t\t\tbool leftToRight = distanceSqToBVHNodeBoundsPoint( point, bvh_bvhBounds, leftIndex ) < distanceSqToBVHNodeBoundsPoint( point, bvh_bvhBounds, rightIndex );//rayDirection[ splitAxis ] >= 0.0;\n\t\t\tuint c1 = leftToRight ? leftIndex : rightIndex;\n\t\t\tuint c2 = leftToRight ? rightIndex : leftIndex;\n\n\t\t\t// set c2 in the stack so we traverse it later. We need to keep track of a pointer in\n\t\t\t// the stack while we traverse. The second pointer added is the one that will be\n\t\t\t// traversed first\n\t\t\tpointer ++;\n\t\t\tstack[ pointer ] = c2;\n\t\t\tpointer ++;\n\t\t\tstack[ pointer ] = c1;\n\n\t\t}\n\n\t}\n\n\treturn sqrt( closestDistanceSquared );\n\n}\n`;\n","/**\n * Set of shader functions used for interacting with the packed BVH in a shader and sampling\n * VertexAttributeTextures. Provides ray intersection functions. See\n * [src/webgl/glsl](https://github.com/gkjohnson/three-mesh-bvh/tree/master/src/webgl/glsl)\n * for full implementations and declarations.\n *\n * Accessed as `BVHShaderGLSL.bvh_ray_functions`.\n *\n * @section Shader and Texture Packing API\n * @type {string}\n */\nexport const bvh_ray_functions = /* glsl */`\n\n#ifndef TRI_INTERSECT_EPSILON\n#define TRI_INTERSECT_EPSILON 1e-5\n#endif\n\n// Raycasting\nbool intersectsBounds( vec3 rayOrigin, vec3 rayDirection, vec3 boundsMin, vec3 boundsMax, out float dist ) {\n\n\t// https://www.reddit.com/r/opengl/comments/8ntzz5/fast_glsl_ray_box_intersection/\n\t// https://tavianator.com/2011/ray_box.html\n\tvec3 invDir = 1.0 / rayDirection;\n\n\t// find intersection distances for each plane\n\tvec3 tMinPlane = invDir * ( boundsMin - rayOrigin );\n\tvec3 tMaxPlane = invDir * ( boundsMax - rayOrigin );\n\n\t// get the min and max distances from each intersection\n\tvec3 tMinHit = min( tMaxPlane, tMinPlane );\n\tvec3 tMaxHit = max( tMaxPlane, tMinPlane );\n\n\t// get the furthest hit distance\n\tvec2 t = max( tMinHit.xx, tMinHit.yz );\n\tfloat t0 = max( t.x, t.y );\n\n\t// get the minimum hit distance\n\tt = min( tMaxHit.xx, tMaxHit.yz );\n\tfloat t1 = min( t.x, t.y );\n\n\t// set distance to 0.0 if the ray starts inside the box\n\tdist = max( t0, 0.0 );\n\n\treturn t1 >= dist;\n\n}\n\nbool intersectsTriangle(\n\tvec3 rayOrigin, vec3 rayDirection, vec3 a, vec3 b, vec3 c,\n\tout vec3 barycoord, out vec3 norm, out float dist, out float side\n) {\n\n\t// https://stackoverflow.com/questions/42740765/intersection-between-line-and-triangle-in-3d\n\tvec3 edge1 = b - a;\n\tvec3 edge2 = c - a;\n\tnorm = cross( edge1, edge2 );\n\n\tfloat det = - dot( rayDirection, norm );\n\tfloat invdet = 1.0 / det;\n\n\tvec3 AO = rayOrigin - a;\n\tvec3 DAO = cross( AO, rayDirection );\n\n\tvec4 uvt;\n\tuvt.x = dot( edge2, DAO ) * invdet;\n\tuvt.y = - dot( edge1, DAO ) * invdet;\n\tuvt.z = dot( AO, norm ) * invdet;\n\tuvt.w = 1.0 - uvt.x - uvt.y;\n\n\t// set the hit information\n\tbarycoord = uvt.wxy; // arranged in A, B, C order\n\tdist = uvt.z;\n\tside = sign( det );\n\tnorm = side * normalize( norm );\n\n\t// add an epsilon to avoid misses between triangles\n\tuvt += vec4( TRI_INTERSECT_EPSILON );\n\n\treturn all( greaterThanEqual( uvt, vec4( 0.0 ) ) );\n\n}\n\nbool intersectTriangles(\n\t// geometry info and triangle range\n\tsampler2D positionAttr, usampler2D indexAttr, uint offset, uint count,\n\n\t// ray\n\tvec3 rayOrigin, vec3 rayDirection,\n\n\t// outputs\n\tinout float minDistance, inout uvec4 faceIndices, inout vec3 faceNormal, inout vec3 barycoord,\n\tinout float side, inout float dist\n) {\n\n\tbool found = false;\n\tvec3 localBarycoord, localNormal;\n\tfloat localDist, localSide;\n\tfor ( uint i = offset, l = offset + count; i < l; i ++ ) {\n\n\t\tuvec3 indices = uTexelFetch1D( indexAttr, i ).xyz;\n\t\tvec3 a = texelFetch1D( positionAttr, indices.x ).rgb;\n\t\tvec3 b = texelFetch1D( positionAttr, indices.y ).rgb;\n\t\tvec3 c = texelFetch1D( positionAttr, indices.z ).rgb;\n\n\t\tif (\n\t\t\tintersectsTriangle( rayOrigin, rayDirection, a, b, c, localBarycoord, localNormal, localDist, localSide )\n\t\t\t&& localDist < minDistance\n\t\t) {\n\n\t\t\tfound = true;\n\t\t\tminDistance = localDist;\n\n\t\t\tfaceIndices = uvec4( indices.xyz, i );\n\t\t\tfaceNormal = localNormal;\n\n\t\t\tside = localSide;\n\t\t\tbarycoord = localBarycoord;\n\t\t\tdist = localDist;\n\n\t\t}\n\n\t}\n\n\treturn found;\n\n}\n\nbool intersectsBVHNodeBounds( vec3 rayOrigin, vec3 rayDirection, sampler2D bvhBounds, uint currNodeIndex, out float dist ) {\n\n\tuint cni2 = currNodeIndex * 2u;\n\tvec3 boundsMin = texelFetch1D( bvhBounds, cni2 ).xyz;\n\tvec3 boundsMax = texelFetch1D( bvhBounds, cni2 + 1u ).xyz;\n\treturn intersectsBounds( rayOrigin, rayDirection, boundsMin, boundsMax, dist );\n\n}\n\n// use a macro to hide the fact that we need to expand the struct into separate fields\n#define\\\n\tbvhIntersectFirstHit(\\\n\t\tbvh,\\\n\t\trayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist\\\n\t)\\\n\t_bvhIntersectFirstHit(\\\n\t\tbvh.position, bvh.index, bvh.bvhBounds, bvh.bvhContents,\\\n\t\trayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist\\\n\t)\n\nbool _bvhIntersectFirstHit(\n\t// bvh info\n\tsampler2D bvh_position, usampler2D bvh_index, sampler2D bvh_bvhBounds, usampler2D bvh_bvhContents,\n\n\t// ray\n\tvec3 rayOrigin, vec3 rayDirection,\n\n\t// output variables split into separate variables due to output precision\n\tinout uvec4 faceIndices, inout vec3 faceNormal, inout vec3 barycoord,\n\tinout float side, inout float dist\n) {\n\n\t// stack needs to be twice as long as the deepest tree we expect because\n\t// we push both the left and right child onto the stack every traversal\n\tint pointer = 0;\n\tuint stack[ BVH_STACK_DEPTH ];\n\tstack[ 0 ] = 0u;\n\n\tfloat triangleDistance = INFINITY;\n\tbool found = false;\n\twhile ( pointer > - 1 && pointer < BVH_STACK_DEPTH ) {\n\n\t\tuint currNodeIndex = stack[ pointer ];\n\t\tpointer --;\n\n\t\t// check if we intersect the current bounds\n\t\tfloat boundsHitDistance;\n\t\tif (\n\t\t\t! intersectsBVHNodeBounds( rayOrigin, rayDirection, bvh_bvhBounds, currNodeIndex, boundsHitDistance )\n\t\t\t|| boundsHitDistance > triangleDistance\n\t\t) {\n\n\t\t\tcontinue;\n\n\t\t}\n\n\t\tuvec2 boundsInfo = uTexelFetch1D( bvh_bvhContents, currNodeIndex ).xy;\n\t\tbool isLeaf = bool( boundsInfo.x & 0xffff0000u );\n\n\t\tif ( isLeaf ) {\n\n\t\t\tuint count = boundsInfo.x & 0x0000ffffu;\n\t\t\tuint offset = boundsInfo.y;\n\n\t\t\tfound = intersectTriangles(\n\t\t\t\tbvh_position, bvh_index, offset, count,\n\t\t\t\trayOrigin, rayDirection, triangleDistance,\n\t\t\t\tfaceIndices, faceNormal, barycoord, side, dist\n\t\t\t) || found;\n\n\t\t} else {\n\n\t\t\tuint leftIndex = currNodeIndex + 1u;\n\t\t\tuint splitAxis = boundsInfo.x & 0x0000ffffu;\n\t\t\tuint rightIndex = currNodeIndex + boundsInfo.y;\n\n\t\t\tbool leftToRight = rayDirection[ splitAxis ] >= 0.0;\n\t\t\tuint c1 = leftToRight ? leftIndex : rightIndex;\n\t\t\tuint c2 = leftToRight ? rightIndex : leftIndex;\n\n\t\t\t// set c2 in the stack so we traverse it later. We need to keep track of a pointer in\n\t\t\t// the stack while we traverse. The second pointer added is the one that will be\n\t\t\t// traversed first\n\t\t\tpointer ++;\n\t\t\tstack[ pointer ] = c2;\n\n\t\t\tpointer ++;\n\t\t\tstack[ pointer ] = c1;\n\n\t\t}\n\n\t}\n\n\treturn found;\n\n}\n`;\n","// Note that a struct cannot be used for the hit record including faceIndices, faceNormal, barycoord,\n// side, and dist because on some mobile GPUS (such as Adreno) numbers are afforded less precision specifically\n// when in a struct leading to inaccurate hit results. See KhronosGroup/WebGL#3351 for more details.\n\n/**\n * Set of shader structs and defined constants used for interacting with the packed BVH in a\n * shader. See [src/webgl/glsl/bvh_struct_definitions.glsl.js](https://github.com/gkjohnson/three-mesh-bvh/blob/master/src/webgl/glsl/bvh_struct_definitions.glsl.js)\n * for full implementations and declarations.\n *\n * Accessed as `BVHShaderGLSL.bvh_struct_definitions`.\n *\n * @section Shader and Texture Packing API\n * @type {string}\n */\nexport const bvh_struct_definitions = /* glsl */`\nstruct BVH {\n\n\tusampler2D index;\n\tsampler2D position;\n\n\tsampler2D bvhBounds;\n\tusampler2D bvhContents;\n\n};\n`;\n","export * from './core/BVH.js';\nexport * from './core/GeometryBVH.js';\nexport * from './core/MeshBVH.js';\nexport * from './core/LineBVH.js';\nexport * from './core/PointsBVH.js';\nexport * from './core/ObjectBVH.js';\nexport * from './core/SkinnedMeshBVH.js';\nexport * from './objects/BVHHelper.js';\nexport { CENTER, AVERAGE, SAH, NOT_INTERSECTED, INTERSECTED, CONTAINED, SKIP_GENERATION } from './core/Constants.js';\nexport { getBVHExtremes, estimateMemoryInBytes, getJSONStructure, validateBounds } from './debug/Debug.js';\nexport * from './utils/ExtensionUtilities.js';\nexport { getTriangleHitPointInfo } from './utils/TriangleUtilities.js';\nexport * from './math/ExtendedTriangle.js';\nexport * from './math/OrientedBox.js';\nexport * from './webgl/MeshBVHUniformStruct.js';\nexport * from './webgl/VertexAttributeTexture.js';\nexport * from './utils/StaticGeometryGenerator.js';\nexport * as BVHShaderGLSL from './webgl/BVHShaderGLSL.js';\n\n// backwards compatibility\nimport * as BVHShaderGLSL from './webgl/BVHShaderGLSL.js';\nexport const shaderStructs = BVHShaderGLSL.bvh_struct_definitions;\nexport const shaderDistanceFunction = BVHShaderGLSL.bvh_distance_functions;\nexport const shaderIntersectFunction = `\n\t${ BVHShaderGLSL.common_functions }\n\t${ BVHShaderGLSL.bvh_ray_functions }\n`;\n","import { Box3, Line3, Matrix4, Vector3 } from 'three';\nimport { ExtendedTriangle } from 'three-mesh-bvh';\n\nconst EPSILON = 1e-5;\n\n/** Continuous capsule/triangle contact in double-precision, foot-local metres.\n * Borrows native geometry; never changes indices, installs global colliders,\n * retains a tile graph or sends Earth-radius coordinates to float32 physics. */\nexport class SurfaceCapsuleCollider {\n    constructor() {\n        this.origin = new Vector3();this.up = new Vector3();\n        this.axis = new Line3();this.segment = new Line3();\n        this.triangle = new ExtendedTriangle();\n        this.inverse = new Matrix4();this.bounds = new Box3();\n        this.localStart = new Vector3();this.localEnd = new Vector3();this.localDelta = new Vector3();\n        this.trianglePoint = new Vector3();this.axisPoint = new Vector3();this.normal = new Vector3();\n        this.translation = new Vector3();this.remaining = new Vector3();this.request = new Vector3();\n        this.hitNormal = new Vector3();this.bestNormal = new Vector3();\n        this.clipNormal = new Vector3();\n        this.baseline = new Vector3();this.stepped = new Vector3();this.vertical = new Vector3();\n        this.result = new Vector3();this.zero = new Vector3();\n        this.stats = { trianglesScanned: 0, trianglesTested: 0, casts: 0 };\n    }\n\n    _setup({ foot, up, height, radius, skin = 0.01 }) {\n        this.origin.copy(foot);this.up.copy(up).normalize();this.radius = radius + skin;\n        this.axis.start.copy(this.up).multiplyScalar(radius);\n        this.axis.end.copy(this.up).multiplyScalar(Math.max(radius, height - radius));\n        this.stats.trianglesScanned = this.stats.trianglesTested = this.stats.casts = 0;\n    }\n\n    _triangles(meshes, offset, motion, visit) {\n        const { triangle, bounds, inverse, localStart, localEnd, localDelta } = this;\n        for (const mesh of meshes) {\n            const geometry = mesh.geometry, position = geometry?.attributes?.position, index = geometry?.index;\n            if (!position) continue;\n            inverse.copy(mesh.matrixWorld).invert();\n            localStart.copy(this.axis.start).add(offset).add(this.origin).applyMatrix4(inverse);\n            localEnd.copy(this.axis.end).add(offset).add(this.origin).applyMatrix4(inverse);\n            localDelta.copy(this.origin).add(motion).applyMatrix4(inverse)\n                .sub(this.axisPoint.copy(this.origin).applyMatrix4(inverse));\n            bounds.makeEmpty().expandByPoint(localStart).expandByPoint(localEnd);\n            bounds.expandByPoint(this.axisPoint.copy(localStart).add(localDelta));\n            bounds.expandByPoint(this.axisPoint.copy(localEnd).add(localDelta));\n            bounds.expandByScalar(this.radius * inverse.getMaxScaleOnAxis());\n            const count = index ? index.count : position.count;\n            const start = Math.max(0, geometry.drawRange.start || 0);\n            const end = Math.min(count, start + geometry.drawRange.count);\n            for (let i = start; i + 2 < end; i += 3) {\n                this.stats.trianglesScanned++;\n                const { a, b, c } = triangle;\n                a.fromBufferAttribute(position, index ? index.getX(i) : i);\n                b.fromBufferAttribute(position, index ? index.getX(i + 1) : i + 1);\n                c.fromBufferAttribute(position, index ? index.getX(i + 2) : i + 2);\n                if (Math.max(a.x, b.x, c.x) < bounds.min.x || Math.min(a.x, b.x, c.x) > bounds.max.x\n                    || Math.max(a.y, b.y, c.y) < bounds.min.y || Math.min(a.y, b.y, c.y) > bounds.max.y\n                    || Math.max(a.z, b.z, c.z) < bounds.min.z || Math.min(a.z, b.z, c.z) > bounds.max.z) continue;\n                a.applyMatrix4(mesh.matrixWorld).sub(this.origin);\n                b.applyMatrix4(mesh.matrixWorld).sub(this.origin);\n                c.applyMatrix4(mesh.matrixWorld).sub(this.origin);\n                triangle.needsUpdate = true;\n                this.stats.trianglesTested++;\n                visit(triangle);\n            }\n        }\n    }\n\n    _cast(meshes, offset, motion) {\n        this.stats.casts++;\n        let first = Infinity;\n        if (motion.lengthSq() < 1e-16) return first;\n        this._triangles(meshes, offset, motion, triangle => {\n            let time = 0;\n            // Distance between convex shapes is convex under translation.\n            // Its separating normal gives a conservative advancement step.\n            for (let iteration = 0; iteration < 16 && time <= 1 && time < first; iteration++) {\n                this.segment.start.copy(this.axis.start).add(offset).addScaledVector(motion, time);\n                this.segment.end.copy(this.axis.end).add(offset).addScaledVector(motion, time);\n                const distance = triangle.closestPointToSegment(this.segment, this.trianglePoint, this.axisPoint);\n                this.normal.subVectors(this.axisPoint, this.trianglePoint);\n                if (distance > 1e-10) this.normal.multiplyScalar(1 / distance);\n                else {\n                    triangle.getNormal(this.normal);\n                    if (this.normal.dot(motion) > 0) this.normal.negate();\n                }\n                const closing = -this.normal.dot(motion);\n                if (closing <= 1e-10) break;\n                const gap = distance - this.radius;\n                if (gap <= EPSILON) { first = time;this.bestNormal.copy(this.normal);break; }\n                time += Math.max(EPSILON, gap / closing);\n            }\n        });\n        if (Number.isFinite(first)) this.hitNormal.copy(this.bestNormal);\n        return first;\n    }\n\n    _slide(meshes, offset, motion, target, slopeDot) {\n        target.copy(offset);this.remaining.copy(motion);let wall = false;\n        for (let bump = 0; bump < 5 && this.remaining.lengthSq() > 1e-12; bump++) {\n            const time = this._cast(meshes, target, this.remaining);\n            if (!Number.isFinite(time)) { target.add(this.remaining);break; }\n            target.addScaledVector(this.remaining, time);\n            this.remaining.multiplyScalar(1 - time);\n            const vertical = this.hitNormal.dot(this.up);\n            this.clipNormal.copy(this.hitNormal);\n            if (vertical < slopeDot) {\n                wall = true;\n                // Horizontal intent must not roll the capsule up an\n                // unwalkable wall/step edge. Vertical intent stays explicit.\n                if (Math.abs(motion.dot(this.up)) < EPSILON) {\n                    this.clipNormal.addScaledVector(this.up, -vertical).normalize();\n                }\n            }\n            const into = this.remaining.dot(this.clipNormal);\n            if (into < 0) this.remaining.addScaledVector(this.clipNormal, -into);\n        }\n        return wall;\n    }\n\n    _lift(meshes, slopeDot) {\n        if (slopeDot > 1) return 0;\n        let height = 0;\n        // Resolve the complete rounded foot against walkable faces. The body\n        // may require more clearance than the single vertical center ray.\n        for (let pass = 0; pass < 4; pass++) {\n            let correction = 0;\n            this.translation.copy(this.up).multiplyScalar(height);\n            this._triangles(meshes, this.translation, this.zero, triangle => {\n                this.segment.start.copy(this.axis.start).add(this.translation);\n                this.segment.end.copy(this.axis.end).add(this.translation);\n                const distance = triangle.closestPointToSegment(this.segment, this.trianglePoint, this.axisPoint);\n                this.normal.subVectors(this.axisPoint, this.trianglePoint);\n                if (distance <= 1e-10) {\n                    triangle.getNormal(this.normal);if (this.normal.dot(this.up) < 0) this.normal.negate();\n                } else this.normal.multiplyScalar(1 / distance);\n                const vertical = this.normal.dot(this.up);\n                if (vertical >= slopeDot && distance < this.radius - EPSILON) {\n                    correction = Math.max(correction, (this.radius - distance + EPSILON) / vertical);\n                }\n            });\n            height += correction;\n            if (correction < EPSILON) break;\n        }\n        return height;\n    }\n\n    clearance(meshes, capsule, slopeDot = 0.58) {\n        this._setup(capsule);\n        return this._lift(meshes, slopeDot);\n    }\n\n    move(meshes, capsule, motion, { stepHeight = 0.55, snap = 0.3, slopeDot = 0.58 } = {}) {\n        this._setup(capsule);this.request.copy(motion);\n        const lift = this._lift(meshes, slopeDot);\n        this.translation.copy(this.up).multiplyScalar(lift);\n        const wall = this._slide(meshes, this.translation, this.request, this.baseline, slopeDot);\n        if (wall && stepHeight > 0) {\n            this.vertical.copy(this.up).multiplyScalar(stepHeight);\n            const ceiling = this._cast(meshes, this.translation, this.vertical);\n            if (!Number.isFinite(ceiling)) {\n                this.translation.add(this.vertical);\n                this._slide(meshes, this.translation, this.request, this.stepped, slopeDot);\n                this.vertical.copy(this.up).multiplyScalar(-stepHeight - snap);\n                const landing = this._cast(meshes, this.stepped, this.vertical);\n                if (Number.isFinite(landing) && this.hitNormal.dot(this.up) >= slopeDot) {\n                    this.stepped.addScaledVector(this.vertical, landing);\n                    const baseProgress = this.baseline.dot(this.request);\n                    if (this.stepped.dot(this.up) - lift <= stepHeight + EPSILON\n                        && this.stepped.dot(this.request) > baseProgress + 1e-8) this.baseline.copy(this.stepped);\n                }\n            }\n        }\n        // A real downward hull sweep maintains support across a curb/descent;\n        // an unsupported ledge remains airborne for the existing gravity owner.\n        this.vertical.copy(this.up).multiplyScalar(-snap);\n        const ground = this._cast(meshes, this.baseline, this.vertical);\n        if (Number.isFinite(ground) && this.hitNormal.dot(this.up) >= slopeDot) this.baseline.addScaledVector(this.vertical, ground);\n        return this.result.copy(this.baseline);\n    }\n}\n","/** C1 virtual trackball extension. Exact sphere projection in the inner disc,\n * a tangent-matched hyperbola outside it; no ray-hit/closest-point cliff. */\nexport function projectOrbitDragRay(origin, direction, radius, out, metrics = {}) {\n  if (!(radius > 0) || !Number.isFinite(radius)) return null;\n  const t = -origin.dot(direction);\n  out.copy(origin).addScaledVector(direction, t);\n  const impact = out.length(), split = radius / Math.SQRT2;\n  metrics.impactRatio = t > 0 ? impact / radius : Infinity;\n  const depth = impact <= split ? Math.sqrt(Math.max(0, radius * radius - impact * impact))\n    : radius * radius / (2 * Math.max(impact, 1e-9));\n  out.addScaledVector(direction, -depth);\n  return out.lengthSq() > 1e-12 && [out.x,out.y,out.z].every(Number.isFinite) ? out.normalize() : null;\n}\n","// Sampling shares only already-published provider transforms. This is neither\n// a contact-height cache nor a frame clock, and never changes tile ownership.\nconst publications = new WeakMap();\n\nexport function invalidatePhotorealSamplingMatrices(root) {\n    if (root && typeof root === 'object') publications.delete(root);\n}\n\nexport function publishPhotorealSamplingMatrices(root, xrFrame = null) {\n    if (typeof root?.updateWorldMatrix !== 'function') return false;\n    const sequence = root.userData?.photoModelChangeSeq;\n    const qualified = root.isObject3D === true && Number.isSafeInteger(sequence) && sequence >= 0\n        && xrFrame && typeof xrFrame === 'object' && root.matrixWorld?.elements?.length === 16;\n    if (!qualified) {\n        invalidatePhotorealSamplingMatrices(root);\n        root.updateWorldMatrix(true, true);\n        return true;\n    }\n\n    // Ancestor/root changes can occur between two probes in the SAME frame.\n    // Refresh that short chain before comparing the actual world transform.\n    root.updateWorldMatrix(true, false);\n    const elements = root.matrixWorld.elements;\n    let previous = publications.get(root);\n    if (previous?.frame === xrFrame && previous.sequence === sequence\n        && previous.matrix.every((value, index) => value === elements[index])) return false;\n\n    root.updateWorldMatrix(false, true);\n    if (root.userData?.photoModelChangeSeq === sequence && elements.every(Number.isFinite)) {\n        previous ||= { matrix: new Float64Array(16) };\n        previous.frame = xrFrame;\n        previous.sequence = sequence;\n        previous.matrix.set(elements);\n        publications.set(root, previous);\n    } else invalidatePhotorealSamplingMatrices(root);\n    return true;\n}\n","const SVG_NS = 'http://www.w3.org/2000/svg';\n\nexport function normalizeLocatorHeading(headingDeg = 0) {\n  const heading = Number(headingDeg);\n  if (!Number.isFinite(heading)) return 0;\n  return ((heading % 360) + 360) % 360;\n}\n\nexport function clampLocatorFov(fovDeg = 60) {\n  const fov = Number(fovDeg);\n  if (!Number.isFinite(fov)) return 60;\n  return Math.max(10, Math.min(150, fov));\n}\n\n/**\n * Give each boot locator a slightly different, alternating crosshair rhythm.\n * Directions remain deterministic (left/right/left/right) while magnitudes\n * and tempo vary per mount, avoiding the mechanical look of a linear spin.\n */\nexport function createCrosshairMotion(random = Math.random) {\n  const sample = typeof random === 'function' ? random : Math.random;\n  const between = (min, max) => min + (max - min) * Math.max(0, Math.min(1, Number(sample()) || 0));\n  return {\n    leftA: -between(24, 52),\n    rightA: between(16, 40),\n    leftB: -between(12, 34),\n    rightB: between(30, 62),\n    durationMs: between(6200, 8600),\n    armDelayMs: -between(0, 1800),\n  };\n}\n\n/**\n * Build an SVG sector centered on the locator. Zero degrees points north and\n * positive headings turn clockwise, matching the surface camera convention.\n */\nexport function buildViewshedSectorPath(headingDeg = 0, fovDeg = 60, radius = 60) {\n  const heading = normalizeLocatorHeading(headingDeg);\n  const fov = clampLocatorFov(fovDeg);\n  const safeRadius = Number.isFinite(Number(radius))\n    ? Math.max(1, Number(radius))\n    : 60;\n  const halfFov = fov / 2;\n  const pointAt = (degrees) => {\n    const radians = degrees * Math.PI / 180;\n    return {\n      x: Math.sin(radians) * safeRadius,\n      y: -Math.cos(radians) * safeRadius,\n    };\n  };\n  const start = pointAt(heading - halfFov);\n  const end = pointAt(heading + halfFov);\n  return [\n    'M 0 0',\n    `L ${start.x.toFixed(3)} ${start.y.toFixed(3)}`,\n    `A ${safeRadius} ${safeRadius} 0 0 1 ${end.x.toFixed(3)} ${end.y.toFixed(3)}`,\n    'Z',\n  ].join(' ');\n}\n\nfunction appendClass(element, ...names) {\n  element.classList.add(...names.filter(Boolean));\n  return element;\n}\n\nexport function createSceneLocationIndicator({\n  documentRef = globalThis.document,\n  id = '',\n  variant = 'map',\n  className = '',\n  label = 'Current scene location and camera viewshed',\n  showViewshed = variant === 'map',\n} = {}) {\n  if (!documentRef?.createElement) return null;\n\n  const locator = documentRef.createElement('span');\n  if (id) locator.id = id;\n  locator.className = [\n    'nca-scene-locator',\n    `nca-scene-locator--${variant}`,\n    className,\n  ].filter(Boolean).join(' ');\n  locator.setAttribute('role', 'img');\n  locator.setAttribute('aria-label', label);\n  locator.dataset.heading = '0';\n  locator.dataset.fov = '60';\n\n  if (showViewshed) {\n    const radar = documentRef.createElement('span');\n    radar.className = 'nca-scene-locator__radar';\n    radar.setAttribute('aria-hidden', 'true');\n\n    const svg = documentRef.createElementNS(SVG_NS, 'svg');\n    svg.setAttribute('class', 'nca-scene-locator__viewshed');\n    svg.setAttribute('viewBox', '-70 -70 140 140');\n    svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');\n\n    for (const radius of [24, 42, 60]) {\n      const circle = documentRef.createElementNS(SVG_NS, 'circle');\n      circle.setAttribute('class', 'nca-scene-locator__range');\n      circle.setAttribute('cx', '0');\n      circle.setAttribute('cy', '0');\n      circle.setAttribute('r', String(radius));\n      svg.appendChild(circle);\n    }\n\n    const sector = documentRef.createElementNS(SVG_NS, 'path');\n    sector.setAttribute('class', 'nca-scene-locator__sector');\n    sector.setAttribute('d', buildViewshedSectorPath(0, 60));\n    svg.appendChild(sector);\n    radar.appendChild(svg);\n\n    locator.appendChild(radar);\n  }\n\n  const core = appendClass(\n    documentRef.createElement('span'),\n    'nca-scene-locator__core',\n    'boot-map-anchor-core',\n  );\n  core.setAttribute('aria-hidden', 'true');\n\n  const crosshair = appendClass(\n    documentRef.createElement('span'),\n    'nca-scene-locator__crosshair',\n    'boot-map-anchor-sweep',\n  );\n  crosshair.setAttribute('aria-hidden', 'true');\n  const motion = createCrosshairMotion();\n  crosshair.style.setProperty('--nca-crosshair-left-a', `${motion.leftA.toFixed(2)}deg`);\n  crosshair.style.setProperty('--nca-crosshair-right-a', `${motion.rightA.toFixed(2)}deg`);\n  crosshair.style.setProperty('--nca-crosshair-left-b', `${motion.leftB.toFixed(2)}deg`);\n  crosshair.style.setProperty('--nca-crosshair-right-b', `${motion.rightB.toFixed(2)}deg`);\n  crosshair.style.setProperty('--nca-crosshair-motion-duration', `${motion.durationMs.toFixed(0)}ms`);\n  crosshair.style.setProperty('--nca-crosshair-arm-delay', `${motion.armDelayMs.toFixed(0)}ms`);\n  for (const direction of ['north', 'east', 'south', 'west']) {\n    const arm = documentRef.createElement('span');\n    appendClass(\n      arm,\n      'nca-scene-locator__arm',\n      `nca-scene-locator__arm--${direction}`,\n      'boot-map-anchor-arm',\n      `boot-map-anchor-arm--${direction}`,\n    );\n    crosshair.appendChild(arm);\n  }\n\n  locator.append(core, crosshair);\n  return locator;\n}\n\nexport function updateSceneLocationIndicator(\n  locator,\n  {\n    x = null,\n    y = null,\n    headingDeg = null,\n    fovDeg = null,\n    active = null,\n    photoreal = null,\n  } = {},\n) {\n  if (!locator) return null;\n  if (x !== null && Number.isFinite(Number(x))) locator.style.left = `${Number(x)}px`;\n  if (y !== null && Number.isFinite(Number(y))) locator.style.top = `${Number(y)}px`;\n  if (active !== null) locator.classList.toggle('active', Boolean(active));\n  if (photoreal !== null) locator.classList.toggle('is-photo', Boolean(photoreal));\n\n  const heading = headingDeg === null\n    ? normalizeLocatorHeading(locator.dataset.heading)\n    : normalizeLocatorHeading(headingDeg);\n  const fov = fovDeg === null\n    ? clampLocatorFov(locator.dataset.fov)\n    : clampLocatorFov(fovDeg);\n  const headingKey = heading.toFixed(2);\n  const fovKey = fov.toFixed(2);\n  if (locator.dataset.heading !== headingKey || locator.dataset.fov !== fovKey) {\n    locator.dataset.heading = headingKey;\n    locator.dataset.fov = fovKey;\n    locator.querySelector('.nca-scene-locator__sector')\n      ?.setAttribute('d', buildViewshedSectorPath(heading, fov));\n    locator.setAttribute(\n      'aria-label',\n      `Current scene location, heading ${Math.round(heading)}°, ${Math.round(fov)}° viewshed`,\n    );\n  }\n  return { headingDeg: heading, fovDeg: fov };\n}\n","/**\n * Device Sensors Module\n *\n * Manages device orientation and compass for mobile devices.\n * Provides quaternion-based camera orientation and compass heading.\n * Handles iOS/Android permission requests and calibration.\n */\n\nimport * as THREE from 'three';\n\nexport class DeviceSensors {\n  constructor() {\n    // Enabled/ready flags\n    this.enabled = false;\n    this.ready = false;\n\n    // Legacy orientation (degrees) for back-compat\n    this.orient = { a: 0, b: 0, g: 0, ready: false };\n\n    // Public Euler angles (extracted from final cameraQuat for display/legacy use)\n    this.yaw = 0;\n    this.pitch = 0;\n    this.roll = 0;\n\n    // One-time yaw align to compass heading\n    this._compassAligned = false;\n\n    // Screen orientation (radians)\n    this._screenOri = 0;\n\n    // Math helpers\n    this._zee = new THREE.Vector3(0, 0, 1);\n    this._yAxis = new THREE.Vector3(0, 1, 0);\n    this._xAxis = new THREE.Vector3(1, 0, 0);\n\n    // -PI/2 around X (to convert device frame to camera-forward frame)\n    this._qTilt = new THREE.Quaternion(-Math.SQRT1_2, 0, 0, Math.SQRT1_2);\n\n    // Input Euler for deviceorientation -> quaternion\n    this._eulerIn = new THREE.Euler();\n\n    // Device quaternion (screen-compensated, no offsets)\n    this._orientationQuat = new THREE.Quaternion();\n\n    // Single offset quaternion (pre-multiplied for calibration)\n    // Usage: displayQuat = qOffset * rawQuat\n    this.qOffset = new THREE.Quaternion();\n\n    // Final, camera-ready quaternion (recommended to drive camera directly)\n    // This is qOffset * _orientationQuat\n    this.cameraQuat = new THREE.Quaternion();\n\n    // Temps\n    this._fwd = new THREE.Vector3(0, 0, -1);\n    this._up = new THREE.Vector3(0, 1, 0);\n    this._right = new THREE.Vector3(1, 0, 0);\n    this._tmpV = new THREE.Vector3();\n    this._qYawInv = new THREE.Quaternion();\n    this._qTmp = new THREE.Quaternion();\n    this._q0 = new THREE.Quaternion();\n    this._qTmp2 = new THREE.Quaternion();\n\n    // Motion/accel\n    this._accelRaw = new THREE.Vector3();\n    this._accelWorld = new THREE.Vector3();\n    this.motion = { ax: 0, ay: 0, az: 0, ready: false, timestamp: 0 };\n    this._motionListening = false;\n\n    // Magnetometer\n    this._magSensor = null;\n    this._magStartAttempted = false;\n    this._magVec = new THREE.Vector3();\n    this._magTemp = new THREE.Vector3();\n    this._magWorld = new THREE.Vector3();\n    this._magReady = false;\n\n    // Platform-reported heading (iOS)\n    this._webHeadingDeg = null;\n\n    // Gravity for tilt-comp fallback\n    this._gravityVec = new THREE.Vector3();\n    this._gravityTemp = new THREE.Vector3();\n    this._gravityReady = false;\n\n    // Enable flow\n    this._enabling = false;\n    this._autoGestureAttached = false;\n    this._autoGestureHandler = null;\n\n    // Public heading state\n    this.headingDeg = null; // 0..360\n    this.headingRad = null; // 0..2π, 0 = North(-Z), clockwise +\n    this.headingSource = 'unknown';\n    this.headingConfidence = 0;\n\n    // Calibration state\n    this._calibrationPending = false;\n    this._calibrationCallback = null;\n\n    // Bind handlers\n    this._onDO = this._onDO.bind(this);\n    this._onDM = this._onDM.bind(this);\n\n    // Track screen orientation\n    this._updateScreenOrientation();\n    window.addEventListener('orientationchange', () => this._updateScreenOrientation(), false);\n\n    // Event listeners for external notification\n    this._listeners = {\n      'enabled': [],\n      'heading-update': [],\n      'orientation-update': [],\n      'calibration-ready': [],\n      'permission-denied': []\n    };\n  }\n\n  // ───────────────────── Event System ─────────────────────\n\n  on(event, callback) {\n    if (this._listeners[event]) {\n      this._listeners[event].push(callback);\n    }\n    return () => this.off(event, callback);\n  }\n\n  off(event, callback) {\n    if (this._listeners[event]) {\n      this._listeners[event] = this._listeners[event].filter(cb => cb !== callback);\n    }\n  }\n\n  _emit(event, data) {\n    const list = this._listeners[event];\n    if (!list || list.length === 0) return;\n    // Snapshot + try/catch so a throwing listener cannot halt the\n    // remaining subscribers or (worse) terminate the deviceorientation\n    // handler that called us — that was producing \"one frame then stall\"\n    // symptoms on iPhone where a DOM update inside a subscriber threw\n    // after the first reading.\n    const snapshot = list.slice();\n    for (let i = 0; i < snapshot.length; i++) {\n      try {\n        snapshot[i](data);\n      } catch (err) {\n        console.warn('[DeviceSensors] listener threw in', event, err);\n      }\n    }\n  }\n\n  // ───────────────────── Device Detection ─────────────────────\n\n  /**\n   * Check if this is a mobile/touch device\n   */\n  static isMobile() {\n    if (typeof window === 'undefined') return false;\n    return (\n      ('ontouchstart' in window) ||\n      (navigator.maxTouchPoints > 0) ||\n      /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)\n    );\n  }\n\n  /**\n   * Check if device orientation is potentially available\n   */\n  static hasOrientationSupport() {\n    return typeof window !== 'undefined' && (\n      'DeviceOrientationEvent' in window ||\n      'ondeviceorientationabsolute' in window ||\n      'ondeviceorientation' in window\n    );\n  }\n\n  /**\n   * Check if the device needs permission request (iOS 13+)\n   */\n  static needsPermissionRequest() {\n    return typeof DeviceOrientationEvent?.requestPermission === 'function';\n  }\n\n  // ───────────────────── Public API ─────────────────────\n\n  async enable() {\n    if (this.enabled) {\n      this._startMagnetometer();\n      return { success: true };\n    }\n    if (this._enabling) return { success: false, reason: 'pending' };\n\n    this._enabling = true;\n    let reason = null;\n\n    try {\n      // iOS permission prompts (orientation is the one that blocks)\n      if (typeof DeviceOrientationEvent?.requestPermission === 'function') {\n        let status;\n        try {\n          status = await DeviceOrientationEvent.requestPermission();\n        } catch (err) {\n          reason = (`${err?.message || ''}`).toLowerCase().includes('gesture') ? 'gesture' : 'error';\n        }\n        if (!reason && status && status !== 'granted') {\n          reason = (status === 'denied') ? 'denied' : 'error';\n        }\n      }\n      if (reason) {\n        this._emit('permission-denied', { reason });\n        return { success: false, reason };\n      }\n\n      if (typeof DeviceMotionEvent?.requestPermission === 'function') {\n        try { await DeviceMotionEvent.requestPermission(); } catch {}\n      }\n\n      // Guard against duplicate registration on retry/re-enable paths.\n      // iOS Safari silently ignores duplicate addEventListener on window,\n      // but defensive flag avoids accidental double-fire when 'absolute'\n      // and standard 'deviceorientation' are both bound across calls.\n      if (!this._orientListening) {\n        const type = ('ondeviceorientationabsolute' in window)\n          ? 'deviceorientationabsolute' : 'deviceorientation';\n        this._orientListenerType = type;\n        window.addEventListener(type, this._onDO, true);\n        // Fallback: always also listen to plain 'deviceorientation'\n        // because some iOS builds stop delivering 'absolute' events\n        // after the first frame while still emitting the plain one.\n        if (type !== 'deviceorientation') {\n          window.addEventListener('deviceorientation', this._onDO, true);\n        }\n        this._orientListening = true;\n      }\n\n      if (!this._motionListening) {\n        window.addEventListener('devicemotion', this._onDM, true);\n        this._motionListening = true;\n      }\n\n      this.enabled = true;\n      this._emit('enabled', { success: true });\n      this._clearGestureEnableHandlers();\n      this._startMagnetometer();\n      return { success: true };\n    } finally {\n      const gestureNeeded = reason === 'gesture';\n      this._enabling = false;\n      if (gestureNeeded) this._installGestureEnable();\n    }\n  }\n\n  /**\n   * Calibrate the sensor with a target yaw (degrees)\n   * Sets qOffset so that current orientation maps to targetYaw\n   */\n  calibrate(targetYawDeg = 0) {\n    this._composeFinalQuat();\n    const currentHeadingDeg = this._headingFromQuatDeg(this.cameraQuat);\n    if (currentHeadingDeg == null) {\n      // Fallback if device is too vertical - just set offset directly\n      this.qOffset.setFromAxisAngle(this._yAxis, -targetYawDeg * Math.PI / 180);\n    } else {\n      // Use same pattern as calibrateToCompass\n      const deltaDeg = ((targetYawDeg - currentHeadingDeg + 540) % 360) - 180;\n      const deltaRad = deltaDeg * Math.PI / 180;\n      const qDelta = this._qTmp.setFromAxisAngle(this._yAxis, -deltaRad);\n      this.qOffset.premultiply(qDelta);\n    }\n    this._composeFinalQuat();\n    this.ready = true;\n    this.orient.ready = true;\n    this._emit('calibration-ready', { targetYawDeg });\n  }\n\n  /**\n   * Reset calibration offset to identity\n   */\n  resetCalibration() {\n    this.qOffset.identity();\n    this._compassAligned = false;\n    this._composeFinalQuat();\n  }\n\n  /**\n   * Check if device is in an upright position suitable for calibration\n   * Device should be roughly vertical (held naturally in portrait mode)\n   */\n  isUprightForCalibration() {\n    if (!this.orient.ready) return false;\n    // beta should be close to 90 deg (phone upright), roll (gamma) near 0\n    const beta = this.orient.b;\n    const gamma = this.orient.g;\n    const isUpright = Math.abs(beta - 90) < 25; // within 25 deg of vertical\n    const isNotRolled = Math.abs(gamma) < 20; // not tilted sideways\n    return isUpright && isNotRolled;\n  }\n\n  /**\n   * Perform automatic compass calibration when device is upright\n   * Returns true if calibration was performed\n   *\n   * Reference implementation pattern (phone-twins):\n   *   var deltaDeg = ((targetH - currentH + 540) % 360) - 180;\n   *   var qDelta = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,1,0), -deltaRad);\n   *   my.qOffset.premultiply(qDelta);\n   */\n  calibrateToCompass() {\n    if (!Number.isFinite(this.headingRad)) return false;\n    if (!this.orient?.ready) return false;\n\n    // Get current heading from displayed quaternion (in degrees, 0-360)\n    this._composeFinalQuat();\n    const currentHeadingDeg = this._headingFromQuatDeg(this.cameraQuat);\n    if (currentHeadingDeg == null) return false;\n\n    // Target is compass heading (degrees)\n    const targetHeadingDeg = this.headingDeg;\n\n    // Calculate delta using reference pattern: ((target - current + 540) % 360) - 180\n    // This properly wraps to -180..180\n    const deltaDeg = ((targetHeadingDeg - currentHeadingDeg + 540) % 360) - 180;\n    const deltaRad = deltaDeg * Math.PI / 180;\n\n    // Apply as yaw rotation offset - NEGATIVE like reference!\n    const qDelta = this._qTmp.setFromAxisAngle(this._yAxis, -deltaRad);\n    this.qOffset.premultiply(qDelta);\n\n    this._composeFinalQuat();\n    this._compassAligned = true;\n    this._emit('calibration-ready', { heading: this.headingDeg });\n    return true;\n  }\n\n  /**\n   * Get heading from quaternion in degrees (0-360, 0 = North/-Z, clockwise positive)\n   * Uses forward axis to align with surface heading math\n   */\n  _headingFromQuatDeg(q) {\n    // Project the forward axis onto XZ plane to get heading\n    this._tmpV.set(0, 0, -1).applyQuaternion(q);\n    this._tmpV.y = 0;\n    const len = this._tmpV.length();\n    if (len < 1e-4) return null; // Device is nearly vertical\n    this._tmpV.multiplyScalar(1 / len);\n    // Reference: var deg = Math.atan2(top.x, -top.z) * 180 / Math.PI;\n    let deg = Math.atan2(this._tmpV.x, -this._tmpV.z) * 180 / Math.PI;\n    deg = (deg + 360) % 360;\n    return deg;\n  }\n\n  /**\n   * Get heading from quaternion (0 = North/-Z, clockwise positive)\n   * Returns radians or null if device is too vertical\n   */\n  _headingFromQuat(q) {\n    // Project the \"top\" of device onto XZ plane to get heading\n    this._tmpV.set(0, 1, 0).applyQuaternion(q);\n    this._tmpV.y = 0;\n    const len = this._tmpV.length();\n    if (len < 0.01) return null; // Device is nearly vertical\n    this._tmpV.multiplyScalar(1 / len);\n    // atan2(x, -z) gives heading where 0 = North(-Z), clockwise positive\n    let heading = Math.atan2(this._tmpV.x, -this._tmpV.z);\n    if (heading < 0) heading += 2 * Math.PI;\n    return heading;\n  }\n\n  /**\n   * Force re-alignment to current compass heading\n   */\n  forceCompassAlign() {\n    return this.calibrateToCompass();\n  }\n\n  // Getters for state\n\n  /** Euler path (radians). Prefer getCameraQuaternion() instead. */\n  getYawPitch() {\n    return { yaw: this.yaw, pitch: this.pitch, ready: (this.ready && this.enabled) };\n  }\n\n  /** Device quaternion (screen-compensated, without offsets). */\n  getQuaternion() {\n    return { q: this._orientationQuat.clone(), ready: (this.ready && this.enabled) };\n  }\n\n  /** Final camera quaternion (includes yaw & optional pitch offsets). */\n  getCameraQuaternion() {\n    return { q: this.cameraQuat.clone(), ready: (this.ready && this.enabled) };\n  }\n\n  /** Heading info. */\n  getHeading() {\n    return {\n      rad: this.headingRad,\n      deg: this.headingDeg,\n      source: this.headingSource,\n      confidence: this.headingConfidence\n    };\n  }\n\n  getAcceleration() {\n    return this.motion;\n  }\n\n  // ───────────────────── Internals ─────────────────────\n\n  _updateScreenOrientation() {\n    const ang = (screen.orientation && typeof screen.orientation.angle === 'number')\n      ? screen.orientation.angle\n      : (window.orientation || 0);\n    this._screenOri = THREE.MathUtils.degToRad(ang || 0);\n  }\n\n  _screenAngleDeg() {\n    if (screen.orientation && typeof screen.orientation.angle === 'number') {\n      return screen.orientation.angle || 0;\n    }\n    return (typeof window.orientation === 'number') ? (window.orientation || 0) : 0;\n  }\n\n  /** Yaw from world Y: 0 = North(-Z), +90 = East(+X), clockwise positive. */\n  _yawFromQuat(q) {\n    // Forward vector from quaternion: (0,0,-1) rotated by q\n    this._tmpV.set(0, 0, -1).applyQuaternion(q);\n    // atan2(x, -z) gives 0=North, positive=East (clockwise from above)\n    return Math.atan2(this._tmpV.x, -this._tmpV.z);\n  }\n\n  /**\n   * Extract yaw, pitch, and roll from quaternion.\n   * Uses same method as surface-camera-controller for consistency.\n   */\n  _extractYawPitchRoll(q) {\n    // Get forward and up vectors from quaternion\n    const deviceFwd = this._tmpV.set(0, 0, -1).applyQuaternion(q);\n    const deviceUp = this._up.set(0, 1, 0).applyQuaternion(q);\n\n    // Yaw: horizontal direction from forward vector\n    // atan2(x, -z) gives 0=North(-Z), positive=East(+X) (clockwise from above)\n    const yaw = Math.atan2(deviceFwd.x, -deviceFwd.z);\n\n    // Pitch: vertical tilt of forward vector\n    const horizLen = Math.sqrt(deviceFwd.x * deviceFwd.x + deviceFwd.z * deviceFwd.z);\n    const pitch = Math.atan2(deviceFwd.y, horizLen);\n\n    // Roll: how much deviceUp points in the \"camera right\" direction\n    // Camera right = cross(forward, worldUp)\n    const camRight = this._right.crossVectors(deviceFwd, this._yAxis);\n    const camRightLen = camRight.length();\n    let roll = 0;\n    if (camRightLen > 0.001) {\n      camRight.multiplyScalar(1 / camRightLen);\n      roll = Math.asin(THREE.MathUtils.clamp(deviceUp.dot(camRight), -1, 1));\n    }\n\n    return { yaw, pitch, roll };\n  }\n\n  _normalizeAngle(rad) {\n    const twoPi = Math.PI * 2;\n    let out = rad % twoPi;\n    if (out < 0) out += twoPi;\n    return out;\n  }\n\n  _wrapPi(rad) {\n    return Number.isFinite(rad) ? Math.atan2(Math.sin(rad), Math.cos(rad)) : 0;\n  }\n\n  _orientationHeading() {\n    const yaw = this._yawFromQuat(this._orientationQuat);\n    return Number.isFinite(yaw) ? this._normalizeAngle(yaw) : null;\n  }\n\n  _composeFinalQuat() {\n    // cameraQuat = qOffset * rawQuat (like reference implementation)\n    this.cameraQuat.copy(this.qOffset).multiply(this._orientationQuat);\n  }\n\n  // ───────────────────── Event handlers ─────────────────────\n\n  _onDO(e) {\n    const a = e.alpha, b = e.beta, g = e.gamma;\n    if (a == null && b == null && g == null) return;\n\n    // Legacy (deg)\n    this.orient.a = a || 0;\n    this.orient.b = b || 0;\n    this.orient.g = g || 0;\n    this.orient.ready = true;\n\n    // Convert to radians\n    const alpha = THREE.MathUtils.degToRad(this.orient.a);\n    const beta = THREE.MathUtils.degToRad(this.orient.b);\n    const gamma = THREE.MathUtils.degToRad(this.orient.g);\n\n    // Device quaternion: set(beta, alpha, -gamma, 'YXZ') -> -PI/2 X -> -screen orientation Z\n    this._orientationQuat\n      .setFromEuler(this._eulerIn.set(beta, alpha, -gamma, 'YXZ'))\n      .multiply(this._qTilt)\n      .multiply(this._q0.setFromAxisAngle(this._zee, -this._screenOri));\n\n    // Compose final camera quaternion: cameraQuat = qOffset * rawQuat\n    this._composeFinalQuat();\n\n    // Extract yaw/pitch/roll from the FINAL calibrated quaternion for display/legacy use\n    const { yaw, pitch, roll } = this._extractYawPitchRoll(this.cameraQuat);\n    this.yaw = yaw;\n    this.pitch = pitch;\n    this.roll = roll;\n\n    // Emit orientation update\n    this._emit('orientation-update', {\n      yaw: this.yaw,\n      pitch: this.pitch,\n      roll: this.roll,\n      quaternion: this.cameraQuat\n    });\n\n    // Platform heading (iOS)\n    if (typeof e.webkitCompassHeading === 'number' && Number.isFinite(e.webkitCompassHeading)) {\n      this._webHeadingDeg = (e.webkitCompassHeading % 360 + 360) % 360;\n      this._setHeading(THREE.MathUtils.degToRad(this._webHeadingDeg), 'webkit');\n      return;\n    }\n\n    // Alpha-based fallback heading\n    if (typeof e.alpha === 'number' && Number.isFinite(e.alpha)) {\n      let hdg = 360 - e.alpha;\n      hdg += this._screenAngleDeg();\n      this._setHeading(THREE.MathUtils.degToRad((hdg % 360 + 360) % 360), 'orientation');\n      return;\n    }\n\n    // Last resort: derive from orientation quaternion\n    const oHead = this._orientationHeading();\n    if (Number.isFinite(oHead)) {\n      this._setHeading(oHead, 'orientation');\n    } else if (!Number.isFinite(this.headingRad)) {\n      this.headingDeg = null;\n      this.headingRad = null;\n      this.headingSource = 'unknown';\n      this.headingConfidence = 0;\n    }\n  }\n\n  _onDM(e) {\n    const incl = e.accelerationIncludingGravity;\n    if (incl) {\n      this._gravityTemp.set(incl.x ?? 0, incl.y ?? 0, incl.z ?? 0);\n      if (!this._gravityReady) {\n        this._gravityVec.copy(this._gravityTemp);\n        this._gravityReady = true;\n      } else {\n        this._gravityVec.lerp(this._gravityTemp, 0.18);\n      }\n      this._updateTiltCompensatedHeading();\n    }\n\n    let ax = 0, ay = 0, az = 0;\n    if (e.acceleration) {\n      ax = e.acceleration.x ?? 0;\n      ay = e.acceleration.y ?? 0;\n      az = e.acceleration.z ?? 0;\n    } else if (incl) {\n      ax = (incl.x ?? 0) - this._gravityVec.x;\n      ay = (incl.y ?? 0) - this._gravityVec.y;\n      az = (incl.z ?? 0) - this._gravityVec.z;\n    }\n\n    this._accelRaw.set(ax, ay, az);\n    const worldVec = this._accelWorld.copy(this._accelRaw).applyQuaternion(this._orientationQuat);\n    this.motion.ax = worldVec.x;\n    this.motion.ay = worldVec.y;\n    this.motion.az = worldVec.z;\n    this.motion.ready = true;\n    this.motion.timestamp = (typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now();\n  }\n\n  // ───────────── Magnetometer / Heading ─────────────\n\n  _startMagnetometer() {\n    if (this._magStartAttempted) return;\n    this._magStartAttempted = true;\n    const SensorCtor = typeof window !== 'undefined' ? window.Magnetometer : null;\n    if (typeof SensorCtor !== 'function') return;\n\n    try {\n      const sensor = new SensorCtor({ frequency: 30 });\n      sensor.addEventListener('reading', () => {\n        if (!Number.isFinite(sensor.x) || !Number.isFinite(sensor.y) || !Number.isFinite(sensor.z)) return;\n        this._magTemp.set(sensor.x, sensor.y, sensor.z);\n        if (!this._magReady) this._magVec.copy(this._magTemp);\n        else this._magVec.lerp(this._magTemp, 0.25);\n        this._magReady = true;\n        this._updateTiltCompensatedHeading();\n      });\n      sensor.addEventListener('error', () => {\n        try { sensor.stop(); } catch {}\n        this._magSensor = null;\n        this._magReady = false;\n      });\n      sensor.start();\n      this._magSensor = sensor;\n    } catch {\n      this._magSensor = null;\n      this._magReady = false;\n    }\n  }\n\n  _updateTiltCompensatedHeading() {\n    if (!this._magReady) return false;\n\n    const magNorm = this._magVec.length();\n    if (magNorm < 1e-6) return false;\n\n    // Use orientation quaternion to rotate mag -> world, then read heading\n    if (this.orient?.ready) {\n      const world = this._magWorld.copy(this._magVec).applyQuaternion(this._orientationQuat);\n      const headingRaw = this._normalizeAngle(Math.atan2(-world.x, -world.z));\n      const oHead = this._orientationHeading();\n      let finalHeading = headingRaw;\n      if (Number.isFinite(oHead)) {\n        const diff = this._wrapPi(headingRaw - oHead);\n        if (Math.abs(diff) > Math.PI / 2) finalHeading = this._normalizeAngle(headingRaw + Math.PI);\n      }\n      return this._setHeading(finalHeading, 'magnetometer');\n    }\n\n    // Fallback: gravity-based tilt compensation\n    if (!this._gravityReady) return false;\n\n    const ax = -this._gravityVec.x, ay = -this._gravityVec.y, az = -this._gravityVec.z;\n    const aNorm = Math.hypot(ax, ay, az);\n    if (aNorm < 1e-6) return false;\n    const axn = ax / aNorm, ayn = ay / aNorm, azn = az / aNorm;\n\n    const mx = this._magVec.x / magNorm, my = this._magVec.y / magNorm, mz = this._magVec.z / magNorm;\n\n    const roll = Math.atan2(ayn, azn);\n    const horiz = Math.sqrt(ayn * ayn + azn * azn);\n    if (horiz < 1e-6) return false;\n    const pitch = Math.atan2(-axn, horiz);\n\n    const sr = Math.sin(roll), cr = Math.cos(roll);\n    const sp = Math.sin(pitch), cp = Math.cos(pitch);\n\n    const mxComp = mx * cp + mz * sp;\n    const myComp = mx * sr * sp + my * cr - mz * sr * cp;\n\n    let headingRad = Math.atan2(-myComp, mxComp);\n    if (!Number.isFinite(headingRad)) return false;\n\n    headingRad = this._normalizeAngle(headingRad);\n    return this._setHeading(headingRad, 'magnetometer');\n  }\n\n  _setHeading(headingRad, source = 'unknown') {\n    if (!Number.isFinite(headingRad)) return false;\n    let target = this._normalizeAngle(headingRad);\n    if (Number.isFinite(this.headingRad)) {\n      const delta = this._wrapPi(target - this.headingRad);\n      target = this._normalizeAngle(this.headingRad + delta * 0.22);\n    }\n    this.headingRad = target;\n    const deg = THREE.MathUtils.radToDeg(target);\n    this.headingDeg = (deg % 360 + 360) % 360;\n    this.headingSource = source || this.headingSource || 'unknown';\n    this.headingConfidence = source === 'magnetometer'\n      ? Math.min(1, this.headingConfidence * 0.6 + 0.45)\n      : Math.max(0.2, this.headingConfidence * 0.85);\n\n    this._emit('heading-update', {\n      deg: this.headingDeg,\n      rad: this.headingRad,\n      source: this.headingSource,\n      confidence: this.headingConfidence\n    });\n    return true;\n  }\n\n  _tryInitialCompassAlign() {\n    if (this._compassAligned) return;\n    if (!Number.isFinite(this.headingRad)) return;\n    if (!this.orient?.ready) return;\n\n    // Use the same calibration logic\n    this.calibrateToCompass();\n  }\n\n  // ───────────────────── Auto-enable helpers ─────────────────────\n\n  _setupAutoEnable() {\n    this.enable()\n      .then((res) => {\n        if (!res?.success && res?.reason === 'gesture') {\n          this._installGestureEnable();\n        }\n      })\n      .catch(() => { this._installGestureEnable(); });\n  }\n\n  _installGestureEnable() {\n    if (this._autoGestureAttached) return;\n    const handler = () => {\n      this._clearGestureEnableHandlers();\n      this.enable().catch(() => {});\n    };\n    this._autoGestureAttached = true;\n    this._autoGestureHandler = handler;\n    window.addEventListener('pointerdown', handler, { passive: true });\n    window.addEventListener('touchstart', handler, { passive: true });\n    window.addEventListener('keydown', handler, false);\n    window.addEventListener('click', handler, false);\n  }\n\n  _clearGestureEnableHandlers() {\n    if (!this._autoGestureAttached || !this._autoGestureHandler) return;\n    const h = this._autoGestureHandler;\n    window.removeEventListener('pointerdown', h);\n    window.removeEventListener('touchstart', h);\n    window.removeEventListener('keydown', h, false);\n    window.removeEventListener('click', h, false);\n    this._autoGestureAttached = false;\n    this._autoGestureHandler = null;\n  }\n\n  /**\n   * Dispose of event listeners\n   */\n  dispose() {\n    this._clearGestureEnableHandlers();\n    window.removeEventListener('deviceorientation', this._onDO, true);\n    window.removeEventListener('deviceorientationabsolute', this._onDO, true);\n    window.removeEventListener('devicemotion', this._onDM, true);\n    this._orientListening = false;\n    this._motionListening = false;\n    if (this._magSensor) {\n      try { this._magSensor.stop(); } catch {}\n      this._magSensor = null;\n    }\n    this.enabled = false;\n    this.ready = false;\n  }\n}\n\n// Singleton instance\nlet deviceSensorsInstance = null;\n\nexport function getDeviceSensors() {\n  if (!deviceSensorsInstance) {\n    deviceSensorsInstance = new DeviceSensors();\n  }\n  return deviceSensorsInstance;\n}\n\n/**\n * Initialize device sensors with auto-enable attempt\n * Call this early in app initialization for mobile devices\n */\nexport function initDeviceSensors() {\n  const sensors = getDeviceSensors();\n  if (DeviceSensors.isMobile() && DeviceSensors.hasOrientationSupport()) {\n    sensors._setupAutoEnable();\n  }\n  return sensors;\n}\n","/**\n * Surface camera controller for first-person ground mode\n */\n\nimport * as THREE from 'three';\nimport { curvedSurfaceGroundRadius, finestSurfaceContactHits } from './surface-ground-support.js';\nimport { SurfaceCapsuleCollider } from './surface-capsule-collider.js';\nimport { projectOrbitDragRay } from './orbit-drag-projection.js';\nimport { XRSurfaceRig } from '../refactor/vr/XRSurfaceRig.js';\nimport { publishPhotorealSamplingMatrices, invalidatePhotorealSamplingMatrices } from '../refactor/tiles/PhotorealSamplingMatrices.js';\nimport { PLANET_RADIUS, EARTH_ORBIT_MAX_DISTANCE_M, CAMERA_NEAR, DEG2RAD, RAD2DEG, WGS84_SEMI_MAJOR_AXIS, WGS84_SEMI_MINOR_AXIS, MOON_DISTANCE_M, MOON_RADIUS_M, SUN_EARTH_DISTANCE_M, SUN_RADIUS_M } from './constants.js';\nimport {\n    createSceneLocationIndicator,\n    updateSceneLocationIndicator,\n} from '../refactor/ui/SceneLocationIndicator.js';\n\n/**\n * Black Sun framework: returns true when the scene is currently in\n * metaverse mode. The metaverse uses a different coordinate system\n * (the canonical Snow Crash 10,430 km black sphere) and owns its own\n * camera placement; surface-controller per-frame writes must short-\n * circuit so they don't clobber the metaverse spawn position with\n * Earth-relative coordinates.\n */\nfunction _isMetaverseSceneMode() {\n    if (typeof globalThis === 'undefined') return false;\n    const scene = globalThis.window?.__noclipScene;\n    if (!scene || typeof scene.getSceneMode !== 'function') return false;\n    return scene.getSceneMode() === 'metaverse';\n}\nimport { dirToLatLonLocal, latLonToLocalDir, rayEllipsoidIntersection, raySphereIntersection } from './geometry-utils.js';\nimport { getDeviceSensors, DeviceSensors } from './device-sensors.js';\n\nconst WGS84_A2 = WGS84_SEMI_MAJOR_AXIS * WGS84_SEMI_MAJOR_AXIS;\nconst WGS84_B2 = WGS84_SEMI_MINOR_AXIS * WGS84_SEMI_MINOR_AXIS;\n// A photoreal contact sample is point-local. Reusing it across the old two\n// metre footprint visibly floated the camera above curbs, steps, and other\n// fine tile geometry. This tolerance absorbs only numerical/pose jitter;\n// actual horizontal movement must acquire the surface directly underneath.\nconst PHOTO_CONTACT_REUSE_RADIUS_M = 0.12;\n\n// Walking height stabilisation (see _stabilizeWalkingRadius).\nconst WALK_HEIGHT_MAX_SLOPE = 1.2;   // m of height per m walked\nconst WALK_HEIGHT_SETTLE_MPS = 0.4;  // extra settle speed while moving\nconst WALK_NO_CLIP_M = 0.8;          // eye may dip this far below target before the floor snaps\nconst WALK_LEDGE_DROP_M = 3;\nconst WALK_FALL_MPS = 9;\n\nexport class SurfaceController {\n    constructor(camera, renderer, controls, triTree) {\n        this.camera = camera;\n        this.renderer = renderer;\n        this.controls = controls;\n        this.triTree = triTree;\n\n        // Configuration constants\n        this.SURFACE_EYE_HEIGHT = 1.6;              // meters above surface\n        this.SURFACE_ALTITUDE_MIN = this.SURFACE_EYE_HEIGHT;\n        this.SURFACE_MIN_CLEARANCE = 1;            // absolute minimum meters above terrain\n        this.SURFACE_ALTITUDE_MAX = 100000;         // meters above surface\n        this.SURFACE_SCROLL_TRANSITION_START_ALT = 50000;  // exit surface at 50km (matches TRANSIT_SURFACE_ALT)\n        this.SURFACE_SCROLL_TRANSITION_END_ALT = 25000;    // finish soft scroll transition (meters)\n        this.SURFACE_ENTER_ALT = this.SURFACE_SCROLL_TRANSITION_END_ALT; // altitude threshold (meters)\n        this.SURFACE_SCROLL_SOFTEN_START_ALT = 1000;       // start extra slow-down near surface (meters)\n        this.SURFACE_AUTO_MSL_HOLD_MIN_ALT = this.SURFACE_SCROLL_SOFTEN_START_ALT; // above this, terrain hydration should not lift camera\n        this.SURFACE_SCROLL_FINE_CONTROL_MAX_ALT = 100;    // preserve coarse wheel response at and above 100m AGL\n        this.SURFACE_SCROLL_SOFTEN_MIN_SCALE = 0.02;       // minimum scroll scale at surface\n        this.SURFACE_SCROLL_SOFTEN_EXP = 2.8;              // exponential coefficient for near-surface fine control\n        this.SURFACE_SCROLL_HOLD_MS = 280;                 // hold scroll intent to avoid terrain snapback\n        this.SURFACE_SCROLL_RESPONSE_SEC = 0.10;            // smooth event bursts into continuous altitude motion\n        this.SURFACE_EXIT_TRANSITION_MS = 480;             // smooth surface ceiling -> orbit handoff\n        this.TRANSIT_ENTER_ALT = 100000;            // enter transit mode below this alt (meters)\n        this.TRANSIT_EXIT_ALT = 120000;             // leave transit back to orbit above this alt (meters)\n        this.TRANSIT_SURFACE_ALT = 50000;            // finalize into surface mode at 50km (was 100m — caused earth-spinning-under-you)\n        this.SURFACE_TRANSITION_MS = 0;              // transition duration (0 = instant)\n        this.DOUBLE_CLICK_SURFACE_TRANSITION_MS = 1000; // deliberate point entry gets a visible eased descent\n        this.SURFACE_TERRAIN_CLEARANCE = 0;         // extra height to avoid z-fighting\n        this.SURFACE_TERRAIN_SAMPLE_MS = 90;        // terrain sampling throttle\n        this.SURFACE_MOVE_SPEED = 1.4;              // meters per second (realistic walk speed)\n        this.SURFACE_MOVE_ACCEL = 18;              // m/s^2 acceleration toward target\n        this.SURFACE_MOVE_DECEL = 26;              // m/s^2 deceleration toward zero\n        this.SURFACE_MOVE_ATTACK_SECONDS = 0.16;   // target-relative response, stable at every altitude\n        this.SURFACE_MOVE_RELEASE_SECONDS = 0.075; // short release tail; no high-altitude runaway coast\n        this.SURFACE_MOVE_HOLD_MAX = 2;            // deliberate long holds travel faster than taps\n        this.SURFACE_MOVE_HOLD_RAMP_SECONDS = 1.4;\n        this.SURFACE_VERTICAL_SPEED = 10;           // meters per second (base)\n        this.SURFACE_VERTICAL_ACCEL = 28;          // m/s^2 acceleration for vertical motion\n        this.SURFACE_VERTICAL_DECEL = 36;          // m/s^2 deceleration for vertical motion\n        this.SURFACE_VERTICAL_BOOST_MAX = 100;      // max multiplier for Q/E dolly\n        this.SURFACE_VERTICAL_BOOST_ACCEL = 50;     // boost per second\n        this.SURFACE_VERTICAL_BOOST_DECAY = 650;    // release altitude thrust in roughly one-sixth second\n        this.SURFACE_VERTICAL_ATTACK_SECONDS = 0.13;\n        this.SURFACE_VERTICAL_RELEASE_SECONDS = 0.065;\n        this.SURFACE_SHIFT_BOOST_MAX = 4;           // max multiplier for Shift sprint (~5.6 m/s)\n        this.SURFACE_SHIFT_BOOST_ACCEL = 8;         // boost per second\n        this.SURFACE_SHIFT_BOOST_DECAY = 10;        // decay per second\n        this.SURFACE_WALK_ALT_SCALE_MAX = 64;       // max walk speed multiplier at max altitude\n        this.SURFACE_ZOOM_OUT_THRESHOLD = 3;        // scroll events to exit\n        this.SURFACE_FOV_MIN = 5;                  // min FOV when in surface pointer lock\n        this.SURFACE_FOV_MAX = 170;                 // max FOV when in surface pointer lock\n        this.SURFACE_FOV_SCROLL_SCALE = 0.02;       // FOV degrees per scroll delta unit\n        this.SURFACE_FOV_SCROLL_MIN = 0.5;          // min FOV delta per scroll event\n        this.SURFACE_FOV_SCROLL_MAX = 6;            // max FOV delta per scroll event\n        this.POINTER_LOCK_HOLD_MS = 3000;           // hold duration to enter pointer lock\n        this.POINTER_LOCK_RING_DELAY_MS = 1000;     // delay before ring appears\n        this.POINTER_LOCK_STILLNESS_PX = 1;         // movement tolerance before canceling hold\n        this.ORBIT_ROTATE_SPEED_SCALE = 1.0;        // scaling for orbit drag responsiveness\n        this.ORBIT_ROTATE_SPEED_MIN = 0.08;         // lower clamp for near-surface orbiting\n        this.ORBIT_ROTATE_SPEED_MAX = 1.6;          // upper clamp for far orbiting\n        this.ORBIT_DRAG_DOT_THRESHOLD = 0.999999999; // allow smooth drag at high altitude\n        this.ORBIT_ZOOM_WHEEL_SCALE = 0.001;        // exponential zoom factor per wheel delta unit\n        this.ORBIT_ZOOM_RESPONSE_SEC = 0.12;        // frame-rate-independent wheel target response\n        this.ALTITUDE_WHEEL_DIRECTION_HOLD_MS = 90; // reject tiny opposite-sign trackpad tail events\n        this.ALTITUDE_WHEEL_REVERSAL_THRESHOLD = 12;\n        this.ORBIT_SCROLL_DAMP_START_ALT = 200000;  // start damping scroll at 200km\n        this.ORBIT_SCROLL_DAMP_MIN = 0.05;          // minimum wheel influence near surface\n        this.ORBIT_VIEW_PIVOT_SENS = 0.0022;        // radians per px for orbit right-drag look offset\n        this.ORBIT_VIEW_PIVOT_MAX_ANGLE = THREE.MathUtils.degToRad(90);\n        this.ORBIT_VIEW_PIVOT_SOFT_START = 0.82;    // fraction of max angle where edge damping starts\n        this.ORBIT_VIEW_PIVOT_RESPONSE_SEC = 0.10;  // target follow smoothing while dragging\n        this.ORBIT_VIEW_PIVOT_INERTIA_SEC = 0.70;   // release velocity damping\n        this.ORBIT_VIEW_PIVOT_RECENTER_ANGLE = THREE.MathUtils.degToRad(5);\n        this.ORBIT_VIEW_PIVOT_RETURN_SEC = 1.6;\n        this.SURFACE_HUG_MAX_ALT = 5;              // meters: bias to hug surface below this\n        this.SURFACE_HUG_ENTER_ALT = 2;            // meters: start hugging below this\n        this.SURFACE_HUG_EXIT_ALT = 8;             // meters: stop hugging above this\n        this.SURFACE_HUG_ALT_LERP_RATE = 6;         // per-second rate toward eye height\n        this.SURFACE_HUG_TERRAIN_UP_SEC = 0.08;     // seconds to catch rising terrain\n        this.SURFACE_HUG_TERRAIN_DOWN_SEC = 0.35;   // seconds to ease down slopes\n        this.SURFACE_HUG_MAX_LAG = 0.25;            // meters allowed below raw terrain\n        this.SURFACE_GRAVITY_CAPTURE_ALT = 8;       // near-ground free motion falls back to contact\n        this.SURFACE_FLIGHT_AGL_SAMPLE_MS = 250;    // read-only regional AGL telemetry while ASL owns flight\n        this.SURFACE_FLIGHT_AGL_SAMPLE_RADIUS_MIN = 40;\n        this.SURFACE_FLIGHT_AGL_SAMPLE_RADIUS_MAX = 180;\n        this.SURFACE_TERMINAL_VELOCITY = 55;        // m/s downward cap for surface gravity\n        this.SURFACE_TERRAIN_ALT_MAX_DELTA = 40;    // meters per second clamp on altitude changes from terrain shifts\n        this.SURFACE_TERRAIN_MAX_OFFSET = 200000;   // meters max terrain offset from ellipsoid for safety\n        this.SWIM_MAX_DEPTH = 80;                   // meters below mean sea level, ocean polygons only\n        this.SURFACE_BODY_RADIUS = 0.34;            // capsule radius used for photoreal wall contact\n        this.SURFACE_COLLISION_SKIN = 0.08;         // stop slightly before a tile wall\n        this.SURFACE_COLLISION_CACHE_MS = 180;      // bound tile-hierarchy scans during movement\n        this.SURFACE_MAX_WALKABLE_STEP = 0.55;      // never promote a building roof into the walking floor\n        this.SURFACE_MAX_WALKABLE_SLOPE_DOT = 0.58; // abs(radial normal dot) below this is a wall\n\n        // Set minimum distance for orbit controls\n        controls.minDistance = PLANET_RADIUS + this.SURFACE_EYE_HEIGHT;\n\n        // Camera mode state\n        this.cameraMode = 'orbit'; // 'orbit' | 'transit' | 'toSurface' | 'surface' | 'toOrbit'\n        this.lodMode = 'orbit';\n\n        // Surface state\n        this.surfaceState = {\n            up: new THREE.Vector3(0, 1, 0),\n            yaw: 0,\n            pitch: 0,\n            roll: 0,  // Roll angle in radians (tilt left/right)\n            dragging: false,\n            lastX: 0,\n            lastY: 0,\n            sens: 0.0022,\n        };\n        this._rollQuat = new THREE.Quaternion();  // Reusable quaternion for roll\n\n        // Transition animation state\n        this.camTransition = null;\n        this._transitState = {\n            startQuat: new THREE.Quaternion(),\n            horizonQuat: new THREE.Quaternion(),\n            active: false\n        };\n\n        // Terrain sampling\n        this.surfaceRaycaster = new THREE.Raycaster();\n        this._lastTerrainSample = 0;\n        this._terrainRadius = PLANET_RADIUS;\n        this._terrainRadiusRaw = PLANET_RADIUS;\n        this._terrainSampleReliable = true;\n        /** @type {THREE.Object3D|null} Optional photorealistic tile group for terrain raycasting */\n        this.photoTileGroup = null;\n        this.mapSourceTerrainGroup = null;\n        /** Last valid radius from photorealistic tile raycasts (held during tile gaps) */\n        this._photoTerrainRadius = null;\n        /**\n         * Hard safety floor for photoreal mode — the persisted GROUND\n         * radius (planet center to ground surface). When the photoreal\n         * sampler returns a hit, this holds that verified ground while\n         * geometry is temporarily absent. When\n         * the sampler returns null (tile outage, transient between\n         * LODs, sparse coverage), this serves as the held floor so the\n         * camera cannot dip below previously-verified ground.\n         *\n         * NOTE: this is the GROUND radius, NOT the camera radius. The\n         * camera floor is `_lastSafeGroundR + currentClearance`, where\n         * currentClearance follows the user's commanded agl. This lets\n         * the user scroll up and down freely (any agl ≥ 0) while still\n         * enforcing \"never below tiles\".\n         *\n         * Invalidated to null when the user travels horizontally by about\n         * two metres so a new ground reading seeds at the new location.\n         * At a fixed footprint ordinary sampling cannot lower the floor\n         * through a transient gap. A fresh model-sequence underfoot adoption\n         * may replace it in either direction because the newly renderable\n         * center surface is authoritative.\n         */\n        this._lastSafeGroundR = null;\n        this._lastSafeUpDir = null;\n        this._photoGroundEmaR = null;\n        this._photoGroundEmaAt = 0;\n        this._photoGroundFrameIdx = null;\n        this._photoGroundLastRawR = null;\n        this._photoLastKnownReferenceR = null;\n        // Pedestrian terrain and the outermost rendered center skin are two\n        // different contracts. The former may follow a lower, spatially\n        // supported street/ground plane; the latter is an unconditional\n        // collision guard and must never be erased by that inference.\n        this._photoWalkableReferenceR = null;\n        this._photoCenterSkinR = null;\n        this._photoCenterSkinLocalDir = null;\n        this._photoCenterSkinModelSeq = null;\n        this._lastGroundSampleCenterSkinR = null;\n        this._groundTruthCacheR = null;\n        this._groundTruthCacheWalkable = false;\n        this._groundTruthCacheAt = 0;\n        this._groundTruthCacheLocalDir = null;\n        // Model-change seq of the photo tile group at the last accepted\n        // ground raycast; a mismatch means tiles streamed in since then.\n        this._groundTruthSampleModelSeq = null;\n        // Boot's exact centre ray is a hard safety skin, not proof that the\n        // skin is pedestrian ground. It may be a roof or tree canopy. Keep it\n        // until a bounded exterior-ring fit establishes a supported local\n        // ground plane, then replace the locomotion floor in one step.\n        this._photoWalkableSeedPending = false;\n        this._lastGroundSampleEstablishedWalkablePlane = false;\n        this.surfaceAltitudeMeters = this.SURFACE_EYE_HEIGHT;\n        this.surfaceAltitudeMSL = null;\n        // Default surface behavior uses altitude-above-terrain; MSL is explicit-only.\n        this._surfaceAltitudeReference = 'terrain';\n        // Once free flight clears the near-ground gravity band, radial altitude\n        // (ASL/MSL) becomes the placement authority. A bounded generalized\n        // terrain sample feeds calculated AGL only; photoreal floors, roofs,\n        // trees, facades, and LOD swaps cannot steer the airborne camera.\n        this._airborneMSLGlideActive = false;\n        this._airborneMSLGlideMsl = null;\n        this._photoFlightGroundR = null;\n        this._photoFlightGroundAt = 0;\n        this._photoFlightGroundLocalDir = null;\n        this._photoFlightGroundModelSeq = null;\n        this._photoFlightGroundCameraR = null;\n        this._cameraFloorClampAt = 0;\n        this._cameraFloorClampRadius = null;\n        this.surfaceVerticalBoost = 1;\n        this.surfaceShiftBoost = 1;\n        this._hugActive = false;\n        this._oceanResolver = null;\n        this._oceanState = {\n            isOcean: false,\n            swimming: false,\n            underwater: false,\n            depthMeters: 0\n        };\n        this._photoCollisionCandidates = [];\n        this._photoCollisionCandidatesAt = 0;\n        this._photoCollisionCandidatesOrigin = new THREE.Vector3();\n        this._photoCollisionCandidatesDirection = new THREE.Vector3();\n        this._photoCollisionCandidatesFar = 0;\n        this.pointerLockState = {\n            active: false,\n            holding: false,\n            holdStart: 0,\n            holdPointerId: null,\n            holdX: 0,\n            holdY: 0,\n            raf: null,\n            ring: document.getElementById('pointer-lock-ring')\n        };\n\n        // Keyboard state\n        this.keyState = {\n            w: false, a: false, s: false, d: false,\n            shift: false,\n            q: false, e: false,\n            r: false, f: false, z: false, x: false,\n            space: false, ctrl: false,\n            arrowup: false, arrowdown: false, arrowleft: false, arrowright: false\n        };\n        this.mobileMoveInput = { x: 0, y: 0 };\n\n        // Jump physics state\n        this.JUMP_VELOCITY = 5.0;           // m/s initial upward velocity\n        this.GRAVITY = 9.8;                 // m/s²\n        this._jumpVelocity = 0;\n        this._isJumping = false;\n        this._jumpRequested = false;\n\n        // Crouch state\n        this._isCrouching = false;\n        this.CROUCH_EYE_HEIGHT = 0.9;       // meters when crouching\n        this.STAND_EYE_HEIGHT = 1.6;        // meters when standing\n\n        // Velocity tracking for animation\n        this._prevCamPos = null;\n        this._velocity = new THREE.Vector3();\n        this._speed = 0;\n        this._moveSpeed = 0;\n        this._moveDir = new THREE.Vector3(0, 0, 0);\n        this._verticalSpeed = 0;\n        this._verticalDir = 0;\n        this._moveInputHoldSeconds = 0;\n\n        // Scroll accumulator for exit detection\n        this.surfaceZoomOutAccumulator = 0;\n        this._surfaceScrollHoldUntil = 0;\n        this._surfaceScrollHoldDir = 0;\n        this._surfaceScrollAltitudeTarget = null;\n        this._surfaceScrollExitRequested = false;\n        this._altitudeWheelGestureDir = 0;\n        this._altitudeWheelGestureUntil = 0;\n        this._altitudeWheelReverseDelta = 0;\n        this._surfaceAutoMSLHold = null;\n        this._surfaceAutoMSLHoldActive = false;\n\n        // Orbit drag / zoom state\n        this.orbitState = {\n            dragging: false,\n            pointerId: null,\n            anchorDir: new THREE.Vector3(),\n            lastDir: new THREE.Vector3(),\n            pointers: new Map(),\n            pinchDistance: null\n        };\n        this.orbitZoomTarget = null;\n        this._orbitZoomLastUpdateAt = 0;\n        this._orbitRaycaster = new THREE.Raycaster();\n        this._orbitNdc = new THREE.Vector2();\n        this._orbitQuat = new THREE.Quaternion();\n        this.orbitViewPivot = {\n            dragging: false,\n            pointerId: null,\n            lastX: 0,\n            lastY: 0,\n            yaw: 0,\n            pitch: 0,\n            targetYaw: 0,\n            targetPitch: 0,\n            roll: 0,\n            targetRoll: 0,\n            velocityYaw: 0,\n            velocityPitch: 0,\n            lastInteractionAt: 0,\n            lastUpdateAt: 0,\n        };\n\n        // Navigation profile (classic | geospatial)\n        this.navProfile = 'classic';\n        this.NAV_RUN_SPEED = 1;\n        this.NAV_DRAG_SPEED = 1;\n        this.NAV_ROTATE_SPEED = 1;\n        this.NAV_ZOOM_SPEED = 1;\n\n        this.geoNav = {\n            active: false,\n            action: null,\n            pointerId: null,\n            pivotPoint: new THREE.Vector3(),\n            pivotNormal: new THREE.Vector3(),\n            dragReady: false,\n            dragStartX: 0,\n            dragStartY: 0,\n            dragPivotRadius: 0,\n            dragStepQuaternion: new THREE.Quaternion(),\n            dragTargetQuaternion: new THREE.Quaternion(),\n            dragHitSource: null,\n            lastX: 0,\n            lastY: 0,\n            touchPointers: new Map(),\n            pinchDistance: null,\n            orbitTouch: null,\n            pinchFovActive: false\n        };\n        this._surfaceDragMSLLock = false;\n        this._surfaceDragLockedMSL = null;\n        this._surfaceDragAGLLock = false;\n        this._surfaceDragLockedAltitude = null;\n        this._surfaceDragReferenceBeforeLock = null;\n        this._geoRaycaster = new THREE.Raycaster();\n        this._geoNdc = new THREE.Vector2();\n        this._geoQuat = new THREE.Quaternion();\n        this._geoHit = new THREE.Vector3();\n        this._lastGeoHitSource = null;\n        this._surfaceGrabRing = null;\n\n        // Cached vectors (avoid allocations)\n        this._origin = new THREE.Vector3(0, 0, 0);\n        this._wNorth = new THREE.Vector3(0, 1, 0);\n        this._wEastRef = new THREE.Vector3(1, 0, 0);\n        this._vA = new THREE.Vector3();\n        this._vB = new THREE.Vector3();\n        this._vC = new THREE.Vector3();\n        this._vD = new THREE.Vector3();\n        this._look = new THREE.Vector3();\n        this._target = new THREE.Vector3();\n        this._tmpObj = new THREE.Object3D();\n        this._rayOrigin = new THREE.Vector3();\n        this._rayDir = new THREE.Vector3();\n        this._prevMode = 'orbit';\n        this._orbitReturnPose = null; // diagnostic entry pose only; never restore it on upward exit\n        this._suppressTransit = false;\n        this._earthAxis = new THREE.Vector3(0, 1, 0);\n        this._earthAxisQuat = new THREE.Quaternion();\n        this._ellipsoidDir = new THREE.Vector3();\n        this._ellipsoidQuat = new THREE.Quaternion();\n\n        // Event handlers (bound methods)\n        this._onPointerDown = this._onPointerDown.bind(this);\n        this._onPointerMove = this._onPointerMove.bind(this);\n        this._onPointerUp = this._onPointerUp.bind(this);\n        this._onPointerCancel = this._onPointerCancel.bind(this);\n        this._onWheel = this._onWheel.bind(this);\n        this._onMouseMove = this._onMouseMove.bind(this);\n        this._onPointerLockChange = this._onPointerLockChange.bind(this);\n        this._onPointerLockError = this._onPointerLockError.bind(this);\n        this._updatePointerLockHold = this._updatePointerLockHold.bind(this);\n        this._onKeyDown = this._onKeyDown.bind(this);\n        this._onKeyUp = this._onKeyUp.bind(this);\n        this._onKeyboardLookBlur = () => this.resetKeyboardLook();\n        this._onKeyboardLookFocus = event => { if (this.isEditableTarget(event.target)) this.resetKeyboardLook(); };\n        this._onKeyboardLookVisibility = () => { if (document.hidden) this.resetKeyboardLook(); };\n        this._onContextMenu = this._onContextMenu.bind(this);\n\n        // Attach event listeners\n        this.attachEventListeners();\n\n        // UI update callbacks (optional, set externally)\n        this.onCameraModeChange = null;\n        this.onModeTransitionComplete = null;\n\n        // Device orientation / mobile sensor integration\n        this._deviceSensorsEnabled = false;\n        this._useDeviceOrientation = false;\n        this._deviceSensors = null;\n        this._deviceTangentQuat = new THREE.Quaternion();\n        this._deviceBaseWorldQuat = new THREE.Quaternion();\n        this._deviceWorldQuat = new THREE.Quaternion();\n        this._deviceYawOffsetQuat = new THREE.Quaternion();\n        this._devicePitchOffsetQuat = new THREE.Quaternion();\n        this._deviceOffsetRight = new THREE.Vector3();\n        this._tangentMatrix = new THREE.Matrix4();\n        this._gpsPositionLockActive = false;\n        this._deviceLookOffsetYaw = 0;\n        this._deviceLookOffsetPitch = 0;\n        this._deviceLookRecenterAt = 0;\n        this._deviceLookRecenterFromYaw = 0;\n        this._deviceLookRecenterFromPitch = 0;\n        this.DEVICE_LOOK_RECENTER_DELAY_MS = 2400;\n        this.DEVICE_LOOK_RECENTER_DURATION_MS = 700;\n\n        // VR/XR mode support\n        this._vrDolly = null;  // Reference to VR dolly (set externally via setVRDolly)\n        this._vrModeActive = false;\n        this._vrMoveSpeed = 5; // meters per second in VR\n        this._vrRunMultiplier = 3;\n        this._tmpVRPos = new THREE.Vector3();\n        this._tmpVRQuat = new THREE.Quaternion();\n\n        // Celestial body anchor — which body the orbit camera orbits around\n        // 'terra' = Earth (default, target 0,0,0), 'luna' = Moon, 'sol' = Sun\n        this._bodyAnchor = 'terra';\n        this._bodyTransition = null; // active body tween state\n        this._bodyPositionGetter = null; // fn(bodyName) => THREE.Vector3 | null\n        this.onBodyAnchorChange = null; // callback(bodyName)\n        this.BODY_TRANSITION_MS = 2000; // 2 second smooth tween\n\n        // Initialize device sensors on mobile\n        if (DeviceSensors.isMobile() && DeviceSensors.hasOrientationSupport()) {\n            this._initDeviceSensors();\n        }\n\n        // Sync initial LOD mode to triTree\n        this.setLODMode(this.lodMode);\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Device Sensor Integration\n    // ──────────────────────────────────────────────────────────────\n\n    _initDeviceSensors() {\n        this._deviceSensors = getDeviceSensors();\n\n        // Listen for sensor enable\n        this._deviceSensors.on('enabled', () => {\n            this._deviceSensorsEnabled = true;\n            // Auto-enable device orientation in surface mode\n            if (this.cameraMode === 'surface') {\n                this.enableDeviceOrientation();\n            }\n        });\n\n        // Listen for calibration\n        this._deviceSensors.on('calibration-ready', () => {\n            if (this.cameraMode === 'surface') {\n                this._updateFromDeviceSensors();\n            }\n        });\n    }\n\n    /**\n     * Enable device orientation control (for mobile - works in both surface and orbit modes)\n     */\n    enableDeviceOrientation() {\n        if (!this._deviceSensors || !this._deviceSensors.enabled) {\n            return false;\n        }\n        this._useDeviceOrientation = true;\n\n        if (this.cameraMode === 'surface') {\n            this._updateFromDeviceSensors();\n        }\n\n        console.log('[SurfaceController] Device orientation enabled for mode:', this.cameraMode);\n        return true;\n    }\n\n    /**\n     * Disable device orientation control\n     */\n    disableDeviceOrientation() {\n        this._useDeviceOrientation = false;\n        console.log('[SurfaceController] Device orientation disabled');\n    }\n\n    /**\n     * Refresh device orientation after a calibration update\n     */\n    recalibrateDeviceOrientation() {\n        if (!this._deviceSensors || !this._deviceSensors.enabled) return false;\n\n        if (this.cameraMode === 'surface') {\n            this._updateFromDeviceSensors();\n        }\n\n        console.log('[SurfaceController] Device orientation recalibrated');\n        return true;\n    }\n\n    /**\n     * Check if device orientation is available and can be used\n     */\n    canUseDeviceOrientation() {\n        return this._deviceSensors && this._deviceSensors.enabled && this._deviceSensors.ready;\n    }\n\n    /**\n     * Mark device GPS as the current position owner. While this lock is\n     * active, a one-finger surface gesture adjusts the view relative to the\n     * device orientation instead of moving the GPS-owned camera position.\n     */\n    setGPSPositionLock(active) {\n        this._gpsPositionLockActive = active === true;\n        if (!this._gpsPositionLockActive) {\n            this._resetDeviceLookOffset();\n        }\n    }\n\n    isGPSPositionLocked() {\n        return this._gpsPositionLockActive === true;\n    }\n\n    _resetDeviceLookOffset() {\n        this._deviceLookOffsetYaw = 0;\n        this._deviceLookOffsetPitch = 0;\n        this._deviceLookRecenterAt = 0;\n        this._deviceLookRecenterFromYaw = 0;\n        this._deviceLookRecenterFromPitch = 0;\n    }\n\n    _beginDeviceLookGesture() {\n        this._deviceLookRecenterAt = 0;\n    }\n\n    _scheduleDeviceLookRecenter(now = performance.now()) {\n        if (!this._useDeviceOrientation) return;\n        const delay = Number.isFinite(this.DEVICE_LOOK_RECENTER_DELAY_MS)\n            ? this.DEVICE_LOOK_RECENTER_DELAY_MS\n            : 2400;\n        this._deviceLookRecenterAt = now + delay;\n        this._deviceLookRecenterFromYaw = this._deviceLookOffsetYaw || 0;\n        this._deviceLookRecenterFromPitch = this._deviceLookOffsetPitch || 0;\n    }\n\n    _updateDeviceLookRecentering(now = performance.now()) {\n        const startsAt = this._deviceLookRecenterAt || 0;\n        if (!startsAt || now < startsAt) return;\n        const duration = Math.max(\n            1,\n            Number.isFinite(this.DEVICE_LOOK_RECENTER_DURATION_MS)\n                ? this.DEVICE_LOOK_RECENTER_DURATION_MS\n                : 700\n        );\n        const t = THREE.MathUtils.clamp((now - startsAt) / duration, 0, 1);\n        const smooth = t * t * (3 - (2 * t));\n        const remaining = 1 - smooth;\n        this._deviceLookOffsetYaw = (this._deviceLookRecenterFromYaw || 0) * remaining;\n        this._deviceLookOffsetPitch = (this._deviceLookRecenterFromPitch || 0) * remaining;\n        if (t >= 1) {\n            this._resetDeviceLookOffset();\n        }\n    }\n\n    /**\n     * Update camera orientation from device sensors (call in update loop)\n     * Applies device quaternion in the local tangent frame; calibration lives in DeviceSensors.qOffset\n     */\n    _updateFromDeviceSensors() {\n        if (this._xrSurfaceRig) return false; // Native tracking exclusively owns head pose.\n        if (!this._useDeviceOrientation || !this._deviceSensors) return false;\n        if (!this._deviceSensors.enabled || !this._deviceSensors.orient.ready) return false;\n\n        if (this.cameraMode === 'surface') {\n            const deviceQuat = this._deviceSensors.cameraQuat;\n\n            const up = this.surfaceState.up;\n            const east = this._vA;\n            const north = this._vB;\n            this.computeTangentBasis(up, east, north);\n\n            this._vC.copy(north).negate();\n            this._tangentMatrix.makeBasis(east, up, this._vC);\n            this._deviceTangentQuat.setFromRotationMatrix(this._tangentMatrix);\n\n            this._deviceBaseWorldQuat.copy(this._deviceTangentQuat).multiply(deviceQuat);\n            this._updateDeviceLookRecentering();\n            this._deviceWorldQuat.copy(this._deviceBaseWorldQuat);\n\n            const yawOffset = this._deviceLookOffsetYaw || 0;\n            const pitchOffset = this._deviceLookOffsetPitch || 0;\n            if (Math.abs(yawOffset) > 1e-6) {\n                this._deviceYawOffsetQuat.setFromAxisAngle(up, yawOffset);\n                this._deviceWorldQuat.premultiply(this._deviceYawOffsetQuat);\n            }\n            if (Math.abs(pitchOffset) > 1e-6) {\n                this._deviceOffsetRight\n                    .set(1, 0, 0)\n                    .applyQuaternion(this._deviceWorldQuat)\n                    .normalize();\n                this._devicePitchOffsetQuat.setFromAxisAngle(this._deviceOffsetRight, pitchOffset);\n                this._deviceWorldQuat.premultiply(this._devicePitchOffsetQuat);\n            }\n\n            const deviceFwd = this._vC.set(0, 0, -1).applyQuaternion(this._deviceWorldQuat);\n            const deviceUp = this._vD.set(0, 1, 0).applyQuaternion(this._deviceWorldQuat);\n\n            const upComp = THREE.MathUtils.clamp(deviceFwd.dot(up), -1, 1);\n            const pitch = Math.asin(upComp);\n\n            const fwdT = this._look.copy(deviceFwd).addScaledVector(up, -upComp);\n            if (fwdT.lengthSq() > 1e-8) {\n                fwdT.normalize();\n                this.surfaceState.yaw = Math.atan2(fwdT.dot(east), fwdT.dot(north));\n            }\n\n            const camRight = this._target.copy(deviceFwd).cross(up);\n            const camRightLen = camRight.length();\n            if (camRightLen > 0.001) {\n                camRight.multiplyScalar(1 / camRightLen);\n                this.surfaceState.roll = Math.asin(THREE.MathUtils.clamp(deviceUp.dot(camRight), -1, 1));\n            } else {\n                this.surfaceState.roll = 0;\n            }\n\n            this.surfaceState.pitch = THREE.MathUtils.clamp(pitch, -1.45, 1.45);\n        } else if (this.cameraMode === 'orbit') {\n            this._updateOrbitFromDeviceSensors();\n        }\n\n        return true;\n    }\n\n    /**\n     * Update orbit camera orientation from device sensors\n     * Device orientation controls the view direction while maintaining orbit distance\n     */\n    _updateOrbitFromDeviceSensors() {\n        if (!this._deviceSensors || !this._deviceSensors.enabled) return;\n\n        // Get the calibrated camera quaternion from device\n        const { q: deviceQuat, ready } = this._deviceSensors.getCameraQuaternion();\n        if (!ready) return;\n\n        // Get current camera distance from planet center\n        const distance = this.camera.position.length();\n\n        // Device quaternion gives us the look direction\n        const lookDir = this._vA.set(0, 0, -1).applyQuaternion(deviceQuat);\n\n        // Camera position is opposite of look direction at the current distance\n        const newPos = this._vB.copy(lookDir).negate().multiplyScalar(distance);\n\n        // Apply the new position\n        this.camera.position.copy(newPos);\n\n        // Apply device quaternion directly to camera\n        this.camera.quaternion.copy(deviceQuat);\n\n        // Update controls target if using orbit controls\n        if (this.controls) {\n            this.controls.target.set(0, 0, 0);\n            this.controls.update();\n        }\n    }\n\n    /**\n     * Toggle device orientation control on/off\n     */\n    toggleDeviceOrientation() {\n        if (this._useDeviceOrientation) {\n            this.disableDeviceOrientation();\n            return false;\n        } else {\n            return this.enableDeviceOrientation();\n        }\n    }\n\n    /**\n     * Get device orientation status for UI\n     */\n    getDeviceOrientationStatus() {\n        return {\n            available: this._deviceSensors && DeviceSensors.hasOrientationSupport(),\n            enabled: this._deviceSensorsEnabled,\n            active: this._useDeviceOrientation,\n            calibrated: this._deviceSensors?.ready || false,\n            heading: this._deviceSensors?.headingDeg || null\n        };\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Core coordinate/basis functions\n    // ──────────────────────────────────────────────────────────────\n\n    computeTangentBasis(up, outEast, outNorth) {\n        this._wNorth.set(0, 1, 0);\n        this._wEastRef.set(1, 0, 0);\n        if (this.triTree?.group?.getWorldQuaternion) {\n            this.triTree.group.getWorldQuaternion(this._earthAxisQuat);\n            this._wNorth.applyQuaternion(this._earthAxisQuat);\n            this._wEastRef.applyQuaternion(this._earthAxisQuat);\n        }\n        this._wNorth.normalize();\n        this._wEastRef.normalize();\n\n        outEast.crossVectors(this._wNorth, up);\n        if (outEast.lengthSq() < 1e-8) {\n            outEast.crossVectors(this._wEastRef, up);\n        }\n        if (outEast.lengthSq() < 1e-8) {\n            outEast.set(1, 0, 0);\n        }\n        outEast.normalize();\n        outNorth.crossVectors(up, outEast).normalize();\n    }\n\n    _getEllipsoidRadiusForDir(dir) {\n        if (!dir) return PLANET_RADIUS;\n        const localDir = this._ellipsoidDir.copy(dir);\n        if (localDir.lengthSq() > 0) localDir.normalize();\n        const planetGroup = this.triTree?.group;\n        if (planetGroup?.getWorldQuaternion) {\n            planetGroup.getWorldQuaternion(this._ellipsoidQuat);\n            this._ellipsoidQuat.invert();\n            localDir.applyQuaternion(this._ellipsoidQuat);\n        }\n        const x = localDir.x || 0;\n        const y = localDir.y || 0;\n        const z = localDir.z || 0;\n        const xx = x * x + z * z;\n        const yy = y * y;\n        const denom = (xx / WGS84_A2) + (yy / WGS84_B2);\n        if (!Number.isFinite(denom) || denom <= 0) return PLANET_RADIUS;\n        return 1 / Math.sqrt(denom);\n    }\n\n    setSurfaceFromDir(upDir, preserveLook = true) {\n        this.surfaceState.up.copy(upDir).normalize();\n\n        const east = this._vA, north = this._vB;\n        this.computeTangentBasis(this.surfaceState.up, east, north);\n\n        if (preserveLook) this.camera.getWorldDirection(this._look);\n        else this._look.copy(north).negate();\n\n        const up = this.surfaceState.up;\n        const upComp = this._look.dot(up);\n\n        this.surfaceState.pitch = THREE.MathUtils.clamp(\n            Math.asin(THREE.MathUtils.clamp(upComp, -1, 1)),\n            -1.45, 1.45\n        );\n\n        // tangent component for yaw\n        this._look.addScaledVector(up, -upComp);\n        if (this._look.lengthSq() < 1e-8) this._look.copy(north);\n        this._look.normalize();\n\n        this.surfaceState.yaw = Math.atan2(this._look.dot(east), this._look.dot(north));\n    }\n\n    _alignYawToCameraHorizon() {\n        const up = this.surfaceState.up;\n        const east = this._vA, north = this._vB;\n        this.computeTangentBasis(up, east, north);\n        const camDir = this.camera.getWorldDirection ? this.camera.getWorldDirection(new THREE.Vector3()) : null;\n        let flatDir = null;\n        if (camDir) {\n            const dot = camDir.dot(up);\n            flatDir = camDir.clone().addScaledVector(up, -dot);\n        }\n        if (!flatDir || flatDir.lengthSq() < 1e-8) {\n            flatDir = north.clone().negate();\n        } else {\n            flatDir.normalize();\n        }\n        this.surfaceState.yaw = Math.atan2(flatDir.dot(east), flatDir.dot(north));\n    }\n\n    _reanchorUpPreserveOrientation(newUp) {\n        if (!newUp) return;\n        // Preserve current yaw/pitch, just update up and basis\n        this.surfaceState.up.copy(newUp).normalize();\n        const east = this._vA, north = this._vB;\n        this.computeTangentBasis(this.surfaceState.up, east, north);\n        // Clamp pitch to bounds just in case\n        this.surfaceState.pitch = THREE.MathUtils.clamp(this.surfaceState.pitch, -1.45, 1.45);\n    }\n\n    surfaceLookDir(out) {\n        const up = this.surfaceState.up;\n        const east = this._vA, north = this._vB;\n        this.computeTangentBasis(up, east, north);\n\n        // dirT = north*cos(yaw) + east*sin(yaw)\n        out.copy(north).multiplyScalar(Math.cos(this.surfaceState.yaw));\n        out.addScaledVector(east, Math.sin(this.surfaceState.yaw));\n        out.normalize();\n\n        // look = dirT*cos(pitch) + up*sin(pitch)\n        out.multiplyScalar(Math.cos(this.surfaceState.pitch));\n        out.addScaledVector(up, Math.sin(this.surfaceState.pitch));\n        return out.normalize();\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Terrain sampling\n    // ──────────────────────────────────────────────────────────────\n\n    // Existing overlay consumers read photoTileGroup as the active native\n    // triangle/contact root. Preserve that contract for the Mapsource stack;\n    // provider readiness explicitly selects the separately retained Cesium root.\n    get photoTileGroup() {\n        return this._providerOnlyTerrainProbe ? this._nativePhotoTileGroup\n            : (this.mapSourceTerrainGroup || this._nativePhotoTileGroup);\n    }\n    set photoTileGroup(group) { this._nativePhotoTileGroup = group; }\n    get terrainTileGroup() { return this.photoTileGroup; }\n\n    _publishPhotorealSamplingMatrices() {\n        const xr = this.renderer?.xr;\n        const frame = xr?.isPresenting === true ? xr.getFrame?.() : null;\n        return publishPhotorealSamplingMatrices(this.terrainTileGroup, frame);\n    }\n\n    _isPhotoTileMeshRenderable(obj, root = this.terrainTileGroup) {\n        if (!obj?.isMesh || !obj.geometry) return false;\n\n        // Raycaster does not reliably enforce ancestor visibility. During a\n        // 3D Tiles refinement both parent and child meshes can remain attached,\n        // so testing only obj.visible can select a retired low-detail surface\n        // several metres below the tile the user actually sees.\n        let cursor = obj;\n        while (cursor) {\n            const presentationOnlyRoot = cursor === root\n                && cursor.userData?.photoPresentationSuppressed === true;\n            if (cursor.visible === false && !presentationOnlyRoot) return false;\n            if (cursor === root) break;\n            cursor = cursor.parent;\n        }\n        if (cursor !== root) return false;\n\n        const material = obj.material;\n        if (!material) return true;\n        if (Array.isArray(material)) {\n            for (const entry of material) {\n                if (entry\n                    && entry.visible !== false\n                    && !(entry.transparent === true && Number.isFinite(entry.opacity) && entry.opacity <= 0.001)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n        return material.visible !== false\n            && !(material.transparent === true\n                && Number.isFinite(material.opacity)\n                && material.opacity <= 0.001);\n    }\n\n    /**\n     * Phase 4 spatial pre-filter helper for _samplePhotoTileRadius.\n     *\n     * Walks photoTileGroup once and collects leaf meshes whose world-space\n     * bounding sphere intersects the ray. Avoids the recursive raycast cost\n     * of three's Raycaster.intersectObject(group, true) by using a cheap\n     * O(n) ray-sphere test that culls non-intersecting tiles before any\n     * triangle-level math runs.\n     *\n     * @param {THREE.Vector3} rayOrigin\n     * @param {THREE.Vector3} rayDir   normalized direction\n     * @returns {THREE.Mesh[]}\n     */\n    _collectPhotoTileRayCandidates(rayOrigin, rayDir, farLimitOverride = null) {\n        const out = [];\n        // Resolved once: the getter chain ran twice per ancestor per mesh.\n        const root = this.terrainTileGroup;\n        if (!root) return out;\n        const farLimit = Number.isFinite(farLimitOverride)\n            ? farLimitOverride\n            : ((this.surfaceRaycaster?.far) || Infinity);\n\n        // Reusable temporaries.\n        if (!this._photoTileTmpCenter) this._photoTileTmpCenter = new THREE.Vector3();\n        if (!this._photoTileTmpClosest) this._photoTileTmpClosest = new THREE.Vector3();\n        const tmpCenter = this._photoTileTmpCenter;\n        const tmpClosest = this._photoTileTmpClosest;\n\n        // Tile selection changes far more often than a footprint probe is\n        // requested, and the model sequence is advanced whenever meshes are\n        // attached/removed. Cache the flat mesh list at that boundary so a\n        // batch of overlay probes never recursively walks the full 3D Tiles\n        // hierarchy once per ray. `_isPhotoTileMeshRenderable` still runs for\n        // every candidate, preserving live REPLACE/visibility semantics.\n        const modelSeq = root.userData?.photoModelChangeSeq | 0;\n        if (this._photoRayMeshRoot !== root\n            || this._photoRayMeshModelSeq !== modelSeq\n            || !Array.isArray(this._photoRayMeshes)) {\n            const meshes = [];\n            root.traverse((obj) => {\n                if (obj?.isMesh && obj.geometry) meshes.push(obj);\n            });\n            this._photoRayMeshRoot = root;\n            this._photoRayMeshModelSeq = modelSeq;\n            this._photoRayMeshes = meshes;\n        }\n\n        for (const obj of this._photoRayMeshes) {\n            // Cheap ray-sphere rejection first; the ancestor visibility walk\n            // runs only for the few tiles the ray can actually reach.\n            const bs = obj.geometry.boundingSphere;\n            if (!bs || !Number.isFinite(bs.radius) || bs.radius <= 0) continue;\n\n            // Project the bounding sphere center into world space.\n            tmpCenter.copy(bs.center).applyMatrix4(obj.matrixWorld);\n\n            // World-space radius is sphere.radius scaled by the matrix's\n            // largest scale axis. For these tiles scale is ~uniform so we\n            // approximate via getMaxScaleOnAxis.\n            const worldRadius = bs.radius * (obj.matrixWorld.getMaxScaleOnAxis ? obj.matrixWorld.getMaxScaleOnAxis() : 1);\n\n            // Closest point on the ray (clamped to forward direction).\n            tmpClosest.copy(tmpCenter).sub(rayOrigin);\n            const projectedT = tmpClosest.dot(rayDir);\n            // A large tile sphere can overlap a short collision segment even\n            // when its center lies beyond either endpoint. Reject against the\n            // sphere-expanded interval, then measure from the closest point on\n            // the finite segment. The former center-only bound made local\n            // dynamic contact miss broad ground tiles entirely.\n            if (projectedT < -worldRadius || projectedT > farLimit + worldRadius) continue;\n            const t = THREE.MathUtils.clamp(projectedT, 0, farLimit);\n            tmpClosest.copy(rayDir).multiplyScalar(t).add(rayOrigin);\n            const distSq = tmpClosest.distanceToSquared(tmpCenter);\n            const r = worldRadius + 50; // 50m skirt for tile bounds drift\n            if (distSq <= r * r && this._isPhotoTileMeshRenderable(obj, root)) out.push(obj);\n        }\n        return out;\n    }\n\n    _samplePhotoTileHit(upDir) {\n        if (!this.terrainTileGroup || !upDir) return null;\n\n        const startR = (PLANET_RADIUS * 3.0) + 1_000_000.0;\n        this._rayOrigin.copy(upDir).normalize().multiplyScalar(startR);\n        this._rayDir.copy(upDir).normalize().negate();\n\n        this.surfaceRaycaster.set(this._rayOrigin, this._rayDir);\n        this.surfaceRaycaster.near = 0;\n        this.surfaceRaycaster.far = startR + 10.0;\n\n        const candidates = this._collectPhotoTileRayCandidates(this._rayOrigin, this._rayDir);\n        const hits = candidates.length > 0\n            ? this.surfaceRaycaster.intersectObjects(candidates, false)\n            : [];\n        if (hits.length === 0) return null;\n\n        const ellipsoidR = this._getEllipsoidRadiusForDir(upDir);\n        const maxOffset = Number.isFinite(this.SURFACE_TERRAIN_MAX_OFFSET)\n            ? this.SURFACE_TERRAIN_MAX_OFFSET\n            : this.SURFACE_ALTITUDE_MAX;\n\n        // The first visible surface encountered from space is the physical\n        // surface. Retain the full hit as well as its radius so coverage-repair\n        // geometry can reuse the source tile's UV/texture without a second\n        // raycast or a framebuffer readback.\n        let best = null;\n        let highestR = null;\n        for (let i = 0; i < hits.length; i++) {\n            const hit = hits[i];\n            const p = hit?.point;\n            if (!p) continue;\n            const r = p.length();\n            if (!Number.isFinite(r)) continue;\n            if (Math.abs(r - ellipsoidR) > maxOffset) continue;\n            if (r < ellipsoidR - 600) continue;\n            if (highestR === null || r > highestR) {\n                highestR = r;\n                best = hit;\n            }\n        }\n        if (!best || highestR === null) return null;\n\n        const sourceMaterial = Array.isArray(best.object?.material)\n            ? best.object.material[best.face?.materialIndex || 0]\n            : best.object?.material;\n        let radialNormalDot = null;\n        if (best.face?.normal && best.object?.matrixWorld && best.point) {\n            this._photoTileTmpNormal ||= new THREE.Vector3();\n            this._photoTileTmpUp ||= new THREE.Vector3();\n            this._photoTileNormalMatrix ||= new THREE.Matrix3();\n            this._photoTileNormalMatrix.getNormalMatrix(best.object.matrixWorld);\n            this._photoTileTmpNormal\n                .copy(best.face.normal)\n                .applyNormalMatrix(this._photoTileNormalMatrix)\n                .normalize();\n            this._photoTileTmpUp.copy(best.point).normalize();\n            radialNormalDot = Math.abs(this._photoTileTmpNormal.dot(this._photoTileTmpUp));\n        }\n        return {\n            radius: highestR,\n            object: best.object || null,\n            uv: best.uv?.clone?.() || null,\n            material: sourceMaterial || null,\n            texture: sourceMaterial?.map || null,\n            // Exact CPU equivalent of abs(dot(nWorld, radialUp)) in the\n            // photoreal wireframe protrusion shader. Coverage repair consumes\n            // this existing ray result; it never adds a normal-buffer pass.\n            radialNormalDot,\n        };\n    }\n\n    /**\n     * Read-only photoreal surface sample for bounded overlay work. Unlike the\n     * camera sampler this never adopts the result as the underfoot floor.\n     */\n    samplePhotorealSurfaceForDir(upDir, opts = {}) {\n        if (!this.terrainTileGroup) return null;\n        if (opts.skipWorldMatrixUpdate !== true) {\n            this._publishPhotorealSamplingMatrices();\n        }\n        return this._samplePhotoTileHit(upDir);\n    }\n\n    /**\n     * Raycast against photorealistic tile meshes (if available) to get terrain radius.\n     * upDir is world-space (normalized camera position). Three.js Raycaster handles\n     * mesh world matrices internally, so we raycast in world space directly.\n     * Since planetGroup is pure rotation around origin, hit.point.length() == local radius.\n     */\n    _samplePhotoTileRadius(upDir, {\n        mutateCache = true,\n        allowCachedFallback = true,\n        preferCandidates: _preferCandidates = false\n    } = {}) {\n        if (!this.terrainTileGroup) return null;\n        const surface = this._samplePhotoTileHit(upDir);\n        if (!surface) {\n            return allowCachedFallback ? this._photoTerrainRadius : null;\n        }\n        const highestR = surface.radius;\n\n        // Rise immediately for contact safety; ease only downward so a parent\n        // retiring under a child cannot produce a down/up camera flap.\n        if (mutateCache) {\n            const prev = Number.isFinite(this._photoTerrainRadius) ? this._photoTerrainRadius : highestR;\n            if (highestR >= prev) {\n                this._photoTerrainRadius = highestR;\n            } else {\n                this._photoTerrainRadius = prev + (highestR - prev) * 0.2;\n            }\n            return this._photoTerrainRadius;\n        }\n        return highestR;\n    }\n\n    /**\n     * Refresh terrain transforms once before a bulk, read-only sampling pass.\n     * Callers then pass skipWorldMatrixUpdate:true to each individual sample.\n     */\n    prepareTerrainSamplingBatch() {\n        this._publishPhotorealSamplingMatrices();\n        this.triTree?.group?.updateWorldMatrix?.(true, true);\n    }\n\n    /**\n     * Probe the radial branch directly beneath the current camera and report\n     * whether real photoreal geometry is renderable there. This deliberately\n     * rejects the held ground cache: startup may only leave the boot surface\n     * after a fresh mesh hit at the current location.\n     */\n    getPhotorealUnderfootState(worldPosition = null, { providerOnly = false } = {}) {\n        const previous = this._providerOnlyTerrainProbe;\n        this._providerOnlyTerrainProbe = providerOnly;\n        try { return this._getTerrainUnderfootState(worldPosition); }\n        finally { this._providerOnlyTerrainProbe = previous; }\n    }\n\n    _getTerrainUnderfootState(worldPosition = null) {\n        worldPosition ||= this.getPhotorealContactWorldPosition(\n            this._photoContactProbeWorld || (this._photoContactProbeWorld = new THREE.Vector3())\n        );\n        if (!this.terrainTileGroup || !worldPosition || worldPosition.lengthSq?.() < 1e-8) {\n            return { ready: false, reason: 'photo-group-loading', radius: null };\n        }\n\n        this._publishPhotorealSamplingMatrices();\n        const direction = (\n            this._bootUnderfootDir || (this._bootUnderfootDir = new THREE.Vector3())\n        );\n        this._getPhotorealContactWorldDirection(worldPosition, direction);\n        const radius = this._samplePhotoTileRadius(direction, {\n            mutateCache: false,\n            allowCachedFallback: false,\n            preferCandidates: true\n        });\n        const ready = Number.isFinite(radius);\n        return {\n            ready,\n            reason: ready ? 'photoreal-underfoot' : 'underfoot-branch-loading',\n            radius: ready ? radius : null\n        };\n    }\n\n    _getPhotorealContactWorldDirection(worldPosition, target) {\n        // During a point-entry transition the visible camera is still moving\n        // along its orbital arc, while the focused tile branch is pinned to\n        // the clicked landing direction. Sampling the transient camera\n        // direction can accept an unrelated coarse parent and release focus\n        // before the destination has a physical surface.\n        const source = this.cameraMode === 'toSurface' && this.surfaceState?.up\n            ? this.surfaceState.up\n            : worldPosition;\n        target.copy(source);\n        if (target.lengthSq() > 0) target.normalize();\n        return target;\n    }\n\n    /**\n     * Adopt the first fresh center-tile contact produced by the focused boot\n     * traversal. This closes the asynchronous walking/landing handoff between\n     * tile selection and camera placement before the focus mask is released.\n     * Fixed-ASL flight acknowledges the handoff without adopting its radius.\n     * The commanded AGL is never rewritten, so a requested 1.16 m remains\n     * physically 1.16 m above the verified mesh instead of merely displaying\n     * that number while the camera sits below it.\n     */\n    adoptPhotorealUnderfootRadius(\n        radius,\n        worldPosition = this.camera?.position,\n        { walkableVerified = true, visibleSkinRadius = radius } = {}\n    ) {\n        if (!Number.isFinite(radius) || radius < 1e6 || !worldPosition) return false;\n\n        // A streamed photoreal LOD is never an airborne altitude command.\n        // Returning success still lets the loader release its temporary focus,\n        // but fixed-ASL flight must not inherit or write walking-floor caches.\n        if (this.cameraMode === 'surface' && !this._isSurfaceWalkingTopologyActive()) {\n            return true;\n        }\n\n        const now = performance.now();\n        // This method is called only after a fresh center ray has resolved\n        // against a newly prepared or newly visible underfoot tile. That\n        // model-sequence change is an authoritative replacement, not an\n        // intermittent sampler reading. A coarse parent can overestimate the\n        // surface by hundreds of metres; clamping with\n        // Math.max(previousFloor, radius) made every downward child correction\n        // impossible until pointer-drag invalidated the held floor.\n        const floorR = radius;\n        const collisionFloorR = Number.isFinite(visibleSkinRadius)\n            ? Math.max(floorR, visibleSkinRadius)\n            : floorR;\n\n        this._photoTerrainRadius = floorR;\n        this._groundTruthCacheR = floorR;\n        this._groundTruthCacheWalkable = walkableVerified === true;\n        this._groundTruthCacheAt = now;\n        this._groundTruthSampleModelSeq = this.terrainTileGroup?.userData?.photoModelChangeSeq | 0;\n        const worldUp = this._getPhotorealContactWorldDirection(\n            worldPosition,\n            this._photoContactWorldUp || (this._photoContactWorldUp = new THREE.Vector3())\n        );\n        const localPosition = this._toPlanetLocal(\n            worldUp,\n            this._vCacheLocal || (this._vCacheLocal = new THREE.Vector3())\n        );\n        this._groundTruthCacheLocalDir = this._groundTruthCacheLocalDir || new THREE.Vector3();\n        this._groundTruthCacheLocalDir.copy(localPosition);\n        if (this._groundTruthCacheLocalDir.lengthSq() > 0) {\n            this._groundTruthCacheLocalDir.normalize();\n        }\n\n        this._photoGroundEmaR = floorR;\n        this._photoGroundEmaAt = now;\n        this._photoGroundFrameIdx = null;\n        this._photoGroundLastRawR = floorR;\n        this._photoLastKnownReferenceR = floorR;\n        this._photoWalkableReferenceR = floorR;\n        this._lastSafeGroundR = floorR;\n        this._photoWalkableSeedPending = walkableVerified !== true;\n        this._lastGroundSampleEstablishedWalkablePlane = walkableVerified === true;\n\n        this._lastSafeUpDir = this._lastSafeUpDir || new THREE.Vector3();\n        this._toPlanetLocalDirection(worldUp, this._lastSafeUpDir).normalize();\n        this._recordPhotoCenterSkinRadius(\n            collisionFloorR,\n            worldUp,\n            this._groundTruthSampleModelSeq\n        );\n\n        const commandedAgl = Number.isFinite(this.surfaceAltitudeMeters)\n            ? this.surfaceAltitudeMeters\n            : this._getAltitudeClampMin(worldUp);\n        // The verified walkable plane owns radial placement. The outermost\n        // center skin is retained only for facade/obstacle semantics: promoting\n        // that skin to a floor is what teleported pedestrians onto roofs.\n        const targetR = floorR + commandedAgl + (this.SURFACE_TERRAIN_CLEARANCE || 0)\n            + this._getPhotoBodyClearance(floorR, worldUp, commandedAgl);\n        const ellipsoidR = this._getEllipsoidRadiusForDir(worldUp);\n        this.surfaceAltitudeMSL = targetR - ellipsoidR;\n\n        // If contact resolves during the one-second descent, retarget its end\n        // point before the next interpolation step. Every remaining lerp point\n        // is then at or above the physical surface.\n        if (this.cameraMode === 'toSurface' && this.camTransition?.endPos) {\n            this.camTransition.endPos.copy(worldUp).multiplyScalar(targetR);\n            if (this.camera?.position?.length?.() < targetR) {\n                this.camera.position.copy(worldUp).multiplyScalar(targetR);\n            }\n        } else if (this.cameraMode === 'surface') {\n            // Tile loading occurs after normal camera placement. Write the\n            // exact authoritative radius directly instead of routing through\n            // applySurfaceCamera(), which performs another raycast and can\n            // still see the retiring coarse parent during REPLACE handoff.\n            // The next ordinary frame reads the model-sequence cache seeded\n            // above and continues from this exact floor.\n            const anchor = this._getCameraAnchor?.() || this.camera;\n            if (anchor?.position) {\n                anchor.position.copy(worldUp).multiplyScalar(targetR);\n                anchor.updateMatrixWorld?.(true);\n                if (anchor !== this.camera) this.camera?.updateMatrixWorld?.(true);\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Reconcile a post-boot photoreal LOD change with locomotion semantics.\n     * Boot contact can adopt the first visible center skin because no prior\n     * floor exists. Once walking, a model change must pass through the\n     * continuity-bounded multi-hit sampler so a newly resolved roof cannot\n     * replace the street under the user's feet.\n     */\n    refreshPhotorealWalkableContact(worldPosition = null) {\n        if (!this._isSurfaceWalkingTopologyActive()) return false;\n        worldPosition ||= this.getPhotorealContactWorldPosition(\n            this._photoContactProbeWorld || (this._photoContactProbeWorld = new THREE.Vector3())\n        );\n        const calibrationPending = this._photoWalkableSeedPending === true;\n        this._lastGroundSampleEstablishedWalkablePlane = false;\n        const radius = this._sampleGroundTruthRadius(worldPosition, {\n            forceWalkableCalibration: calibrationPending,\n        });\n        if (!Number.isFinite(radius)) return false;\n        // A failed exterior fit must retain the exact boot safety skin. A\n        // later photoreal model sequence will retry after more descendants\n        // have become renderable; it must not silently bless a roof merely\n        // because the centre ray still resolves there.\n        if (calibrationPending\n            && this._lastGroundSampleEstablishedWalkablePlane !== true) {\n            return false;\n        }\n        return this.adoptPhotorealUnderfootRadius(radius, worldPosition, {\n            walkableVerified: true,\n            visibleSkinRadius: this._lastGroundSampleCenterSkinR,\n        });\n    }\n\n    needsPhotorealWalkableCalibration() {\n        return this._photoWalkableSeedPending === true;\n    }\n\n    /**\n     * Sample terrain radius for a direction.\n     * @param {THREE.Vector3} upDir — world-space direction\n     * @param {Object} [opts]\n     * @param {boolean} [opts.mutateCache=true] — pass false from overlays\n     *   hovering arbitrary points to avoid contaminating camera clamp state\n     * @param {boolean} [opts.requireFreshPhotoHit=false] — reject the\n     *   camera-owned photoreal ground cache and return null unless this exact\n     *   direction intersects currently rendered photoreal geometry\n     */\n    sampleTerrainRadiusForDir(upDir, opts = {}) {\n        const mutateCache = opts.mutateCache !== false;\n        if (mutateCache) this._terrainSampleReliable = false;\n\n        // If photorealistic tiles are active, prefer raycasting against them\n        const requireFreshPhotoHit = opts.requireFreshPhotoHit === true;\n        const photoR = this._samplePhotoTileRadius(upDir, {\n            mutateCache,\n            allowCachedFallback: !requireFreshPhotoHit,\n        });\n        if (Number.isFinite(photoR)) {\n            if (mutateCache) this._terrainSampleReliable = true;\n            return photoR;\n        }\n        // Surface anchors at arbitrary coordinates must never inherit the\n        // camera's last underfoot radius. When a fresh photoreal hit is\n        // required, null means \"this anchor is not mated yet\"; the tile\n        // visibility event for its own region will retry it.\n        if (requireFreshPhotoHit && this.terrainTileGroup) return null;\n\n        if (opts.allowTriTreeFallback === false || !this.triTree || !this.triTree.group) {\n            return this._getEllipsoidRadiusForDir(upDir);\n        }\n\n        // Single camera/contact probes own their matrix refresh. Bulk overlay\n        // draping calls prepareTerrainSamplingBatch() once and opts out here;\n        // recursively updating the full planet tree for every border vertex\n        // is quadratic and can monopolize the main thread for many seconds.\n        if (opts.skipWorldMatrixUpdate !== true) {\n            this.triTree.group.updateMatrixWorld(true);\n        }\n\n        const isTileReliable = (tile) => {\n            if (!tile || !tile.elevationHasData) return false;\n            if (tile.elevationHoldUntilComplete) return false;\n            if (Number.isFinite(tile.elevationExpected) && tile.elevationExpected > 0) {\n                return tile.elevationDone >= tile.elevationExpected;\n            }\n            return tile.elevationComplete === true;\n        };\n\n        // First try: raycast the leaf tile underfoot, even if it's off-screen\n        const leafTile = (typeof this.triTree.findLeafTileForWorldDir === 'function')\n            ? this.triTree.findLeafTileForWorldDir(upDir)\n            : null;\n        if (leafTile) {\n            leafTile.ensureMesh(this.triTree.group, this.triTree.material);\n            const mesh = leafTile.mesh;\n            if (mesh && mesh.geometry && mesh.geometry.boundingSphere !== null) {\n                const prevVisible = mesh.visible;\n                if (!prevVisible) mesh.visible = true;\n\n                // Start outside the planet and raycast inward so we hit FRONT faces\n                const startR = (PLANET_RADIUS * 3.0) + 1000000.0; // safely outside\n                this._rayOrigin.copy(upDir).normalize().multiplyScalar(startR);\n                this._rayDir.copy(upDir).normalize().negate();\n                this.surfaceRaycaster.set(this._rayOrigin, this._rayDir);\n                this.surfaceRaycaster.near = 0;\n                this.surfaceRaycaster.far = startR + 10.0;\n\n                const hit = this.surfaceRaycaster.intersectObject(mesh, false);\n                if (mesh.visible !== prevVisible) mesh.visible = prevVisible;\n                if (hit && hit.length && hit[0].point) {\n                    const hitR = hit[0].point.length();\n                    const ellipsoidR = this._getEllipsoidRadiusForDir(upDir);\n                    const maxOffset = Number.isFinite(this.SURFACE_TERRAIN_MAX_OFFSET)\n                        ? this.SURFACE_TERRAIN_MAX_OFFSET\n                        : this.SURFACE_ALTITUDE_MAX;\n                    const delta = hitR - ellipsoidR;\n                    const withinBounds = Number.isFinite(hitR) && Number.isFinite(ellipsoidR)\n                        && Number.isFinite(maxOffset)\n                        && Math.abs(delta) <= maxOffset;\n                    if (mutateCache) this._terrainSampleReliable = isTileReliable(leafTile) && withinBounds;\n                    return withinBounds ? hitR : ellipsoidR;\n                }\n            }\n        }\n\n        // Start outside the planet and raycast inward so we hit FRONT faces\n        const startR = (PLANET_RADIUS * 3.0) + 1000000.0; // safely outside\n        this._rayOrigin.copy(upDir).normalize().multiplyScalar(startR);\n        this._rayDir.copy(upDir).normalize().negate();\n\n        this.surfaceRaycaster.set(this._rayOrigin, this._rayDir);\n        this.surfaceRaycaster.near = 0;\n        this.surfaceRaycaster.far = startR + 10.0;\n\n        // Only intersect visible meshes (not the whole group)\n        // Filter out meshes with null geometry or missing bounding spheres\n        const visibleMeshes = this.triTree.getVisibleMeshes().filter(mesh =>\n            !!(mesh && mesh.geometry && mesh.geometry.boundingSphere !== null)\n        );\n        const hits = visibleMeshes.length > 0\n            ? this.surfaceRaycaster.intersectObjects(visibleMeshes, false)\n            : [];\n\n        if (hits && hits.length && hits[0].point) {\n            const hitR = hits[0].point.length();\n            const ellipsoidR = this._getEllipsoidRadiusForDir(upDir);\n            const maxOffset = Number.isFinite(this.SURFACE_TERRAIN_MAX_OFFSET)\n                ? this.SURFACE_TERRAIN_MAX_OFFSET\n                : this.SURFACE_ALTITUDE_MAX;\n            const delta = hitR - ellipsoidR;\n            const withinBounds = Number.isFinite(hitR) && Number.isFinite(ellipsoidR)\n                && Number.isFinite(maxOffset)\n                && Math.abs(delta) <= maxOffset;\n            const hitTile = hits[0]?.object?.userData?.tile || null;\n            if (mutateCache) this._terrainSampleReliable = withinBounds && isTileReliable(hitTile);\n            return withinBounds ? hitR : ellipsoidR;\n        }\n        return this._getEllipsoidRadiusForDir(upDir);\n    }\n\n    updateSurfaceTerrainThrottled() {\n        const now = performance.now();\n        const elapsedMs = now - this._lastTerrainSample;\n        if (elapsedMs < this.SURFACE_TERRAIN_SAMPLE_MS) return;\n        this._lastTerrainSample = now;\n\n        // Use the current surface up direction\n        let rawRadius = this.sampleTerrainRadiusForDir(this.surfaceState.up);\n        if (!Number.isFinite(rawRadius)) {\n            rawRadius = Number.isFinite(this._terrainRadiusRaw)\n                ? this._terrainRadiusRaw\n                : this._getEllipsoidRadiusForDir(this.surfaceState.up);\n        }\n        this._terrainRadiusRaw = Number.isFinite(rawRadius) ? rawRadius : PLANET_RADIUS;\n\n        // ── Stationary jitter hold ───────────────────────────────────────\n        // When the user is geographically still, the terrain mesh under them\n        // does not change — but the LOD tile system keeps refining/swapping\n        // meshes, so each periodic raycast returns a slightly different\n        // elevation (adjacent LODs disagree by a metre or two). The smoother\n        // below would faithfully track that oscillation, producing the visible\n        // up/down shimmy. While stationary we therefore PIN the raw radius to\n        // the already-settled value so the placement radius is byte-identical\n        // every frame. Genuine elevation corrections (larger than the\n        // deadband) still pass through, and any movement immediately releases\n        // the hold. Mirrors the photoreal path's _sampleGroundTruthRadius\n        // deadband + stationary cache.\n        //\n        // Movement is detected two ways, both required to declare \"still\":\n        //   1. No active movement intent (keys / jump).\n        //   2. No geographic translation — compared in the planet-LOCAL frame\n        //      so Earth-rotation compensation (~7.7 m/frame of world drift on\n        //      a stationary observer) is not mistaken for movement.\n        const STILL_DEADBAND_M = 1.5;   // ignore LOD shimmer up to this\n        const STILL_MOVE_M2 = 0.25;     // < 0.5 m of local translation = still\n        const movementIntent = this._hasSurfaceMovementIntent();\n        let geoStill = false;\n        const stillAnchor = (this._getCameraAnchor && this._getCameraAnchor()) || this.camera;\n        if (!movementIntent && stillAnchor?.position) {\n            const localPos = this._toPlanetLocal(\n                stillAnchor.position,\n                this._vTerrainHoldLocal || (this._vTerrainHoldLocal = new THREE.Vector3())\n            );\n            if (this._terrainHoldHasPos) {\n                geoStill = this._terrainHoldLocalPos.distanceToSquared(localPos) < STILL_MOVE_M2;\n            }\n            (this._terrainHoldLocalPos || (this._terrainHoldLocalPos = new THREE.Vector3())).copy(localPos);\n            this._terrainHoldHasPos = true;\n        } else {\n            this._terrainHoldHasPos = false;\n        }\n        if (geoStill\n            && Number.isFinite(this._terrainRadius)\n            && Math.abs(this._terrainRadiusRaw - this._terrainRadius) < STILL_DEADBAND_M) {\n            // Pin raw to the settled value → the smoother below is a no-op and\n            // the camera holds a perfectly constant altitude.\n            this._terrainRadiusRaw = this._terrainRadius;\n        }\n\n        const hugSurface = this._shouldHugSurface();\n        const dt = Math.max(elapsedMs / 1000, 1e-3);\n\n        if (hugSurface) {\n            const prev = Number.isFinite(this._terrainRadius) ? this._terrainRadius : this._terrainRadiusRaw;\n            const target = this._terrainRadiusRaw;\n            const rising = target > prev;\n            const tau = rising ? this.SURFACE_HUG_TERRAIN_UP_SEC : this.SURFACE_HUG_TERRAIN_DOWN_SEC;\n            const alpha = tau > 0 ? (1 - Math.exp(-dt / tau)) : 1;\n            let next = prev + (target - prev) * alpha;\n            if (Number.isFinite(this.SURFACE_HUG_MAX_LAG)) {\n                next = Math.max(next, target - this.SURFACE_HUG_MAX_LAG);\n            }\n            this._terrainRadius = next;\n        } else {\n            // Surface input is an explicit altitude command.  Do not let a\n            // terrain EMA put the camera temporarily below/above that command\n            // while the user is grabbing or scrolling across the surface.\n            const directAltitudeInput = this._surfaceDragAGLLock\n                || now < this._surfaceScrollHoldUntil;\n            const altitude = this.surfaceAltitudeMeters ?? this.SURFACE_EYE_HEIGHT;\n            const nearSurface = Number.isFinite(altitude) && altitude <= this.SURFACE_SCROLL_SOFTEN_START_ALT;\n            if (Number.isFinite(this._terrainRadius)) {\n                // Always smooth terrain radius changes to prevent flapping\n                // when photorealistic tiles load and shift terrain height\n                const target = this._terrainRadiusRaw;\n                if (directAltitudeInput) {\n                    this._terrainRadius = target;\n                } else {\n                    const prev = this._terrainRadius;\n                const maxDelta = Number.isFinite(this.SURFACE_TERRAIN_ALT_MAX_DELTA)\n                    ? Math.max(0.5, this.SURFACE_TERRAIN_ALT_MAX_DELTA * dt)\n                    : Infinity;\n                const delta = target - prev;\n                const step = Number.isFinite(maxDelta)\n                    ? THREE.MathUtils.clamp(delta, -maxDelta, maxDelta)\n                    : delta;\n                this._terrainRadius = prev + step;\n                }\n            } else {\n                this._terrainRadius = this._terrainRadiusRaw;\n            }\n        }\n\n        const ellipsoidR = this._getEllipsoidRadiusForDir(this.surfaceState.up);\n        const maxOffset = Number.isFinite(this.SURFACE_TERRAIN_MAX_OFFSET)\n            ? this.SURFACE_TERRAIN_MAX_OFFSET\n            : Infinity;\n        const terrainElevRaw = THREE.MathUtils.clamp(\n            this._terrainRadiusRaw - ellipsoidR,\n            -maxOffset,\n            maxOffset\n        );\n        const minAltitude = this._getNavigationFloorAltitude(this.surfaceState.up);\n\n        if (hugSurface) {\n            let currentAlt = Number.isFinite(this.surfaceAltitudeMeters)\n                ? this.surfaceAltitudeMeters\n                : minAltitude;\n            const rate = Number.isFinite(this.SURFACE_HUG_ALT_LERP_RATE)\n                ? this.SURFACE_HUG_ALT_LERP_RATE\n                : 0;\n            const alphaAlt = rate > 0 ? (1 - Math.exp(-rate * dt)) : 1;\n            currentAlt = currentAlt + (minAltitude - currentAlt) * alphaAlt;\n            if (!Number.isFinite(currentAlt)) currentAlt = minAltitude;\n            this.surfaceAltitudeMeters = Math.max(minAltitude, currentAlt);\n            this.surfaceAltitudeMSL = terrainElevRaw + this.surfaceAltitudeMeters + this.SURFACE_TERRAIN_CLEARANCE;\n            return;\n        }\n\n        if (this._isJumping) {\n            if (!Number.isFinite(this.surfaceAltitudeMeters) || this.surfaceAltitudeMeters < minAltitude) {\n                this.surfaceAltitudeMeters = minAltitude;\n            }\n            return;\n        }\n\n        const terrainElev = THREE.MathUtils.clamp(\n            this._terrainRadius - ellipsoidR,\n            -maxOffset,\n            maxOffset\n        );\n        const altitudeForMSL = Number.isFinite(this.surfaceAltitudeMeters)\n            ? this.surfaceAltitudeMeters\n            : minAltitude;\n        const activeMSL = this._getEffectiveSurfaceMSL(altitudeForMSL);\n        if (Number.isFinite(activeMSL)) {\n            if (this._surfaceDragMSLLock && Number.isFinite(this._surfaceDragLockedMSL)) {\n                this.surfaceAltitudeMSL = this._surfaceDragLockedMSL;\n            }\n            const nextAlt = activeMSL - terrainElev - this.SURFACE_TERRAIN_CLEARANCE;\n            if (this._airborneMSLGlideActive) {\n                // Airborne AGL is telemetry, not a placement constraint. Keep\n                // the signed value so terrain rising beneath a level flight is\n                // visible to callers without converting it into an ASL jump.\n                this.surfaceAltitudeMeters = Number.isFinite(nextAlt) ? nextAlt : altitudeForMSL;\n                this.surfaceAltitudeMSL = activeMSL;\n                return;\n            }\n            const maxAltitude = Number.isFinite(this.SURFACE_ALTITUDE_MAX)\n                ? this.SURFACE_ALTITUDE_MAX\n                : Infinity;\n            let clampedAlt = Number.isFinite(nextAlt)\n                ? THREE.MathUtils.clamp(nextAlt, minAltitude, maxAltitude)\n                : minAltitude;\n            if (this._surfaceDragMSLLock && this.cameraMode === 'surface') {\n                this.surfaceAltitudeMeters = clampedAlt;\n                return;\n            }\n            const currentAlt = Number.isFinite(this.surfaceAltitudeMeters)\n                ? this.surfaceAltitudeMeters\n                : clampedAlt;\n            if (now < this._surfaceScrollHoldUntil && this._surfaceScrollHoldDir !== 0) {\n                if (this._surfaceScrollHoldDir < 0 && clampedAlt > currentAlt) {\n                    clampedAlt = currentAlt;\n                } else if (this._surfaceScrollHoldDir > 0 && clampedAlt < currentAlt) {\n                    clampedAlt = currentAlt;\n                }\n            } else if (this._surfaceScrollHoldDir !== 0) {\n                this._surfaceScrollHoldDir = 0;\n            }\n            // `surfaceAltitudeMeters` is the canonical AGL value written to\n            // and restored from the URL.  A rate-limited correction here made\n            // the visible camera altitude lag the URL by seconds after a drag\n            // or scroll. Apply the resolved value in the same frame instead.\n            this.surfaceAltitudeMeters = Math.max(minAltitude, clampedAlt);\n            if (!Number.isFinite(nextAlt) || clampedAlt !== nextAlt) {\n                this.surfaceAltitudeMSL = terrainElev + this.surfaceAltitudeMeters + this.SURFACE_TERRAIN_CLEARANCE;\n            } else {\n                this.surfaceAltitudeMSL = activeMSL;\n            }\n            if (this._surfaceAutoMSLHoldActive && Number.isFinite(this.surfaceAltitudeMSL)) {\n                this._surfaceAutoMSLHold = this.surfaceAltitudeMSL;\n            }\n            return;\n        }\n\n        if (!Number.isFinite(this.surfaceAltitudeMeters) || this.surfaceAltitudeMeters < minAltitude) {\n            this.surfaceAltitudeMeters = minAltitude;\n        }\n    }\n\n    _getSurfaceFloorAltitude() {\n        if (this._vrModeActive && Number.isFinite(this._xrCalibratedEyeHeight)) {\n            // Native local-floor tracking already carries standing, seated,\n            // and physical-crouch height. Reapplying the desktop avatar eye\n            // height here would lift or bury the XR reference-space floor.\n            return Math.max(0.25, this._xrCalibratedEyeHeight);\n        }\n        const standHeight = Number.isFinite(this.STAND_EYE_HEIGHT)\n            ? this.STAND_EYE_HEIGHT\n            : this.SURFACE_EYE_HEIGHT;\n        const crouchHeight = Number.isFinite(this.CROUCH_EYE_HEIGHT)\n            ? this.CROUCH_EYE_HEIGHT\n            : standHeight;\n        const desired = (this._isCrouching || this._xrLocomotionInput?.crouch) ? crouchHeight : standHeight;\n        const minClearance = Number.isFinite(this.SURFACE_MIN_CLEARANCE)\n            ? this.SURFACE_MIN_CLEARANCE\n            : 1;\n        return Math.max(minClearance, desired);\n    }\n\n    _getAbsoluteMinAltitude() {\n        const minClearance = Number.isFinite(this.SURFACE_MIN_CLEARANCE)\n            ? this.SURFACE_MIN_CLEARANCE\n            : 1;\n        return Math.max(1, minClearance);\n    }\n\n    /**\n     * Install a synchronous land/ocean lookup. The resolver receives geodetic\n     * latitude/longitude and returns either an ocean descriptor or null.\n     * Swimming is never inferred from tile color or missing geometry: it is\n     * enabled only after this authoritative world-boundary lookup succeeds.\n     */\n    setOceanResolver(resolver) {\n        this._oceanResolver = typeof resolver === 'function' ? resolver : null;\n        this._updateOceanNavigationState(this.surfaceState?.up);\n    }\n\n    _getOceanDescriptorForDir(worldDir) {\n        if (!this._oceanResolver || !worldDir || worldDir.lengthSq?.() < 1e-12) return null;\n        const localDir = this._vC.copy(worldDir).normalize();\n        this._toPlanetLocalDirection(localDir, localDir);\n        const geo = dirToLatLonLocal(localDir);\n        if (!Number.isFinite(geo?.latDeg) || !Number.isFinite(geo?.lonDeg)) return null;\n        try {\n            const result = this._oceanResolver(geo.latDeg, geo.lonDeg);\n            if (result?.isOcean !== true) return null;\n            if (!this.oceanWaterLevel) return result;\n            if (!this.oceanWaterLevel.ready || !this.oceanWaterLevel.tides) this.oceanWaterLevel.load?.();\n            const level = this.oceanWaterLevel.sample(geo.latDeg, geo.lonDeg);\n            return level ? { ...result, ...level } : null;\n        } catch {\n            return null;\n        }\n    }\n\n    _isOceanForDir(worldDir) {\n        return !!this._getOceanDescriptorForDir(worldDir);\n    }\n\n    _getNavigationFloorAltitude(worldDir = this.surfaceState?.up) {\n        if (this.cameraMode === 'surface' && this._isOceanForDir(worldDir)) {\n            const descriptor = this._getOceanDescriptorForDir(worldDir);\n            let seabed = descriptor?.seabedElevationMeters;\n            if (!Number.isFinite(seabed)) seabed = this._getResidentOceanSeabedElevation(worldDir);\n            const seaHeight = descriptor?.seaLevelEllipsoidMeters || 0;\n            if (Number.isFinite(seabed) && seabed < seaHeight) return seabed - seaHeight + 1;\n            // Until measured bathymetry arrives, retain a bounded swim volume.\n            const maxDepth = Number.isFinite(this.SWIM_MAX_DEPTH) ? Math.max(1, this.SWIM_MAX_DEPTH) : 80;\n            return -maxDepth;\n        }\n        return this._getSurfaceFloorAltitude();\n    }\n\n    /** Measured seabed elevation (negative metres) under an ocean position, or null. */\n    getOceanSeabedElevation(worldDir = this.surfaceState?.up) {\n        const descriptor = this._getOceanDescriptorForDir(worldDir);\n        if (!descriptor) return null;\n        let seabed = descriptor.seabedElevationMeters;\n        if (!Number.isFinite(seabed)) seabed = this._getResidentOceanSeabedElevation(worldDir);\n        const seaHeight = descriptor.seaLevelEllipsoidMeters || 0;\n        return Number.isFinite(seabed) && seabed < seaHeight ? seabed - seaHeight : null;\n    }\n\n    _getResidentOceanSeabedElevation(worldDir) {\n        const tree = this.triTree;\n        if (!tree?.getSurfaceRadiusAtDir || !worldDir) return null;\n        const local = this._vOceanFloorDir || (this._vOceanFloorDir = new THREE.Vector3());\n        this._toPlanetLocalDirection(worldDir, local);\n        const cached = this._oceanSeabedSample;\n        const nearby = cached && local.distanceToSquared(cached.direction) < (2 / PLANET_RADIUS) ** 2;\n        const now = performance.now();\n        if (nearby && now - cached.time < 250) return cached.elevation;\n        const leaf = tree.findLeafTileForWorldDir?.(worldDir);\n        const ready = leaf?.elevationHasData === true && !leaf.elevationHoldUntilComplete\n            && (leaf.elevationExpected > 0 ? leaf.elevationDone >= leaf.elevationExpected : leaf.elevationComplete === true);\n        if (!ready) return nearby ? cached.elevation : null;\n        // One bounded resident leaf-vertex query, at most four times per second\n        // while still. Never raycast the full terrain tree from altitude clamps.\n        const radius = tree.getSurfaceRadiusAtDir(worldDir);\n        const elevation = radius - this._getEllipsoidRadiusForDir(worldDir);\n        if (!Number.isFinite(radius)) return nearby ? cached.elevation : null;\n        this._oceanSeabedSample = { direction: local.clone(), elevation, time: now };\n        return elevation;\n    }\n\n    _updateOceanNavigationState(worldDir = this.surfaceState?.up) {\n        const descriptor = this.cameraMode === 'surface' ? this._getOceanDescriptorForDir(worldDir) : null;\n        const isOcean = !!descriptor;\n        const commanded = Number.isFinite(this.surfaceAltitudeMeters) ? this.surfaceAltitudeMeters : Infinity;\n        // Flight over water may be referenced to the photoreal seabed, so the\n        // camera's own sea-level height decides submersion and depth.\n        const cameraMsl = isOcean ? this._computeCameraMSL() : null;\n        const seaHeight = descriptor?.seaLevelEllipsoidMeters || 0;\n        const altitude = Number.isFinite(cameraMsl) ? cameraMsl - seaHeight : commanded;\n        const surfaceFloor = this._getSurfaceFloorAltitude();\n        const next = {\n            isOcean,\n            swimming: isOcean && commanded < surfaceFloor - 0.01,\n            underwater: isOcean && altitude < 0,\n            depthMeters: isOcean ? Math.max(0, -altitude) : 0,\n            altitudeAboveSeaMeters: isOcean ? altitude : null,\n            seaLevelEllipsoidMeters: seaHeight,\n            tideMeters: descriptor?.tideMeters || 0,\n        };\n        const prev = this._oceanState || {};\n        const changed = prev.isOcean !== next.isOcean\n            || prev.swimming !== next.swimming\n            || prev.underwater !== next.underwater\n            || Math.abs((prev.depthMeters || 0) - next.depthMeters) >= 0.25;\n        this._oceanState = next;\n        if (!changed) return next;\n        try {\n            if (typeof window !== 'undefined') window.__noclipOceanState = { ...next };\n            if (typeof document !== 'undefined' && typeof CustomEvent !== 'undefined') {\n                document.dispatchEvent(new CustomEvent('noclip:ocean-state', { detail: { ...next } }));\n            }\n        } catch { /* diagnostics must never affect navigation */ }\n        return next;\n    }\n\n    getOceanNavigationState() {\n        return { ...(this._oceanState || {}) };\n    }\n\n    /**\n     * Return the best settled contact radius without triggering another tile\n     * raycast. Avatars use this same contact contract as the camera, preventing\n     * feet from drifting to the ellipsoid while photoreal ground is elevated.\n     */\n    getSurfaceContactRadius(worldDir = this.surfaceState?.up) {\n        if (!worldDir) return PLANET_RADIUS;\n        const ellipsoidR = this._getEllipsoidRadiusForDir(worldDir);\n        if (this.terrainTileGroup) {\n            // Photoreal tile coordinates are ECEF ellipsoidal heights. Their\n            // visible surface may legitimately be below the WGS84 reference\n            // ellipsoid (negative ellipsoidal height is common where the\n            // geoid is below the ellipsoid). Clamping a valid tile hit with\n            // Math.max(ellipsoidR, hitR) lifts avatars many metres off the\n            // rendered pavement while the HUD still reports the commanded\n            // 1.16 m AGL.\n            //\n            // Use the same exact, direction-scoped center skin that owns the\n            // camera contact constraint. The retained walkable values are\n            // gap fallbacks only and intentionally remain unclamped. The\n            // ellipsoid is used only until no photoreal contact has ever been\n            // established at this footprint.\n            const centerSkinR = this._getPhotoCenterSkinRadiusForDirection?.(worldDir);\n            if (Number.isFinite(centerSkinR)) return centerSkinR;\n            if (Number.isFinite(this._photoGroundEmaR)) return this._photoGroundEmaR;\n            if (Number.isFinite(this._photoGroundLastRawR)) return this._photoGroundLastRawR;\n            if (Number.isFinite(this._photoLastKnownReferenceR)) return this._photoLastKnownReferenceR;\n        }\n        const terrainR = Number.isFinite(this._terrainRadius) ? this._terrainRadius : this._terrainRadiusRaw;\n        return Number.isFinite(terrainR) ? Math.max(ellipsoidR, terrainR) : ellipsoidR;\n    }\n\n    getSurfaceContactPoint(target = new THREE.Vector3(), worldDir = this.surfaceState?.up) {\n        if (!worldDir) return target.set(0, 0, 0);\n        const oceanState = this._oceanState || {};\n        if (oceanState.swimming && this.camera?.position) {\n            const eyeHeight = Number.isFinite(this.SURFACE_EYE_HEIGHT) ? this.SURFACE_EYE_HEIGHT : 1.6;\n            const radius = Math.max(1, this._getCameraAnchor().position.length() - eyeHeight * 0.55);\n            return target.copy(worldDir).normalize().multiplyScalar(radius);\n        }\n        return target.copy(worldDir).normalize().multiplyScalar(this.getSurfaceContactRadius(worldDir));\n    }\n\n    _getPhotoCollisionCandidates(origin, direction, far) {\n        const now = typeof performance !== 'undefined' && performance.now ? performance.now() : Date.now();\n        const cacheAge = now - (this._photoCollisionCandidatesAt || 0);\n        const modelSeq = this.terrainTileGroup?.userData?.photoModelChangeSeq | 0;\n        this._photoCollisionCandidatesOrigin ||= new THREE.Vector3();\n        this._photoCollisionCandidatesDirection ||= new THREE.Vector3();\n        const movedSq = this._photoCollisionCandidatesOrigin.distanceToSquared(origin);\n        const directionStable = this._photoCollisionCandidatesDirection.lengthSq() > 0\n            && this._photoCollisionCandidatesDirection.dot(direction) > 0.965;\n        const distanceCovered = this._photoCollisionCandidatesFar >= far;\n        if (this._photoCollisionCandidatesAt > 0\n            && cacheAge <= this.SURFACE_COLLISION_CACHE_MS\n            && this._photoCollisionCandidatesModelSeq === modelSeq\n            && movedSq < 9\n            && directionStable\n            && distanceCovered) {\n            return this._photoCollisionCandidates;\n        }\n        this._publishPhotorealSamplingMatrices();\n        this._photoCollisionCandidates = this._collectPhotoTileRayCandidates(origin, direction, far);\n        this._photoCollisionCandidatesAt = now;\n        this._photoCollisionCandidatesModelSeq = modelSeq;\n        this._photoCollisionCandidatesOrigin.copy(origin);\n        this._photoCollisionCandidatesDirection.copy(direction);\n        this._photoCollisionCandidatesFar = far;\n        return this._photoCollisionCandidates;\n    }\n\n    /**\n     * Return true when currently rendered photoreal terrain intersects the\n     * finite camera-to-label segment before its endpoint. LabelSystem already\n     * handles the planet-scale horizon; this is the narrow local ridge,\n     * building, and terrain test and is called under a strict frame budget.\n     */\n    isTerrainOccludedBetween(cameraWorldPos, labelWorldPos) {\n        if (!this.terrainTileGroup || !cameraWorldPos || !labelWorldPos) return false;\n\n        const direction = (this._labelOcclusionDirection\n            || (this._labelOcclusionDirection = new THREE.Vector3()))\n            .copy(labelWorldPos)\n            .sub(cameraWorldPos);\n        const segmentLength = direction.length();\n        const endpointClearance = 2;\n        const far = segmentLength - endpointClearance;\n        if (!(far > 0.2)) return false;\n        direction.multiplyScalar(1 / segmentLength);\n\n        const renderFrame = this.renderer?.info?.render?.frame;\n        if (!Number.isFinite(renderFrame)\n            || renderFrame !== this._labelOcclusionMatrixFrame) {\n            this._publishPhotorealSamplingMatrices();\n            this._labelOcclusionMatrixFrame = renderFrame;\n        }\n        const candidates = this._collectPhotoTileRayCandidates(\n            cameraWorldPos,\n            direction,\n            far\n        );\n        if (candidates.length === 0) return false;\n\n        const raycaster = this._labelOcclusionRaycaster\n            || (this._labelOcclusionRaycaster = new THREE.Raycaster());\n        raycaster.set(cameraWorldPos, direction);\n        raycaster.near = 0.15;\n        raycaster.far = far;\n        return raycaster.intersectObjects(candidates, false).length > 0;\n    }\n\n    /**\n     * Sample the rendered photoreal scene as an acoustic boundary. This is a\n     * bounded geometric-acoustics approximation: the direct segment owns\n     * transmission/occlusion, while the first visible tile hit owns one early\n     * reflection and its path delay. Callers retain the last sample between\n     * probes so audio never depends on per-audio-frame scene traversal.\n     */\n    samplePhotorealAcousticPath(sourceWorldPos, listenerWorldPos, target = {}, options = {}) {\n        const reflectionPoint = target.reflectionPoint?.isVector3\n            ? target.reflectionPoint\n            : (target._reflectionPoint || new THREE.Vector3());\n        target._reflectionPoint = reflectionPoint;\n        target.occluded = false;\n        target.directGain = 1;\n        target.lowpassHz = 18000;\n        target.reflectionPoint = null;\n        target.reflectionGain = 0;\n        target.reflectionDelaySeconds = 0;\n        target.diffusion = 0;\n        if (!this.terrainTileGroup || !sourceWorldPos || !listenerWorldPos) return target;\n\n        const direction = (this._acousticDirection ||= new THREE.Vector3())\n            .copy(sourceWorldPos).sub(listenerWorldPos);\n        const distance = direction.length();\n        if (!(distance > 0.5) || distance > 2500) return target;\n        direction.multiplyScalar(1 / distance);\n        if (options.skipWorldMatrixUpdate !== true) {\n            this._publishPhotorealSamplingMatrices();\n        }\n        const candidates = this._collectPhotoTileRayCandidates(\n            listenerWorldPos,\n            direction,\n            Math.max(0.1, distance - 0.3)\n        );\n        const raycaster = this._acousticRaycaster ||= new THREE.Raycaster();\n        raycaster.set(listenerWorldPos, direction);\n        raycaster.near = 0.12;\n        raycaster.far = Math.max(0.1, distance - 0.3);\n        const hit = candidates.length ? raycaster.intersectObjects(candidates, false)[0] : null;\n        if (hit?.point) {\n            const normal = (this._acousticNormal ||= new THREE.Vector3());\n            if (hit.face?.normal && hit.object?.matrixWorld) {\n                const normalMatrix = this._acousticNormalMatrix ||= new THREE.Matrix3();\n                normal.copy(hit.face.normal).applyNormalMatrix(normalMatrix.getNormalMatrix(hit.object.matrixWorld)).normalize();\n            } else normal.copy(listenerWorldPos).normalize();\n            const incidence = THREE.MathUtils.clamp(Math.abs(normal.dot(direction)), 0, 1);\n            target.occluded = true;\n            target.directGain = THREE.MathUtils.lerp(0.22, 0.08, incidence);\n            target.lowpassHz = THREE.MathUtils.lerp(2300, 650, incidence);\n            target.reflectionPoint = reflectionPoint.copy(hit.point).addScaledVector(normal, 0.08);\n            target.reflectionGain = THREE.MathUtils.lerp(0.1, 0.26, incidence);\n            target.reflectionDelaySeconds = (4 + 9 * (1 - incidence)) / 343;\n            target.diffusion = THREE.MathUtils.lerp(0.72, 0.3, incidence);\n            return target;\n        }\n\n        // With an unobstructed direct path, probe the rendered ground below\n        // the path midpoint for a real first-order floor/terrain reflection.\n        const midpoint = (this._acousticMidpoint ||= new THREE.Vector3())\n            .copy(sourceWorldPos).add(listenerWorldPos).multiplyScalar(0.5);\n        const up = (this._acousticUp ||= new THREE.Vector3()).copy(midpoint).normalize();\n        const groundRay = this._acousticGroundRay ||= new THREE.Ray();\n        groundRay.origin.copy(midpoint).addScaledVector(up, 60);\n        groundRay.direction.copy(up).multiplyScalar(-1);\n        const ground = this._getGeoPhotoSurfaceHitFromRay(\n            groundRay,\n            this._acousticGroundPoint ||= new THREE.Vector3(),\n            { skipWorldMatrixUpdate: options.skipWorldMatrixUpdate === true }\n        );\n        if (ground) {\n            const reflectedDistance = sourceWorldPos.distanceTo(ground) + listenerWorldPos.distanceTo(ground);\n            const excessDistance = Math.max(0, reflectedDistance - distance);\n            target.reflectionPoint = reflectionPoint.copy(ground).addScaledVector(up, 0.06);\n            target.reflectionGain = THREE.MathUtils.clamp(0.18 / (1 + excessDistance * 0.08), 0.035, 0.18);\n            target.reflectionDelaySeconds = THREE.MathUtils.clamp(excessDistance / 343, 0.004, 0.12);\n            target.diffusion = 0.2;\n        }\n        return target;\n    }\n\n    preparePhotorealAcousticSampling() {\n        this._publishPhotorealSamplingMatrices();\n    }\n\n    /**\n     * True when rendered photoreal geometry lies on the segment from `fromWorld`\n     * (usually the camera) to `toWorld` — used to hide DOM overlays (theater\n     * iframes) behind hills and buildings. Callers publish matrices once per\n     * frame via preparePhotorealAcousticSampling().\n     */\n    isPhotorealSegmentOccluded(fromWorld, toWorld, { maxDistance = 6000 } = {}) {\n        if (!this.terrainTileGroup || !fromWorld || !toWorld) return false;\n        const direction = (this._occlusionDirection ||= new THREE.Vector3()).copy(toWorld).sub(fromWorld);\n        const distance = direction.length();\n        if (!(distance > 0.5) || distance > maxDistance) return false;\n        direction.multiplyScalar(1 / distance);\n        const far = Math.max(0.1, distance - Math.max(0.3, distance * 0.002));\n        const candidates = this._collectPhotoTileRayCandidates(fromWorld, direction, far);\n        if (!candidates.length) return false;\n        const raycaster = this._occlusionRaycaster ||= new THREE.Raycaster();\n        raycaster.set(fromWorld, direction);\n        raycaster.near = 0.12;\n        raycaster.far = far;\n        raycaster.firstHitOnly = true;\n        return raycaster.intersectObjects(candidates, false).length > 0;\n    }\n\n    /** Resolve a full rounded character sweep. The returned tangent vector's\n     * magnitude is the admitted fraction, never a renormalized wall slide. */\n    _resolvePhotoSurfaceMoveDirection(moveDir, moveMeters, up, target) {\n        target.copy(moveDir).normalize();\n        if (!this.terrainTileGroup || !this.camera || moveMeters <= 0 || this._oceanState?.swimming) return target;\n        const bodyRadius = Number(this.SURFACE_BODY_RADIUS) || 0.34;\n        const eyeHeight = this._getSurfaceFloorAltitude();\n        const bodyHeight = Math.max(2 * bodyRadius + 0.01, eyeHeight + 0.18);\n        const cameraPos = this._getCameraAnchor().position;\n        const candidates = this._getPhotoCollisionCandidates(cameraPos, target, moveMeters + bodyRadius + bodyHeight);\n        if (!candidates.length) return target;\n        const solver = this._surfaceCapsuleCollider ||= new SurfaceCapsuleCollider();\n        const foot = (this._capsuleFoot ||= new THREE.Vector3()).copy(cameraPos).addScaledVector(up, -eyeHeight);\n        const motion = (this._capsuleMotion ||= new THREE.Vector3()).copy(target).multiplyScalar(moveMeters);\n        const grounded = this._isSurfaceWalkingTopologyActive() && !this._isJumping\n            && this.surfaceAltitudeMeters <= eyeHeight + 0.35;\n        const resolved = solver.move(candidates, { foot, up, height: bodyHeight, radius: bodyRadius }, motion, {\n            stepHeight: grounded ? (this.SURFACE_MAX_WALKABLE_STEP ?? 0.55) : 0,\n            snap: grounded ? 0.3 : 0,\n            slopeDot: this._isSurfaceWalkingTopologyActive() ? (this.SURFACE_MAX_WALKABLE_SLOPE_DOT ?? 0.58) : 2,\n        });\n        target.copy(resolved).addScaledVector(up, -resolved.dot(up)).multiplyScalar(1 / moveMeters);\n        if (target.lengthSq() > 1) target.normalize();\n        return target;\n    }\n\n    /** Rounded feet need geometric clearance on a slope. Keep this physical\n     * capsule constraint separate from the exact native terrain height and\n     * the user's commanded AGL; the HUD continues measuring the real pose. */\n    _getPhotoBodyClearance(floorR, worldUp, eyeHeight = this._getSurfaceFloorAltitude()) {\n        if (!Number.isFinite(floorR) || !this.terrainTileGroup?.traverse || this._isJumping\n            || this.surfaceAltitudeMeters > this._getSurfaceFloorAltitude() + 0.35) return 0;\n        const foot = (this._bodyClearanceFoot ||= new THREE.Vector3()).copy(worldUp).multiplyScalar(floorR);\n        const origin = (this._bodyClearanceOrigin ||= new THREE.Vector3()).copy(foot).addScaledVector(worldUp, eyeHeight);\n        const down = (this._bodyClearanceDown ||= new THREE.Vector3()).copy(worldUp).negate();\n        const candidates = this._getPhotoCollisionCandidates(origin, down, eyeHeight + 2);\n        if (!candidates.length) return 0;\n        const signature = candidates.map(mesh => `${mesh.id}:${mesh.geometry?.id}`).join(',');\n        const local = this._toPlanetLocalDirection(worldUp, this._bodyClearanceLocal ||= new THREE.Vector3()).normalize();\n        const samePoint = this._bodyClearanceCachedLocal\n            && local.distanceToSquared(this._bodyClearanceCachedLocal) * PLANET_RADIUS * PLANET_RADIUS < 1e-4;\n        const radius = Number(this.SURFACE_BODY_RADIUS) || 0.34;\n        if (signature === this._bodyClearanceSignature && samePoint\n            && Math.abs(this._bodyClearanceFloorR - floorR) < 1e-5 && this._bodyClearanceEye === eyeHeight\n            && this._bodyClearanceRadius === radius) return this._bodyClearanceM;\n        const solver = this._surfaceCapsuleCollider ||= new SurfaceCapsuleCollider();\n        const clearance = solver.clearance(candidates, { foot, up: worldUp,\n            height: Math.max(2 * radius + 0.01, eyeHeight + 0.18), radius }, this.SURFACE_MAX_WALKABLE_SLOPE_DOT ?? 0.58);\n        this._bodyClearanceSignature = signature;this._bodyClearanceFloorR = floorR;\n        this._bodyClearanceEye = eyeHeight;this._bodyClearanceRadius = radius;this._bodyClearanceM = clearance;\n        (this._bodyClearanceCachedLocal ||= new THREE.Vector3()).copy(local);\n        return clearance;\n    }\n\n    /**\n     * Resolve one dynamic rigid body against the currently renderable local\n     * photoreal mesh. This is a bounded swept query, not a second terrain\n     * update loop: it runs only for active physics objects and only against\n     * tile bounding spheres intersecting the body's short motion segment.\n     * TriTree mode keeps using its native Rapier tile colliders.\n     */\n    resolveDynamicSurfaceContact(previousPosition, proposedPosition, radius = 0.25, mesh = null) {\n        if (!this.terrainTileGroup || !previousPosition || !proposedPosition) return null;\n        if (previousPosition.lengthSq() < 1e-8 || proposedPosition.lengthSq() < 1e-8) return null;\n\n        const safeRadius = THREE.MathUtils.clamp(Number(radius) || 0.25, 0.02, 50);\n        const skin = Math.max(0.01, Number(this.SURFACE_COLLISION_SKIN) || 0.08);\n        const motion = (this._dynamicContactMotion || (this._dynamicContactMotion = new THREE.Vector3()))\n            .copy(proposedPosition)\n            .sub(previousPosition);\n        const motionDistance = motion.length();\n        const direction = (this._dynamicContactDirection\n            || (this._dynamicContactDirection = new THREE.Vector3()));\n        const origin = this._dynamicContactOrigin\n            || (this._dynamicContactOrigin = new THREE.Vector3());\n        let far = 0;\n\n        if (motionDistance > 1e-5) {\n            direction.copy(motion).multiplyScalar(1 / motionDistance);\n            origin.copy(previousPosition);\n            far = motionDistance + safeRadius + skin;\n        } else {\n            direction.copy(proposedPosition).normalize().negate();\n            origin.copy(proposedPosition);\n            far = safeRadius + skin + 0.25;\n        }\n\n        const frame = this.renderer?.info?.render?.frame;\n        if (!Number.isFinite(frame) || frame !== this._dynamicContactMatrixFrame) {\n            this._publishPhotorealSamplingMatrices();\n            this._dynamicContactMatrixFrame = frame;\n        }\n        const candidates = this._collectPhotoTileRayCandidates(origin, direction, far);\n        if (candidates.length === 0) return null;\n\n        const raycaster = this._dynamicContactRaycaster\n            || (this._dynamicContactRaycaster = new THREE.Raycaster());\n        raycaster.set(origin, direction);\n        raycaster.near = 0.001;\n        raycaster.far = far;\n        const hit = raycaster.intersectObjects(candidates, false)[0];\n        if (!hit?.point || !hit.face?.normal) return null;\n\n        const normal = mesh?.userData?._photoContactNormal\n            || new THREE.Vector3();\n        if (mesh?.userData) mesh.userData._photoContactNormal = normal;\n        normal.copy(hit.face.normal).transformDirection(hit.object.matrixWorld).normalize();\n        if (normal.dot(direction) > 0) normal.negate();\n\n        const position = mesh?.userData?._photoContactPosition\n            || new THREE.Vector3();\n        if (mesh?.userData) mesh.userData._photoContactPosition = position;\n        position.copy(hit.point).addScaledVector(normal, safeRadius + skin);\n\n        // A grazing extension can see a surface beyond the proposed center.\n        // Only accept that extension when the center would penetrate the\n        // body's collision radius this step.\n        const proposedSide = (this._dynamicContactProposedSide\n            || (this._dynamicContactProposedSide = new THREE.Vector3()))\n            .copy(proposedPosition)\n            .sub(hit.point)\n            .dot(normal);\n        if (proposedSide > safeRadius + skin + 1e-3) return null;\n        return { position, normal };\n    }\n\n    /**\n     * Choose a walkable photoreal floor without confusing roofs with terrain.\n     * The ordinary scene/overlay sampler intentionally selects the outermost\n     * visible skin. Locomotion has a different contract: it may step only a\n     * small distance above the previously occupied floor, while arbitrarily\n     * large downward changes remain valid. Building sides are handled by the\n     * horizontal capsule sweep above.\n     */\n    _selectWalkablePhotoGroundRadius(validHits, referenceGroundR, maxStepUp = null) {\n        if (!Array.isArray(validHits) || validHits.length === 0) return null;\n        if (!Number.isFinite(referenceGroundR)) return this._selectPhotoGroundRadius(validHits);\n\n        const stepUp = Number.isFinite(maxStepUp)\n            ? Math.max(0, maxStepUp)\n            : Math.max(0, Number(this.SURFACE_MAX_WALKABLE_STEP) || 0.55);\n        const slopeDot = Number.isFinite(this.SURFACE_MAX_WALKABLE_SLOPE_DOT)\n            ? this.SURFACE_MAX_WALKABLE_SLOPE_DOT\n            : 0.58;\n        const ceilingR = referenceGroundR + stepUp;\n        let bestCenter = null;\n        let bestFallback = null;\n        let nearestOffset = Infinity;\n\n        for (const hit of validHits) {\n            if (!Number.isFinite(hit?.r) || hit.r > ceilingR + 1e-4) continue;\n            if (Number.isFinite(hit.radialNormalDot) && hit.radialNormalDot < slopeDot) continue;\n            if (hit.isCenter) {\n                bestCenter = Number.isFinite(bestCenter) ? Math.max(bestCenter, hit.r) : hit.r;\n                continue;\n            }\n            const offset = Number.isFinite(hit.offsetM) ? hit.offsetM : Infinity;\n            if (offset < nearestOffset - 1e-3) {\n                nearestOffset = offset;\n                bestFallback = hit.r;\n            } else if (Math.abs(offset - nearestOffset) <= 1e-3) {\n                bestFallback = Number.isFinite(bestFallback) ? Math.max(bestFallback, hit.r) : hit.r;\n            }\n        }\n        return Number.isFinite(bestCenter) ? bestCenter : bestFallback;\n    }\n\n    /**\n     * Infer the pedestrian ground beneath an unverified boot skin.\n     *\n     * Each exterior ray contributes its lowest slope-valid surface. Small\n     * RANSAC-style affine fits then distinguish a broad terrain plane from\n     * built-up or foliage skins. Four inliers with support in both ENU axes\n     * are required, and the inferred plane must have a matching slope-valid\n     * intersection on the exact center ray. Neighboring low terrain can\n     * therefore classify the scene, but can never pull the camera through an\n     * unsupported center surface. The outermost center skin remains separate\n     * obstacle/picking context after pedestrian ground is established; it is\n     * not a radial floor.\n     */\n    _inferInitialWalkablePhotoGroundRadius(\n        validHits,\n        referenceGroundR,\n        { allowSupportedRise = false } = {}\n    ) {\n        if (!Array.isArray(validHits) || !Number.isFinite(referenceGroundR)) return null;\n        const slopeDot = Number.isFinite(this.SURFACE_MAX_WALKABLE_SLOPE_DOT)\n            ? Math.max(0.05, Math.min(1, this.SURFACE_MAX_WALKABLE_SLOPE_DOT))\n            : 0.58;\n        const maxGradient = Math.sqrt(Math.max(0, (1 / (slopeDot * slopeDot)) - 1));\n        const perRay = new Map();\n\n        for (const hit of validHits) {\n            if (!hit || hit.isCenter || !Number.isFinite(hit.r)\n                || !Number.isFinite(hit.dE) || !Number.isFinite(hit.dN)) continue;\n            if (Number.isFinite(hit.radialNormalDot) && hit.radialNormalDot < slopeDot) continue;\n            const key = hit.sampleKey || `${hit.dE}:${hit.dN}`;\n            const previous = perRay.get(key);\n            if (!previous || hit.r < previous.r) perRay.set(key, hit);\n        }\n\n        const points = Array.from(perRay.values());\n        if (points.length < 4) return null;\n        const residualToleranceM = 1.5;\n        const minimumAxisSpanM = 25;\n        let best = null;\n\n        const fitThree = (p0, p1, p2) => {\n            const x1 = p1.dE - p0.dE;\n            const y1 = p1.dN - p0.dN;\n            const z1 = p1.r - p0.r;\n            const x2 = p2.dE - p0.dE;\n            const y2 = p2.dN - p0.dN;\n            const z2 = p2.r - p0.r;\n            const determinant = x1 * y2 - y1 * x2;\n            if (Math.abs(determinant) < 1e-5) return null;\n            const a = (z1 * y2 - y1 * z2) / determinant;\n            const b = (x1 * z2 - z1 * x2) / determinant;\n            const c = p0.r - a * p0.dE - b * p0.dN;\n            if (![a, b, c].every(Number.isFinite)\n                || Math.hypot(a, b) > maxGradient + 1e-4) return null;\n            return { a, b, c };\n        };\n\n        for (let i = 0; i < points.length - 2; i += 1) {\n            for (let j = i + 1; j < points.length - 1; j += 1) {\n                for (let k = j + 1; k < points.length; k += 1) {\n                    const plane = fitThree(points[i], points[j], points[k]);\n                    if (!plane) continue;\n                    const inliers = points.filter((point) => Math.abs(\n                        point.r - (plane.a * point.dE + plane.b * point.dN + plane.c)\n                    ) <= residualToleranceM);\n                    if (inliers.length < 4) continue;\n\n                    let minE = Infinity;\n                    let maxE = -Infinity;\n                    let minN = Infinity;\n                    let maxN = -Infinity;\n                    let maxOffsetM = 0;\n                    for (const point of inliers) {\n                        minE = Math.min(minE, point.dE);\n                        maxE = Math.max(maxE, point.dE);\n                        minN = Math.min(minN, point.dN);\n                        maxN = Math.max(maxN, point.dN);\n                        maxOffsetM = Math.max(maxOffsetM, Math.hypot(point.dE, point.dN));\n                    }\n                    const eastSpanM = maxE - minE;\n                    const northSpanM = maxN - minN;\n                    if (eastSpanM < minimumAxisSpanM || northSpanM < minimumAxisSpanM) continue;\n\n                    // Refit c from all inliers while retaining the candidate\n                    // slopes. This removes sub-metre photogrammetry noise at\n                    // the predicted centre without allocating a matrix solver.\n                    let interceptSum = 0;\n                    for (const point of inliers) {\n                        interceptSum += point.r - plane.a * point.dE - plane.b * point.dN;\n                    }\n                    const centerR = interceptSum / inliers.length;\n                    const supportArea = eastSpanM * northSpanM;\n                    const candidate = {\n                        radius: centerR,\n                        inlierCount: inliers.length,\n                        supportArea,\n                        maxOffsetM,\n                    };\n                    if (!best\n                        || candidate.inlierCount > best.inlierCount\n                        || (candidate.inlierCount === best.inlierCount\n                            && candidate.supportArea > best.supportArea + 1e-3)\n                        || (candidate.inlierCount === best.inlierCount\n                            && Math.abs(candidate.supportArea - best.supportArea) <= 1e-3\n                            && candidate.maxOffsetM > best.maxOffsetM + 1e-3)\n                        || (candidate.inlierCount === best.inlierCount\n                            && Math.abs(candidate.supportArea - best.supportArea) <= 1e-3\n                            && Math.abs(candidate.maxOffsetM - best.maxOffsetM) <= 1e-3\n                            && candidate.radius < best.radius)) {\n                        best = candidate;\n                    }\n                }\n            }\n        }\n\n        if (!best || !Number.isFinite(best.radius)) return null;\n        const maxStepUp = Math.max(0, Number(this.SURFACE_MAX_WALKABLE_STEP) || 0.55);\n        if (!allowSupportedRise && best.radius > referenceGroundR + maxStepUp) return null;\n\n        // The exterior plane is evidence, not permission to move the camera\n        // radially at a different coordinate. Require the same terrain plane\n        // to exist beneath the exact camera ray and return that real mesh\n        // intersection rather than the fitted estimate.\n        const centerToleranceM = 2.0;\n        let centerGroundR = null;\n        let centerResidualM = Infinity;\n        for (const hit of validHits) {\n            if (!hit?.isCenter || !Number.isFinite(hit.r)) continue;\n            if (Number.isFinite(hit.radialNormalDot) && hit.radialNormalDot < slopeDot) continue;\n            const residualM = Math.abs(hit.r - best.radius);\n            if (residualM > centerToleranceM) continue;\n            if (residualM < centerResidualM - 1e-4\n                || (Math.abs(residualM - centerResidualM) <= 1e-4\n                    && (!Number.isFinite(centerGroundR) || hit.r > centerGroundR))) {\n                centerResidualM = residualM;\n                centerGroundR = hit.r;\n            }\n        }\n        return centerGroundR;\n    }\n\n    resetPhotorealGroundCache(reason = 'reset') {\n        this._photoTerrainRadius = null;\n        this._photoGroundEmaR = null;\n        this._photoGroundEmaAt = 0;\n        this._photoGroundFrameIdx = null;\n        this._photoGroundLastRawR = null;\n        this._photoLastKnownReferenceR = null;\n        this._photoWalkableReferenceR = null;\n        this._photoCenterSkinR = null;\n        this._photoCenterSkinLocalDir = null;\n        this._photoCenterSkinModelSeq = null;\n        this._lastGroundSampleCenterSkinR = null;\n        this._groundTruthCacheR = null;\n        this._groundTruthCacheAt = 0;\n        this._groundTruthCacheLocalDir = null;\n        this._groundTruthSampleModelSeq = null;\n        this._photoWalkableSeedPending = false;\n        this._lastGroundSampleEstablishedWalkablePlane = false;\n        this._photoFlightGroundR = null;\n        this._photoFlightGroundAt = 0;\n        this._photoFlightGroundLocalDir = null;\n        this._photoFlightGroundModelSeq = null;\n        this._photoFlightGroundCameraR = null;\n        this._lastSafeGroundR = null;\n        this._lastSafeUpDir = null;\n        this._cameraFloorClampAt = 0;\n        this._cameraFloorClampRadius = null;\n        this._groundTruthLastStationary = false;\n        this._groundTruthLastHorizontalDistSq = Infinity;\n        this._bodyClearanceSignature = null;this._bodyClearanceCachedLocal = null;\n        this._photoGroundFrameDir = null;this._photoGroundFrameModelSeq = null;\n        this._photorealGroundCacheResetReason = reason;\n    }\n\n    _getAltitudeClampMin(worldDir = this.surfaceState?.up) {\n        if (this.cameraMode === 'surface' && this._isOceanForDir(worldDir)) {\n            return this._getNavigationFloorAltitude(worldDir);\n        }\n        const absoluteMin = this._getAbsoluteMinAltitude();\n        const baseMin = Number.isFinite(this.SURFACE_ALTITUDE_MIN)\n            ? this.SURFACE_ALTITUDE_MIN\n            : absoluteMin;\n        return Math.max(absoluteMin, baseMin);\n    }\n\n    _getSafeTerrainRadiusForDir(dir, { useSample = false } = {}) {\n        const ellipsoidR = this._getEllipsoidRadiusForDir(dir);\n        let terrainR = null;\n        if (useSample) {\n            terrainR = this.sampleTerrainRadiusForDir(dir);\n        } else {\n            terrainR = Number.isFinite(this._terrainRadiusRaw)\n                ? this._terrainRadiusRaw\n                : this._terrainRadius;\n        }\n        if (!Number.isFinite(terrainR)) {\n            terrainR = ellipsoidR;\n        }\n        return Math.max(terrainR, ellipsoidR);\n    }\n\n    /**\n     * Use the same translation sources for navigation and photoreal ground\n     * caching. Mobile analog movement was previously absent here, so a moving\n     * phone camera could be treated as stationary and retain the prior\n     * footprint's elevation for the 30-second idle cache lifetime.\n     */\n    _hasSurfaceMovementIntent() {\n        const k = this.keyState;\n        const keyboard = !!(k && (\n            k.w || k.a || k.s || k.d || k.q || k.e ||\n            k.arrowup || k.arrowdown || k.arrowleft || k.arrowright || k.space\n        ));\n        const mobileX = Number(this.mobileMoveInput?.x) || 0;\n        const mobileY = Number(this.mobileMoveInput?.y) || 0;\n        const mobile = Math.abs(mobileX) > 1e-4 || Math.abs(mobileY) > 1e-4;\n        const xr = Math.abs(Number(this._xrLocomotionInput?.forward) || 0) > 1e-4\n            || Math.abs(Number(this._xrLocomotionInput?.right) || 0) > 1e-4\n            || Math.abs(Number(this._xrLocomotionInput?.vertical) || 0) > 1e-4;\n        const coasting = Number.isFinite(this._moveSpeed) && this._moveSpeed > 1e-4;\n        const geoTranslation = !!(this.geoNav?.active && (\n            this.geoNav.action === 'pan' ||\n            this.geoNav.action === 'surface-pan' ||\n            this.geoNav.action === 'drag'\n        ));\n        return keyboard || mobile || xr || coasting || geoTranslation ||\n            !!this._isJumping || !!this._jumpRequested;\n    }\n\n    /**\n     * Compute a temporally-smoothed photo tile ground radius for the given\n     * world position. Single source of truth for \"where is the ground?\"\n     * when photo tiles are active. Both _enforceCameraAboveTerrain and\n     * applySurfaceCamera read through this helper.\n     *\n     * Smoothing policy: upward readings are authoritative immediately;\n     * stationary downward changes ease to avoid LOD-swap bobbing. A camera\n     * may temporarily float above a retiring surface, but it must never wait\n     * below a newly rendered surface. Moving users track the active center\n     * hit directly so commanded AGL remains physical AGL.\n     *\n     * Per-frame caching: several code paths call this helper during one\n     * animation frame (applySurfaceCamera + _enforceCameraAboveTerrain +\n     * cloud elevation feed). Caching by frameClock.frameIndex guarantees\n     * they all see the identical value within a frame, so the camera\n     * transform is stable across those callers.\n     *\n     * @param {THREE.Vector3} seedPos world-space camera position\n     * @returns {number|null} smoothed ground radius, null if no cache + no sample\n     */\n    _getSmoothedPhotoGroundRadius(seedPos) {\n        if (!this.terrainTileGroup || !seedPos) return null;\n\n        // Per-frame cache: return the same value to every caller within\n        // a single animation frame. This prevents multiple call sites\n        // from each seeing a different sampler snapshot and placing the\n        // camera at disagreeing heights within one frame.\n        const fi = (typeof globalThis !== 'undefined'\n            && globalThis.__noclipAsync?.harness?.frameClock?.getFrameState?.())?.frameIndex;\n        const modelSeq = this.terrainTileGroup.userData?.photoModelChangeSeq | 0;\n        const frameDirection = this._toPlanetLocalDirection(seedPos,\n            this._photoGroundFrameProbeDir ||= new THREE.Vector3()).normalize();\n        if (Number.isFinite(fi) && this._photoGroundFrameIdx === fi\n            && this._photoGroundFrameModelSeq === modelSeq && this._photoGroundFrameDir\n            && frameDirection.distanceToSquared(this._photoGroundFrameDir) * PLANET_RADIUS * PLANET_RADIUS < 1e-8\n            && Number.isFinite(this._photoGroundEmaR)) {\n            return this._photoGroundEmaR;\n        }\n\n        const nowMs = performance.now();\n        const commandedAlt = Number.isFinite(this.surfaceAltitudeMeters)\n            ? this.surfaceAltitudeMeters\n            : this.SURFACE_EYE_HEIGHT;\n        let cached = this._photoGroundEmaR;\n        let groundR = this._sampleGroundTruthRadius(seedPos);\n        if (!Number.isFinite(groundR) || groundR < 1e6) {\n            // Camera radius is NOT a ground sample. Treating it as one adds the\n            // commanded AGL again on every cache miss. Hold a previously\n            // verified tile radius until active underfoot geometry returns.\n            groundR = Number.isFinite(this._photoWalkableReferenceR)\n                ? this._photoWalkableReferenceR\n                : (Number.isFinite(this._photoLastKnownReferenceR)\n                    ? this._photoLastKnownReferenceR\n                    : (Number.isFinite(cached) ? cached : this._lastSafeGroundR));\n        }\n        if (!Number.isFinite(cached) && Number.isFinite(groundR)) {\n            // First valid sample: seed the EMA from the TRUE ground radius\n            // (the photoreal surface), not the camera position. Seeding from\n            // the camera position captures ellipsoidR + aglTarget (sea level),\n            // which is ~10 m below the real surface; the stationary branch\n            // then treats every upward correction as noise and holds that\n            // wrong value forever, forcing the camera to be clamped up to the\n            // jittery terrain mesh each frame. Seeding from groundR makes the\n            // EMA track the real surface from frame 1.\n            cached = groundR;\n            this._photoGroundEmaR = (Number.isFinite(groundR) && groundR > 1e6) ? groundR : (Number.isFinite(this._lastSafeGroundR) ? this._lastSafeGroundR : groundR);\n            this._photoLastKnownReferenceR = groundR;\n            this._photoWalkableReferenceR = groundR;\n        }\n        const stationary = this._groundTruthLastStationary === true;\n        const cachedAt = this._photoGroundEmaAt || 0;\n        const cachedAge = nowMs - cachedAt;\n        const HOLD_STALE_MS = 5000;\n        const STATIONARY_SAMPLE_DEADBAND_M = 2.0;\n        const STATIONARY_MAX_STEP_M = 0.35;\n        const NEAR_GROUND_SNAP_ALT_M = Math.max(\n            3,\n            Number.isFinite(this.SURFACE_HUG_EXIT_ALT) ? this.SURFACE_HUG_EXIT_ALT : 8\n        );\n\n        if (Number.isFinite(groundR)) {\n            // Direct surface navigation is position-authoritative. Applying\n            // the photo-ground EMA while the user is dragging or scrolling\n            // makes their commanded altitude visibly lag and then drift after\n            // input stops. Seed from the current ground sample instead so\n            // the camera radius and the URL/state altitude agree this frame.\n            const directSurfaceCommand = this._surfaceDragAGLLock\n                || this.geoNav?.active\n                || nowMs < this._surfaceScrollHoldUntil;\n            if (directSurfaceCommand) {\n                this._photoGroundEmaR = groundR;\n                this._photoGroundEmaAt = nowMs;\n                this._photoGroundFrameIdx = fi;\n                this._photoGroundFrameModelSeq = modelSeq;\n                (this._photoGroundFrameDir ||= new THREE.Vector3()).copy(frameDirection);\n                this._photoGroundLastRawR = groundR;\n                this._photoLastKnownReferenceR = groundR;\n                this._photoWalkableReferenceR = groundR;\n                return groundR;\n            }\n            const delta = Number.isFinite(cached) ? groundR - cached : 0;\n            let next = groundR;\n            if (Number.isFinite(cached)) {\n                if (delta > 0) {\n                    // The active underfoot surface rose. Adopt it before camera\n                    // placement in this same frame; confirmation delays leave\n                    // the eye physically inside a newly refined tile.\n                    next = groundR;\n                } else if (stationary) {\n                    if (delta < -STATIONARY_SAMPLE_DEADBAND_M\n                        && Number.isFinite(commandedAlt)\n                        && commandedAlt <= NEAR_GROUND_SNAP_ALT_M) {\n                        // True descent toward the ground — follow it down so we\n                        // don't clip into terrain.\n                        next = groundR;\n                    } else if (Math.abs(delta) < STATIONARY_SAMPLE_DEADBAND_M) {\n                        // A small downward difference under a stationary\n                        // camera is usually LOD noise. Hold the higher cached\n                        // reference so safety and visual stability agree.\n                        next = cached;\n                    } else if (delta < 0) {\n                        // Large downward drop beyond the deadband: ease down\n                        // slowly (capped per-frame step) as a safety net.\n                        next = cached + THREE.MathUtils.clamp(delta, -STATIONARY_MAX_STEP_M, 0);\n                    }\n                } else {\n                    // While walking/dragging, the currently rendered center\n                    // surface is the contact constraint, not a lagging EMA.\n                    next = groundR;\n                }\n            }\n            // Always commit the resolved floor. The old stationary guard\n            // returned a higher value once but left the stored EMA below the\n            // tile, so the next caller in the same frame could place the\n            // camera underground again.\n            this._photoGroundEmaR = next;\n            this._photoGroundEmaAt = nowMs;\n            this._photoGroundFrameIdx = fi;\n            this._photoGroundFrameModelSeq = modelSeq;\n            (this._photoGroundFrameDir ||= new THREE.Vector3()).copy(frameDirection);\n            this._photoGroundLastRawR = groundR;\n            // Also refresh the last-known reference used by callers as\n            // a final safety net when both EMA and raw are unavailable.\n            this._photoLastKnownReferenceR = next;\n            this._photoWalkableReferenceR = next;\n            return next;\n        }\n        if (Number.isFinite(cached) && cachedAge < HOLD_STALE_MS) {\n            this._photoGroundFrameIdx = fi;\n            this._photoGroundFrameModelSeq = modelSeq;\n            (this._photoGroundFrameDir ||= new THREE.Vector3()).copy(frameDirection);\n            return cached;\n        }\n        // Cache stale or never seeded — invalidate the EMA but KEEP the\n        // last raw reading and the last-known reference so callers still\n        // have something to hold against. This is the critical \"never\n        // fall below tiles\" guarantee: once we have seen ground once, we\n        // never forget it, even if the sampler goes silent for extended\n        // periods. Only resetting happens when the user explicitly exits\n        // surface/photo-tile mode.\n        this._photoGroundEmaR = null;\n        return null;\n    }\n\n    /**\n     * The most recent RAW (unfiltered) photo-tile ground sample. Used by\n     * the safety clamp to guarantee the camera is never below a verified\n     * ground hit, even if the EMA hasn't caught up yet.\n     * @returns {number|null}\n     */\n    _getLastRawPhotoGroundRadius() {\n        return Number.isFinite(this._photoGroundLastRawR) ? this._photoGroundLastRawR : null;\n    }\n\n    _recordPhotoCenterSkinRadius(radius, worldUp, modelSeq = null) {\n        if (!Number.isFinite(radius) || !worldUp) return false;\n        this._photoCenterSkinR = radius;\n        this._lastGroundSampleCenterSkinR = radius;\n        this._photoCenterSkinModelSeq = Number.isFinite(modelSeq) ? modelSeq : null;\n        this._photoCenterSkinLocalDir = this._photoCenterSkinLocalDir || new THREE.Vector3();\n        this._toPlanetLocalDirection(worldUp, this._photoCenterSkinLocalDir).normalize();\n        return true;\n    }\n\n    _getPhotoCenterSkinRadiusForDirection(\n        worldUp,\n        footprintRadiusM = PHOTO_CONTACT_REUSE_RADIUS_M\n    ) {\n        if (!worldUp || !Number.isFinite(this._photoCenterSkinR)\n            || !this._photoCenterSkinLocalDir) return null;\n        this._photoCenterSkinCheckDir = this._photoCenterSkinCheckDir || new THREE.Vector3();\n        this._toPlanetLocalDirection(worldUp, this._photoCenterSkinCheckDir).normalize();\n        const horizontalDistanceSq = this._photoCenterSkinLocalDir\n            .distanceToSquared(this._photoCenterSkinCheckDir)\n            * PLANET_RADIUS * PLANET_RADIUS;\n        return horizontalDistanceSq <= footprintRadiusM * footprintRadiusM\n            ? this._photoCenterSkinR\n            : null;\n    }\n\n    _invalidatePhotoSafeFloorForDirection(\n        worldUp,\n        footprintRadiusM = PHOTO_CONTACT_REUSE_RADIUS_M\n    ) {\n        if (!worldUp) return false;\n        this._upLocalCheck = this._upLocalCheck || new THREE.Vector3();\n        this._toPlanetLocalDirection(worldUp, this._upLocalCheck).normalize();\n        const limitSq = footprintRadiusM * footprintRadiusM;\n        let invalidated = false;\n        if (Number.isFinite(this._lastSafeGroundR) && this._lastSafeUpDir) {\n            const safeDistanceSq = this._lastSafeUpDir.distanceToSquared(this._upLocalCheck)\n                * PLANET_RADIUS * PLANET_RADIUS;\n            if (safeDistanceSq > limitSq) {\n                this._lastSafeGroundR = null;\n                this._lastSafeUpDir = null;\n                invalidated = true;\n            }\n        }\n        if (Number.isFinite(this._photoCenterSkinR) && this._photoCenterSkinLocalDir) {\n            const skinDistanceSq = this._photoCenterSkinLocalDir.distanceToSquared(this._upLocalCheck)\n                * PLANET_RADIUS * PLANET_RADIUS;\n            if (skinDistanceSq > limitSq) {\n                this._photoCenterSkinR = null;\n                this._photoCenterSkinLocalDir = null;\n                this._photoCenterSkinModelSeq = null;\n                invalidated = true;\n            }\n        }\n        return invalidated;\n    }\n\n    _resolvePhotoGroundFloorRadius(smoothedGround, rawGround, worldUp = null) {\n        // Camera height follows the continuity- and slope-validated pedestrian\n        // plane, never the outermost center skin. Photoreal roofs, trees, and\n        // facade caps are legitimate collision geometry but are not stairs.\n        // `_sampleGroundTruthRadius` has already reduced raw hits to a walkable\n        // continuation when walking is active; the separately retained center\n        // skin remains available to horizontal obstacle/click systems only.\n        let floorR = null;\n        if (Number.isFinite(smoothedGround)) {\n            floorR = smoothedGround;\n        }\n        if (Number.isFinite(rawGround)) {\n            floorR = Number.isFinite(floorR) ? Math.max(floorR, rawGround) : rawGround;\n        }\n        if (!Number.isFinite(floorR) && Number.isFinite(this._photoLastKnownReferenceR)) {\n            floorR = this._photoLastKnownReferenceR;\n        }\n        // At one geographic footprint the verified floor is monotonic. A\n        // refining child may sit above its parent, but a retiring child or a\n        // transient empty sample must never lower the camera through geometry.\n        // applySurfaceCamera clears this value after real horizontal travel,\n        // allowing legitimate downhill movement to establish a new floor.\n        if (Number.isFinite(this._lastSafeGroundR)) {\n            floorR = Number.isFinite(floorR)\n                ? Math.max(floorR, this._lastSafeGroundR)\n                : this._lastSafeGroundR;\n        }\n        return floorR;\n    }\n\n    _enforceCameraAboveTerrain({ minClearance = null, useSample = false, anchor = null, syncAltitude = false } = {}) {\n        const target = anchor && anchor.position ? anchor.position : this.camera?.position;\n        if (!target) return false;\n        const pos = target;\n        if (pos.lengthSq() < 1e-8) return false;\n\n        // Ocean navigation intentionally permits crossing the sea-level\n        // surface. Keep a bounded radial safety floor, but do not let the\n        // terrain/photo ground gates snap a swimmer back above the water.\n        const oceanDir = this._vA.copy(pos).normalize();\n        const commandedAltitude = Number.isFinite(this.surfaceAltitudeMeters)\n            ? this.surfaceAltitudeMeters\n            : Infinity;\n        if (this.cameraMode === 'surface'\n            && commandedAltitude < this._getSurfaceFloorAltitude()\n            && this._isOceanForDir(oceanDir)) {\n            const ellipsoidR = this._getEllipsoidRadiusForDir(oceanDir);\n            const seaHeight = this._getOceanDescriptorForDir(oceanDir)?.seaLevelEllipsoidMeters || 0;\n            const minR = ellipsoidR + seaHeight + this._getNavigationFloorAltitude(oceanDir);\n            if (pos.length() < minR) {\n                pos.copy(oceanDir).multiplyScalar(minR);\n                if (anchor?.updateMatrixWorld) anchor.updateMatrixWorld(true);\n                this.surfaceAltitudeMeters = minR - ellipsoidR - seaHeight;\n                this.surfaceAltitudeMSL = minR - ellipsoidR;\n                this._updateOceanNavigationState(oceanDir);\n                return true;\n            }\n            if (syncAltitude) {\n                this.surfaceAltitudeMeters = pos.length() - ellipsoidR - seaHeight;\n                this.surfaceAltitudeMSL = pos.length() - ellipsoidR;\n            }\n            this._updateOceanNavigationState(oceanDir);\n            return false;\n        }\n\n        // BYPASS when photorealistic tiles are active in surface mode.\n        //\n        // Google's photo tiles bake buildings INTO the terrain mesh, so a\n        // single downward raycast can't distinguish street from rooftop —\n        // the \"terrain radius\" for a point over a street might be the roof\n        // of an adjacent building, which would push the camera up and block\n        // street-level navigation.\n        //\n        // Photo tile mode: clamp against the shared smoothed ground but\n        // NEVER lower the floor to sea level if we don't have sampler\n        // data. The previous implementation fell back to ellR + 1 on\n        // null readings, which collapsed the camera to sea level in any\n        // city with elevation every time the sampler was briefly empty\n        // (tile loading, LOD swap, camera move into new area).\n        if (this.terrainTileGroup && this.cameraMode === 'surface') {\n            if (!this._isSurfaceWalkingTopologyActive()) return false;\n            const dir0 = this._vA.copy(pos).normalize();\n            this._invalidatePhotoSafeFloorForDirection(dir0);\n            const ellR = this._getEllipsoidRadiusForDir(dir0);\n            const smoothedGround = this._getSmoothedPhotoGroundRadius(pos);\n            const rawGround = this._getLastRawPhotoGroundRadius();\n\n            // The active raw CENTER hit is a hard upward constraint; the\n            // smoothed value is retained only when it is higher, so downward\n            // LOD changes can settle without a down/up flap. This guarantees\n            // the commanded clearance is measured above visible geometry,\n            // not above an older low-detail ring sample.\n            const floorR = this._resolvePhotoGroundFloorRadius(smoothedGround, rawGround, dir0);\n\n            if (!Number.isFinite(floorR)) {\n                // No ground data at all AND no previous reference.\n                // Refuse to clamp — the camera stays where the motion\n                // path left it. Still enforce the ellipsoid + 1 m\n                // sanity floor (camera should never be below sea level).\n                const sanityMin = ellR + 1;\n                if (pos.length() < sanityMin) {\n                    pos.copy(dir0).multiplyScalar(sanityMin);\n                    if (anchor?.updateMatrixWorld) anchor.updateMatrixWorld(true);\n                    return true;\n                }\n                return false;\n            }\n\n            // Honor caller-provided minClearance so the post-placement\n            // gate from applySurfaceCamera (photoreal) keeps the\n            // camera at the requested eye-height above ground, not\n            // just at the absolute minimum 0.5 m.\n            const photoClearance = Number.isFinite(minClearance) && minClearance > 0\n                ? minClearance\n                : 0.5;\n\n            const bodyClearance = this._getPhotoBodyClearance(floorR, dir0, photoClearance);\n            const minR = Number.isFinite(floorR)\n                // A verified photoreal floor may be below the reference\n                // ellipsoid. Reapplying an `ellR + 1` floor here leaves the\n                // camera hovering by the full geoid/ellipsoid separation\n                // even though the center tile hit is valid. The ellipsoid\n                // sanity fallback belongs only to the no-hit branch above.\n                ? floorR + photoClearance + bodyClearance\n                : null;\n\n            let clamped = false;\n            if (Number.isFinite(minR) && pos.length() < minR) {\n                pos.copy(dir0).multiplyScalar(minR);\n                if (anchor?.updateMatrixWorld) anchor.updateMatrixWorld(true);\n                clamped = true;\n            }\n\n            // _lastSafeUpDir is stored in PLANET-LOCAL frame so the travel\n            // check is invariant to Earth rotation. Preserve the original\n            // footprint direction until it is invalidated; updating it every\n            // frame would make the two-metre radius a moving window that never\n            // expires during ordinary walking.\n            if (Number.isFinite(floorR)) {\n                const needsFootprintSeed = !Number.isFinite(this._lastSafeGroundR)\n                    || !this._lastSafeUpDir;\n                this._lastSafeGroundR = Number.isFinite(this._lastSafeGroundR)\n                    ? Math.max(this._lastSafeGroundR, floorR)\n                    : floorR;\n                if (needsFootprintSeed) {\n                    this._lastSafeUpDir = this._lastSafeUpDir || new THREE.Vector3();\n                    this._toPlanetLocalDirection(dir0, this._lastSafeUpDir).normalize();\n                }\n            }\n\n            // This helper is nominally an upward collision gate, but once a\n            // fresh exact center skin arrives at minimum surface AGL it also\n            // owns the first ellipsoid-fallback correction. Snap downward to\n            // the requested physical clearance instead of leaving the camera\n            // stranded metres above a legitimate sub-ellipsoid surface.\n            const commandedClearance = Number.isFinite(this.surfaceAltitudeMeters)\n                ? this.surfaceAltitudeMeters\n                : photoClearance;\n            const nearGroundContact = commandedClearance <= Math.max(\n                Number(this.SURFACE_HUG_EXIT_ALT) || 8,\n                Number(this.SURFACE_EYE_HEIGHT) || 1.6\n            );\n            const currentCenterSkinR = this._getPhotoCenterSkinRadiusForDirection?.(dir0);\n            const targetContactR = floorR + photoClearance + bodyClearance;\n            if (!clamped\n                && nearGroundContact\n                && Number.isFinite(currentCenterSkinR)\n                && pos.length() > targetContactR + 1e-4) {\n                pos.copy(dir0).multiplyScalar(targetContactR);\n                if (anchor?.updateMatrixWorld) anchor.updateMatrixWorld(true);\n                clamped = true;\n            }\n\n            if (syncAltitude) {\n                // Photoreal AGL remains the user's canonical command; floor\n                // refinement moves the physical camera to satisfy that value\n                // and must not rewrite it. MSL, however, describes the actual\n                // world-space camera radius and must be refreshed after every\n                // late clamp. Previously this branch returned without\n                // honoring syncAltitude, leaving the HUD/state pose stale\n                // until right-click drag called _syncSurfaceFromCamera().\n                this.surfaceAltitudeMSL = pos.length() - ellR;\n            }\n\n            return clamped;\n        }\n\n        const dir = this._vA.copy(pos).normalize();\n        let terrainR = null;\n        if (useSample) {\n            const now = performance.now();\n            const reuse = (now - this._cameraFloorClampAt) < this.SURFACE_TERRAIN_SAMPLE_MS\n                && Number.isFinite(this._cameraFloorClampRadius);\n            if (reuse) {\n                terrainR = this._cameraFloorClampRadius;\n            } else {\n                terrainR = this.sampleTerrainRadiusForDir(dir);\n                this._cameraFloorClampRadius = terrainR;\n                this._cameraFloorClampAt = now;\n            }\n        } else {\n            terrainR = Number.isFinite(this._terrainRadiusRaw)\n                ? this._terrainRadiusRaw\n                : this._terrainRadius;\n        }\n        const ellipsoidR = this._getEllipsoidRadiusForDir(dir);\n        if (!Number.isFinite(terrainR)) terrainR = ellipsoidR;\n        const safeTerrainR = Math.max(terrainR, ellipsoidR);\n\n        const baseClearance = Number.isFinite(minClearance)\n            ? minClearance\n            : this._getAbsoluteMinAltitude();\n        const clearance = Math.max(this._getAbsoluteMinAltitude(), baseClearance)\n            + (this.SURFACE_TERRAIN_CLEARANCE || 0);\n        const minR = safeTerrainR + clearance;\n        const radius = pos.length();\n        let clamped = false;\n        if (radius < minR) {\n            pos.copy(dir).multiplyScalar(minR);\n            if (anchor?.updateMatrixWorld) {\n                anchor.updateMatrixWorld(true);\n            }\n            clamped = true;\n        }\n\n        if (syncAltitude && this.cameraMode === 'surface') {\n            const radiusNow = pos.length();\n            const floorAlt = this._getSurfaceFloorAltitude();\n            const nextAlt = Math.max(\n                floorAlt,\n                radiusNow - safeTerrainR - (this.SURFACE_TERRAIN_CLEARANCE || 0)\n            );\n            this.surfaceAltitudeMeters = Number.isFinite(nextAlt) ? nextAlt : floorAlt;\n            const maxOffset = Number.isFinite(this.SURFACE_TERRAIN_MAX_OFFSET)\n                ? this.SURFACE_TERRAIN_MAX_OFFSET\n                : Infinity;\n            const terrainElev = THREE.MathUtils.clamp(\n                safeTerrainR - ellipsoidR,\n                -maxOffset,\n                maxOffset\n            );\n            if (this._surfaceDragMSLLock && Number.isFinite(this._surfaceDragLockedMSL)) {\n                this.surfaceAltitudeMSL = this._surfaceDragLockedMSL;\n            } else {\n                this.surfaceAltitudeMSL = terrainElev + this.surfaceAltitudeMeters + (this.SURFACE_TERRAIN_CLEARANCE || 0);\n            }\n            if (this._surfaceAutoMSLHoldActive && Number.isFinite(this.surfaceAltitudeMSL)) {\n                this._surfaceAutoMSLHold = this.surfaceAltitudeMSL;\n            }\n        }\n        return clamped;\n    }\n\n    _shouldHugSurface() {\n        if (this.cameraMode !== 'surface') return false;\n        if (this._isJumping) return false;\n        if (this._airborneMSLGlideActive) return false;\n        if (this.keyState?.q || this.keyState?.e) return false;\n        const altitude = this.surfaceAltitudeMeters ?? this.SURFACE_EYE_HEIGHT;\n        if (!Number.isFinite(altitude)) return false;\n        if (altitude < this._getSurfaceFloorAltitude() && this._isOceanForDir(this.surfaceState?.up)) {\n            this._hugActive = false;\n            return false;\n        }\n        const enterAlt = Number.isFinite(this.SURFACE_HUG_ENTER_ALT)\n            ? this.SURFACE_HUG_ENTER_ALT\n            : this.SURFACE_HUG_MAX_ALT;\n        const exitAlt = Number.isFinite(this.SURFACE_HUG_EXIT_ALT)\n            ? this.SURFACE_HUG_EXIT_ALT\n            : this.SURFACE_HUG_MAX_ALT;\n        if (this._hugActive) {\n            this._hugActive = altitude <= exitAlt;\n        } else {\n            this._hugActive = altitude <= enterAlt;\n        }\n        return this._hugActive;\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Camera application\n    // ──────────────────────────────────────────────────────────────\n\n    applySurfaceCamera(externalOwnerToken = null) {\n        this._applySurfaceCamera(externalOwnerToken);\n        this.commitVRRigPose();\n    }\n\n    _applySurfaceCamera(externalOwnerToken = null) {\n        // Black Sun framework: short-circuit when the scene is in\n        // metaverse mode — MetaverseScene owns camera placement there,\n        // and our Earth-relative writes would corrupt it.\n        if (_isMetaverseSceneMode()) return;\n        // Target noclip owns the camera directly. update() already observes\n        // this override; keep the two methods called separately by the main\n        // animation loop from writing a stale surface pose over it.\n        if (this._externalCameraOverride\n            && this._externalCameraOverrideOwner !== externalOwnerToken) return;\n        // An active surface grab owns a complete camera pose. Reapplying the\n        // ordinary terrain/ASL placement while the button is held would move\n        // the immutable picked point away from the cursor before rendering.\n        if (this.geoNav?.active\n            && this.geoNav.action === 'drag'\n            && this.geoNav.dragReady) {\n            this.camera?.updateMatrixWorld?.(true);\n            return;\n        }\n        const up = this.surfaceState.up;\n        this._updateOceanNavigationState(up);\n\n        // Photoreal surface mode has two altitude authorities. Gravity-bound\n        // walking follows a continuity-validated floor. Free flight follows a\n        // fixed WGS84 ASL shell; photoreal geometry is then sampled only for\n        // regional AGL telemetry and cannot write camera height.\n        if (this.terrainTileGroup) {\n            const minFloorPhoto = this._getAltitudeClampMin();\n            let aglTarget = Number.isFinite(this.surfaceAltitudeMeters)\n                ? this.surfaceAltitudeMeters\n                : minFloorPhoto;\n            if (!Number.isFinite(aglTarget)) aglTarget = minFloorPhoto;\n            const maxAlt = Number.isFinite(this.SURFACE_ALTITUDE_MAX)\n                ? this.SURFACE_ALTITUDE_MAX\n                : 100000;\n            const ellipsoidRPhoto = this._getEllipsoidRadiusForDir(up);\n            const referenceR = ellipsoidRPhoto;\n            const anchorPhoto = this._getCameraAnchor();\n            const anchorPosition = (anchorPhoto || this.camera).position;\n\n            // A restored/high-altitude surface pose enters free flight before\n            // any terrain query. This closes the one-frame window where a roof\n            // could become the placement floor during reload or mode handoff.\n            if (!this._airborneMSLGlideActive\n                && !this._isJumping\n                && aglTarget > this._getAirborneMSLGlideThreshold()) {\n                this._activateAirborneMSLGlide(\n                    Number.isFinite(this.surfaceAltitudeMSL)\n                        ? this.surfaceAltitudeMSL\n                        : this._computeCameraMSL(anchorPosition)\n                );\n            }\n\n            const walkingTopologyActive = this._isSurfaceWalkingTopologyActive();\n            let contactGround = null;\n            if (walkingTopologyActive) {\n                aglTarget = THREE.MathUtils.clamp(aglTarget, minFloorPhoto, maxAlt);\n                this._invalidatePhotoSafeFloorForDirection(up);\n                const contactProbe = (this._photoProposedContactPosition ||= new THREE.Vector3())\n                    .copy(up).multiplyScalar(anchorPosition.length());\n                const smoothedGround = this._getSmoothedPhotoGroundRadius(contactProbe);\n                const rawGround = this._getLastRawPhotoGroundRadius();\n                contactGround = this._resolvePhotoGroundFloorRadius(smoothedGround, rawGround, up);\n            } else {\n                contactGround = this._samplePhotoFlightGroundRadius(anchorPosition);\n            }\n            const oceanSwimming = aglTarget < this._getSurfaceFloorAltitude() && this._isOceanForDir(up);\n            // Ocean depth is MSL-relative, not seabed-relative. Photoreal\n            // meshes may contain bathymetry or an arbitrary water cap, so\n            // using their sampled radius here would move the swimmer when LOD\n            // changes and could place the camera beneath the collision floor.\n            let groundForPlacement = oceanSwimming\n                ? ellipsoidRPhoto + (this._getOceanDescriptorForDir(up)?.seaLevelEllipsoidMeters || 0)\n                : (Number.isFinite(contactGround) ? contactGround : referenceR);\n            const activeMSL = this._getActiveSurfaceMSL();\n            let mslOwnsPlacement = Number.isFinite(activeMSL) && (\n                this._airborneMSLGlideActive\n                || this._surfaceAltitudeReference === 'msl'\n                || this._surfaceDragMSLLock\n            );\n            let rPhoto = mslOwnsPlacement\n                ? ellipsoidRPhoto + activeMSL\n                : groundForPlacement + aglTarget;\n\n            // Regional terrain may eventually meet a level flight shell. It\n            // cannot lift the aircraft early, but at physical eye/floor contact\n            // it must prevent penetration and hand control back to walking.\n            if (this._airborneMSLGlideActive\n                && Number.isFinite(contactGround)\n                && rPhoto < contactGround + minFloorPhoto) {\n                this._clearAirborneMSLGlide();\n                this._photoWalkableReferenceR = contactGround;\n                this._photoGroundEmaR = contactGround;\n                this._photoGroundLastRawR = contactGround;\n                this._photoLastKnownReferenceR = contactGround;\n                this._lastSafeGroundR = contactGround;\n                aglTarget = minFloorPhoto;\n                groundForPlacement = contactGround;\n                rPhoto = contactGround + minFloorPhoto;\n                mslOwnsPlacement = false;\n                this.surfaceAltitudeMeters = minFloorPhoto;\n                this.surfaceAltitudeMSL = rPhoto - ellipsoidRPhoto;\n            }\n            if (mslOwnsPlacement) {\n                // AGL is informational in flight. It is intentionally allowed\n                // to vary as generalized terrain changes under a fixed ASL.\n                aglTarget = rPhoto - groundForPlacement - (this.SURFACE_TERRAIN_CLEARANCE || 0);\n                this.surfaceAltitudeMeters = aglTarget;\n                this.surfaceAltitudeMSL = activeMSL;\n            }\n            const useDeviceOrientation = this._updateFromDeviceSensors();\n\n            if (walkingTopologyActive && !mslOwnsPlacement && !oceanSwimming) {\n                rPhoto += this._getPhotoBodyClearance(contactGround, up, aglTarget);\n                rPhoto = this._stabilizeWalkingRadius(rPhoto, contactGround, up, minFloorPhoto, aglTarget);\n            } else {\n                this._walkingHeightHold = null;\n            }\n            const posPhoto = this._vC.copy(up).multiplyScalar(rPhoto);\n\n            // Device-orientation fast path for photo-tile mode.\n            //\n            // Apply the fully composed world-space quaternion DIRECTLY\n            // to the anchor. Do NOT route it through\n            // surfaceLookDir(yaw,pitch) → lookAt(target) → rollQuat\n            // multiply — that is a quaternion → Euler → quaternion\n            // round-trip which introduces gimbal-lock singularities at\n            // ±π/2 pitch and leaks pitch energy into yaw at large\n            // tilt angles. Mirror the terrain branch's pattern at\n            // line ~1411 exactly.\n            if (useDeviceOrientation) {\n                if (anchorPhoto === this.camera) {\n                    this.camera.position.copy(posPhoto);\n                    this.camera.up.copy(up);\n                    this.camera.quaternion.copy(this._deviceWorldQuat);\n                } else if (anchorPhoto) {\n                    anchorPhoto.position.copy(posPhoto);\n                    anchorPhoto.up.copy(up);\n                    anchorPhoto.quaternion.copy(this._deviceWorldQuat);\n                }\n                // Final upward gate against the photoreal ground —\n                // catches the first-frame-of-surface-mode case where\n                // the smoothed sampler hadn't seeded yet, and any\n                // race where the seed pos under-estimated the ground.\n                // Clamp is upward-only so it cannot cause descending\n                // jitter even on LOD-driven step changes.\n                if (!mslOwnsPlacement) {\n                    this._enforceCameraAboveTerrain({\n                        minClearance: aglTarget,\n                        useSample: true,\n                        anchor: anchorPhoto === this.camera ? null : anchorPhoto,\n                        syncAltitude: false\n                    });\n                    this.surfaceAltitudeMSL = (anchorPhoto || this.camera).position.length() - ellipsoidRPhoto;\n                }\n                return;\n            }\n\n            this.surfaceLookDir(this._look);\n            this._target.copy(posPhoto).add(this._look);\n            if (anchorPhoto === this.camera) {\n                this.camera.position.copy(posPhoto);\n                this.camera.up.copy(up);\n                this.camera.lookAt(this._target);\n                if (Math.abs(this.surfaceState.roll) > 0.001) {\n                    this._rollQuat.setFromAxisAngle(this._look, this.surfaceState.roll);\n                    this.camera.quaternion.multiply(this._rollQuat);\n                }\n            } else if (anchorPhoto) {\n                this._tmpObj.position.copy(posPhoto);\n                this._tmpObj.up.copy(up);\n                this._tmpObj.lookAt(this._target);\n                if (Math.abs(this.surfaceState.roll) > 0.001) {\n                    this._rollQuat.setFromAxisAngle(this._look, this.surfaceState.roll);\n                    this._tmpObj.quaternion.multiply(this._rollQuat);\n                }\n                anchorPhoto.position.copy(this._tmpObj.position);\n                anchorPhoto.quaternion.copy(this._tmpObj.quaternion);\n                anchorPhoto.up.copy(up);\n            }\n\n            // Final upward gate (see device-orientation branch above\n            // for rationale). aglTarget is passed as minClearance so\n            // the camera always stays at least 1.6 m (or the user's\n            // commanded altitude) above the photoreal ground after\n            // the gate runs.\n            if (!mslOwnsPlacement) {\n                this._enforceCameraAboveTerrain({\n                    minClearance: aglTarget,\n                    useSample: true,\n                    anchor: anchorPhoto === this.camera ? null : anchorPhoto,\n                    syncAltitude: false\n                });\n            }\n\n            // Surface MSL readout for HUD callers. We use the post-\n            // gate camera radius rather than the input aglTarget so\n            // the readout reflects the actual displayed altitude\n            // (camera radius - ellipsoid).\n            if (!mslOwnsPlacement) {\n                const postGateR = (anchorPhoto || this.camera).position.length();\n                this.surfaceAltitudeMSL = postGateR - ellipsoidRPhoto;\n            }\n            return;\n        }\n\n        this.updateSurfaceTerrainThrottled();\n\n        const useDeviceOrientation = this._updateFromDeviceSensors();\n\n        const minFloor = this._getNavigationFloorAltitude(up);\n        let altitude = Number.isFinite(this.surfaceAltitudeMeters) ? this.surfaceAltitudeMeters : minFloor;\n        if (!Number.isFinite(altitude) || altitude < minFloor) {\n            altitude = minFloor;\n            this.surfaceAltitudeMeters = altitude;\n        }\n        const ellipsoidR = this._getEllipsoidRadiusForDir(up);\n        const oceanSwimming = altitude < this._getSurfaceFloorAltitude() && this._isOceanForDir(up);\n        const terrainBasisR = oceanSwimming\n            ? ellipsoidR + (this._getOceanDescriptorForDir(up)?.seaLevelEllipsoidMeters || 0)\n            : Math.max(\n            Number.isFinite(this._terrainRadius)\n                ? this._terrainRadius\n                : (Number.isFinite(this._terrainRadiusRaw) ? this._terrainRadiusRaw : PLANET_RADIUS),\n            ellipsoidR\n        );\n        const terrainElev = terrainBasisR - ellipsoidR;\n        const clearance = this.SURFACE_TERRAIN_CLEARANCE || 0;\n        let r = terrainBasisR + altitude + clearance;\n        const activeMSL = this._getEffectiveSurfaceMSL(altitude);\n        const mslOwnsPlacement = Number.isFinite(activeMSL) && (\n            this._airborneMSLGlideActive\n            || this._surfaceAltitudeReference === 'msl'\n            || this._surfaceDragMSLLock\n            || this._surfaceAutoMSLHoldActive\n        );\n        if (Number.isFinite(activeMSL)) {\n            r = ellipsoidR + activeMSL;\n            if (this._surfaceDragMSLLock && Number.isFinite(this._surfaceDragLockedMSL)) {\n                this.surfaceAltitudeMSL = this._surfaceDragLockedMSL;\n            }\n            if (!this._airborneMSLGlideActive) {\n                const floorTerrainR = Math.max(\n                    Number.isFinite(this._terrainRadiusRaw) ? this._terrainRadiusRaw : terrainBasisR,\n                    ellipsoidR\n                );\n                const minRadius = floorTerrainR + minFloor + clearance;\n                if (r < minRadius) {\n                    r = minRadius;\n                    const clampedMsl = r - ellipsoidR;\n                    if (!(this._surfaceDragMSLLock && Number.isFinite(this._surfaceDragLockedMSL))) {\n                        this.surfaceAltitudeMSL = clampedMsl;\n                    }\n                    if (this._surfaceAutoMSLHoldActive && Number.isFinite(clampedMsl)) {\n                        this._surfaceAutoMSLHold = clampedMsl;\n                    }\n                }\n            }\n            altitude = this._airborneMSLGlideActive\n                ? r - terrainBasisR - clearance\n                : Math.max(minFloor, r - terrainBasisR - clearance);\n            this.surfaceAltitudeMeters = altitude;\n        } else {\n            this.surfaceAltitudeMSL = terrainElev + altitude + clearance;\n        }\n        const pos = this._vC.copy(up).multiplyScalar(r);\n\n        if (useDeviceOrientation) {\n            const anchor = this._getCameraAnchor();\n            if (anchor) {\n                anchor.position.copy(pos);\n                anchor.up.copy(up);\n                anchor.quaternion.copy(this._deviceWorldQuat);\n            }\n            if (!mslOwnsPlacement) {\n                this._enforceCameraAboveTerrain({\n                    minClearance: minFloor,\n                    useSample: true,\n                    anchor,\n                    syncAltitude: true\n                });\n            }\n            return;\n        }\n\n        this.surfaceLookDir(this._look);\n        this._target.copy(pos).add(this._look);\n\n        const anchor = this._getCameraAnchor();\n        if (anchor === this.camera) {\n            this.camera.position.copy(pos);\n            this.camera.up.copy(up);\n            this.camera.lookAt(this._target);\n\n            // Apply roll rotation around the look direction (camera's local Z axis)\n            if (Math.abs(this.surfaceState.roll) > 0.001) {\n                this._rollQuat.setFromAxisAngle(this._look, this.surfaceState.roll);\n                this.camera.quaternion.multiply(this._rollQuat);\n            }\n        } else if (anchor) {\n            this._tmpObj.position.copy(pos);\n            this._tmpObj.up.copy(up);\n            this._tmpObj.lookAt(this._target);\n\n            // Apply roll rotation around the look direction\n            if (Math.abs(this.surfaceState.roll) > 0.001) {\n                this._rollQuat.setFromAxisAngle(this._look, this.surfaceState.roll);\n                this._tmpObj.quaternion.multiply(this._rollQuat);\n            }\n\n            anchor.position.copy(pos);\n            anchor.quaternion.copy(this._tmpObj.quaternion);\n        }\n        if (!mslOwnsPlacement) {\n            this._enforceCameraAboveTerrain({\n                minClearance: minFloor,\n                useSample: true,\n                anchor,\n                syncAltitude: true\n            });\n        }\n    }\n\n    _getCameraAnchor() {\n        if (this._xrSurfaceRig) return this._xrSurfaceRig.anchor;\n        // In VR mode, return the dolly (rig) for positioning\n        // The camera's local position is controlled by the headset\n        if (this._vrModeActive && this._vrDolly) {\n            return this._vrDolly;\n        }\n        if (!this.renderer || !this.renderer.xr || !this.renderer.xr.isPresenting) {\n            return this.camera;\n        }\n        const parent = this.camera?.parent;\n        if (parent && parent.userData && parent.userData.isVRCameraRig) {\n            return parent;\n        }\n        return this.camera;\n    }\n\n    // ─────────────────────────────────────────────────────────────────────────\n    // VR/XR Mode Support\n    // ─────────────────────────────────────────────────────────────────────────\n\n    /**\n     * Set the VR dolly reference (called from animation-loop after scene init)\n     */\n    setVRDolly(dolly) {\n        this._vrDolly = dolly;\n    }\n\n    /**\n     * Stable world-space contact probe for streamed photoreal terrain.\n     *\n     * The tracked headset may move around the physical room, but the XR\n     * navigation anchor must not be rebuilt from that eye pose. Doing so at a\n     * 6,378 km world radius applies the room-scale tangent offset twice the\n     * next time the dolly is composed. Terrain contact therefore follows the\n     * double-precision navigation anchor; native eye matrices remain the sole\n     * authority for stereo rendering and gaze.\n     */\n    getPhotorealContactWorldPosition(target = new THREE.Vector3()) {\n        const source = this._xrSurfaceRig?.anchor?.position\n            || this.camera?.userData?.worldPosition\n            || this.camera?.position;\n        return source ? target.copy(source) : target.set(0, 0, 0);\n    }\n\n    /** Shared AR/VR lifecycle owner calls this exactly once per session. */\n    enterVRMode() {\n        if (this._xrSurfaceRig) return this._xrSurfaceRig;\n        if (!this._vrDolly) return null;\n        const frame = new XRSurfaceRig(this._vrDolly, this.camera);\n        this._xrSurfaceRig = frame;\n        this._vrModeActive = true;\n        this._xrFloorAlignmentPending = this.cameraMode === 'surface';\n        this._xrCalibratedEyeHeight = null;\n        this._xrUp = new THREE.Vector3();\n        this._xrForward = new THREE.Vector3();\n        this._xrEarthQuaternion = new THREE.Quaternion();\n        if (this.geoNav) {\n            this.geoNav.active = false;\n            this.geoNav.action = null;\n            this.geoNav.pointerId = null;\n        }\n        this._resetGeoDragConstraint?.();\n        this._setSurfaceDragMSLLock?.(false);\n        this._hideSurfaceGrabRing?.();\n        this._exitPointerLock?.();\n        this.resetKeyboardLook();\n        if (this.cameraMode === 'surface') {\n            this._alignYawToCameraHorizon();\n            this.surfaceState.pitch = 0;\n            this.surfaceState.roll = 0;\n        }\n        // Do not force orbital observers onto the ground or change cameraMode.\n        this.commitVRRigPose();\n        this.camera.position.set(0, 0, 0);\n        this.camera.quaternion.identity();\n        return frame;\n    }\n\n    commitVRRigPose() {\n        const frame = this._xrSurfaceRig;\n        if (!frame) return;\n        if (this.cameraMode === 'surface') {\n            // Placement uses the existing radial terrain/GPS authority, but\n            // gravity-up is the WGS84 ellipsoid normal in the current Earth frame.\n            this._xrUp.copy(this.surfaceState.up);\n            this._xrEarthQuaternion.identity();\n            this.triTree?.group?.getWorldQuaternion?.(this._xrEarthQuaternion);\n            this._xrEarthQuaternion.invert();\n            this._xrUp.applyQuaternion(this._xrEarthQuaternion);\n            this._xrUp.set(this._xrUp.x, this._xrUp.y * WGS84_A2 / WGS84_B2, this._xrUp.z).normalize();\n            this._xrEarthQuaternion.invert();\n            this._xrUp.applyQuaternion(this._xrEarthQuaternion);\n            this.surfaceLookDir(this._xrForward);\n            frame.level(this._xrUp, this._xrForward);\n        }\n        frame.apply();\n    }\n\n    /**\n     * Mate the XR local-floor reference origin to the verified terrain plane.\n     * Desktop AGL is an eye-height command, while WebXR supplies the physical\n     * eye height above its floor origin. Reusing the desktop number in XR can\n     * put the reference origin (and controllers/character feet) below the\n     * photoreal mesh. This one-time calibration replaces walking AGL with the\n     * tracked height and keeps all subsequent LOD corrections on the stable\n     * radial anchor.\n     */\n    alignXRReferenceFloor() {\n        const frame = this._xrSurfaceRig;\n        if (!this._xrFloorAlignmentPending\n            || !frame?.calibrated\n            || this.cameraMode !== 'surface'\n            || !this._isSurfaceWalkingTopologyActive()) {\n            return false;\n        }\n\n        const anchor = frame.anchor?.position;\n        if (!anchor || anchor.lengthSq() < 1e-8) return false;\n        const worldUp = this._xrFloorWorldUp || (this._xrFloorWorldUp = new THREE.Vector3());\n        worldUp.copy(anchor).normalize();\n        const viewerOffset = frame.getReferenceViewerOffsetWorld?.(\n            this._xrViewerReferenceOffset\n                || (this._xrViewerReferenceOffset = new THREE.Vector3())\n        );\n        const trackedEyeHeight = viewerOffset?.dot(worldUp);\n        // A `local` fallback reference space can report a head-relative origin\n        // with no usable floor height. Preserve the existing AGL in that case.\n        if (!Number.isFinite(trackedEyeHeight)\n            || trackedEyeHeight < 0.25\n            || trackedEyeHeight > 3.0) {\n            return false;\n        }\n\n        if (this.terrainTileGroup) {\n            // Never align an immersive floor to the ellipsoid fallback while\n            // photoreal geometry is still loading. The boot/contact handoff\n            // seeds at least one of these direction-scoped authorities.\n            const centerSkin = this._getPhotoCenterSkinRadiusForDirection?.(worldUp);\n            const hasVerifiedPhotoFloor = [\n                centerSkin,\n                this._photoGroundEmaR,\n                this._photoGroundLastRawR,\n                this._photoLastKnownReferenceR,\n                this._lastSafeGroundR,\n            ].some(Number.isFinite);\n            if (!hasVerifiedPhotoFloor) return false;\n        }\n\n        const floorRadius = this.getSurfaceContactRadius(worldUp);\n        if (!Number.isFinite(floorRadius) || floorRadius < 1e6) return false;\n        const clearance = Number(this.SURFACE_TERRAIN_CLEARANCE) || 0;\n        const nextAltitude = trackedEyeHeight;\n        const targetRadius = floorRadius + nextAltitude + clearance;\n\n        anchor.copy(worldUp).multiplyScalar(targetRadius);\n        this.surfaceState.up.copy(worldUp);\n        this._xrCalibratedEyeHeight = trackedEyeHeight;\n        this.surfaceAltitudeMeters = nextAltitude;\n        this.surfaceAltitudeMSL = targetRadius - this._getEllipsoidRadiusForDir(worldUp);\n        this._lastSafeGroundR = Number.isFinite(this._lastSafeGroundR)\n            ? Math.max(this._lastSafeGroundR, floorRadius)\n            : floorRadius;\n        this._xrFloorAlignmentPending = false;\n        return true;\n    }\n\n    exitVRMode() {\n        invalidatePhotorealSamplingMatrices(this._nativePhotoTileGroup);\n        invalidatePhotorealSamplingMatrices(this.mapSourceTerrainGroup);\n        const frame = this._xrSurfaceRig;\n        if (!frame) return;\n        frame.restore();\n        this.setXRLocomotionInput(null);\n        this._xrSurfaceRig = null;\n        this._vrModeActive = false;\n        this._xrFloorAlignmentPending = false;\n        this._xrCalibratedEyeHeight = null;\n        if (this.cameraMode === 'surface') {\n            this.camera.getWorldPosition(this._xrUp);\n            const radiusDelta = this._xrUp.length() - frame.anchor.position.length();\n            this.surfaceAltitudeMeters += radiusDelta;\n            this.surfaceAltitudeMSL = this._xrUp.length() - this._getEllipsoidRadiusForDir(this._xrUp);\n            if (this._airborneMSLGlideActive) this._airborneMSLGlideMsl = this.surfaceAltitudeMSL;\n            this._xrUp.normalize();\n            this.setSurfaceFromDir(this._xrUp, true);\n            this.surfaceState.roll = 0;\n        }\n    }\n\n    /**\n     * Check if VR mode is currently active\n     */\n    isVRMode() {\n        return this._vrModeActive || (this.renderer?.xr?.isPresenting ?? false);\n    }\n\n    setXRLocomotionInput(input) {\n        if (!input && this._xrLocomotionInput) {\n            this._moveSpeed = this._verticalSpeed = 0;\n            this._verticalDir = 0;\n            this._jumpRequested = false;\n        }\n        this._xrLocomotionInput = input;\n        if (!input || !this._xrSurfaceRig || this.cameraMode !== 'surface') return;\n        if (input.haltMove) this._moveSpeed = 0;\n        if (input.haltVertical) this._verticalSpeed = this._verticalDir = 0;\n        if (input.jump && !this._isJumping) this._jumpRequested = true;\n        if (input.turn) {\n            this._xrSurfaceRig.beginTurn();\n            this.surfaceState.yaw += input.turn;\n            this.commitVRRigPose();\n            this._xrSurfaceRig.endTurn();\n        }\n    }\n\n    isSurfaceAirborne() {\n        if (this.cameraMode !== 'surface') return false;\n        if (this._airborneMSLGlideActive || this._isJumping) return true;\n        const altitude = Number(this.surfaceAltitudeMeters);\n        return Number.isFinite(altitude) && altitude > this._getSurfaceFloorAltitude() + 0.35;\n    }\n\n    /**\n     * Get the current effective camera position (accounts for VR dolly)\n     */\n    getEffectiveCameraPosition() {\n        // XR eye/union cameras have no parent; getWorldPosition() on them\n        // would overwrite the matrix explicitly installed by WebXRManager.\n        return this.camera.getWorldPosition(new THREE.Vector3());\n    }\n\n    /**\n     * Update VR dolly position for surface mode\n     * Called from updateSurface when in VR\n     */\n    updateVRSurface(dt) {\n        if (!this._vrModeActive || !this._vrDolly) return;\n\n        // Get the direction the user is looking (from XR camera)\n        let lookDir = this._vA.set(0, 0, -1);\n        if (this.renderer?.xr?.isPresenting) {\n            const xrCamera = this.renderer.xr.getCamera(this.camera);\n            if (xrCamera) {\n                xrCamera.getWorldDirection(lookDir);\n            }\n        }\n\n        // Project to horizontal for movement direction\n        const moveDir = this._vB.copy(lookDir);\n        moveDir.y = 0;\n        if (moveDir.lengthSq() > 0.001) {\n            moveDir.normalize();\n        } else {\n            moveDir.set(0, 0, -1);\n        }\n\n        // Calculate right vector for strafing\n        const rightDir = this._vC.crossVectors(new THREE.Vector3(0, 1, 0), moveDir).normalize();\n\n        // Check for keyboard input (WASD)\n        let moveX = 0, moveZ = 0;\n        if (this.keyState.w) moveZ += 1;\n        if (this.keyState.s) moveZ -= 1;\n        if (this.keyState.a) moveX -= 1;\n        if (this.keyState.d) moveX += 1;\n\n        if (moveX !== 0 || moveZ !== 0) {\n            const altitude = this.surfaceAltitudeMeters ?? this.SURFACE_EYE_HEIGHT;\n            const altitudeFactor = this._getAltitudeSpeedMultiplier(altitude);\n            const speed = this._vrMoveSpeed * altitudeFactor * (this.keyState.shift ? this._vrRunMultiplier : 1);\n            const movement = this._vD.set(0, 0, 0);\n            movement.addScaledVector(moveDir, moveZ * speed * dt);\n            movement.addScaledVector(rightDir, moveX * speed * dt);\n\n            this._vrDolly.position.add(movement);\n            this._vrDolly.updateMatrixWorld(true);\n        }\n\n        // Vertical movement (Q/E)\n        let vertMove = 0;\n        if (this.keyState.q) vertMove -= 1;\n        if (this.keyState.e) vertMove += 1;\n        if (vertMove !== 0) {\n            // Move along local up (surface normal)\n            const upDir = this._vrDolly.position.clone().normalize();\n            this._vrDolly.position.addScaledVector(upDir, vertMove * this._vrMoveSpeed * dt);\n            this._vrDolly.updateMatrixWorld(true);\n        }\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Transition animation\n    // ──────────────────────────────────────────────────────────────\n\n    startCamTransition(\n        endPos,\n        endQuat,\n        nextMode,\n        durationMs = this.SURFACE_TRANSITION_MS,\n        {\n            radialArc = nextMode === 'surface',\n            pathFacing = false,\n            arcLiftMeters = 0\n        } = {}\n    ) {\n        this.camTransition = {\n            t0: performance.now(),\n            dur: Number.isFinite(durationMs) ? Math.max(0, durationMs) : 0,\n            startPos: this.camera.position.clone(),\n            startQuat: this.camera.quaternion.clone(),\n            endPos: endPos.clone(),\n            endQuat: endQuat.clone(),\n            nextMode,\n            radialArc: !!radialArc,\n            pathFacing: !!pathFacing,\n            arcLiftMeters: Number.isFinite(arcLiftMeters)\n                ? THREE.MathUtils.clamp(arcLiftMeters, 0, 1_250_000)\n                : 0\n        };\n    }\n\n    updateCamTransition() {\n        if (!this.camTransition) return false;\n\n        // Handle instant transition (dur = 0)\n        const dur = this.camTransition.dur || 1;\n        const t = dur <= 0 ? 1 : (performance.now() - this.camTransition.t0) / dur;\n        const a = THREE.MathUtils.clamp(t, 0, 1);\n        const e = a * a * (3 - 2 * a); // smoothstep\n\n        if (this.camTransition.radialArc || this.camTransition.nextMode === 'surface') {\n            // A Cartesian lerp cuts a chord through Earth whenever the clicked\n            // destination is angularly separated from the orbital camera. The\n            // late terrain clamp then fights that below-surface path and makes\n            // altitude jump as LODs arrive. Interpolate direction on a radial\n            // arc and radius independently so every transition point remains\n            // outside the planet while the focused endpoint can still be\n            // retargeted to a newly refined contact mesh.\n            const startDir = (this._camTransitionStartDir\n                || (this._camTransitionStartDir = new THREE.Vector3()))\n                .copy(this.camTransition.startPos)\n                .normalize();\n            const endDir = (this._camTransitionEndDir\n                || (this._camTransitionEndDir = new THREE.Vector3()))\n                .copy(this.camTransition.endPos)\n                .normalize();\n            const arcQuat = (this._camTransitionArcQuat\n                || (this._camTransitionArcQuat = new THREE.Quaternion()))\n                .setFromUnitVectors(startDir, endDir);\n            const stepQuat = (this._camTransitionStepQuat\n                || (this._camTransitionStepQuat = new THREE.Quaternion()))\n                .identity()\n                .slerp(arcQuat, e);\n            const baseRadius = THREE.MathUtils.lerp(\n                this.camTransition.startPos.length(),\n                this.camTransition.endPos.length(),\n                e\n            );\n            const radius = baseRadius\n                + this.camTransition.arcLiftMeters * Math.sin(Math.PI * e);\n            this.camera.position.copy(startDir).applyQuaternion(stepQuat).multiplyScalar(radius);\n\n            if (this.camTransition.pathFacing && a < 1) {\n                // Face the actual great-circle flight tangent, not the planet\n                // centre. A small look-ahead sample includes the changing\n                // radial component from the altitude arc as well as angular\n                // travel. Blend into the tangent after departure and back to\n                // the requested destination attitude while decelerating.\n                const aheadA = Math.min(1, a + 0.0025);\n                const aheadE = aheadA * aheadA * (3 - 2 * aheadA);\n                const aheadStepQuat = (this._camTransitionAheadQuat\n                    || (this._camTransitionAheadQuat = new THREE.Quaternion()))\n                    .identity()\n                    .slerp(arcQuat, aheadE);\n                const aheadBaseRadius = THREE.MathUtils.lerp(\n                    this.camTransition.startPos.length(),\n                    this.camTransition.endPos.length(),\n                    aheadE\n                );\n                const aheadRadius = aheadBaseRadius\n                    + this.camTransition.arcLiftMeters * Math.sin(Math.PI * aheadE);\n                const aheadPos = (this._camTransitionAheadPos\n                    || (this._camTransitionAheadPos = new THREE.Vector3()))\n                    .copy(startDir)\n                    .applyQuaternion(aheadStepQuat)\n                    .multiplyScalar(aheadRadius);\n                if (aheadPos.distanceToSquared(this.camera.position) > 1e-8) {\n                    const pathObject = this._camTransitionPathObject\n                        || (this._camTransitionPathObject = new THREE.Camera());\n                    pathObject.position.copy(this.camera.position);\n                    pathObject.up.copy(this.camera.position).normalize();\n                    pathObject.lookAt(aheadPos);\n                    const departureBlend = THREE.MathUtils.smoothstep(a, 0, 0.12);\n                    const arrivalBlend = THREE.MathUtils.smoothstep(a, 0.82, 1);\n                    this.camera.quaternion\n                        .copy(this.camTransition.startQuat)\n                        .slerp(pathObject.quaternion, departureBlend)\n                        .slerp(this.camTransition.endQuat, arrivalBlend);\n                }\n            } else {\n                this.camera.quaternion.slerpQuaternions(\n                    this.camTransition.startQuat,\n                    this.camTransition.endQuat,\n                    e\n                );\n            }\n        } else {\n            this.camera.position.lerpVectors(this.camTransition.startPos, this.camTransition.endPos, e);\n            this.camera.quaternion.slerpQuaternions(\n                this.camTransition.startQuat,\n                this.camTransition.endQuat,\n                e\n            );\n        }\n\n        if ((this.camTransition.nextMode === 'surface' || this.cameraMode === 'toSurface')\n            && !this.terrainTileGroup) {\n            const minClearance = this._getSurfaceFloorAltitude();\n            this._enforceCameraAboveTerrain({ minClearance, useSample: true });\n        }\n\n        if (a >= 1) {\n            this._prevMode = this.cameraMode;\n            this.cameraMode = this.camTransition.nextMode;\n            this.camTransition = null;\n            console.log('[CAMERA MODE] Transition complete, now in:', this.cameraMode);\n\n            if (this.cameraMode === 'surface') {\n                this.controls.enabled = false;\n                this.camera.near = 0.1;\n                this.camera.updateProjectionMatrix();\n                // Preserve yaw/pitch/roll if we were already in surface; only reset when coming from orbit\n                if (this._prevMode === 'orbit' || this._prevMode === 'toOrbit') {\n                    this.surfaceState.pitch = 0;\n                    this.surfaceState.roll = 0;\n                    this._alignYawToCameraHorizon();\n                    console.log('[CAMERA MODE] Reset yaw/pitch/roll from orbit transition');\n                }\n                this.applySurfaceCamera(); // snap exact eye height + horizon look\n                console.log('[CAMERA MODE] Surface mode active - yaw:', this.surfaceState.yaw, 'pitch:', this.surfaceState.pitch);\n            } else {\n                // CRITICAL: Properly reset orbit controls\n                // The camera quaternion has already been set by the transition\n                // so we just need to reset the controls state\n                this.controls.enabled = true;\n                this.camera.near = CAMERA_NEAR;\n                this.camera.updateProjectionMatrix();\n\n                // Reset orbit target to current body anchor\n                const anchorPos = this._getBodyWorldPosition(this._bodyAnchor);\n                this.controls.target.copy(anchorPos || this._origin);\n\n                // Preserve orbit orientation without forcing world-up\n                this._ensureOrbitUp();\n\n                // Update controls to sync with camera state (don't override camera orientation)\n                this.controls.update();\n            }\n\n            // Notify mode change\n            if (typeof this.onCameraModeChange === 'function') {\n                this.onCameraModeChange();\n            }\n\n            // Notify transition complete (for state saving)\n            if (typeof this.onModeTransitionComplete === 'function') {\n                this.onModeTransitionComplete(this.cameraMode);\n            }\n\n            return false;\n        }\n        return true;\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Transit mode helpers\n    // ──────────────────────────────────────────────────────────────\n\n    _enterTransit() {\n        if (this.cameraMode === 'transit') return;\n        console.log('[CAMERA MODE] Entering transit mode');\n        this._orbitReturnPose = {\n            pos: this.camera.position.clone(),\n            quat: this.camera.quaternion.clone()\n        };\n\n        this.setLODMode('zoom');\n\n        // Capture current heading for horizon target\n        const upVec = this.camera.position.clone().normalize();\n        this.setSurfaceFromDir(upVec, true);\n        this._alignYawToCameraHorizon();\n\n        // Build horizon quaternion based on current yaw with zero pitch\n        const savedPitch = this.surfaceState.pitch;\n        this.surfaceState.pitch = 0;\n        this.surfaceLookDir(this._look);\n        this.surfaceState.pitch = savedPitch;\n        this._tmpObj.position.copy(upVec);\n        this._tmpObj.up.copy(upVec);\n        this._tmpObj.lookAt(this._target.copy(upVec).add(this._look));\n        this._transitState.horizonQuat.copy(this._tmpObj.quaternion);\n\n        this._transitState.startQuat.copy(this.camera.quaternion);\n        this._transitState.active = true;\n\n        this.cameraMode = 'transit';\n        this.controls.enabled = false;\n    }\n\n    _exitTransitToOrbit() {\n        if (this.cameraMode !== 'transit') return;\n        console.log('[CAMERA MODE] Exiting transit to orbit');\n        this._transitState.active = false;\n        this.cameraMode = 'orbit';\n        if (!this._externalCameraOverrideOwner) this._externalCameraOverride = false;\n        this.controls.enabled = true;\n        this._ensureOrbitUp();\n        const anchorPos = this._getBodyWorldPosition(this._bodyAnchor);\n        const target = anchorPos || this._origin;\n        this.camera.lookAt(target);\n        this.controls.target.copy(target);\n        this.controls.update();\n\n    }\n\n    _applyTransitZoom() {\n        const dist = this.camera.position.length();\n        const ellipsoidR = this._getEllipsoidRadiusForDir(this.camera.position);\n        if (!Number.isFinite(this.orbitZoomTarget)) {\n            this._orbitZoomLastUpdateAt = 0;\n            return dist - ellipsoidR;\n        }\n        const minDist = this.controls?.minDistance ?? (PLANET_RADIUS + this.SURFACE_EYE_HEIGHT);\n        const maxDist = this.controls?.maxDistance ?? EARTH_ORBIT_MAX_DISTANCE_M;\n        const clampedTarget = THREE.MathUtils.clamp(this.orbitZoomTarget, minDist, maxDist);\n        const next = this._stepOrbitZoomDistance(dist, clampedTarget);\n        if (Math.abs(next - dist) < 1e-3) {\n            this.orbitZoomTarget = null;\n            this._orbitZoomLastUpdateAt = 0;\n            return dist - ellipsoidR;\n        }\n        this.camera.position.setLength(next);\n        if (Math.abs(next - clampedTarget) < 0.05) {\n            this.orbitZoomTarget = null;\n            this._orbitZoomLastUpdateAt = 0;\n        }\n        return next - ellipsoidR;\n    }\n\n    _updateTransitCamera(alt) {\n        // Blend from stored orbit orientation to horizon as we descend\n        const upVec = this.camera.position.clone().normalize();\n        this.camera.up.copy(upVec);\n\n        const start = this.TRANSIT_ENTER_ALT;\n        const end = this.TRANSIT_SURFACE_ALT;\n        const tRaw = THREE.MathUtils.clamp((start - alt) / Math.max(1, (start - end)), 0, 1);\n        const t = tRaw * tRaw * (3 - 2 * tRaw); // smoothstep\n\n        this.camera.quaternion.copy(this._transitState.startQuat).slerp(this._transitState.horizonQuat, t);\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Mode transitions (public API)\n    // ──────────────────────────────────────────────────────────────\n\n    /**\n     * Initialize directly in surface mode from lat/lon (robust restoration method)\n     * @param {number} latDeg - Latitude in degrees\n     * @param {number} lonDeg - Longitude in degrees\n     * @param {number|null} terrainRadius - Saved terrain radius (null to raycast)\n     * @param {number} yaw - Yaw angle\n     * @param {number} pitch - Pitch angle\n     * @param {number} altitude - Absolute altitude in meters above terrain\n     */\n    initializeSurfaceModeFromLatLon(latDeg, lonDeg, terrainRadius = null, yaw = 0, pitch = 0, altitude = null) {\n        console.log('[CAMERA MODE] Initializing surface mode from lat/lon - lat:', latDeg, 'lon:', lonDeg, 'terrainR:', terrainRadius, 'yaw:', yaw, 'pitch:', pitch, 'altitude:', altitude);\n\n        this.setLODMode('zoom');\n        this._cancelSurfaceScrollAltitude({ resetGesture: true });\n        this._clearAirborneMSLGlide();\n        this.resetPhotorealGroundCache('surface-latlon-init');\n\n        // Convert lat/lon to local direction vector (handles prime meridian offset internally)\n        const dir = latLonToLocalDir(latDeg, lonDeg);\n\n        // Transform from planet-local space to world space using the planet group's quaternion.\n        // This is necessary because worldPosToLatLonLocal() applies the inverse quaternion when\n        // reading coordinates, so we must apply the forward quaternion when writing them back.\n        if (this.triTree?.group?.getWorldQuaternion) {\n            const planetQuat = new THREE.Quaternion();\n            this.triTree.group.getWorldQuaternion(planetQuat);\n            dir.applyQuaternion(planetQuat);\n        }\n\n        this.setSurfaceFromDir(dir, false);\n        this.surfaceState.yaw = yaw;\n        this.surfaceState.pitch = pitch;\n\n        const upVec = this.surfaceState.up;\n\n        // Use saved terrain radius if available, otherwise raycast\n        let finalTerrainR;\n        if (terrainRadius !== null && terrainRadius !== undefined && Number.isFinite(terrainRadius)) {\n            // Use saved terrain radius for exact position restoration\n            finalTerrainR = terrainRadius;\n            console.log('[CAMERA MODE] Using saved terrain radius:', finalTerrainR);\n        } else {\n            // Fallback: raycast to get current terrain elevation\n            finalTerrainR = this.sampleTerrainRadiusForDir(upVec);\n            console.log('[CAMERA MODE] Raycasted terrain radius:', finalTerrainR);\n        }\n\n        this._terrainRadius = finalTerrainR;\n        this._terrainRadiusRaw = finalTerrainR;\n        if (Number.isFinite(terrainRadius)) {\n            this._lastTerrainSample = performance.now();\n        }\n\n        // Use provided altitude or default to eye height (clamped to surface max)\n        const maxAlt = Number.isFinite(this.SURFACE_ALTITUDE_MAX) ? this.SURFACE_ALTITUDE_MAX : Infinity;\n        const nextAlt = (altitude !== null && altitude !== undefined) ? altitude : this.SURFACE_EYE_HEIGHT;\n        const minAlt = this._getAltitudeClampMin();\n        this.surfaceAltitudeMeters = THREE.MathUtils.clamp(nextAlt, minAlt, maxAlt);\n        this._surfaceAltitudeReference = 'terrain';\n        this.surfaceVerticalBoost = 1;\n        this.surfaceShiftBoost = 1;\n        const ellipsoidR = this._getEllipsoidRadiusForDir(upVec);\n        this.surfaceAltitudeMSL = (finalTerrainR - ellipsoidR)\n            + this.surfaceAltitudeMeters\n            + this.SURFACE_TERRAIN_CLEARANCE;\n\n        const pos = upVec.clone().multiplyScalar(finalTerrainR + this.surfaceAltitudeMeters + this.SURFACE_TERRAIN_CLEARANCE);\n\n        // Set camera position and orientation directly\n        this.camera.position.copy(pos);\n        this.surfaceLookDir(this._look);\n        this._tmpObj.position.copy(pos);\n        this._tmpObj.up.copy(upVec);\n        this._tmpObj.lookAt(this._target.copy(pos).add(this._look));\n        this.camera.quaternion.copy(this._tmpObj.quaternion);\n\n        // Set mode directly to surface (no transition)\n        this.cameraMode = 'surface';\n        this.controls.enabled = false;\n        this.camera.near = 0.1;\n        this.camera.updateProjectionMatrix();\n        this.applySurfaceCamera();\n\n        // Enable device orientation on mobile\n        if (this._deviceSensorsEnabled) {\n            this.enableDeviceOrientation();\n        }\n\n        console.log('[CAMERA MODE] Initialized in surface mode from lat/lon - exact position restored');\n\n        // Notify mode change\n        if (typeof this.onCameraModeChange === 'function') {\n            this.onCameraModeChange();\n        }\n    }\n\n    /**\n     * Update surface position from lat/lon without resetting LOD staging.\n     * Intended for small tracking adjustments (e.g., GPS watch updates).\n     */\n    updateSurfaceFromLatLon(latDeg, lonDeg, altitude = null) {\n        if (!Number.isFinite(latDeg) || !Number.isFinite(lonDeg)) return;\n        if (this.cameraMode !== 'surface') return;\n\n        const dir = latLonToLocalDir(latDeg, lonDeg);\n        if (this.triTree?.group?.getWorldQuaternion) {\n            const planetQuat = new THREE.Quaternion();\n            this.triTree.group.getWorldQuaternion(planetQuat);\n            dir.applyQuaternion(planetQuat);\n        }\n\n        this._reanchorUpPreserveOrientation(dir);\n        if (Number.isFinite(altitude)) {\n            this._cancelSurfaceScrollAltitude();\n            const minAlt = this._getAltitudeClampMin();\n            this.surfaceAltitudeMeters = Math.max(minAlt, altitude);\n            this._surfaceAltitudeReference = 'terrain';\n        }\n        this.applySurfaceCamera();\n    }\n\n    /**\n     * Initialize directly in surface mode without transition (for page load restoration)\n     * @param {THREE.Vector3} dir - Direction vector (surface normal)\n     * @param {number} yaw - Yaw angle\n     * @param {number} pitch - Pitch angle\n     * @param {number} altitude - Absolute altitude in meters above terrain\n     * @param {number|null} terrainRadius - Saved terrain radius (null to raycast)\n     */\n    initializeSurfaceMode(dir, yaw = 0, pitch = 0, altitude = null, terrainRadius = null) {\n        console.log('[CAMERA MODE] Initializing directly in surface mode at:', dir, 'yaw:', yaw, 'pitch:', pitch, 'altitude:', altitude);\n\n        this.setLODMode('zoom');\n        this._cancelSurfaceScrollAltitude({ resetGesture: true });\n        this._clearAirborneMSLGlide();\n        this.resetPhotorealGroundCache('surface-init');\n        this.setSurfaceFromDir(dir, false);\n        this.surfaceState.yaw = yaw;\n        this.surfaceState.pitch = pitch;\n\n        const upVec = this.surfaceState.up;\n        const terrainR = Number.isFinite(terrainRadius)\n            ? terrainRadius\n            : this.sampleTerrainRadiusForDir(upVec);\n        this._terrainRadius = terrainR;\n        this._terrainRadiusRaw = terrainR;\n        if (Number.isFinite(terrainRadius)) {\n            this._lastTerrainSample = performance.now();\n        }\n        // Use provided altitude or default to eye height (clamped to surface max)\n        const maxAlt = Number.isFinite(this.SURFACE_ALTITUDE_MAX) ? this.SURFACE_ALTITUDE_MAX : Infinity;\n        const nextAlt = (altitude !== null && altitude !== undefined) ? altitude : this.SURFACE_EYE_HEIGHT;\n        const minAlt = this._getAltitudeClampMin();\n        this.surfaceAltitudeMeters = THREE.MathUtils.clamp(nextAlt, minAlt, maxAlt);\n        this._surfaceAltitudeReference = 'terrain';\n        this.surfaceVerticalBoost = 1;\n        this.surfaceShiftBoost = 1;\n        const ellipsoidR = this._getEllipsoidRadiusForDir(upVec);\n        this.surfaceAltitudeMSL = (terrainR - ellipsoidR)\n            + this.surfaceAltitudeMeters\n            + this.SURFACE_TERRAIN_CLEARANCE;\n        const pos = upVec.clone().multiplyScalar(terrainR + this.surfaceAltitudeMeters + this.SURFACE_TERRAIN_CLEARANCE);\n\n        // Set camera position and orientation directly\n        this.camera.position.copy(pos);\n        this.surfaceLookDir(this._look);\n        this._tmpObj.position.copy(pos);\n        this._tmpObj.up.copy(upVec);\n        this._tmpObj.lookAt(this._target.copy(pos).add(this._look));\n        this.camera.quaternion.copy(this._tmpObj.quaternion);\n\n        // Set mode directly to surface (no transition)\n        this.cameraMode = 'surface';\n        this.controls.enabled = false;\n        this.camera.near = 0.1;\n        this.camera.updateProjectionMatrix();\n        this.applySurfaceCamera();\n\n        // Enable device orientation on mobile\n        if (this._deviceSensorsEnabled) {\n            this.enableDeviceOrientation();\n        }\n\n        console.log('[CAMERA MODE] Initialized in surface mode - no transition');\n\n        // Notify mode change\n        if (typeof this.onCameraModeChange === 'function') {\n            this.onCameraModeChange();\n        }\n    }\n\n    enterSurfaceAt(dir, {\n        preserveAltitude = false,\n        transitionDurationMs = this.SURFACE_TRANSITION_MS,\n        targetAltitudeMeters = null,\n        pathFacing = false,\n        travelArcLiftMeters = 0\n    } = {}) {\n        console.log('[CAMERA MODE] Entering surface mode from:', this.cameraMode);\n        this._resetTouchNavigationState();\n        const enteringFromSurface = (this.cameraMode === 'surface' || this.cameraMode === 'toSurface');\n        const keepAltitude = preserveAltitude || enteringFromSurface;\n\n        this.setLODMode('zoom');\n        this._cancelSurfaceScrollAltitude();\n        this._clearAirborneMSLGlide();\n        if (!enteringFromSurface) {\n            this.resetPhotorealGroundCache('surface-enter');\n        }\n\n        if (enteringFromSurface) {\n            this._orbitReturnPose = null;\n            // Preserve current yaw/pitch; re-anchor up to the new target without recalculating yaw from camera\n            this._reanchorUpPreserveOrientation(dir);\n        } else {\n            // Fresh setup when coming from orbit\n            this._orbitReturnPose = {\n                pos: this.camera.position.clone(),\n                quat: this.camera.quaternion.clone()\n            };\n            this.setSurfaceFromDir(dir, false);\n            this.surfaceState.pitch = 0;\n            this.surfaceState.roll = 0;\n            this._alignYawToCameraHorizon();\n        }\n\n        const upVec = this.surfaceState.up;\n        const terrainR = this.sampleTerrainRadiusForDir(upVec);\n        const ellipsoidR = this._getEllipsoidRadiusForDir(upVec);\n        this._terrainRadius = terrainR;\n        this._terrainRadiusRaw = terrainR;\n        if (Number.isFinite(targetAltitudeMeters)) {\n            const minAlt = this._getAltitudeClampMin();\n            this.surfaceAltitudeMeters = THREE.MathUtils.clamp(\n                targetAltitudeMeters,\n                minAlt,\n                this.SURFACE_ALTITUDE_MAX\n            );\n            this._surfaceAltitudeReference = 'terrain';\n        } else if (!keepAltitude) {\n            this.surfaceAltitudeMeters = this._getAltitudeClampMin();\n            this._surfaceAltitudeReference = 'terrain';\n        } else if (!(enteringFromSurface && Number.isFinite(this.surfaceAltitudeMeters))) {\n            const camRadius = this.camera?.position?.length?.() ?? NaN;\n            const rawAlt = Number.isFinite(camRadius)\n                ? camRadius - terrainR - this.SURFACE_TERRAIN_CLEARANCE\n                : NaN;\n            const minAlt = this._getAltitudeClampMin();\n            this.surfaceAltitudeMeters = Number.isFinite(rawAlt)\n                ? THREE.MathUtils.clamp(rawAlt, minAlt, this.SURFACE_ALTITUDE_MAX)\n                : minAlt;\n            this._surfaceAltitudeReference = 'terrain';\n        }\n        this.surfaceVerticalBoost = 1;\n        this.surfaceShiftBoost = 1;\n        this.surfaceAltitudeMSL = (terrainR - ellipsoidR)\n            + this.surfaceAltitudeMeters\n            + this.SURFACE_TERRAIN_CLEARANCE;\n        const endPos = upVec.clone().multiplyScalar(terrainR + this.surfaceAltitudeMeters + this.SURFACE_TERRAIN_CLEARANCE);\n\n        // build end quaternion from desired surface look\n        this.surfaceLookDir(this._look);\n        this._tmpObj.position.copy(endPos);\n        this._tmpObj.up.copy(upVec);\n        this._tmpObj.lookAt(this._target.copy(endPos).add(this._look));\n        const endQuat = this._tmpObj.quaternion.clone();\n\n        this._prevMode = this.cameraMode;\n        this.cameraMode = 'toSurface';\n        console.log('[CAMERA MODE] Starting transition to surface, yaw:', this.surfaceState.yaw, 'pitch:', this.surfaceState.pitch);\n        // Scroll/transit handoffs retain their existing duration, while a\n        // double-click can request a one-second smoothstep descent through\n        // this same state machine. Keeping one transition owner means camera,\n        // tile refinement, and scene rendering continue every frame.\n        this.startCamTransition(endPos, endQuat, 'surface', transitionDurationMs, {\n            radialArc: true,\n            pathFacing,\n            arcLiftMeters: travelArcLiftMeters\n        });\n    }\n\n    exitSurfaceMode() {\n        console.log('[CAMERA MODE] Exiting surface mode, current mode:', this.cameraMode);\n        if (this.cameraMode !== 'surface') return;\n        this._resetTouchNavigationState();\n        this._cancelSurfaceScrollAltitude({ resetGesture: true });\n        this._clearAirborneMSLGlide();\n        // Cooldown: prevent re-entry for 3 seconds to avoid flapping\n        this._surfaceExitCooldownUntil = performance.now() + 3000;\n\n        // Disable device orientation when leaving surface mode\n        this.disableDeviceOrientation();\n\n        if (this.isPointerLocked()) {\n            this._exitPointerLock();\n        }\n\n        // Never restore the old surface-entry pose here. The entry pose is\n        // around 50 km; a user who scrolls upward to the 95-100 km ceiling\n        // would therefore be moved DOWN by roughly 50 km before orbit resumed,\n        // producing the repeated rise/drop thrash. Continue outward along the\n        // current radial direction and finish beyond transit hysteresis.\n        const up = this.surfaceState.up.clone().normalize();\n        const ellipsoidR = this._getEllipsoidRadiusForDir(up);\n        const currentRadius = this.camera?.position?.length?.() ?? (ellipsoidR + this.SURFACE_ALTITUDE_MAX);\n        const currentAltitude = Math.max(0, currentRadius - ellipsoidR);\n        const orbitExitAltitude = Math.max(\n            currentAltitude,\n            this.TRANSIT_EXIT_ALT + 2000\n        );\n        const endPos = up.clone().multiplyScalar(ellipsoidR + orbitExitAltitude);\n\n        const viewDir = new THREE.Vector3(0, 0, 0).sub(endPos).normalize();\n        const worldUp = new THREE.Vector3(0, 1, 0);\n        const right = new THREE.Vector3().crossVectors(worldUp, viewDir).normalize();\n        if (right.lengthSq() < 0.001) right.set(1, 0, 0);\n        const cameraUp = new THREE.Vector3().crossVectors(viewDir, right).normalize();\n        this._tmpObj.position.copy(endPos);\n        this._tmpObj.up.copy(cameraUp);\n        this._tmpObj.lookAt(0, 0, 0);\n        const endQuat = this._tmpObj.quaternion.clone();\n\n        this.setLODMode('orbit');\n        this._suppressTransit = true;\n        this.orbitZoomTarget = null;\n        this._orbitZoomLastUpdateAt = 0;\n\n        this.cameraMode = 'toOrbit';\n        console.log('[CAMERA MODE] Starting transition to orbit');\n        this.startCamTransition(endPos, endQuat, 'orbit', this.SURFACE_EXIT_TRANSITION_MS);\n    }\n\n    startTransitionToOrbit() {\n        if (this.cameraMode === 'surface') {\n            this.exitSurfaceMode();\n            return true;\n        }\n        if (this.cameraMode !== 'toSurface') return false;\n\n        // Cancel from the camera's current radial position rather than\n        // snapping to either the original orbit pose or the landing target.\n        this._resetTouchNavigationState();\n        this.camTransition = null;\n        const currentUp = this._vA.copy(this.camera.position).normalize();\n        this.surfaceState.up.copy(currentUp);\n        const ellipsoidR = this._getEllipsoidRadiusForDir(currentUp);\n        this.surfaceAltitudeMeters = Math.max(\n            this._getAltitudeClampMin(),\n            this.camera.position.length() - ellipsoidR\n        );\n        this.cameraMode = 'surface';\n        this.exitSurfaceMode();\n        return true;\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Main update loop (public API)\n    // ──────────────────────────────────────────────────────────────\n\n    update() {\n        if (this._xrSurfaceRig) {\n            this.resetKeyboardLook();\n            return; // No desktop orbit/transit/device pose writes below the XR rig.\n        }\n        if (this._externalCameraOverride) {\n            this.resetKeyboardLook();\n            return;\n        }\n        // Body anchor transition in progress?\n        if (this.updateBodyTransition()) { this.resetKeyboardLook(); return; }\n\n        // Track moving bodies (moon/sun) each frame\n        this.updateBodyAnchorTarget();\n\n        // Transition in progress?\n        if (this.updateCamTransition()) { this.resetKeyboardLook(); return; }\n        this._updateKeyboardLook();\n\n        if (this.cameraMode !== 'surface') {\n            if (this.isPointerLocked()) {\n                this._exitPointerLock();\n            }\n            if (this.pointerLockState.holding) {\n                this._cancelPointerLockHold();\n            }\n        }\n        if (this.cameraMode !== 'orbit') {\n            this._resetOrbitViewPivot();\n        }\n\n        switch (this.cameraMode) {\n            case 'orbit':\n                this._updateOrbitMode();\n                break;\n            case 'transit':\n                this._updateTransitMode();\n                break;\n            case 'surface':\n                this.applySurfaceCamera();\n                break;\n            default:\n                break;\n        }\n    }\n\n    _updateOrbitRotateSpeed() {\n        if (!this.controls) return;\n        const dist = this.camera.position.length();\n        const fovRad = this.camera.fov * DEG2RAD;\n        const ellipsoidR = this._getEllipsoidRadiusForDir(this.camera?.position || null);\n        const base = (dist * Math.tan(fovRad * 0.5)) / (Math.PI * ellipsoidR);\n        const scaled = base * this.ORBIT_ROTATE_SPEED_SCALE;\n        this.controls.rotateSpeed = THREE.MathUtils.clamp(\n            scaled,\n            this.ORBIT_ROTATE_SPEED_MIN,\n            this.ORBIT_ROTATE_SPEED_MAX\n        );\n    }\n\n    _orbitScrollDampingFactor(dist) {\n        if (!Number.isFinite(dist)) return 1;\n        const ellipsoidR = this._getEllipsoidRadiusForDir(this.camera?.position || null);\n        const alt = dist - ellipsoidR;\n        const start = this.ORBIT_SCROLL_DAMP_START_ALT;\n        const end = this.SURFACE_SCROLL_TRANSITION_END_ALT;\n        if (!Number.isFinite(alt)) return 1;\n        if (alt >= start) return 1;\n        if (alt <= end) return this.ORBIT_SCROLL_DAMP_MIN;\n        const t = THREE.MathUtils.clamp((alt - end) / (start - end), 0, 1);\n        const eased = Math.pow(t, 2.5); // stronger exponential easing toward surface\n        return this.ORBIT_SCROLL_DAMP_MIN + (1 - this.ORBIT_SCROLL_DAMP_MIN) * eased;\n    }\n\n    _getOrbitWheelDistanceTarget(deltaY, baseDistance, zoomScale = 1) {\n        if (!Number.isFinite(deltaY) || !Number.isFinite(baseDistance)) return baseDistance;\n        const ellipsoidR = this._getEllipsoidRadiusForDir(this.camera?.position || null);\n        const minDistance = this.controls?.minDistance ?? (ellipsoidR + this.SURFACE_EYE_HEIGHT);\n        const maxDistance = this.controls?.maxDistance ?? EARTH_ORBIT_MAX_DISTANCE_M;\n        const minAltitude = Math.max(\n            this.SURFACE_EYE_HEIGHT,\n            minDistance - ellipsoidR\n        );\n        const maxAltitude = Math.max(minAltitude, maxDistance - ellipsoidR);\n        const baseAltitude = THREE.MathUtils.clamp(\n            baseDistance - ellipsoidR,\n            minAltitude,\n            maxAltitude\n        );\n        const damping = this._orbitScrollDampingFactor(ellipsoidR + baseAltitude);\n        const delta = deltaY * zoomScale;\n        const factor = Math.exp(delta * this.ORBIT_ZOOM_WHEEL_SCALE * damping);\n        const nextAltitude = THREE.MathUtils.clamp(\n            baseAltitude * factor,\n            minAltitude,\n            maxAltitude\n        );\n        // Scale height above the local ellipsoid, never the Earth-centered\n        // radius. Multiplying a ~6,500 km radius made one low-orbit wheel tick\n        // jump hundreds of kilometres and its reverse target below ground.\n        return ellipsoidR + nextAltitude;\n    }\n\n    _updateOrbitMode() {\n        // Check if device orientation is controlling the camera\n        if (this._useDeviceOrientation && this._updateFromDeviceSensors()) {\n            // Device orientation is active - skip normal orbit controls\n            // but still handle zoom and transit checks\n            this._applyOrbitZoom();\n            this._updateOrbitViewPivot();\n            const alt = this.camera.position.length() - this._getEllipsoidRadiusForDir(this.camera.position);\n            if (this._suppressTransit) {\n                if (alt > this.TRANSIT_EXIT_ALT + 1000) {\n                    this._suppressTransit = false;\n                }\n            } else if (alt <= this.TRANSIT_ENTER_ALT) {\n                this._enterTransit();\n            }\n            return;\n        }\n\n        if (this.navProfile === 'geospatial') {\n            if (this._bodyAnchor !== 'terra') {\n                // Non-terra: enable native OrbitControls for geospatial too\n                if (this.controls) {\n                    this.controls.enabled = true;\n                    this.controls.enableRotate = true;\n                    this.controls.enableZoom = true;\n                    this.controls.enablePan = false;\n                    this.controls.update();\n                }\n                this._updateOrbitViewPivot();\n                return;\n            }\n            if (this.controls) {\n                this.controls.enabled = false;\n                this.controls.enableRotate = false;\n                this.controls.enableZoom = false;\n                this.controls.enablePan = false;\n            }\n            this._applyOrbitZoom();\n            this._ensureOrbitUp();\n            this.camera.lookAt(this._origin);\n            this._updateOrbitViewPivot();\n            const alt = this.camera.position.length() - this._getEllipsoidRadiusForDir(this.camera.position);\n            if (this._suppressTransit) {\n                if (alt > this.TRANSIT_EXIT_ALT + 1000) {\n                    this._suppressTransit = false;\n                }\n            } else if (alt <= this.TRANSIT_ENTER_ALT) {\n                this._enterTransit();\n            }\n            return;\n        }\n\n        this.controls.enabled = true;\n\n        // Non-terra bodies: use native OrbitControls rotate/zoom\n        if (this._bodyAnchor !== 'terra') {\n            this.controls.enableRotate = true;\n            this.controls.enableZoom = true;\n            this.controls.enablePan = false;\n            this.controls.update();\n            this._updateOrbitViewPivot();\n            return;\n        }\n\n        this.controls.enabled = false;\n        this.controls.enableRotate = false;\n        this.controls.enableZoom = false;\n        this.controls.enablePan = false;\n        this._updateOrbitRotateSpeed();\n        this._applyOrbitZoom();\n        this._ensureOrbitUp();\n\n        this.controls.target.set(0, 0, 0);\n        // Terra's quaternion controller owns this pose. OrbitControls' cached\n        // Y-up spherical clamp would reintroduce a pole singularity here.\n        this.camera.lookAt(this._origin);\n        this._updateOrbitViewPivot();\n\n        // Transit/terrain enforcement only applies when orbiting Earth\n        let alt = this.camera.position.length() - this._getEllipsoidRadiusForDir(this.camera.position);\n        if (alt <= this.TRANSIT_ENTER_ALT + 5000) {\n            this._enforceCameraAboveTerrain({ minClearance: this._getAbsoluteMinAltitude(), useSample: true });\n            alt = this.camera.position.length() - this._getEllipsoidRadiusForDir(this.camera.position);\n        }\n        if (this._suppressTransit) {\n            if (alt > this.TRANSIT_EXIT_ALT + 1000) {\n                this._suppressTransit = false;\n            }\n        } else if (alt <= this.TRANSIT_ENTER_ALT) {\n            this._enterTransit();\n        }\n    }\n\n    _updateTransitMode() {\n        // Prevent pointer lock in transit\n        if (this.isPointerLocked()) {\n            this._exitPointerLock();\n        }\n\n        const alt = this._applyTransitZoom();\n        this._updateTransitCamera(alt);\n        if (alt <= this.TRANSIT_ENTER_ALT + 5000) {\n            this._enforceCameraAboveTerrain({ minClearance: this._getAbsoluteMinAltitude(), useSample: true });\n        }\n\n        const currentAlt = this.camera.position.length() - this._getEllipsoidRadiusForDir(this.camera.position);\n        const transitCooldown = this._surfaceExitCooldownUntil && performance.now() < this._surfaceExitCooldownUntil;\n        if (currentAlt <= this.TRANSIT_SURFACE_ALT && !transitCooldown) {\n            this._transitState.active = false;\n            this.enterSurfaceAt(this.camera.position.clone().normalize(), { preserveAltitude: true });\n            return;\n        }\n        if (currentAlt >= this.TRANSIT_EXIT_ALT) {\n            this._exitTransitToOrbit();\n        }\n    }\n\n    _applyOrbitZoom() {\n        if (this.cameraMode !== 'orbit') return;\n        if (!Number.isFinite(this.orbitZoomTarget)) {\n            this._orbitZoomLastUpdateAt = 0;\n            return;\n        }\n        const dist = this.camera.position.length();\n        const minDist = this.controls?.minDistance ?? (PLANET_RADIUS + this.SURFACE_EYE_HEIGHT);\n        const maxDist = this.controls?.maxDistance ?? EARTH_ORBIT_MAX_DISTANCE_M;\n        const clampedTarget = THREE.MathUtils.clamp(this.orbitZoomTarget, minDist, maxDist);\n        const next = this._stepOrbitZoomDistance(dist, clampedTarget);\n        if (Math.abs(next - dist) < 1e-3) {\n            this.orbitZoomTarget = null;\n            this._orbitZoomLastUpdateAt = 0;\n            return;\n        }\n        this.camera.position.setLength(next);\n        if (this.navProfile !== 'geospatial') {\n            this._ensureOrbitUp();\n            this.camera.lookAt(this._origin);\n        }\n        const alt = next - this._getEllipsoidRadiusForDir(this.camera.position);\n        const cooldownActive = this._surfaceExitCooldownUntil && performance.now() < this._surfaceExitCooldownUntil;\n        const inBand = this.lodMode === 'zoom' && alt <= this.SURFACE_SCROLL_TRANSITION_START_ALT\n            && !this._suppressTransit && !cooldownActive;\n        if (inBand) {\n            // Hold orbit target at band edge and start the smooth surface transition\n            // The surface controller becomes the sole altitude owner here.\n            // Retaining an orbit target would pull the camera back toward this\n            // entry altitude when surface mode later exits.\n            this.orbitZoomTarget = null;\n            this._orbitZoomLastUpdateAt = 0;\n            this.enterSurfaceAt(this.camera.position.clone().normalize(), { preserveAltitude: true });\n            return;\n        }\n        if (Math.abs(next - clampedTarget) < 0.05) {\n            this.orbitZoomTarget = null;\n            this._orbitZoomLastUpdateAt = 0;\n        }\n    }\n\n    _stepOrbitZoomDistance(currentDistance, targetDistance, deltaSeconds = null) {\n        if (!Number.isFinite(currentDistance) || !Number.isFinite(targetDistance)) return currentDistance;\n        let dt = deltaSeconds;\n        if (!Number.isFinite(dt)) {\n            const now = (typeof performance !== 'undefined' && performance.now)\n                ? performance.now()\n                : Date.now();\n            dt = this._orbitZoomLastUpdateAt > 0\n                ? (now - this._orbitZoomLastUpdateAt) / 1000\n                : 1 / 60;\n            this._orbitZoomLastUpdateAt = now;\n        }\n        dt = THREE.MathUtils.clamp(Number.isFinite(dt) ? dt : 1 / 60, 1 / 240, 0.1);\n        const response = Math.max(0.02, Number.isFinite(this.ORBIT_ZOOM_RESPONSE_SEC)\n            ? this.ORBIT_ZOOM_RESPONSE_SEC\n            : 0.12);\n        const alpha = 1 - Math.exp(-dt / response);\n        // lerp with 0<alpha<1 is monotonic and cannot overshoot either an\n        // ascending or descending target, even when frames arrive unevenly.\n        return THREE.MathUtils.lerp(currentDistance, targetDistance, alpha);\n    }\n\n    _updateBoost(current, target, accel, decel, dt) {\n        if (!Number.isFinite(current)) current = 1;\n        if (!Number.isFinite(target)) target = 1;\n        if (Math.abs(target - current) < 1e-4) return target;\n        const rate = target > current ? accel : decel;\n        if (!Number.isFinite(rate) || rate <= 0) return target;\n        const delta = rate * dt;\n        if (target > current) {\n            return Math.min(target, current + delta);\n        }\n        return Math.max(target, current - delta);\n    }\n\n    _approachValue(current, target, accel, decel, dt) {\n        if (!Number.isFinite(current)) current = 0;\n        if (!Number.isFinite(target)) target = 0;\n        const delta = target - current;\n        if (Math.abs(delta) < 1e-4) return target;\n        const rate = delta > 0 ? accel : decel;\n        if (!Number.isFinite(rate) || rate <= 0) return target;\n        const step = rate * dt;\n        if (delta > 0) {\n            return Math.min(target, current + step);\n        }\n        return Math.max(target, current - step);\n    }\n\n    _getAltitudeSpeedMultiplier(altitude) {\n        // Speed is proportional to altitude:\n        // At eye height (~1.6m), speed is base (1.4 m/s = walking speed)\n        // At 1km altitude, speed is ~1 km/s\n        // This gives intuitive movement at any altitude\n        const alt = Number.isFinite(altitude) ? altitude : this.SURFACE_EYE_HEIGHT;\n        const baseAlt = this.SURFACE_EYE_HEIGHT;\n        // Clamp to avoid division issues and cap at max altitude\n        const clampedAlt = Math.max(baseAlt, Math.min(alt, this.SURFACE_ALTITUDE_MAX));\n        // Multiplier is simply altitude / base altitude\n        // At 1.6m: 1x, at 16m: 10x, at 160m: 100x, at 1600m: 1000x\n        return clampedAlt / baseAlt;\n    }\n\n    applySurfaceMovement(deltaTime) {\n        if (_isMetaverseSceneMode()) return;\n        if (this._externalCameraOverride) return;\n        if (this.cameraMode !== 'surface') return;\n        if (this._xrSurfaceRig) deltaTime = Math.max(0, Math.min(deltaTime, 0.05));\n        if (this.geoNav?.active\n            && this.geoNav.action === 'drag'\n            && this.geoNav.dragReady) return;\n\n        // Update velocity tracking for animation systems\n        this._updateVelocityTracking(deltaTime);\n\n        // Update jump physics\n        this._updateJumpPhysics(deltaTime);\n\n        const moveForward = this.keyState.w || this.keyState.arrowup;\n        const moveBackward = this.keyState.s || this.keyState.arrowdown;\n        const moveLeft = this.keyState.a || this.keyState.arrowleft;\n        const moveRight = this.keyState.d || this.keyState.arrowright;\n        const xrVertical = THREE.MathUtils.clamp(Number(this._xrLocomotionInput?.vertical) || 0, -1, 1);\n        const moveUp = this.keyState.e || xrVertical > 0;\n        const moveDown = this.keyState.q || xrVertical < 0;\n        const shiftHeld = this.keyState.shift;\n\n        const wantsVerticalBoost = moveUp || moveDown;\n        this.surfaceShiftBoost = this._updateBoost(\n            this.surfaceShiftBoost,\n            shiftHeld ? this.SURFACE_SHIFT_BOOST_MAX : 1,\n            this.SURFACE_SHIFT_BOOST_ACCEL,\n            this.SURFACE_SHIFT_BOOST_DECAY,\n            deltaTime\n        );\n\n        const verticalAccel = shiftHeld\n            ? this.SURFACE_VERTICAL_BOOST_ACCEL * 1.4\n            : this.SURFACE_VERTICAL_BOOST_ACCEL;\n        this.surfaceVerticalBoost = this._updateBoost(\n            this.surfaceVerticalBoost,\n            wantsVerticalBoost ? this.SURFACE_VERTICAL_BOOST_MAX : 1,\n            verticalAccel,\n            this.SURFACE_VERTICAL_BOOST_DECAY,\n            deltaTime\n        );\n\n        const verticalDirection = this.keyState.e || this.keyState.q\n            ? (this.keyState.e ? 1 : 0) + (this.keyState.q ? -1 : 0)\n            : xrVertical;\n        const manualVerticalOwner = verticalDirection !== 0\n            || this._verticalSpeed > 0\n            || this._isJumping;\n        if (manualVerticalOwner) {\n            // Q/E inertia and jump physics are altitude writers too. Explicitly\n            // transfer ownership away from wheel smoothing so two independent\n            // paths can never pull the camera in opposite directions.\n            this._cancelSurfaceScrollAltitude();\n        } else if (this._applySurfaceScrollAltitude(deltaTime)) {\n            // The smoothed target reached the surface ceiling and initiated the\n            // outward-only surface -> orbit transition. Stop surface movement\n            // immediately; the transition owns the camera from this frame on.\n            return;\n        }\n        if (!this._airborneMSLGlideActive && !this._isJumping) {\n            this._activateAirborneMSLGlide(this.surfaceAltitudeMSL);\n        }\n        if (verticalDirection !== 0) {\n            this._verticalDir = verticalDirection;\n        }\n        if (verticalDirection !== 0 || this._verticalSpeed > 0) {\n            const altitude = this.surfaceAltitudeMeters ?? this.SURFACE_EYE_HEIGHT;\n            const boost = Math.min(\n                this.SURFACE_VERTICAL_BOOST_MAX,\n                this.surfaceVerticalBoost * this.surfaceShiftBoost\n            );\n            const targetVerticalSpeed = verticalDirection !== 0\n                ? this.SURFACE_VERTICAL_SPEED * boost * Math.abs(verticalDirection)\n                : 0;\n            const verticalRateBase = Math.max(Math.abs(this._verticalSpeed), Math.abs(targetVerticalSpeed));\n            this._verticalSpeed = this._approachValue(\n                this._verticalSpeed,\n                targetVerticalSpeed,\n                Math.max(this.SURFACE_VERTICAL_ACCEL, verticalRateBase / this.SURFACE_VERTICAL_ATTACK_SECONDS),\n                Math.max(this.SURFACE_VERTICAL_DECEL, verticalRateBase / this.SURFACE_VERTICAL_RELEASE_SECONDS),\n                deltaTime\n            );\n            if (this._verticalSpeed <= 1e-4) {\n                this._verticalSpeed = 0;\n                if (verticalDirection === 0) {\n                    this._verticalDir = 0;\n                }\n            }\n            const appliedDir = verticalDirection !== 0 ? verticalDirection : this._verticalDir;\n            const altitudeDelta = appliedDir * this._verticalSpeed * deltaTime;\n            const nextAlt = altitude + altitudeDelta;\n            const minAlt = this._getAltitudeClampMin();\n            this._clearSurfaceAutoMSLHold();\n            if (this._airborneMSLGlideActive && Number.isFinite(this._airborneMSLGlideMsl)) {\n                const minGlideMsl = Number.isFinite(this.SURFACE_TERRAIN_MAX_OFFSET)\n                    ? -this.SURFACE_TERRAIN_MAX_OFFSET\n                    : -200000;\n                const maxGlideMsl = Number.isFinite(this.SURFACE_ALTITUDE_MAX)\n                    ? this.SURFACE_ALTITUDE_MAX\n                    : 100000;\n                this._airborneMSLGlideMsl = THREE.MathUtils.clamp(\n                    this._airborneMSLGlideMsl + altitudeDelta,\n                    minGlideMsl,\n                    maxGlideMsl\n                );\n                this.surfaceAltitudeMSL = this._airborneMSLGlideMsl;\n                this.surfaceAltitudeMeters = nextAlt;\n\n                // Deliberate descent can hand control back to walking at the\n                // actual local floor. Horizontal level flight never takes this\n                // path, so a roof or terrain LOD appearing below cannot land or\n                // lift the camera.\n                if (appliedDir < 0 && nextAlt <= minAlt) {\n                    this._clearAirborneMSLGlide();\n                    this.surfaceAltitudeMeters = minAlt;\n                    const terrainR = this._terrainRadius || PLANET_RADIUS;\n                    const ellipsoidR = this._getEllipsoidRadiusForDir(this.surfaceState.up);\n                    this.surfaceAltitudeMSL = terrainR - ellipsoidR\n                        + minAlt + this.SURFACE_TERRAIN_CLEARANCE;\n                }\n            } else {\n                this.surfaceAltitudeMeters = THREE.MathUtils.clamp(\n                    nextAlt,\n                    minAlt,\n                    this.SURFACE_ALTITUDE_MAX\n                );\n                this._surfaceAltitudeReference = 'terrain';\n                const terrainR = this._terrainRadius || PLANET_RADIUS;\n                const ellipsoidR = this._getEllipsoidRadiusForDir(this.surfaceState.up);\n                const terrainElev = terrainR - ellipsoidR;\n                const cameraMsl = this._computeCameraMSL();\n                this.surfaceAltitudeMSL = Number.isFinite(cameraMsl)\n                    ? cameraMsl + altitudeDelta\n                    : terrainElev + this.surfaceAltitudeMeters + this.SURFACE_TERRAIN_CLEARANCE;\n                this._activateAirborneMSLGlide(this.surfaceAltitudeMSL);\n            }\n        }\n\n        const up = this.surfaceState.up;\n        const east = this._vA, north = this._vB;\n        this.computeTangentBasis(up, east, north);\n\n        const mobileX = THREE.MathUtils.clamp(this._xrSurfaceRig ? (this._xrLocomotionInput?.right || 0) : (this.mobileMoveInput?.x || 0), -1, 1);\n        const mobileY = THREE.MathUtils.clamp(this._xrSurfaceRig ? (this._xrLocomotionInput?.forward || 0) : (this.mobileMoveInput?.y || 0), -1, 1);\n        const forwardComp = THREE.MathUtils.clamp(\n            (moveForward ? 1 : 0) + (moveBackward ? -1 : 0) + mobileY,\n            -1,\n            1\n        );\n        const rightComp = THREE.MathUtils.clamp(\n            (moveRight ? 1 : 0) + (moveLeft ? -1 : 0) + mobileX,\n            -1,\n            1\n        );\n        const hasMoveInput = forwardComp !== 0 || rightComp !== 0;\n        const moveInputMagnitude = Math.min(1, Math.hypot(forwardComp, rightComp));\n        this._moveInputHoldSeconds = hasMoveInput\n            ? Math.min(this.SURFACE_MOVE_HOLD_RAMP_SECONDS, this._moveInputHoldSeconds + deltaTime)\n            : 0;\n        const holdProgress = THREE.MathUtils.smoothstep(\n            this._moveInputHoldSeconds,\n            0.12,\n            this.SURFACE_MOVE_HOLD_RAMP_SECONDS\n        );\n        const holdMultiplier = 1 + (this.SURFACE_MOVE_HOLD_MAX - 1) * holdProgress;\n\n        // Move along sphere surface\n        // Flight speed is keyed to its stable ASL command, not calculated AGL.\n        // Otherwise merely crossing a ridge changes horizontal velocity even\n        // though the aircraft has not climbed or descended.\n        const speedAltitude = this._airborneMSLGlideActive\n            && Number.isFinite(this._airborneMSLGlideMsl)\n            ? Math.max(0, this._airborneMSLGlideMsl)\n            : (this.surfaceAltitudeMeters ?? this.SURFACE_EYE_HEIGHT);\n        const altitudeFactor = this._getAltitudeSpeedMultiplier(speedAltitude);\n        const targetSpeed = hasMoveInput\n            ? this.SURFACE_MOVE_SPEED\n                * altitudeFactor\n                * this.surfaceShiftBoost\n                * this.NAV_RUN_SPEED\n                * moveInputMagnitude\n                * holdMultiplier\n            : 0;\n        const moveRateBase = Math.max(Math.abs(this._moveSpeed), Math.abs(targetSpeed));\n        this._moveSpeed = this._approachValue(\n            this._moveSpeed,\n            targetSpeed,\n            Math.max(this.SURFACE_MOVE_ACCEL, moveRateBase / this.SURFACE_MOVE_ATTACK_SECONDS),\n            Math.max(this.SURFACE_MOVE_DECEL, moveRateBase / this.SURFACE_MOVE_RELEASE_SECONDS),\n            deltaTime\n        );\n        if (this._moveSpeed <= 1e-6) return;\n\n        if (hasMoveInput) {\n            let yaw = this.surfaceState.yaw;\n            if (this._xrSurfaceRig) {\n                // Same-frame native head direction, projected onto the local\n                // horizon. Looking up must not make forward movement fly.\n                this.camera.getWorldDirection(this._xrForward);\n                this._xrForward.addScaledVector(up, -this._xrForward.dot(up));\n                if (this._xrForward.lengthSq() > 1e-8) yaw = Math.atan2(this._xrForward.dot(east), this._xrForward.dot(north));\n            }\n            const cosYaw = Math.cos(yaw);\n            const sinYaw = Math.sin(yaw);\n\n            const northMove = forwardComp * cosYaw - rightComp * sinYaw;\n            const eastMove = forwardComp * sinYaw + rightComp * cosYaw;\n\n            this._moveDir.set(0, 0, 0);\n            this._moveDir.addScaledVector(north, northMove);\n            this._moveDir.addScaledVector(east, eastMove);\n            if (this._moveDir.lengthSq() > 0) {\n                this._moveDir.normalize();\n            }\n        }\n\n        if (this._moveDir.lengthSq() < 1e-6) return;\n\n        const moveMeters = this._moveSpeed * deltaTime;\n        this._resolvePhotoSurfaceMoveDirection(this._moveDir, moveMeters, up, this._moveDir);\n        if (this._moveDir.lengthSq() < 1e-6) {\n            this._moveSpeed = 0;\n            return;\n        }\n        const surfaceR = this._getEllipsoidRadiusForDir(up);\n        const moveAngle = moveMeters * this._moveDir.length() / surfaceR; // admitted angular distance\n\n        // Rotate the up vector in the move direction\n        const axis = new THREE.Vector3().crossVectors(up, this._moveDir).normalize();\n        const newUp = up.clone();\n        newUp.applyAxisAngle(axis, moveAngle);\n\n        // Update surface state while preserving local yaw/pitch (avoid pitch drift)\n        this._reanchorUpPreserveOrientation(newUp);\n    }\n\n    applyEarthRotation(deltaRad) {\n        if (_isMetaverseSceneMode()) return;\n        if (this.cameraMode !== 'surface' && this.cameraMode !== 'toSurface') return;\n        if (!Number.isFinite(deltaRad) || deltaRad === 0) return;\n        const axis = this._earthAxis.set(0, 1, 0);\n        if (this.triTree?.group?.getWorldQuaternion) {\n            this.triTree.group.getWorldQuaternion(this._earthAxisQuat);\n            axis.applyQuaternion(this._earthAxisQuat).normalize();\n        }\n        const nextUp = this._vC.copy(this.surfaceState.up).applyAxisAngle(axis, deltaRad);\n        if (this.cameraMode === 'toSurface') {\n            // The landing branch is stored planet-locally by the tile loader,\n            // so its world direction rotates during the one-second descent.\n            // Keep the controller endpoint on that same rotating footprint;\n            // otherwise the camera finishes hundreds of metres west of the\n            // contact branch and immediately samples a different altitude.\n            this.surfaceState.up.copy(nextUp).normalize();\n            const stepQuat = (this._earthRotationStepQuat\n                || (this._earthRotationStepQuat = new THREE.Quaternion()))\n                .setFromAxisAngle(axis, deltaRad);\n            this.camTransition?.endPos?.applyQuaternion(stepQuat);\n            this.camTransition?.endQuat?.premultiply(stepQuat);\n            return;\n        }\n        this._reanchorUpPreserveOrientation(nextUp);\n\n        // Also rotate geo nav pivot point to compensate for Earth rotation during drag\n        // This prevents the camera from sliding when shift+drag repositioning\n        if (this.geoNav?.active && this.geoNav.pivotPoint) {\n            this.geoNav.pivotPoint.applyAxisAngle(axis, deltaRad);\n            if (this.geoNav.pivotNormal) {\n                this.geoNav.pivotNormal.applyAxisAngle(axis, deltaRad).normalize();\n            }\n            if (this.geoNav.dragReady) {\n                // applySurfaceCamera deliberately leaves the exact live drag\n                // pose alone, so rotate that pose with Earth here as well as\n                // rotating its immutable surface anchor.\n                const stepQuat = (this._geoEarthDragQuat\n                    || (this._geoEarthDragQuat = new THREE.Quaternion()))\n                    .setFromAxisAngle(axis, deltaRad);\n                this.camera.position.applyQuaternion(stepQuat);\n                this.camera.quaternion.premultiply(stepQuat);\n                this.camera.updateMatrixWorld?.(true);\n            }\n        }\n    }\n\n    applyEarthRotationOrbit(deltaRad) {\n        if (this._xrSurfaceRig) return;\n        if (_isMetaverseSceneMode()) return;\n        if (this.cameraMode !== 'orbit') return;\n        if (!Number.isFinite(deltaRad) || deltaRad === 0) return;\n        const axis = this._earthAxis.set(0, 1, 0);\n        if (this.triTree?.group?.getWorldQuaternion) {\n            this.triTree.group.getWorldQuaternion(this._earthAxisQuat);\n            axis.applyQuaternion(this._earthAxisQuat).normalize();\n        }\n        const target = this.controls?.target || this._tmpObj.position.set(0, 0, 0);\n        const offset = this._vB.copy(this.camera.position).sub(target);\n        offset.applyAxisAngle(axis, deltaRad);\n        this.camera.position.copy(target).add(offset);\n        this.camera.up.applyAxisAngle(axis, deltaRad);\n        this._ensureOrbitUp();\n        if (this.controls) {\n            this.controls.update();\n        } else {\n            this.camera.lookAt(target);\n        }\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // State queries (public API)\n    // ──────────────────────────────────────────────────────────────\n\n    getCameraMode() {\n        return this.cameraMode;\n    }\n\n    getLODMode() {\n        return this.lodMode;\n    }\n\n    setLODMode(mode) {\n        this.lodMode = mode;\n        // Sync with triTree if available\n        if (this.triTree) {\n            this.triTree.setLODMode(mode);\n        }\n    }\n\n    setNavigationProfile(profile) {\n        const next = (profile === 'geospatial' || profile === 'geo') ? 'geospatial' : 'classic';\n        if (this.navProfile === next) return;\n        this.navProfile = next;\n\n        if (this.navProfile === 'geospatial') {\n            this._cancelPointerLockHold();\n            if (this.isPointerLocked()) {\n                this._exitPointerLock();\n            }\n        }\n    }\n\n    setNavigationConfig(config = {}) {\n        if (!config || typeof config !== 'object') return;\n        if (Number.isFinite(config.runSpeed)) this.NAV_RUN_SPEED = config.runSpeed;\n        if (Number.isFinite(config.dragSpeed)) this.NAV_DRAG_SPEED = config.dragSpeed;\n        if (Number.isFinite(config.rotateSpeed)) this.NAV_ROTATE_SPEED = config.rotateSpeed;\n        if (Number.isFinite(config.zoomSpeed)) this.NAV_ZOOM_SPEED = config.zoomSpeed;\n        if (config.profile) this.setNavigationProfile(config.profile);\n    }\n\n    setMobileMoveInput(x = 0, y = 0) {\n        this.mobileMoveInput ||= { x: 0, y: 0 };\n        this.mobileMoveInput.x = THREE.MathUtils.clamp(Number(x) || 0, -1, 1);\n        this.mobileMoveInput.y = THREE.MathUtils.clamp(Number(y) || 0, -1, 1);\n    }\n\n    /**\n     * Apply one deterministic, collision-aware agent navigation step.\n     * This is the bounded semantic equivalent of a short WASD + mouse-look\n     * input, without synthesizing browser events or retaining a pressed key.\n     */\n    applyAgentCameraStep(input = {}) {\n        if (_isMetaverseSceneMode()) {\n            return { applied: false, errors: ['Agent camera steps are available only in the Earth scene.'] };\n        }\n        if (this._externalCameraOverride || this.cameraMode !== 'surface' || !this.surfaceState?.up) {\n            return { applied: false, errors: ['Agent camera steps require an active surface camera.'] };\n        }\n\n        let forwardMeters = THREE.MathUtils.clamp(Number(input.forwardMeters) || 0, -10, 10);\n        let rightMeters = THREE.MathUtils.clamp(Number(input.rightMeters) || 0, -10, 10);\n        const requestedHorizontalMeters = Math.hypot(forwardMeters, rightMeters);\n        if (requestedHorizontalMeters > 10) {\n            const scale = 10 / requestedHorizontalMeters;\n            forwardMeters *= scale;\n            rightMeters *= scale;\n        }\n        const upMeters = THREE.MathUtils.clamp(Number(input.upMeters) || 0, -5, 5);\n        const yawRadians = THREE.MathUtils.clamp(Number(input.yawRadians) || 0, -Math.PI / 4, Math.PI / 4);\n        const pitchRadians = THREE.MathUtils.clamp(Number(input.pitchRadians) || 0, -Math.PI / 6, Math.PI / 6);\n        if (![forwardMeters, rightMeters, upMeters, yawRadians, pitchRadians].some((value) => Math.abs(value) > 1e-9)) {\n            return { applied: false, errors: ['Agent camera step has no movement or orientation delta.'] };\n        }\n\n        this.surfaceState.yaw = Math.atan2(\n            Math.sin((Number(this.surfaceState.yaw) || 0) + yawRadians),\n            Math.cos((Number(this.surfaceState.yaw) || 0) + yawRadians)\n        );\n        this.surfaceState.pitch = THREE.MathUtils.clamp(\n            (Number(this.surfaceState.pitch) || 0) + pitchRadians,\n            -1.45,\n            1.45\n        );\n\n        let appliedHorizontalMeters = 0;\n        const horizontalMeters = Math.hypot(forwardMeters, rightMeters);\n        if (horizontalMeters > 1e-9) {\n            const up = this.surfaceState.up;\n            const east = new THREE.Vector3();\n            const north = new THREE.Vector3();\n            this.computeTangentBasis(up, east, north);\n            const yaw = this.surfaceState.yaw;\n            const forward = north.clone().multiplyScalar(Math.cos(yaw)).addScaledVector(east, Math.sin(yaw));\n            const right = east.clone().multiplyScalar(Math.cos(yaw)).addScaledVector(north, -Math.sin(yaw));\n            const requestedDirection = forward.multiplyScalar(forwardMeters).addScaledVector(right, rightMeters);\n            if (requestedDirection.lengthSq() > 1e-12) {\n                requestedDirection.normalize();\n                const resolvedDirection = new THREE.Vector3();\n                this._resolvePhotoSurfaceMoveDirection(\n                    requestedDirection,\n                    horizontalMeters,\n                    up,\n                    resolvedDirection\n                );\n                if (resolvedDirection.lengthSq() > 1e-9) {\n                    const admittedMeters = horizontalMeters * Math.min(1, resolvedDirection.length());\n                    resolvedDirection.normalize();\n                    const surfaceRadius = Math.max(1, this._getEllipsoidRadiusForDir(up));\n                    const axis = new THREE.Vector3().crossVectors(up, resolvedDirection).normalize();\n                    const nextUp = up.clone().applyAxisAngle(axis, admittedMeters / surfaceRadius).normalize();\n                    this._reanchorUpPreserveOrientation(nextUp);\n                    appliedHorizontalMeters = admittedMeters;\n                }\n            }\n        }\n\n        const altitudeBefore = this.getSurfaceAltitudeMeters?.() ?? this.surfaceAltitudeMeters ?? 0;\n        if (Math.abs(upMeters) > 1e-9) {\n            this.setSurfaceAltitudeMeters?.(altitudeBefore + upMeters);\n        }\n        this.applySurfaceCamera?.();\n        const altitudeAfter = this.getSurfaceAltitudeMeters?.() ?? this.surfaceAltitudeMeters ?? altitudeBefore;\n\n        return {\n            applied: true,\n            requested: { forwardMeters, rightMeters, upMeters, yawRadians, pitchRadians },\n            appliedHorizontalMeters,\n            appliedVerticalMeters: Number.isFinite(altitudeAfter) ? altitudeAfter - altitudeBefore : 0,\n            surfaceOrientation: {\n                yaw: this.surfaceState.yaw,\n                pitch: this.surfaceState.pitch,\n            },\n            surfaceAltitude: Number.isFinite(altitudeAfter) ? altitudeAfter : null,\n        };\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Celestial body anchor (orbit around Moon, Sun, or Earth)\n    // ──────────────────────────────────────────────────────────────\n\n    /**\n     * Set the function that returns world position of a celestial body.\n     * @param {Function} fn - (bodyName: string) => THREE.Vector3 | null\n     */\n    setBodyPositionGetter(fn) {\n        this._bodyPositionGetter = fn;\n    }\n\n    getBodyAnchor() {\n        return this._bodyAnchor;\n    }\n\n    /**\n     * Transition the orbit camera to orbit around a different celestial body.\n     * @param {'terra'|'luna'|'sol'} bodyName\n     */\n    transitionToBody(bodyName) {\n        const valid = ['terra', 'luna', 'sol'];\n        if (!valid.includes(bodyName)) return;\n        if (bodyName === this._bodyAnchor && !this._bodyTransition) return;\n\n        // Must be in orbit mode (or force back to orbit)\n        if (this.cameraMode === 'surface' || this.cameraMode === 'toSurface') {\n            this.exitSurfaceMode();\n        }\n\n        const targetPos = this._getBodyWorldPosition(bodyName);\n        if (!targetPos) return;\n\n        const currentAnchorPos = this._getBodyWorldPosition(this._bodyAnchor) || this._origin.clone();\n\n        // Compute desired orbit distance for the target body\n        const orbitDist = this._getBodyOrbitDistance(bodyName);\n\n        // Camera end position: place camera at orbitDist from target body\n        // Preserve the viewing direction relative to the current anchor\n        const camDir = this._vA.copy(this.camera.position).sub(currentAnchorPos).normalize();\n        const endPos = camDir.clone().multiplyScalar(orbitDist).add(targetPos);\n\n        // Build end quaternion looking at the target body center\n        this._tmpObj.position.copy(endPos);\n        this._tmpObj.up.set(0, 1, 0);\n        this._tmpObj.lookAt(targetPos);\n        const endQuat = this._tmpObj.quaternion.clone();\n\n        this._bodyTransition = {\n            t0: performance.now(),\n            dur: this.BODY_TRANSITION_MS,\n            startPos: this.camera.position.clone(),\n            startQuat: this.camera.quaternion.clone(),\n            startTarget: this.controls.target.clone(),\n            endPos,\n            endQuat,\n            endTarget: targetPos.clone(),\n            fromBody: this._bodyAnchor,\n            toBody: bodyName\n        };\n\n        // Disable orbit controls during transition\n        this.controls.enabled = false;\n        console.log(`[BODY ANCHOR] Transitioning from ${this._bodyAnchor} to ${bodyName}`);\n    }\n\n    /**\n     * Instantly set the body anchor (e.g. on page load from URL param).\n     */\n    setBodyAnchorImmediate(bodyName) {\n        const valid = ['terra', 'luna', 'sol'];\n        if (!valid.includes(bodyName)) return;\n        if (bodyName === this._bodyAnchor) return;\n\n        const targetPos = this._getBodyWorldPosition(bodyName);\n        if (!targetPos) {\n            console.warn(`[BODY ANCHOR] Cannot resolve position for ${bodyName}`);\n            return;\n        }\n\n        this._bodyAnchor = bodyName;\n        const orbitDist = this._getBodyOrbitDistance(bodyName);\n        const camDir = this.camera.position.clone().normalize();\n        this.camera.position.copy(camDir.multiplyScalar(orbitDist).add(targetPos));\n        this.controls.target.copy(targetPos);\n        this.camera.lookAt(targetPos);\n        // OrbitControls enforces its current maxDistance during update().  Apply\n        // the destination body's limits first; otherwise a Sol URL boot is\n        // clamped by Earth's ~10R max distance and lands inside the Sun.\n        this._applyBodyOrbitLimits(bodyName);\n        this.controls.update();\n\n        if (typeof this.onBodyAnchorChange === 'function') {\n            this.onBodyAnchorChange(bodyName);\n        }\n        console.log(`[BODY ANCHOR] Set immediate: ${bodyName}`);\n    }\n\n    updateBodyTransition() {\n        if (!this._bodyTransition) return false;\n        const bt = this._bodyTransition;\n\n        const dur = bt.dur || 1;\n        const t = dur <= 0 ? 1 : (performance.now() - bt.t0) / dur;\n        const a = THREE.MathUtils.clamp(t, 0, 1);\n        const e = a * a * (3 - 2 * a); // smoothstep\n\n        this.camera.position.lerpVectors(bt.startPos, bt.endPos, e);\n        this.camera.quaternion.slerpQuaternions(bt.startQuat, bt.endQuat, e);\n        this.controls.target.lerpVectors(bt.startTarget, bt.endTarget, e);\n\n        if (a >= 1) {\n            this._bodyAnchor = bt.toBody;\n            this._bodyTransition = null;\n            this.controls.enabled = true;\n            this.controls.target.copy(bt.endTarget);\n\n            // Adjust orbit constraints for the new body\n            this._applyBodyOrbitLimits(bt.toBody);\n\n            this.controls.update();\n            console.log(`[BODY ANCHOR] Transition complete: ${bt.toBody}`);\n\n            if (typeof this.onBodyAnchorChange === 'function') {\n                this.onBodyAnchorChange(bt.toBody);\n            }\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Called each frame to keep orbit target synced with moving bodies.\n     */\n    updateBodyAnchorTarget() {\n        if (this._bodyAnchor === 'terra' || this._bodyTransition) return;\n        const pos = this._getBodyWorldPosition(this._bodyAnchor);\n        if (!pos) return;\n\n        // Move camera + controls target to track body movement\n        const delta = this._vA.copy(pos).sub(this.controls.target);\n        if (delta.lengthSq() < 0.01) return;\n        this.controls.target.copy(pos);\n        this.camera.position.add(delta);\n    }\n\n    _getBodyWorldPosition(bodyName) {\n        if (bodyName === 'terra') return this._origin.clone();\n        if (typeof this._bodyPositionGetter === 'function') {\n            return this._bodyPositionGetter(bodyName);\n        }\n        return null;\n    }\n\n    _getBodyOrbitDistance(bodyName) {\n        switch (bodyName) {\n            case 'luna': return MOON_RADIUS_M * 5; // ~8,700 km from moon center\n            case 'sol': return SUN_RADIUS_M * 4; // ~2.8 million km from sun center\n            case 'terra':\n            default: {\n                // Preserve current orbit distance or default\n                const dist = this.camera.position.length();\n                return dist > 0 ? dist : PLANET_RADIUS * 3;\n            }\n        }\n    }\n\n    _applyBodyOrbitLimits(bodyName) {\n        switch (bodyName) {\n            case 'luna':\n                this.controls.minDistance = MOON_RADIUS_M * 1.5;\n                this.controls.maxDistance = MOON_RADIUS_M * 30;\n                break;\n            case 'sol':\n                this.controls.minDistance = SUN_RADIUS_M * 2;\n                this.controls.maxDistance = SUN_RADIUS_M * 30;\n                break;\n            case 'terra':\n            default:\n                this.controls.minDistance = PLANET_RADIUS + this.SURFACE_EYE_HEIGHT;\n                this.controls.maxDistance = EARTH_ORBIT_MAX_DISTANCE_M;\n                break;\n        }\n    }\n\n    _syncSurfaceFromCamera({ preserveOrientation = false, preserveMSL = null } = {}) {\n        if (!this.camera) return;\n        const pos = this.camera.position;\n        if (!pos || pos.lengthSq() < 1e-8) return;\n\n        const up = pos.clone().normalize();\n        if (preserveOrientation) {\n            this._reanchorUpPreserveOrientation(up);\n        } else {\n            this.setSurfaceFromDir(up, true);\n        }\n\n        if (this._airborneMSLGlideActive) {\n            const posRadius = pos.length();\n            const ellipsoidR = this._getEllipsoidRadiusForDir(pos);\n            const flightMsl = Number.isFinite(preserveMSL)\n                ? preserveMSL\n                : (Number.isFinite(this._airborneMSLGlideMsl)\n                    ? this._airborneMSLGlideMsl\n                    : posRadius - ellipsoidR);\n            const flightGroundR = this.terrainTileGroup\n                ? this._samplePhotoFlightGroundRadius(pos)\n                : (Number.isFinite(this._terrainRadiusRaw)\n                    ? this._terrainRadiusRaw\n                    : (Number.isFinite(this._terrainRadius) ? this._terrainRadius : ellipsoidR));\n            this.surfaceAltitudeMeters = posRadius\n                - (Number.isFinite(flightGroundR) ? flightGroundR : ellipsoidR)\n                - (this.SURFACE_TERRAIN_CLEARANCE || 0);\n            this.surfaceAltitudeMSL = flightMsl;\n            this._airborneMSLGlideMsl = flightMsl;\n            this._surfaceAltitudeReference = 'msl';\n            return;\n        }\n        this.updateSurfaceTerrainThrottled();\n\n        const posRadius = pos.length();\n        const photoGroundSample = this.terrainTileGroup\n            ? this._sampleGroundTruthRadius(pos)\n            : null;\n        const photoGroundRadius = this.terrainTileGroup\n            ? this._resolvePhotoGroundFloorRadius(\n                photoGroundSample,\n                this._getLastRawPhotoGroundRadius(),\n                up,\n            )\n            : null;\n        const terrainRadius = Number.isFinite(photoGroundRadius)\n            ? photoGroundRadius\n            : (this._terrainRadius || PLANET_RADIUS);\n        const altitude = posRadius - terrainRadius - this.SURFACE_TERRAIN_CLEARANCE;\n        const minAlt = this._getAltitudeClampMin();\n        this.surfaceAltitudeMeters = THREE.MathUtils.clamp(\n            altitude,\n            minAlt,\n            this.SURFACE_ALTITUDE_MAX\n        );\n        this._surfaceAltitudeReference = Number.isFinite(preserveMSL) ? 'msl' : 'terrain';\n        const ellipsoidR = this._getEllipsoidRadiusForDir(pos);\n        const computedMsl = posRadius - ellipsoidR;\n        if (Number.isFinite(preserveMSL)) {\n            this.surfaceAltitudeMSL = preserveMSL;\n            // A verified photoreal floor is allowed below WGS84 and must not\n            // be promoted back to the ellipsoid. Non-photoreal terrain keeps\n            // the historical ellipsoid safety basis.\n            const terrainBasisR = Number.isFinite(photoGroundRadius)\n                ? photoGroundRadius\n                : Math.max(\n                    Number.isFinite(this._terrainRadius)\n                        ? this._terrainRadius\n                        : this._getSafeTerrainRadiusForDir(this.surfaceState.up, { useSample: false }),\n                    ellipsoidR\n                );\n            const clearance = this.SURFACE_TERRAIN_CLEARANCE || 0;\n            const terrainElev = terrainBasisR - ellipsoidR;\n            const maxAlt = Number.isFinite(this.SURFACE_ALTITUDE_MAX)\n                ? this.SURFACE_ALTITUDE_MAX\n                : Infinity;\n            const targetAlt = preserveMSL - terrainElev - clearance;\n            const clampedAlt = Number.isFinite(targetAlt)\n                ? THREE.MathUtils.clamp(targetAlt, minAlt, maxAlt)\n                : minAlt;\n            this.surfaceAltitudeMeters = clampedAlt;\n        } else {\n            this.surfaceAltitudeMSL = computedMsl;\n        }\n    }\n\n    _getGeoRayFromClient(clientX, clientY) {\n        if (!this.renderer || !this.camera) return null;\n        const rect = this.renderer.domElement.getBoundingClientRect();\n        const x = ((clientX - rect.left) / rect.width) * 2 - 1;\n        const y = -((clientY - rect.top) / rect.height) * 2 + 1;\n        this._geoNdc.set(x, y);\n        this._geoRaycaster.setFromCamera(this._geoNdc, this.camera);\n        return this._geoRaycaster.ray;\n    }\n\n    _getGeoPhotoSurfaceHitFromRay(ray, out, options = {}) {\n        if (!this.terrainTileGroup || !ray || !out) return null;\n        if (options.skipWorldMatrixUpdate !== true) {\n            this._publishPhotorealSamplingMatrices();\n        }\n        const defaultFar = Math.max(10000, (this.camera?.position?.length?.() || PLANET_RADIUS) * 2);\n        const queryLimit = Number.isFinite(options.maxDistance) && options.maxDistance >= 0\n            ? Math.min(defaultFar, options.maxDistance) : defaultFar;\n        // Sphere/BVH tests use transformed local coordinates. This numerical\n        // guard does not change the caller's exact world-distance acceptance.\n        const roundoffGuard = queryLimit < defaultFar\n            ? Math.max(1e-6, ray.origin.length() * Number.EPSILON * 64) : 0;\n        const far = Math.min(defaultFar, queryLimit + roundoffGuard);\n        this._geoRaycaster.ray.copy(ray);\n        this._geoRaycaster.near = 0;\n        this._geoRaycaster.far = far;\n\n        const candidates = this._collectPhotoTileRayCandidates(ray.origin, ray.direction, far);\n        // Never fall back to recursively raycasting the raw photo group. That\n        // group intentionally retains retiring parent LODs during replacement;\n        // hitting one is what produced displaced surface picks in wireframe and\n        // immediately after a tile upgrade. The candidate collector contains\n        // only currently rendered, authoritative meshes.\n        const hits = candidates.length\n            ? this._geoRaycaster.intersectObjects(candidates, false)\n            : [];\n        if (!hits?.length) return null;\n\n        const ellipsoidR = this._getEllipsoidRadiusForDir(hits[0].point);\n        const maxOffset = Number.isFinite(this.SURFACE_TERRAIN_MAX_OFFSET)\n            ? this.SURFACE_TERRAIN_MAX_OFFSET\n            : this.SURFACE_ALTITUDE_MAX;\n        for (const hit of hits) {\n            if (!hit?.point) continue;\n            const r = hit.point.length();\n            if (!Number.isFinite(r)) continue;\n            if (Number.isFinite(ellipsoidR) && Math.abs(r - ellipsoidR) > maxOffset) continue;\n            return out.copy(hit.point);\n        }\n        return null;\n    }\n\n    /** Controller-ray picking uses the same active photoreal LOD authority. */\n    getSurfacePointFromRay(ray, out = new THREE.Vector3()) {\n        if (!ray || !this.triTree?.group) return null;\n        if (this.terrainTileGroup) {\n            const hit = this._getGeoPhotoSurfaceHitFromRay(ray, out, { maxDistance: 10000 });\n            if (!hit || ray.origin.distanceTo(hit) > 10000) return null;\n            this._lastGeoHitSource = 'photo';\n            return hit;\n        }\n        const hit = rayEllipsoidIntersection(ray.origin, ray.direction, this.triTree.group);\n        if (!hit || ray.origin.distanceTo(hit) > 10000) return null;\n        this._lastGeoHitSource = 'surface';\n        return out.copy(hit);\n    }\n\n    _getGeoPhotoSurfaceHit(clientX, clientY, out) {\n        const ray = this._getGeoRayFromClient(clientX, clientY);\n        if (!ray) return null;\n        return this._getGeoPhotoSurfaceHitFromRay(ray, out);\n    }\n\n    _getGeoSurfaceHit(clientX, clientY, out, radius = null) {\n        const ray = this._getGeoRayFromClient(clientX, clientY);\n        if (!ray) return null;\n        const photoHit = this._isSurfaceWalkingTopologyActive()\n            ? this._getGeoPhotoSurfaceHitFromRay(ray, out)\n            : null;\n        if (photoHit) {\n            this._lastGeoHitSource = 'photo';\n            return photoHit;\n        }\n        const planetGroup = this.triTree?.group || null;\n        let hit = rayEllipsoidIntersection(ray.origin, ray.direction, planetGroup);\n        if (!hit && Number.isFinite(radius) && radius > 0) {\n            hit = raySphereIntersection(ray.origin, ray.direction, radius);\n        }\n        if (!hit) return null;\n        this._lastGeoHitSource = Number.isFinite(radius) && radius > 0 ? 'sphere' : 'ellipsoid';\n        if (Number.isFinite(radius) && radius > 0) {\n            return out.copy(hit).normalize().multiplyScalar(radius);\n        }\n        return out.copy(hit);\n    }\n\n    _getGeoDragSurfaceHit(clientX, clientY, out) {\n        // Dragging must begin on the surface the user can actually see. Unlike\n        // pedestrian floor selection, a tree, facade, or roof remains a valid\n        // visual depth reference even while fixed-ASL flight is active.\n        const photoHit = this.terrainTileGroup\n            ? this._getGeoPhotoSurfaceHit(clientX, clientY, out)\n            : null;\n        if (photoHit) {\n            this._lastGeoHitSource = 'photo';\n            return photoHit;\n        }\n        return this._getGeoSurfaceHit(clientX, clientY, out);\n    }\n\n    _resetGeoDragConstraint() {\n        if (!this.geoNav) return;\n        this.geoNav.dragReady = false;\n        this.geoNav.dragPivotRadius = 0;\n        this.geoNav.dragStepQuaternion?.identity?.();\n        this.geoNav.dragTargetQuaternion?.identity?.();\n        this.geoNav.dragHitSource = null;\n    }\n\n    _beginGeoDragConstraint(clientX, clientY, hit) {\n        this._resetGeoDragConstraint();\n        if (!this.camera || !this.renderer?.domElement || !this.geoNav || !hit) return false;\n        this.camera.updateMatrixWorld?.(true);\n\n        const nav = this.geoNav;\n        nav.dragStartX = clientX;\n        nav.dragStartY = clientY;\n        nav.pivotPoint.copy(hit);\n        nav.pivotNormal.copy(hit).normalize();\n        const center = this._geoDragCenter || (this._geoDragCenter = new THREE.Vector3());\n        center.set(0, 0, 0);\n        this.triTree?.group?.updateWorldMatrix?.(true, false);\n        if (this.triTree?.group?.matrixWorld) {\n            center.setFromMatrixPosition(this.triTree.group.matrixWorld);\n        }\n        nav.dragPivotRadius = hit.distanceTo(center);\n        if (!Number.isFinite(nav.dragPivotRadius) || nav.dragPivotRadius <= 1e-4) return false;\n        nav.dragStepQuaternion ||= new THREE.Quaternion();\n        nav.dragTargetQuaternion ||= new THREE.Quaternion();\n        nav.dragStepQuaternion.identity();\n        nav.dragTargetQuaternion.copy(this.camera.quaternion);\n        nav.dragHitSource = this._lastGeoHitSource;\n        nav.dragReady = true;\n        return nav.dragReady;\n    }\n\n    _getGeoDragTargetDelta(clientX, clientY, out) {\n        const nav = this.geoNav;\n        if (!nav?.dragReady || !this.camera || !out) return null;\n        this.camera.updateMatrixWorld?.(true);\n        const ray = this._getGeoRayFromClient(clientX, clientY);\n        if (!ray) return null;\n\n        // This is the same geometric constraint used by\n        // 3d-tiles-renderer's GlobeControls. Intersect the live pointer ray\n        // with the sphere passing through the immutable rendered grab, then\n        // rotate the complete camera pose until that intersection is the\n        // original point. No linear pixel scale or changing mesh raycast is\n        // involved, so vertical and horizontal pulls obey identical geometry.\n        const center = this._geoDragCenter || (this._geoDragCenter = new THREE.Vector3());\n        center.set(0, 0, 0);\n        this.triTree?.group?.updateWorldMatrix?.(true, false);\n        if (this.triTree?.group?.matrixWorld) {\n            center.setFromMatrixPosition(this.triTree.group.matrixWorld);\n        }\n        const relativeOrigin = this._geoDragRayOrigin\n            || (this._geoDragRayOrigin = new THREE.Vector3());\n        relativeOrigin.copy(ray.origin).sub(center);\n        const sphereHit = raySphereIntersection(\n            relativeOrigin,\n            ray.direction,\n            nav.dragPivotRadius\n        );\n        if (!sphereHit) return null;\n\n        const newPivotDir = this._geoDragNewPivotDir\n            || (this._geoDragNewPivotDir = new THREE.Vector3());\n        const pivotDir = this._geoDragPivotDir\n            || (this._geoDragPivotDir = new THREE.Vector3());\n        newPivotDir.copy(sphereHit).normalize();\n        pivotDir.copy(nav.pivotPoint).sub(center).normalize();\n        if (newPivotDir.lengthSq() < 1e-8 || pivotDir.lengthSq() < 1e-8) return null;\n\n        nav.dragStepQuaternion.setFromUnitVectors(newPivotDir, pivotDir);\n        const relativeCamera = this._geoDragRelativeCamera\n            || (this._geoDragRelativeCamera = new THREE.Vector3());\n        const target = this._geoDragTarget || (this._geoDragTarget = new THREE.Vector3());\n        relativeCamera.copy(this.camera.position).sub(center)\n            .applyQuaternion(nav.dragStepQuaternion);\n        target.copy(center).add(relativeCamera);\n        nav.dragTargetQuaternion.copy(this.camera.quaternion)\n            .premultiply(nav.dragStepQuaternion);\n        out.copy(target).sub(this.camera.position);\n        if (!Number.isFinite(out.x) || !Number.isFinite(out.y) || !Number.isFinite(out.z)) return null;\n        this._lastGeoHitSource = nav.dragHitSource;\n        return out;\n    }\n\n    _rotateAroundPivot(pivot, axis, angle) {\n        if (!axis || !Number.isFinite(angle) || angle === 0) return;\n        this._geoQuat.setFromAxisAngle(axis, angle);\n        const offset = this._geoHit.copy(this.camera.position).sub(pivot);\n        offset.applyQuaternion(this._geoQuat);\n        this.camera.position.copy(pivot).add(offset);\n    }\n\n    getSurfacePosition() {\n        if (this.cameraMode === 'surface' || this.cameraMode === 'toSurface') {\n            // `_terrainRadius` belongs to the legacy terrain provider and may\n            // still equal the WGS84 radius while photoreal tiles are active.\n            // Prefer the accepted rendered-surface radius so downstream HUD,\n            // weather, and overlay consumers do not mistake terrain elevation\n            // (for example ~79 m) for camera AGL.\n            const photoR = this.terrainTileGroup\n                ? this._resolvePhotoGroundFloorRadius(\n                    this._photoGroundEmaR,\n                    this._getLastRawPhotoGroundRadius(),\n                    this.surfaceState?.up,\n                )\n                : null;\n            const baseR = Number.isFinite(photoR)\n                ? photoR\n                : (Number.isFinite(this._terrainRadius)\n                    ? this._terrainRadius\n                    : this._getEllipsoidRadiusForDir(this.surfaceState.up));\n            return this.surfaceState.up.clone().multiplyScalar(baseR);\n        }\n        return null;\n    }\n\n    getSurfaceAltitudeMeters() {\n        // Ground contact exposes the commanded AGL. Once airborne, camera ASL\n        // owns placement and this value becomes the calculated AGL against the\n        // current terrain sample; it may therefore change without moving the\n        // camera vertically.\n        return this.surfaceAltitudeMeters ?? this.SURFACE_EYE_HEIGHT;\n    }\n\n    getActualSurfaceAltitudeMeters() {\n        if (this.terrainTileGroup && this.cameraMode === 'surface' && this.camera?.position) {\n            const cameraPosition = this.getPhotorealContactWorldPosition(\n                this._actualAglPosition\n                    || (this._actualAglPosition = new THREE.Vector3())\n            );\n            if (this._airborneMSLGlideActive) {\n                const flightGroundR = this._samplePhotoFlightGroundRadius(cameraPosition);\n                if (Number.isFinite(flightGroundR)) {\n                    return Math.max(\n                        0,\n                        cameraPosition.length()\n                            - flightGroundR\n                            - (this.SURFACE_TERRAIN_CLEARANCE || 0)\n                    );\n                }\n            }\n            const groundR = this._sampleGroundTruthRadius(cameraPosition);\n            const up = (this._actualAglUp || (this._actualAglUp = new THREE.Vector3()))\n                .copy(cameraPosition)\n                .normalize();\n            // A ray can miss for a frame during a REPLACE handoff even though\n            // the controller has an accepted, point-local photoreal floor.\n            // Resolve the held floor unconditionally. Falling back directly\n            // to `surfaceAltitudeMeters` here exposed MSL/ellipsoid-relative\n            // values as AGL (the observed ~79 m regression).\n            const acceptedSurfaceR = this._resolvePhotoGroundFloorRadius(\n                groundR,\n                this._getLastRawPhotoGroundRadius(),\n                up\n            );\n            if (Number.isFinite(acceptedSurfaceR)) {\n                return Math.max(\n                    0,\n                    cameraPosition.length()\n                        - acceptedSurfaceR\n                        - (this.SURFACE_TERRAIN_CLEARANCE || 0)\n                );\n            }\n        }\n        return this.getSurfaceAltitudeMeters();\n    }\n\n    _selectPhotoGroundRadius(validHits) {\n        if (!Array.isArray(validHits) || validHits.length === 0) return null;\n\n        // The radial center ray is the only sample that answers \"what visible\n        // surface is directly beneath the camera?\" Prefer its outermost hit.\n        // Choosing the lowest point from a 15–30 m ring (the old street-seeking\n        // policy) could put a 1.16 m camera several metres inside the center\n        // tile or a building. Multiple center hits occur while parent/child LODs\n        // overlap; the highest rendered surface is the strict safe contact.\n        let highestCenterR = null;\n        for (const hit of validHits) {\n            if (!hit?.isCenter || !Number.isFinite(hit.r)) continue;\n            highestCenterR = Number.isFinite(highestCenterR)\n                ? Math.max(highestCenterR, hit.r)\n                : hit.r;\n        }\n        if (Number.isFinite(highestCenterR)) return highestCenterR;\n\n        validHits.sort((a, b) => a.offsetM - b.offsetM || b.r - a.r);\n        const nearestOffset = validHits[0]?.offsetM;\n        if (Number.isFinite(nearestOffset)) {\n            let nearestHighestR = null;\n            for (const hit of validHits) {\n                if (!Number.isFinite(hit?.r) || Math.abs(hit.offsetM - nearestOffset) > 0.01) continue;\n                nearestHighestR = Number.isFinite(nearestHighestR)\n                    ? Math.max(nearestHighestR, hit.r)\n                    : hit.r;\n            }\n            if (Number.isFinite(nearestHighestR)) return nearestHighestR;\n        }\n\n        validHits.sort((a, b) => a.r - b.r);\n        const CLUSTER_TOLERANCE_M = 2.0;\n        let clusterEnd = 0;\n        for (let i = 1; i < validHits.length; i++) {\n            if (validHits[i].r - validHits[i - 1].r <= CLUSTER_TOLERANCE_M) {\n                clusterEnd = i;\n            } else {\n                break;\n            }\n        }\n\n        const clusterSize = clusterEnd + 1;\n        if (clusterSize >= 2 || validHits.length === 1) {\n            let sum = 0;\n            for (let i = 0; i <= clusterEnd; i++) sum += validHits[i].r;\n            return sum / clusterSize;\n        }\n\n        return validHits[validHits.length - 1]?.r ?? null;\n    }\n\n    /**\n     * Multi-ray ground truth sampler.\n     * Casts one center and eight fallback rays downward. The center ray owns\n     * camera contact; nearby rays are used only if the active tile has a true\n     * center hole. Only currently renderable meshes participate, so retired\n     * parent LODs cannot pull the floor below the visible surface.\n     *\n     * @param {THREE.Vector3} camPos Camera world position\n     * @returns {number|null} world-space radius of lowest ground point found\n     */\n    _sampleGroundTruthRadius(camPos, { forceWalkableCalibration = false } = {}) {\n        if (!this.terrainTileGroup || !camPos) return null;\n        this._lastGroundSampleEstablishedWalkablePlane = false;\n        const now = performance.now();\n        // Two-tier cache TTL keyed off camera motion. If the camera\n        // is essentially stationary (movement under STATIONARY_M^2),\n        // hold the cached value for the long TTL: the photoreal\n        // tile mesh under a stationary observer should not change\n        // unless a tile streams in. If the camera is moving, fall\n        // back to the short TTL so the sample tracks new locations.\n        //\n        // CRITICAL: the position used for the stationary check must\n        // be in planet-LOCAL coordinates, not world coordinates.\n        //\n        // The Earth rotates beneath the camera at ~7.27e-5 rad/s.\n        // applyEarthRotation() compensates by rotating surfaceState.up\n        // (and therefore the camera's world position) by the same delta\n        // every frame, keeping the user pinned to the same lat/lon.\n        // The net effect: a user standing still on the surface has a\n        // camera position that moves through world space at ~7.7 m per\n        // frame at 60 fps (lat 47°N), even though they are geographically\n        // stationary.\n        //\n        // The previous version compared world positions, so the\n        // stationary check ALWAYS failed for the rotation-compensated\n        // camera and the cache invalidated every frame, producing\n        // continuous re-sampling that re-introduced the half-second\n        // jitter the user reported. Comparing in planet-local space\n        // gives the correct answer: \"stationary\" means stationary\n        // relative to the ground, not relative to the inertial scene.\n        const localPos = this._toPlanetLocal(camPos, this._vCacheLocal || (this._vCacheLocal = new THREE.Vector3()));\n        const localDir = (this._groundTruthLocalDir || (this._groundTruthLocalDir = new THREE.Vector3()))\n            .copy(localPos);\n        if (localDir.lengthSq() > 0) localDir.normalize();\n\n        // TTL tuning: with the planet-local direction cache key\n        // (rotation-invariant and radius-invariant), a stationary user\n        // produces zero cache misses from frame-to-frame. Compare only\n        // lat/lon direction, not full camera position: photoreal LOD\n        // refinement legitimately changes the camera radius by small\n        // amounts, and counting that radial correction as movement causes\n        // a feedback loop: new sample -> camera radius changes -> cache\n        // invalidates -> new sample. Horizontal movement still invalidates\n        // immediately because the normalized direction changes.\n        // At minimum AGL, half a second is long enough to walk into a higher\n        // photoreal surface. Moving contact refreshes at terrain cadence.\n        const SHORT_TTL_MS = Math.max(\n            16,\n            Number.isFinite(this.SURFACE_TERRAIN_SAMPLE_MS)\n                ? this.SURFACE_TERRAIN_SAMPLE_MS\n                : 90\n        );\n        const LONG_TTL_MS = 30000;\n        const contactReuseM2 = PHOTO_CONTACT_REUSE_RADIUS_M * PHOTO_CONTACT_REUSE_RADIUS_M;\n        const horizontalDistSq = this._groundTruthCacheLocalDir\n            ? this._groundTruthCacheLocalDir.distanceToSquared(localDir) * PLANET_RADIUS * PLANET_RADIUS\n            : Infinity;\n        const movementIntent = this._hasSurfaceMovementIntent();\n        const hasCacheDir = !!this._groundTruthCacheLocalDir;\n        // A camera is geographically stationary when the user issues no\n        // movement input. Earth's rotation advances the *world* camera while\n        // its planet-local direction remains fixed, so it does not invalidate\n        // this key. Movement intent still chooses the short TTL, while the\n        // point-local distance check below prevents a stopped camera from\n        // retaining the surface sampled at a nearby coordinate for 30 s.\n        const stationary = !movementIntent;\n        this._groundTruthLastStationary = stationary;\n        this._groundTruthLastHorizontalDistSq = horizontalDistSq;\n        // Photoreal tiles stream/refine under a stationary camera; the long\n        // stationary TTL would keep serving a sample taken against the OLD\n        // mesh for up to 30 s after a finer tile raised the true surface,\n        // leaving the camera clamped underneath the new geometry. The loader\n        // mirrors its model-change counter onto group.userData — when it has\n        // advanced since our last actual raycast, bypass the cached surface\n        // so contact follows the newly rendered mesh immediately.\n        const modelSeq = this.terrainTileGroup?.userData?.photoModelChangeSeq | 0;\n        const geometryChangedSinceSample = modelSeq !== this._groundTruthSampleModelSeq;\n        const ttl = stationary ? LONG_TTL_MS : SHORT_TTL_MS;\n        // A changed model sequence means a different visible surface may now\n        // cover the camera. Never serve even the short movement cache in that\n        // case: the incoming child may be metres above the retired parent and\n        // contact must rise before that child is rendered.\n        if (!forceWalkableCalibration\n            && !geometryChangedSinceSample\n            && this._groundTruthCacheAt && now - this._groundTruthCacheAt < ttl\n            && Number.isFinite(this._groundTruthCacheR)\n            && this._groundTruthCacheLocalDir\n            && horizontalDistSq <= contactReuseM2) {\n            return this._groundTruthCacheR;\n        }\n\n        // Build local ENU basis at the camera's ground direction\n        const upDir = this._vA.copy(camPos).normalize();\n        const worldY = this._vB.set(0, 1, 0);\n        let east = this._vC.crossVectors(worldY, upDir);\n        if (east.lengthSq() < 1e-6) east.set(1, 0, 0);\n        east.normalize();\n        const north = this._vD.crossVectors(upDir, east).normalize();\n\n        const ellipsoidR = this._getEllipsoidRadiusForDir(upDir);\n        const startR = PLANET_RADIUS * 3 + 1_000_000;\n\n        // Ring radii in meters — sample at multiple distances to find streets\n        // even when camera is above a large building footprint\n        const SAMPLE_OFFSETS = [\n            [0, 0],                           // center (straight down)\n            [15, 0], [-15, 0], [0, 15], [0, -15],  // cardinal 15m\n            [30, 0], [-30, 0], [0, 30], [0, -30],  // cardinal 30m\n        ];\n\n        const tmpPt = this._vE || (this._vE = new THREE.Vector3());\n\n        // Collect all valid hits across all rays. We then filter + cluster\n        // to derive a robust ground radius rather than picking a single\n        // min — which is fragile to backface and outlier hits.\n        const validHits = [];\n        this._lastGroundSampleCenterSkinR = null;\n        const commandedAlt = Number.isFinite(this.surfaceAltitudeMeters)\n            ? this.surfaceAltitudeMeters\n            : Infinity;\n        const nearWalkingSurface = this.cameraMode === 'surface'\n            && commandedAlt <= Math.max(\n                Number(this.SURFACE_HUG_EXIT_ALT) || 8,\n                Number(this.SURFACE_EYE_HEIGHT) || 1.6\n            );\n        const walkableReferenceR = Number.isFinite(this._photoWalkableReferenceR)\n            ? this._photoWalkableReferenceR\n            : (Number.isFinite(this._photoGroundEmaR)\n                ? this._photoGroundEmaR\n                : (Number.isFinite(this._photoLastKnownReferenceR)\n                    ? this._photoLastKnownReferenceR\n                    : this._lastSafeGroundR));\n        let needsSupportedCenterRevalidation = false;\n        // Expanded upper ceiling: the previous 500 m cap silently rejected\n        // every hit above mid-elevation, so cities above sea level (any\n        // hill, plateau, mountain town) returned null from the sampler\n        // and the clamp fell back to sea level → camera through the tile.\n        // Everest + margin covers everything on Earth.\n        const MAX_EXPECTED_ELEVATION_M = 9848;\n        const MIN_EXPECTED_ELEVATION_M = -500;              // Dead Sea, Death Valley\n\n        this._publishPhotorealSamplingMatrices();\n        for (const [dE, dN] of SAMPLE_OFFSETS) {\n            const isCenterSample = dE === 0 && dN === 0;\n            const hitCountBeforeRay = validHits.length;\n            tmpPt.copy(camPos);\n            if (dE !== 0) tmpPt.addScaledVector(east, dE);\n            if (dN !== 0) tmpPt.addScaledVector(north, dN);\n\n            // `_rayOrigin` is also the normalized direction scratch here.\n            // Copy the unit vector into `_rayDir` BEFORE scaling the origin.\n            // The former ordering kept `offsetDir` aliased to `_rayOrigin`,\n            // multiplied it by ~20 million, and then copied that non-unit\n            // vector into the ray direction. Raycaster and the finite\n            // ray/sphere candidate prefilter both require a normalized\n            // direction, so every real underfoot tile was rejected and\n            // contact silently fell back to the WGS84 ellipsoid.\n            this._rayOrigin.copy(tmpPt).normalize();\n            this._rayDir.copy(this._rayOrigin).negate();\n            this._rayOrigin.multiplyScalar(startR);\n\n            this.surfaceRaycaster.set(this._rayOrigin, this._rayDir);\n            this.surfaceRaycaster.near = 0;\n            this.surfaceRaycaster.far = startR + 10;\n\n            const candidates = this._collectPhotoTileRayCandidates(this._rayOrigin, this._rayDir);\n            const hits = candidates.length > 0\n                ? this.surfaceRaycaster.intersectObjects(candidates, false)\n                : [];\n            if (!hits || hits.length === 0) continue;\n\n            for (const hit of finestSurfaceContactHits(hits)) {\n                if (!hit.point) continue;\n                const r = hit.point.length();\n                if (!Number.isFinite(r)) continue;\n                const elev = r - ellipsoidR;\n                if (elev < MIN_EXPECTED_ELEVATION_M) continue; // below Dead Sea = noise\n                if (elev > MAX_EXPECTED_ELEVATION_M) continue; // above Everest = noise\n\n                // The ray begins far outside the planet and the selector uses\n                // the highest centre intersection, so the first physical skin\n                // is authoritative. Do not reject it by glTF face winding:\n                // mirrored/transformed r185 tile meshes can report the visible\n                // top skin with an inverted face normal. The former normal gate\n                // discarded that surface and allowed the camera below the tile.\n\n                let radialNormalDot = null;\n                if (hit.face?.normal && hit.object?.matrixWorld) {\n                    const worldNormal = (this._walkableHitNormal\n                        || (this._walkableHitNormal = new THREE.Vector3()))\n                        .copy(hit.face.normal)\n                        .transformDirection(hit.object.matrixWorld)\n                        .normalize();\n                    // `_rayDir` is the normalized inward radial direction;\n                    // the absolute slope test is sign-invariant.\n                    radialNormalDot = Math.abs(worldNormal.dot(this._rayDir));\n                }\n\n                validHits.push({\n                    r,\n                    isCenter: isCenterSample,\n                    offsetM: Math.hypot(dE, dN),\n                    dE,\n                    dN,\n                    sampleKey: `${dE}:${dN}`,\n                    radialNormalDot,\n                });\n            }\n\n            if (isCenterSample && validHits.length > hitCountBeforeRay) {\n                let centerSkinR = null;\n                let hasContinuityGround = false;\n                const stepUp = Math.max(0, Number(this.SURFACE_MAX_WALKABLE_STEP) || 0.55);\n                const slopeDot = Number.isFinite(this.SURFACE_MAX_WALKABLE_SLOPE_DOT)\n                    ? this.SURFACE_MAX_WALKABLE_SLOPE_DOT\n                    : 0.58;\n                for (let i = hitCountBeforeRay; i < validHits.length; i += 1) {\n                    const centerHit = validHits[i];\n                    centerSkinR = Number.isFinite(centerSkinR)\n                        ? Math.max(centerSkinR, centerHit.r)\n                        : centerHit.r;\n                    if (Number.isFinite(walkableReferenceR)\n                        && centerHit.r <= walkableReferenceR + stepUp + 1e-4\n                        && (!Number.isFinite(centerHit.radialNormalDot)\n                            || centerHit.radialNormalDot >= slopeDot)) {\n                        hasContinuityGround = true;\n                    }\n                }\n                if (Number.isFinite(centerSkinR)) {\n                    this._recordPhotoCenterSkinRadius(centerSkinR, upDir, modelSeq);\n                }\n                // A center-only height jump is ambiguous: it can be a finer\n                // terrain LOD, a roof, or foliage. Run the bounded exterior\n                // fit only for that conflict. Broad supported terrain may rise\n                // immediately; an isolated protrusion remains collision-only.\n                needsSupportedCenterRevalidation = nearWalkingSurface\n                    && Number.isFinite(walkableReferenceR)\n                    && Number.isFinite(centerSkinR)\n                    && centerSkinR > walkableReferenceR + stepUp + 1e-4\n                    && !hasContinuityGround;\n            }\n\n            // Center contact is cheap and authoritative in the ordinary\n            // case. Exterior rays are reserved for boot classification or an\n            // abrupt center conflict, never an unconditional per-frame sweep.\n            if (!forceWalkableCalibration\n                && isCenterSample\n                && validHits.length > hitCountBeforeRay\n                && !needsSupportedCenterRevalidation) break;\n        }\n\n        if (validHits.length === 0) return null;\n\n        let result;\n        if (forceWalkableCalibration && Number.isFinite(walkableReferenceR)) {\n            result = this._inferInitialWalkablePhotoGroundRadius(\n                validHits,\n                walkableReferenceR\n            );\n            if (!Number.isFinite(result)) result = curvedSurfaceGroundRadius(validHits, walkableReferenceR,\n                this.SURFACE_MAX_WALKABLE_SLOPE_DOT ?? 0.58);\n            this._lastGroundSampleEstablishedWalkablePlane = Number.isFinite(result);\n        } else if (needsSupportedCenterRevalidation && Number.isFinite(walkableReferenceR)) {\n            result = this._inferInitialWalkablePhotoGroundRadius(\n                validHits,\n                walkableReferenceR,\n                { allowSupportedRise: true }\n            );\n            if (!Number.isFinite(result)) result = curvedSurfaceGroundRadius(validHits, walkableReferenceR,\n                this.SURFACE_MAX_WALKABLE_SLOPE_DOT ?? 0.58);\n        } else {\n            result = nearWalkingSurface && Number.isFinite(walkableReferenceR)\n                ? this._selectWalkablePhotoGroundRadius(validHits, walkableReferenceR)\n                : this._selectPhotoGroundRadius(validHits);\n        }\n        if (!Number.isFinite(result)) {\n            // Consume this model sequence so an isolated roof/canopy does not\n            // trigger nine rays every frame. Keep the occupied walkable floor;\n            // the separately recorded center skin still raises the final\n            // collision gate before rendering.\n            this._groundTruthCacheAt = now;\n            this._groundTruthSampleModelSeq = modelSeq;\n            this._groundTruthCacheLocalDir =\n                (this._groundTruthCacheLocalDir || new THREE.Vector3()).copy(localDir);\n            return Number.isFinite(this._groundTruthCacheR)\n                ? this._groundTruthCacheR\n                : null;\n        }\n\n        // A small downward change may be held to suppress LOD bobbing. Upward\n        // changes are never hidden by this cache: doing so leaves the camera\n        // inside the new active surface for the entire stationary TTL.\n        const JITTER_DEADBAND_M = 2.0;\n        if (Number.isFinite(this._groundTruthCacheR)\n            && stationary\n            && result <= this._groundTruthCacheR\n            && (this._groundTruthCacheR - result) < JITTER_DEADBAND_M) {\n            // Refresh the timestamp so the long TTL stays alive, but do not\n            // move the cached ground value for small high-res LOD deltas.\n            // The fresh raycast validated the cached value against the\n            // current mesh, so the pending geometry change is consumed.\n            this._groundTruthCacheAt = now;\n            this._groundTruthSampleModelSeq = modelSeq;\n            this._groundTruthCacheLocalDir =\n                (this._groundTruthCacheLocalDir || new THREE.Vector3()).copy(localDir);\n            this._photoWalkableReferenceR = this._groundTruthCacheR;\n            return this._groundTruthCacheR;\n        }\n        this._groundTruthCacheR = result;\n        this._groundTruthCacheWalkable = this._lastGroundSampleEstablishedWalkablePlane === true\n            || (nearWalkingSurface && Number.isFinite(walkableReferenceR));\n        this._groundTruthCacheAt = now;\n        this._groundTruthSampleModelSeq = modelSeq;\n        this._groundTruthCacheLocalDir =\n            (this._groundTruthCacheLocalDir || new THREE.Vector3()).copy(localDir);\n        this._photoWalkableReferenceR = result;\n        return result;\n    }\n\n    /**\n     * Transform a world-space position to the planet's local frame.\n     * The planet group rotates per frame (Earth rotation), so a user\n     * who is geographically stationary has a continuously-changing\n     * world position. In the planet's local frame, that same user\n     * has a constant position. Used for cache keys that should be\n     * invariant to Earth rotation.\n     *\n     * @param {THREE.Vector3} worldPos\n     * @param {THREE.Vector3} target reusable scratch vector\n     * @returns {THREE.Vector3} target, written with planet-local position\n     */\n    _toPlanetLocal(worldPos, target) {\n        target.copy(worldPos);\n        const planetGroup = this.triTree?.group;\n        if (planetGroup?.matrixWorld) {\n            // matrixWorldInverse is invalidated by parent updates, but\n            // for a Group at scene origin with only rotation applied,\n            // we can build a fresh inverse cheaply via the existing\n            // world matrix. THREE doesn't auto-update matrixWorldInverse\n            // on Group nodes (only on cameras), so do it manually.\n            this._mPlanetInv = this._mPlanetInv || new THREE.Matrix4();\n            this._mPlanetInv.copy(planetGroup.matrixWorld).invert();\n            target.applyMatrix4(this._mPlanetInv);\n        }\n        return target;\n    }\n\n    /**\n     * Transform a world-space DIRECTION (unit vector) to the planet's\n     * local frame. Differs from _toPlanetLocal only in that it ignores\n     * the translation component of the inverse matrix — directions are\n     * rotation-only by definition. Used for storing the safety-floor\n     * up vector so the teleport-detector compares like with like and\n     * is not fooled by Earth rotation moving `up` through world space.\n     *\n     * @param {THREE.Vector3} worldDir\n     * @param {THREE.Vector3} target\n     * @returns {THREE.Vector3} target, written with planet-local direction\n     */\n    _toPlanetLocalDirection(worldDir, target) {\n        target.copy(worldDir);\n        const planetGroup = this.triTree?.group;\n        if (planetGroup?.matrixWorld) {\n            this._mPlanetInv = this._mPlanetInv || new THREE.Matrix4();\n            this._mPlanetInv.copy(planetGroup.matrixWorld).invert();\n            // Apply rotation only (3x3 portion of the matrix). For a\n            // group with no scale this is equivalent to extracting the\n            // basis from the matrix and rotating the vector.\n            target.transformDirection(this._mPlanetInv);\n        }\n        return target;\n    }\n\n    getSurfaceAltitudeMSL() {\n        return this.surfaceAltitudeMSL;\n    }\n\n    _computeCameraMSL(position = null) {\n        const pos = position || this._getCameraAnchor()?.position;\n        if (!pos || pos.lengthSq() < 1e-8) return null;\n        const ellipsoidR = this._getEllipsoidRadiusForDir(pos);\n        const posRadius = pos.length();\n        const msl = posRadius - ellipsoidR;\n        return Number.isFinite(msl) ? msl : null;\n    }\n\n    _getActiveSurfaceMSL() {\n        if (this._surfaceDragMSLLock && Number.isFinite(this._surfaceDragLockedMSL)) {\n            return this._surfaceDragLockedMSL;\n        }\n        if (this._airborneMSLGlideActive && Number.isFinite(this._airborneMSLGlideMsl)) {\n            return this._airborneMSLGlideMsl;\n        }\n        if (this._surfaceAltitudeReference === 'msl' && Number.isFinite(this.surfaceAltitudeMSL)) {\n            return this.surfaceAltitudeMSL;\n        }\n        if (this._surfaceAltitudeReference === 'msl') {\n            return this._computeCameraMSL();\n        }\n        return null;\n    }\n\n    /**\n     * Walking height: ASL sets the camera height, AGL only keeps it out of\n     * the ground. Photoreal tiles refining under the viewer (and per-sample\n     * noise between neighbouring triangles) move the sampled ground by\n     * decimetres; following each sample made walking visibly jitter.\n     *  - The eye eases toward ground + eye-height in both directions at a\n     *    rate tied to how far the viewer actually moved (slope ≤ ~1.2, plus a\n     *    small settle rate), so a standing viewer is never moved by a tile\n     *    swap and walking follows real terrain smoothly.\n     *  - A hard floor (WALK_NO_CLIP_M under the eye target) snaps at once, so\n     *    the camera never ends up beneath geometry; real drops > 3 m fall.\n     *  - A changed AGL command (scroll / crouch / jump landing) applies at once.\n     */\n    _stabilizeWalkingRadius(targetR, contactGround, worldUp, minFloor, aglCommand) {\n        const now = performance.now();\n        const hold = this._walkingHeightHold;\n        // Measure walking in the planet-fixed frame: the world-space up turns\n        // with Earth's rotation (~290 m/s at 51°N), which read as constant\n        // fast walking and disabled the smoothing.\n        const up = this._planetFixedDirection(worldUp, this._walkUpLocal ||= new THREE.Vector3());\n        if (!hold || this._isJumping || !Number.isFinite(hold.r) || hold.agl !== aglCommand) {\n            this._walkingHeightHold = { r: targetR, up: up.clone(), agl: aglCommand, t: now };\n            return targetR;\n        }\n        const dt = THREE.MathUtils.clamp((now - hold.t) / 1000, 0, 0.25);\n        // Chord, not acos(dot): centimetre steps on a 6371 km radius round to 0 in acos.\n        const movedM = hold.up.distanceTo(up) * targetR;\n        const speed = movedM / Math.max(dt, 1e-3);\n        const followRate = speed * WALK_HEIGHT_MAX_SLOPE + (speed > 0.05 ? WALK_HEIGHT_SETTLE_MPS : 0);\n        let r = hold.r;\n        const delta = targetR - r;\n        if (delta < -WALK_LEDGE_DROP_M) r -= Math.min(-delta, WALK_FALL_MPS * dt); // a real drop\n        else r += THREE.MathUtils.clamp(delta, -followRate * dt, followRate * dt);\n        // Hard no-clip floor: the only instant correction.\n        if (Number.isFinite(contactGround)) {\n            r = Math.max(r, contactGround + Math.max(0.05, minFloor - WALK_NO_CLIP_M));\n        }\n        hold.r = r; hold.up.copy(up); hold.t = now;\n        return r;\n    }\n\n    _planetFixedDirection(worldDir, target) {\n        target.copy(worldDir);\n        const planetGroup = this.triTree?.group;\n        if (planetGroup?.getWorldQuaternion) {\n            planetGroup.getWorldQuaternion(this._walkPlanetQuat ||= new THREE.Quaternion());\n            target.applyQuaternion(this._walkPlanetQuat.invert());\n        }\n        return target;\n    }\n\n    _getAirborneMSLGlideThreshold() {\n        return Math.max(\n            this._getSurfaceFloorAltitude(),\n            Number(this.SURFACE_GRAVITY_CAPTURE_ALT) || 8\n        );\n    }\n\n    /**\n     * Whether photoreal geometry currently owns radial locomotion physics.\n     *\n     * Surface mode contains two deliberately separate regimes: fixed-ASL\n     * free flight and gravity-bound walking. Only the latter may adopt streamed\n     * floors or move the camera in response to a tile LOD. Both regimes may\n     * perform a bounded swept-movement raycast: in flight that sweep can only\n     * reject/slide a commanded horizontal move and can never change ASL. A\n     * jump remains part of the walking regime so it can land again.\n     */\n    _isSurfaceWalkingTopologyActive() {\n        if (this.cameraMode !== 'surface') return false;\n        if (this._airborneMSLGlideActive) return false;\n        if (this._isJumping) return true;\n        const altitude = Number(this.surfaceAltitudeMeters);\n        return !Number.isFinite(altitude)\n            || altitude <= this._getAirborneMSLGlideThreshold();\n    }\n\n    isSurfaceWalkingTopologyActive() {\n        return this._isSurfaceWalkingTopologyActive();\n    }\n\n    _selectPhotoFlightGroundRadius(sampleRadii) {\n        if (!Array.isArray(sampleRadii) || sampleRadii.length === 0) return null;\n        const sorted = sampleRadii.filter(Number.isFinite).sort((a, b) => a - b);\n        if (sorted.length === 0) return null;\n        // Use the lower quartile of the local footprint. One low triangle\n        // cannot dominate, while isolated roofs/tree crowns are deliberately\n        // excluded from the flight AGL reference. Broad terrain changes still\n        // move the complete sample distribution and therefore the result.\n        const index = Math.floor((sorted.length - 1) * 0.25);\n        return sorted[index];\n    }\n\n    /**\n     * Read-only regional ground estimate for airborne AGL telemetry.\n     *\n     * This sampler never touches the pedestrian floor/EMA. It samples a\n     * bounded local footprint at 4 Hz, selects the lower supported terrain\n     * band, and lets ASL remain the sole camera placement authority. An idle\n     * Earth-fixed footprint retains its datum through sub-meter LOD noise;\n     * unchanged geometry needs no repeat raycast. The\n     * separation is essential because photogrammetry contains roofs and tree\n     * canopies that should change reported AGL context, not flight altitude.\n     */\n    _samplePhotoFlightGroundRadius(worldPosition = this.camera?.position) {\n        if (!this.terrainTileGroup || !worldPosition || worldPosition.lengthSq?.() < 1e-8) {\n            return Number.isFinite(this._photoFlightGroundR) ? this._photoFlightGroundR : null;\n        }\n\n        const now = performance.now();\n        const localDir = this._photoFlightSampleLocalDir\n            || (this._photoFlightSampleLocalDir = new THREE.Vector3());\n        this._toPlanetLocalDirection(worldPosition, localDir).normalize();\n        const modelSeq = this.terrainTileGroup?.userData?.photoModelChangeSeq | 0;\n        const ageMs = now - (this._photoFlightGroundAt || 0);\n        const movedM = this._photoFlightGroundLocalDir\n            ? Math.sqrt(this._photoFlightGroundLocalDir.distanceToSquared(localDir)) * PLANET_RADIUS\n            : Infinity;\n        const cameraR = worldPosition.length();\n        const cachedAgl = Number.isFinite(this._photoFlightGroundR)\n            ? cameraR - this._photoFlightGroundR\n            : Infinity;\n        const directCommand = this._surfaceDragAGLLock || this.geoNav?.active\n            || now < this._surfaceScrollHoldUntil;\n        const idleFlight = cachedAgl > 25 && movedM < 0.5\n            && Math.abs(cameraR - this._photoFlightGroundCameraR) < 0.5\n            && !directCommand && !this._hasSurfaceMovementIntent();\n        const intervalMs = cachedAgl < 25\n            ? Math.max(75, Number(this.SURFACE_TERRAIN_SAMPLE_MS) || 90)\n            : Math.max(100, Number(this.SURFACE_FLIGHT_AGL_SAMPLE_MS) || 250);\n        if (Number.isFinite(this._photoFlightGroundR)\n            && (ageMs < intervalMs || idleFlight)\n            && movedM < 20\n            && modelSeq === this._photoFlightGroundModelSeq) {\n            return this._photoFlightGroundR;\n        }\n\n        const up = this._photoFlightSampleUp\n            || (this._photoFlightSampleUp = new THREE.Vector3());\n        up.copy(worldPosition).normalize();\n        const east = this._photoFlightSampleEast\n            || (this._photoFlightSampleEast = new THREE.Vector3());\n        const north = this._photoFlightSampleNorth\n            || (this._photoFlightSampleNorth = new THREE.Vector3());\n        east.crossVectors(this._wNorth || new THREE.Vector3(0, 1, 0), up);\n        if (east.lengthSq() < 1e-6) east.set(1, 0, 0);\n        east.normalize();\n        north.crossVectors(up, east).normalize();\n\n        const ellipsoidR = this._getEllipsoidRadiusForDir(up);\n        const minRadiusM = Math.max(20, Number(this.SURFACE_FLIGHT_AGL_SAMPLE_RADIUS_MIN) || 40);\n        const maxRadiusM = Math.max(minRadiusM, Number(this.SURFACE_FLIGHT_AGL_SAMPLE_RADIUS_MAX) || 180);\n        const reportedAgl = Math.max(0, Number(this.surfaceAltitudeMeters) || 0);\n        const ringM = THREE.MathUtils.clamp(minRadiusM + reportedAgl * 0.12, minRadiusM, maxRadiusM);\n        const offsets = [\n            [0, 0],\n            [ringM, 0], [-ringM, 0], [0, ringM], [0, -ringM],\n            [ringM * 2, 0], [-ringM * 2, 0], [0, ringM * 2], [0, -ringM * 2],\n        ];\n        const maxOffset = Math.max(12_000, Number(this.SURFACE_TERRAIN_MAX_OFFSET) || 200_000);\n        const startR = Math.max(ellipsoidR, PLANET_RADIUS) + maxOffset + 20_000;\n        const far = maxOffset * 2 + 40_000;\n        const minElevation = -500;\n        const maxElevation = 9_848;\n        const slopeDot = Number.isFinite(this.SURFACE_MAX_WALKABLE_SLOPE_DOT)\n            ? this.SURFACE_MAX_WALKABLE_SLOPE_DOT\n            : 0.58;\n        const probe = this._photoFlightSampleProbe\n            || (this._photoFlightSampleProbe = new THREE.Vector3());\n        const rayOrigin = this._photoFlightRayOrigin\n            || (this._photoFlightRayOrigin = new THREE.Vector3());\n        const rayDirection = this._photoFlightRayDirection\n            || (this._photoFlightRayDirection = new THREE.Vector3());\n        const hitNormal = this._photoFlightHitNormal\n            || (this._photoFlightHitNormal = new THREE.Vector3());\n        const sampleRadii = [];\n        let centerRadius = null;\n\n        this._publishPhotorealSamplingMatrices();\n        for (const [dE, dN] of offsets) {\n            probe.copy(up).multiplyScalar(ellipsoidR);\n            if (dE) probe.addScaledVector(east, dE);\n            if (dN) probe.addScaledVector(north, dN);\n            rayOrigin.copy(probe).normalize();\n            rayDirection.copy(rayOrigin).negate();\n            rayOrigin.multiplyScalar(startR);\n            this.surfaceRaycaster.set(rayOrigin, rayDirection);\n            this.surfaceRaycaster.near = 0;\n            this.surfaceRaycaster.far = far;\n            const candidates = this._collectPhotoTileRayCandidates(rayOrigin, rayDirection, far);\n            const hits = candidates.length\n                ? this.surfaceRaycaster.intersectObjects(candidates, false)\n                : [];\n            let sampleR = null;\n            for (const hit of hits) {\n                if (!hit?.point) continue;\n                const radius = hit.point.length();\n                const elevation = radius - ellipsoidR;\n                if (!Number.isFinite(radius)\n                    || elevation < minElevation\n                    || elevation > maxElevation) continue;\n                if (hit.face?.normal && hit.object?.matrixWorld) {\n                    hitNormal.copy(hit.face.normal)\n                        .transformDirection(hit.object.matrixWorld)\n                        .normalize();\n                    if (Math.abs(hitNormal.dot(rayDirection)) < slopeDot) continue;\n                }\n                sampleR = radius;\n                break;\n            }\n            if (dE === 0 && dN === 0) centerRadius = sampleR;\n            if (Number.isFinite(sampleR)) sampleRadii.push(sampleR);\n        }\n\n        const resolved = this._selectPhotoFlightGroundRadius(sampleRadii);\n        if (Number.isFinite(resolved)) {\n            // Flight AGL is calculated against this datum and is serialized\n            // into the URL. Tiny REPLACE/LOD changes at an unchanged footprint\n            // used to rewrite altitude every sample despite constant camera\n            // ASL. Keep the accepted datum, rather than feeding noise back into\n            // the footprint radius through the newly calculated AGL. Movement,\n            // explicit altitude input, significant corrections and the entire\n            // near-contact band still adopt fresh geometry without this hold.\n            const holdDatum = idleFlight && Math.abs(resolved - this._photoFlightGroundR) < 1;\n            if (!holdDatum) {\n                this._photoFlightGroundR = resolved;\n                this._photoFlightGroundLocalDir = this._photoFlightGroundLocalDir || new THREE.Vector3();\n                this._photoFlightGroundLocalDir.copy(localDir);\n            }\n            this._photoFlightGroundAt = now;\n            this._photoFlightGroundModelSeq = modelSeq;\n            this._photoFlightGroundCameraR = cameraR;\n            // Reuse this already sampled center for interior presentation.\n            // This is read-only context, never a new flight placement floor.\n            this._photoFlightCenterR = centerRadius;\n            this._photoFlightCenterModelSeq = modelSeq;\n            (this._photoFlightCenterLocalDir ||= new THREE.Vector3()).copy(localDir);\n        }\n        return Number.isFinite(this._photoFlightGroundR) ? this._photoFlightGroundR : null;\n    }\n\n    _activateAirborneMSLGlide(preferredMsl = null) {\n        if (this.cameraMode !== 'surface' || this._isJumping) return false;\n        if (!Number.isFinite(this.surfaceAltitudeMeters)\n            || this.surfaceAltitudeMeters <= this._getAirborneMSLGlideThreshold()) {\n            return false;\n        }\n        const targetMsl = Number.isFinite(preferredMsl)\n            ? preferredMsl\n            : (Number.isFinite(this.surfaceAltitudeMSL)\n                ? this.surfaceAltitudeMSL\n                : this._computeCameraMSL());\n        if (!Number.isFinite(targetMsl)) return false;\n        this._clearSurfaceAutoMSLHold();\n        this._airborneMSLGlideMsl = targetMsl;\n        this._airborneMSLGlideActive = true;\n        this.surfaceAltitudeMSL = targetMsl;\n        return true;\n    }\n\n    _clearAirborneMSLGlide() {\n        this._airborneMSLGlideActive = false;\n        this._airborneMSLGlideMsl = null;\n    }\n\n    _clearSurfaceAutoMSLHold() {\n        this._surfaceAutoMSLHold = null;\n        this._surfaceAutoMSLHoldActive = false;\n    }\n\n    _shouldAutoHoldSurfaceMSL(altitude = null) {\n        if (this.cameraMode !== 'surface') return false;\n        if (this._surfaceDragMSLLock || this._surfaceDragAGLLock) return false;\n        if (this._surfaceAltitudeReference === 'msl') return false;\n        if (this._isJumping) return false;\n        if (this.keyState?.q || this.keyState?.e) return false;\n        if (performance.now() < this._surfaceScrollHoldUntil) return false;\n\n        // Photoreal surface mode keeps the user-facing altitude as commanded\n        // AGL. Holding MSL here converts every tile-ground refinement into an\n        // apparent altitude change while the user is idle; the photoreal camera\n        // path already has an upward-only floor clamp for safety.\n        if (this.terrainTileGroup) return false;\n\n        const resolvedAlt = Number.isFinite(altitude) ? altitude : this.surfaceAltitudeMeters;\n        if (!Number.isFinite(resolvedAlt)) return false;\n        const lockMinAlt = Number.isFinite(this.SURFACE_AUTO_MSL_HOLD_MIN_ALT)\n            ? this.SURFACE_AUTO_MSL_HOLD_MIN_ALT\n            : this.SURFACE_SCROLL_SOFTEN_START_ALT;\n        return resolvedAlt >= lockMinAlt;\n    }\n\n    _getEffectiveSurfaceMSL(altitude = null) {\n        const explicitMSL = this._getActiveSurfaceMSL();\n        if (Number.isFinite(explicitMSL)) {\n            this._clearSurfaceAutoMSLHold();\n            return explicitMSL;\n        }\n\n        if (!this._shouldAutoHoldSurfaceMSL(altitude)) {\n            this._clearSurfaceAutoMSLHold();\n            return null;\n        }\n\n        if (!this._surfaceAutoMSLHoldActive || !Number.isFinite(this._surfaceAutoMSLHold)) {\n            const computedMSL = this._computeCameraMSL();\n            if (!Number.isFinite(computedMSL)) {\n                this._clearSurfaceAutoMSLHold();\n                return null;\n            }\n            this._surfaceAutoMSLHold = computedMSL;\n            this._surfaceAutoMSLHoldActive = true;\n        }\n\n        return this._surfaceAutoMSLHold;\n    }\n\n    _setSurfaceDragMSLLock(enabled) {\n        if (!enabled || this.cameraMode !== 'surface') {\n            const hadLock = this._surfaceDragMSLLock;\n            this._surfaceDragMSLLock = false;\n            this._surfaceDragLockedMSL = null;\n            this._surfaceDragAGLLock = false;\n            this._surfaceDragLockedAltitude = null;\n            if (hadLock &&\n                this._surfaceDragReferenceBeforeLock === 'terrain' &&\n                this._surfaceAltitudeReference === 'msl') {\n                this._surfaceAltitudeReference = 'terrain';\n            }\n            this._surfaceDragReferenceBeforeLock = null;\n            return;\n        }\n\n        // URL and normal surface controls express altitude as AGL. Preserve\n        // that exact user command while panning; locking MSL here used to\n        // cause a terrain-dependent altitude jump and a delayed correction.\n        // Keep the MSL path for the small number of explicit-MSL callers.\n        if (this._surfaceAltitudeReference !== 'msl' && !this._airborneMSLGlideActive) {\n            const minAlt = this._getAltitudeClampMin();\n            const currentAlt = Number.isFinite(this.surfaceAltitudeMeters)\n                ? this.surfaceAltitudeMeters\n                : minAlt;\n            this._surfaceDragMSLLock = false;\n            this._surfaceDragLockedMSL = null;\n            this._surfaceDragReferenceBeforeLock = 'terrain';\n            this._surfaceDragAGLLock = true;\n            this._surfaceDragLockedAltitude = THREE.MathUtils.clamp(\n                currentAlt,\n                minAlt,\n                this.SURFACE_ALTITUDE_MAX\n            );\n            return;\n        }\n\n        this._surfaceDragAGLLock = false;\n        this._surfaceDragLockedAltitude = null;\n\n        if (!this._surfaceDragMSLLock) {\n            this._surfaceDragReferenceBeforeLock = (this._surfaceAltitudeReference === 'msl')\n                ? 'msl'\n                : 'terrain';\n        }\n\n        if (!this._surfaceDragMSLLock || !Number.isFinite(this._surfaceDragLockedMSL)) {\n            const baseline = this._getActiveSurfaceMSL();\n            const fallback = this._computeCameraMSL();\n            this._surfaceDragLockedMSL = Number.isFinite(baseline)\n                ? baseline\n                : (Number.isFinite(fallback) ? fallback : null);\n        }\n        this._surfaceDragMSLLock = true;\n    }\n\n    /**\n     * Set altitude in meters above terrain, updating MSL to match.\n     * This keeps altitude and MSL in sync so terrain updates don't overwrite.\n     * @param {number} alt - Altitude in meters above terrain\n     */\n    setSurfaceAltitudeMeters(alt) {\n        if (!Number.isFinite(alt)) return;\n        this._cancelSurfaceScrollAltitude();\n        this._clearSurfaceAutoMSLHold();\n        this._clearAirborneMSLGlide();\n        // Treat explicit altitude sets (HUD drag, remote camera sync) as user intent:\n        // suppress auto-MSL hold briefly so altitude-above-ground changes are not\n        // immediately overwritten by a fixed-MSL clamp.\n        const now = (typeof performance !== 'undefined' && typeof performance.now === 'function')\n            ? performance.now()\n            : Date.now();\n        const holdMs = Number.isFinite(this.SURFACE_SCROLL_HOLD_MS)\n            ? Math.max(50, this.SURFACE_SCROLL_HOLD_MS)\n            : 280;\n        this._surfaceScrollHoldUntil = Math.max(this._surfaceScrollHoldUntil || 0, now + holdMs);\n        this._surfaceScrollHoldDir = 0;\n        const minAlt = this._getAltitudeClampMin();\n        const clampedAlt = THREE.MathUtils.clamp(alt, minAlt, this.SURFACE_ALTITUDE_MAX);\n        this.surfaceAltitudeMeters = clampedAlt;\n        this._surfaceAltitudeReference = 'terrain';\n        // Update MSL to match so updateSurfaceTerrainThrottled doesn't overwrite\n        const terrainR = this._terrainRadius || PLANET_RADIUS;\n        const ellipsoidR = this._getEllipsoidRadiusForDir(this.surfaceState.up);\n        const maxOffset = Number.isFinite(this.SURFACE_TERRAIN_MAX_OFFSET)\n            ? this.SURFACE_TERRAIN_MAX_OFFSET\n            : Infinity;\n        const terrainElev = THREE.MathUtils.clamp(\n            terrainR - ellipsoidR,\n            -maxOffset,\n            maxOffset\n        );\n        this.surfaceAltitudeMSL = terrainElev + clampedAlt + this.SURFACE_TERRAIN_CLEARANCE;\n    }\n\n    setSurfaceAltitudeMSL(msl) {\n        if (!Number.isFinite(msl)) return;\n        this._cancelSurfaceScrollAltitude();\n        this._clearSurfaceAutoMSLHold();\n        this._clearAirborneMSLGlide();\n        this._surfaceAltitudeReference = 'msl';\n        const ellipsoidR = this._getEllipsoidRadiusForDir(this.surfaceState.up);\n        const terrainR = this._getSafeTerrainRadiusForDir(this.surfaceState.up, { useSample: false });\n        const maxOffset = Number.isFinite(this.SURFACE_TERRAIN_MAX_OFFSET)\n            ? this.SURFACE_TERRAIN_MAX_OFFSET\n            : Infinity;\n        const terrainElev = THREE.MathUtils.clamp(\n            terrainR - ellipsoidR,\n            -maxOffset,\n            maxOffset\n        );\n        const minAltitude = this._getNavigationFloorAltitude(this.surfaceState.up);\n        const maxAltitude = Number.isFinite(this.SURFACE_ALTITUDE_MAX)\n            ? this.SURFACE_ALTITUDE_MAX\n            : Infinity;\n        const minMsl = terrainElev + minAltitude + this.SURFACE_TERRAIN_CLEARANCE;\n        const maxMsl = Number.isFinite(maxAltitude)\n            ? terrainElev + maxAltitude + this.SURFACE_TERRAIN_CLEARANCE\n            : Infinity;\n        const clampedMsl = THREE.MathUtils.clamp(msl, minMsl, maxMsl);\n        this.surfaceAltitudeMSL = clampedMsl;\n        this.surfaceAltitudeMeters = clampedMsl - terrainElev - this.SURFACE_TERRAIN_CLEARANCE;\n    }\n\n    enforceSurfaceFloor({ useSample = true } = {}) {\n        if (this.cameraMode !== 'surface') return false;\n        if (this.geoNav?.active\n            && this.geoNav.action === 'drag'\n            && this.geoNav.dragReady) return false;\n        const anchor = this._getCameraAnchor();\n        const minClearance = this._getSurfaceFloorAltitude();\n        const corrected = this._enforceCameraAboveTerrain({\n            minClearance,\n            useSample: !!useSample,\n            anchor,\n            syncAltitude: true\n        });\n        this.commitVRRigPose();\n        return corrected;\n    }\n\n    getSurfaceAltitudeMin() {\n        return this._getAltitudeClampMin();\n    }\n\n    getSurfaceAltitudeMax() {\n        return this.SURFACE_ALTITUDE_MAX;\n    }\n\n    getSurfacePitchDeg() {\n        return this.surfaceState.pitch * RAD2DEG;\n    }\n\n    getSurfaceHeadingDeg() {\n        const heading = this.surfaceState.yaw * RAD2DEG;\n        return (heading % 360 + 360) % 360;\n    }\n\n    setExternalCameraOverride(enabled) {\n        // Legacy camera owners use this boolean API. Never let one of them\n        // silently clear a tokenized MotionRuntime owner. A new legacy owner\n        // may request takeover; the token gets one synchronous cancellation\n        // opportunity and must release before the legacy write proceeds.\n        if (this._externalCameraOverrideOwner) {\n            if (enabled) this._externalCameraOverrideOwner.onConflict?.('CAMERA_OWNERSHIP_REPLACED');\n            if (this._externalCameraOverrideOwner) return false;\n        }\n        this._externalCameraOverride = !!enabled;\n        return true;\n    }\n\n    acquireExternalCameraOverride(owner = 'external') {\n        if (this._externalCameraOverride || this._externalCameraOverrideOwner) return null;\n        const descriptor = owner && typeof owner === 'object' ? owner : { owner };\n        const token = Object.freeze({\n            owner: String(descriptor.owner || 'external'),\n            generation: (this._externalCameraOverrideGeneration || 0) + 1,\n            onConflict: typeof descriptor.onConflict === 'function' ? descriptor.onConflict : null,\n        });\n        this._externalCameraOverrideGeneration = token.generation;\n        this._externalCameraOverrideOwner = token;\n        this._externalCameraOverride = true;\n        return token;\n    }\n\n    releaseExternalCameraOverride(token) {\n        if (!token || this._externalCameraOverrideOwner !== token) return false;\n        this._externalCameraOverrideOwner = null;\n        this._externalCameraOverride = false;\n        return true;\n    }\n\n    /** Apply a runtime-owned AGL surface pose without reopening terrain/GPS\n     * initialization on every frame. The exact ownership token is mandatory. */\n    applyExternalSurfacePose(token, pose = {}) {\n        if (!token || this._externalCameraOverrideOwner !== token\n            || this._xrSurfaceRig || _isMetaverseSceneMode()) return false;\n        if (!Number.isFinite(pose.latitude) || !Number.isFinite(pose.longitude)\n            || !Number.isFinite(pose.altitudeM)) return false;\n        const dir = latLonToLocalDir(pose.latitude, pose.longitude, this._vA);\n        if (this.triTree?.group?.getWorldQuaternion) {\n            this.triTree.group.getWorldQuaternion(this._tmpVRQuat);\n            dir.applyQuaternion(this._tmpVRQuat);\n        }\n        this._reanchorUpPreserveOrientation(dir);\n        this.surfaceAltitudeMeters = THREE.MathUtils.clamp(\n            pose.altitudeM,\n            this._getAltitudeClampMin(),\n            Number.isFinite(this.SURFACE_ALTITUDE_MAX) ? this.SURFACE_ALTITUDE_MAX : Infinity\n        );\n        this._surfaceAltitudeReference = 'terrain';\n        if (Number.isFinite(pose.headingDeg)) this.surfaceState.yaw = pose.headingDeg * DEG2RAD;\n        if (Number.isFinite(pose.pitchDeg)) this.surfaceState.pitch = pose.pitchDeg * DEG2RAD;\n        if (Number.isFinite(pose.rollDeg)) this.surfaceState.roll = pose.rollDeg * DEG2RAD;\n        this.cameraMode = 'surface';\n        this.lodMode = 'zoom';\n        if (this.controls) this.controls.enabled = false;\n        this._applySurfaceCamera(token);\n        this.camera?.updateMatrixWorld?.(true);\n        return true;\n    }\n\n    isInSurfaceMode() {\n        return this.cameraMode === 'surface';\n    }\n\n    /**\n     * Resolve a screen coordinate to the visible photoreal surface, falling\n     * back to the local WGS84 ellipsoid when no photoreal mesh is available.\n     * Intended for deliberate, low-frequency scene gestures such as mobile\n     * field-note placement; never call this from the render loop.\n     */\n    getSurfacePointFromClient(clientX, clientY, out = null) {\n        if (!Number.isFinite(clientX) || !Number.isFinite(clientY)) return null;\n        const target = out?.isVector3 ? out : new THREE.Vector3();\n        // Deliberate picks must use the same authoritative rendered-tile\n        // candidate set as right-button surface dragging. _getGeoSurfaceHit\n        // intentionally limits photoreal hits to pedestrian topology and\n        // therefore displaced fixed-ASL/orbit selections onto the ellipsoid.\n        return this._getGeoDragSurfaceHit(clientX, clientY, target);\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Event handlers\n    // ──────────────────────────────────────────────────────────────\n\n    isEditableTarget(el) {\n        if (!el) return false;\n        const tag = (el.tagName || '').toLowerCase();\n        if (tag === 'input' || tag === 'textarea' || tag === 'select') return true;\n        if (el.isContentEditable) return true;\n        if (el.getAttribute && el.getAttribute('contenteditable') === 'true') return true;\n        return false;\n    }\n\n    isPointerLocked() {\n        return document.pointerLockElement === this.renderer.domElement;\n    }\n\n    _requestPointerLock() {\n        const el = this.renderer?.domElement;\n        if (!el || typeof el.requestPointerLock !== 'function') return;\n        try {\n            const result = el.requestPointerLock();\n            if (result && typeof result.catch === 'function') {\n                result.catch(() => { });\n            }\n        } catch { }\n    }\n\n    _exitPointerLock() {\n        if (document.pointerLockElement) {\n            try { document.exitPointerLock?.(); } catch { }\n        }\n    }\n\n    _positionPointerLockRing(clientX, clientY) {\n        const ring = this.pointerLockState.ring;\n        if (!ring) return;\n        const rect = this.renderer.domElement.getBoundingClientRect();\n        const x = clientX - rect.left;\n        const y = clientY - rect.top;\n        ring.style.left = `${x}px`;\n        ring.style.top = `${y}px`;\n    }\n\n    _showPointerLockRing(scale) {\n        const ring = this.pointerLockState.ring;\n        if (!ring) return;\n        ring.classList.add('active');\n        ring.style.transform = `translate(-50%, -50%) scale(${scale.toFixed(3)})`;\n    }\n\n    _hidePointerLockRing() {\n        const ring = this.pointerLockState.ring;\n        if (!ring) return;\n        ring.classList.remove('active');\n        ring.style.transform = '';\n    }\n\n    _startPointerLockHold(e) {\n        if (this.pointerLockState.holding || this.isPointerLocked()) return;\n        this.pointerLockState.holding = true;\n        this.pointerLockState.holdStart = performance.now();\n        this.pointerLockState.holdPointerId = e.pointerId;\n        this.pointerLockState.holdX = e.clientX;\n        this.pointerLockState.holdY = e.clientY;\n        this._positionPointerLockRing(e.clientX, e.clientY);\n        this._updatePointerLockHold();\n    }\n\n    _cancelPointerLockHold() {\n        if (!this.pointerLockState.holding) return;\n        this.pointerLockState.holding = false;\n        this.pointerLockState.holdPointerId = null;\n        if (this.pointerLockState.raf) {\n            cancelAnimationFrame(this.pointerLockState.raf);\n            this.pointerLockState.raf = null;\n        }\n        this._hidePointerLockRing();\n    }\n\n    _updatePointerLockHold() {\n        if (!this.pointerLockState.holding) return;\n        const elapsed = performance.now() - this.pointerLockState.holdStart;\n        if (elapsed >= this.POINTER_LOCK_HOLD_MS) {\n            this._requestPointerLock();\n            this._cancelPointerLockHold();\n            return;\n        }\n\n        if (elapsed >= this.POINTER_LOCK_RING_DELAY_MS) {\n            const span = this.POINTER_LOCK_HOLD_MS - this.POINTER_LOCK_RING_DELAY_MS;\n            const t = Math.min(1, (elapsed - this.POINTER_LOCK_RING_DELAY_MS) / span);\n            const phase = t < 0.5 ? (t / 0.5) : ((1 - t) / 0.5);\n            const scale = 0.45 + phase * 0.9;\n            this._showPointerLockRing(scale);\n        } else {\n            this._hidePointerLockRing();\n        }\n\n        this.pointerLockState.raf = requestAnimationFrame(this._updatePointerLockHold);\n    }\n\n    _onPointerLockChange() {\n        const locked = this.isPointerLocked();\n        this.pointerLockState.active = locked;\n        this.surfaceState.dragging = false;\n        this._cancelPointerLockHold();\n    }\n\n    _onPointerLockError() {\n        this._cancelPointerLockHold();\n    }\n\n    _onContextMenu(e) {\n        if (this.navProfile === 'geospatial'\n            || e.shiftKey\n            || this.geoNav?.active\n            || this.orbitViewPivot?.dragging\n            || (this.cameraMode === 'orbit' && e.button === 2)\n            || (this.cameraMode === 'surface' && e.button === 2)) {\n            e.preventDefault();\n        }\n    }\n\n    _onGeoPointerDown(e) {\n        if (this._xrSurfaceRig) return;\n        if (this.cameraMode === 'toSurface' || this.cameraMode === 'toOrbit') return;\n        if (e.pointerType === 'mouse' && e.button !== 0 && e.button !== 1 && e.button !== 2) return;\n        const isMiddle = e.button === 1;\n        const wantsRotate = isMiddle\n            || (e.shiftKey && e.button === 2)\n            || (e.shiftKey && e.button === 0 && this.cameraMode === 'orbit');\n        const wantsDrag = !wantsRotate\n            && this.cameraMode === 'surface'\n            && ((!e.shiftKey && e.button === 2) || (e.shiftKey && e.button === 0));\n        if (!wantsRotate && !wantsDrag) return;\n        let hit = null;\n        if (wantsRotate && this.cameraMode === 'orbit' && e.shiftKey) {\n            hit = this._getOrbitPivotUnderCamera(this._geoHit);\n        }\n        if (!hit) {\n            hit = wantsDrag\n                ? this._getGeoDragSurfaceHit(e.clientX, e.clientY, this._geoHit)\n                : this._getGeoSurfaceHit(e.clientX, e.clientY, this._geoHit);\n        }\n        if (!hit) return;\n        e.preventDefault();\n\n        this.geoNav.active = true;\n        this.geoNav.pointerId = e.pointerId;\n        this.geoNav.lastX = e.clientX;\n        this.geoNav.lastY = e.clientY;\n        this.geoNav.pivotPoint.copy(hit);\n        this.geoNav.pivotNormal.copy(hit).normalize();\n        this.geoNav.action = wantsRotate ? 'rotate' : 'drag';\n        if (this.geoNav.action === 'drag') {\n            if (!this._beginGeoDragConstraint(e.clientX, e.clientY, hit)) {\n                this.geoNav.active = false;\n                this.geoNav.action = null;\n                this.geoNav.pointerId = null;\n                return;\n            }\n        } else {\n            this._resetGeoDragConstraint();\n        }\n        this._setSurfaceDragMSLLock(this.geoNav.action === 'drag');\n        if (this.geoNav.action === 'drag' && this.cameraMode === 'surface') {\n            this._showSurfaceGrabRing(e.clientX, e.clientY, this._lastGeoHitSource);\n        }\n        this.renderer?.domElement.setPointerCapture?.(e.pointerId);\n    }\n\n    _getOrbitPivotUnderCamera(out) {\n        if (!this.camera || !out) return null;\n        const camPos = this.camera.position;\n        if (!camPos || camPos.lengthSq() < 1e-6) return null;\n        const dir = this._vA.copy(camPos).normalize().negate();\n        const planetGroup = this.triTree?.group || null;\n        const hit = rayEllipsoidIntersection(camPos, dir, planetGroup);\n        if (hit) {\n            return out.copy(hit);\n        }\n        const radius = this._getEllipsoidRadiusForDir(camPos);\n        if (Number.isFinite(radius) && radius > 0) {\n            return out.copy(dir).multiplyScalar(radius);\n        }\n        return null;\n    }\n\n    _startGeoTouch(e, action) {\n        // Orbital input owns the whole canvas, including the sky. Surface\n        // gestures keep their exact terrain-hit admission below.\n        if (action === 'orbit' && this._bodyAnchor === 'terra') {\n            if (!this._beginOrbitDrag(e.clientX, e.clientY, e.pointerId)) return false;\n            Object.assign(this.geoNav, { active: true, pointerId: e.pointerId,\n                lastX: e.clientX, lastY: e.clientY, action });\n            this._resetGeoDragConstraint();\n            this._setSurfaceDragMSLLock(false);\n            this.renderer?.domElement.setPointerCapture?.(e.pointerId);\n            return true;\n        }\n        const hit = action === 'drag'\n            ? this._getGeoDragSurfaceHit(e.clientX, e.clientY, this._geoHit)\n            : this._getGeoSurfaceHit(e.clientX, e.clientY, this._geoHit);\n        if (!hit) return false;\n        this.geoNav.active = true;\n        this.geoNav.pointerId = e.pointerId;\n        this.geoNav.lastX = e.clientX;\n        this.geoNav.lastY = e.clientY;\n        this.geoNav.pivotPoint.copy(hit);\n        this.geoNav.pivotNormal.copy(hit).normalize();\n        this.geoNav.action = action;\n        if (action === 'drag') {\n            if (!this._beginGeoDragConstraint(e.clientX, e.clientY, hit)) {\n                this.geoNav.active = false;\n                this.geoNav.action = null;\n                this.geoNav.pointerId = null;\n                return false;\n            }\n        } else {\n            this._resetGeoDragConstraint();\n        }\n        this._setSurfaceDragMSLLock(action === 'drag');\n        if (action === 'orbit') {\n            this._beginOrbitDrag(e.clientX, e.clientY, e.pointerId);\n        }\n        this.renderer?.domElement.setPointerCapture?.(e.pointerId);\n        return true;\n    }\n\n    _startSurfaceTouch(e) {\n        if (this._startGeoTouch(e, 'drag')) return true;\n\n        // A low-altitude camera can legitimately have no globe/terrain\n        // intersection under a finger (sky, an unhydrated photo-tile gap, or\n        // a near-horizontal view). Never turn that into a dead gesture.\n        // Fall back to a view-relative tangent pan that preserves altitude.\n        this.geoNav.active = true;\n        this.geoNav.action = 'surface-pan';\n        this.geoNav.pointerId = e.pointerId;\n        this.geoNav.lastX = e.clientX;\n        this.geoNav.lastY = e.clientY;\n        this._resetGeoDragConstraint();\n        this._setSurfaceDragMSLLock(true);\n        this._showSurfaceGrabRing(e.clientX, e.clientY, 'tangent');\n        this.renderer?.domElement.setPointerCapture?.(e.pointerId);\n        return true;\n    }\n\n    _onGeoTouchPointerDown(e) {\n        if (this.cameraMode === 'toSurface' || this.cameraMode === 'toOrbit') return;\n        e.preventDefault();\n        this.geoNav.touchPointers.set(e.pointerId, { x: e.clientX, y: e.clientY });\n        const count = this.geoNav.touchPointers.size;\n\n        if (count === 2) {\n            this.geoNav.pinchDistance = this._getGeoTouchPinchDistance();\n            this.geoNav.action = 'pinch';\n            this.geoNav.active = false;\n            this.geoNav.pointerId = null;\n            this.orbitState.dragging = false;\n            this.orbitState.pointerId = null;\n            this._beginOrbitTouchGesture();\n            this._resetGeoDragConstraint();\n            this._setSurfaceDragMSLLock(false);\n            this._hideSurfaceGrabRing();\n            this.renderer?.domElement.setPointerCapture?.(e.pointerId);\n            return;\n        }\n\n        if (count > 2) {\n            this.renderer?.domElement.setPointerCapture?.(e.pointerId);\n            return;\n        }\n\n        if (this.cameraMode === 'surface') {\n            if (this.isGPSPositionLocked()) {\n                // GPS owns translation. Keep the camera anchored to its next\n                // fix and let the finger temporarily offset the live device\n                // orientation instead.\n                this._beginDeviceLookGesture();\n                this.geoNav.active = true;\n                this.geoNav.action = 'gps-look';\n                this.geoNav.pointerId = e.pointerId;\n                this.geoNav.lastX = e.clientX;\n                this.geoNav.lastY = e.clientY;\n                this.renderer?.domElement.setPointerCapture?.(e.pointerId);\n                return;\n            }\n\n            // In ordinary surface mode the canvas is the planet: one finger\n            // grabs the visible terrain and translates the camera along it.\n            if (!this._startSurfaceTouch(e)) {\n                this.geoNav.touchPointers.delete(e.pointerId);\n            }\n            return;\n        }\n\n        if (!this._startGeoTouch(e, 'orbit')) {\n            this.geoNav.touchPointers.delete(e.pointerId);\n        }\n    }\n\n    _onGeoTouchPointerMove(e) {\n        const entry = this.geoNav.touchPointers.get(e.pointerId);\n        if (!entry) return;\n        e.preventDefault();\n        entry.x = e.clientX;\n        entry.y = e.clientY;\n\n        if (this.geoNav.touchPointers.size >= 2) {\n            if (this.geoNav.orbitTouch && this.cameraMode === 'orbit') {\n                this._applyOrbitTouchGesture();\n                return;\n            }\n            const nextDist = this._getGeoTouchPinchDistance();\n            if (Number.isFinite(nextDist) && Number.isFinite(this.geoNav.pinchDistance) && this.geoNav.pinchDistance > 0) {\n                if (this.cameraMode === 'surface') {\n                    this._setSurfacePinchAltitude(this.geoNav.pinchDistance, nextDist);\n                } else if (this.cameraMode === 'orbit') {\n                    const ratio = this.geoNav.pinchDistance / Math.max(1, nextDist);\n                    const dist = this.camera.position.length();\n                    const base = Number.isFinite(this.orbitZoomTarget) ? this.orbitZoomTarget : dist;\n                    const minDist = this.controls?.minDistance ?? (PLANET_RADIUS + this.SURFACE_EYE_HEIGHT);\n                    const maxDist = this.controls?.maxDistance ?? EARTH_ORBIT_MAX_DISTANCE_M;\n                    this.orbitZoomTarget = THREE.MathUtils.clamp(base * ratio, minDist, maxDist);\n                }\n                this.geoNav.pinchDistance = nextDist;\n            }\n            return;\n        }\n\n        if (this.geoNav.active && this.geoNav.pointerId === e.pointerId) {\n            if (this.geoNav.action === 'gps-look' && this.cameraMode === 'surface') {\n                const dx = e.clientX - this.geoNav.lastX;\n                const dy = e.clientY - this.geoNav.lastY;\n                this.geoNav.lastX = e.clientX;\n                this.geoNav.lastY = e.clientY;\n                this._beginDeviceLookGesture();\n                this._deviceLookOffsetYaw = THREE.MathUtils.clamp(\n                    // This is a temporary camera-look offset, not a terrain\n                    // grab: a rightward finger drag must turn the view right.\n                    (this._deviceLookOffsetYaw || 0) + (dx * this.surfaceState.sens),\n                    -Math.PI,\n                    Math.PI\n                );\n                this._deviceLookOffsetPitch = THREE.MathUtils.clamp(\n                    (this._deviceLookOffsetPitch || 0) + (dy * this.surfaceState.sens),\n                    -1.2,\n                    1.2\n                );\n            } else {\n                this._onGeoPointerMove(e);\n            }\n        }\n    }\n\n    _onGeoTouchPointerUp(e) {\n        const pointers = this.geoNav.touchPointers;\n        if (!pointers.has(e.pointerId)) return;\n        e.preventDefault();\n        pointers.delete(e.pointerId);\n        if (this.orbitState.pointerId === e.pointerId) {\n            this.orbitState.dragging = false;\n            this.orbitState.pointerId = null;\n        }\n        try { this.renderer?.domElement.releasePointerCapture?.(e.pointerId); } catch { }\n\n        if (pointers.size < 2) {\n            this.geoNav.pinchDistance = null;\n            this._endOrbitTouchGesture();\n        } else {\n            // A third contact may replace either member of the pair. Rebase\n            // at the current pose instead of interpreting that as a twist.\n            this.geoNav.pinchDistance = this._getGeoTouchPinchDistance();\n            this._beginOrbitTouchGesture();\n            return;\n        }\n\n        if (!pointers.size) {\n            if (this.geoNav.action === 'gps-look') {\n                this._scheduleDeviceLookRecenter();\n            }\n            this.geoNav.active = false;\n            this.geoNav.action = null;\n            this.geoNav.pointerId = null;\n            this._resetGeoDragConstraint();\n            this._setSurfaceDragMSLLock(false);\n            this._hideSurfaceGrabRing();\n            return;\n        }\n\n        const [nextId, pos] = pointers.entries().next().value;\n        this.geoNav.pointerId = nextId;\n        this.geoNav.lastX = pos.x;\n        this.geoNav.lastY = pos.y;\n        this._setSurfaceDragMSLLock(false);\n\n        if (this.cameraMode === 'orbit') {\n            this.geoNav.action = 'orbit';\n            this.geoNav.active = true;\n            this._beginOrbitDrag(pos.x, pos.y, nextId);\n        } else if (this.isGPSPositionLocked()) {\n            this._beginDeviceLookGesture();\n            this.geoNav.action = 'gps-look';\n            this.geoNav.active = true;\n        } else {\n            this.geoNav.active = false;\n            this.geoNav.action = null;\n            if (!this._startSurfaceTouch({\n                pointerId: nextId,\n                clientX: pos.x,\n                clientY: pos.y,\n            })) {\n                pointers.delete(nextId);\n            }\n        }\n    }\n\n    _setSurfacePinchAltitude(previousDistance, nextDistance) {\n        if (!Number.isFinite(previousDistance)\n            || !Number.isFinite(nextDistance)\n            || previousDistance <= 0\n            || nextDistance <= 0) {\n            return;\n        }\n        const minimum = this._getAltitudeClampMin();\n        const current = Number.isFinite(this._surfaceScrollAltitudeTarget)\n            ? this._surfaceScrollAltitudeTarget\n            : (Number.isFinite(this.surfaceAltitudeMeters)\n                ? this.surfaceAltitudeMeters\n                : this.SURFACE_EYE_HEIGHT);\n        // Use a small virtual dolly offset so pinch remains responsive at eye\n        // height. Closing the fingers ascends; spreading descends.\n        const dollyOffset = 5;\n        const ratio = previousDistance / nextDistance;\n        const next = THREE.MathUtils.clamp(\n            (Math.max(0, current - minimum) + dollyOffset) * ratio\n                - dollyOffset\n                + minimum,\n            minimum,\n            this.SURFACE_ALTITUDE_MAX\n        );\n        this._verticalSpeed = 0;\n        this._verticalDir = 0;\n        this._clearSurfaceAutoMSLHold();\n        this._surfaceScrollAltitudeTarget = next;\n        this._surfaceScrollExitRequested = next >= this.SURFACE_ALTITUDE_MAX * 0.95;\n        this._surfaceAltitudeReference = 'terrain';\n    }\n\n    _resetTouchNavigationState() {\n        this.resetKeyboardLook();\n        this._endOrbitTouchGesture();\n        if (this.geoNav?.action === 'gps-look') {\n            this._scheduleDeviceLookRecenter();\n        }\n        const pointers = this.geoNav?.touchPointers;\n        if (pointers) {\n            for (const pointerId of pointers.keys()) {\n                try { this.renderer?.domElement.releasePointerCapture?.(pointerId); } catch { }\n            }\n            pointers.clear();\n        }\n        if (this.geoNav) {\n            this.geoNav.active = false;\n            this.geoNav.action = null;\n            this.geoNav.pointerId = null;\n            this.geoNav.pinchDistance = null;\n            this.geoNav.pinchFovActive = false;\n            this._resetGeoDragConstraint();\n        }\n        this.orbitState?.pointers?.clear?.();\n        if (this.orbitState) {\n            this.orbitState.dragging = false;\n            this.orbitState.pointerId = null;\n            this.orbitState.pinchDistance = null;\n        }\n        this._setSurfaceDragMSLLock(false);\n        this._hideSurfaceGrabRing();\n        this._hideFovIndicator();\n    }\n\n    _getGeoTouchPinchDistance() {\n        if (this.geoNav.touchPointers.size < 2) return null;\n        const pts = Array.from(this.geoNav.touchPointers.values());\n        const dx = pts[1].x - pts[0].x;\n        const dy = pts[1].y - pts[0].y;\n        return Math.sqrt(dx * dx + dy * dy);\n    }\n\n    _beginOrbitTouchGesture() {\n        if (this.cameraMode !== 'orbit' || this._bodyAnchor !== 'terra') return;\n        const [a, b] = this.geoNav.touchPointers.values();\n        if (!a || !b) return;\n        const x = (a.x + b.x) / 2, y = (a.y + b.y) / 2;\n        if (!this._beginOrbitViewPivot(x, y, null)) return;\n        const pivot = this.orbitViewPivot;\n        this.geoNav.orbitTouch = {\n            x, y, distance: Math.max(1, Math.hypot(b.x - a.x, b.y - a.y)),\n            angle: Math.atan2(b.y - a.y, b.x - a.x),\n            yaw: pivot.targetYaw, pitch: pivot.targetPitch,\n            roll: pivot.targetRoll || 0,\n            zoom: Number.isFinite(this.orbitZoomTarget) ? this.orbitZoomTarget : this.camera.position.length(),\n        };\n    }\n\n    _applyOrbitTouchGesture() {\n        const gesture = this.geoNav.orbitTouch, pivot = this.orbitViewPivot;\n        const [a, b] = this.geoNav.touchPointers.values();\n        if (!gesture || !pivot || !a || !b) return;\n        const dx = (a.x + b.x) / 2 - gesture.x, dy = (a.y + b.y) / 2 - gesture.y;\n        const sens = this.ORBIT_VIEW_PIVOT_SENS ?? 0.0022;\n        const cos = Math.cos(gesture.roll), sin = Math.sin(gesture.roll);\n        // All three components share the same pair snapshot. Separate native\n        // pointer events for one pinch must not accumulate look/roll inertia.\n        this._setOrbitViewPivotTarget(\n            gesture.yaw + (dx * cos + dy * sin) * sens,\n            gesture.pitch + (-dx * sin + dy * cos) * sens,\n            true,\n        );\n        const angle = Math.atan2(b.y - a.y, b.x - a.x);\n        const delta = Math.atan2(Math.sin(angle - gesture.angle), Math.cos(angle - gesture.angle));\n        pivot.targetRoll = (pivot.targetRoll || 0) + delta;\n        gesture.angle = angle;\n        pivot.velocityYaw = pivot.velocityPitch = 0;\n        pivot.lastInteractionAt = this._orbitNow();\n        const distance = Math.max(1, Math.hypot(b.x - a.x, b.y - a.y));\n        const min = this.controls?.minDistance ?? (PLANET_RADIUS + this.SURFACE_EYE_HEIGHT);\n        const max = this.controls?.maxDistance ?? EARTH_ORBIT_MAX_DISTANCE_M;\n        this.orbitZoomTarget = THREE.MathUtils.clamp(gesture.zoom * gesture.distance / distance, min, max);\n    }\n\n    _endOrbitTouchGesture() {\n        if (!this.geoNav?.orbitTouch) return;\n        this.geoNav.orbitTouch = null;\n        this._endOrbitViewPivot();\n        // Touch stops at release; mouse right-drag keeps its existing inertia.\n        this.orbitViewPivot.velocityYaw = this.orbitViewPivot.velocityPitch = 0;\n    }\n\n    _showFovIndicator() {\n        const fovEl = document.getElementById('hud-fov');\n        if (!fovEl) return;\n        fovEl.classList.add('pinch-active');\n        // Clear any pending hide timer\n        if (this._fovHideTimer) {\n            clearTimeout(this._fovHideTimer);\n            this._fovHideTimer = null;\n        }\n    }\n\n    _hideFovIndicator() {\n        if (typeof document === 'undefined') return;\n        const fovEl = document.getElementById('hud-fov');\n        if (!fovEl) return;\n        // Delay hiding so users can see the final value\n        this._fovHideTimer = setTimeout(() => {\n            fovEl.classList.remove('pinch-active');\n            this._fovHideTimer = null;\n        }, 800);\n    }\n\n    _ensureSurfaceGrabRing() {\n        if (this._surfaceGrabRing?.isConnected) return this._surfaceGrabRing;\n        if (typeof document === 'undefined') return null;\n        let ring = document.getElementById('surface-grab-ring');\n        if (!ring) {\n            ring = createSceneLocationIndicator({\n                id: 'surface-grab-ring',\n                variant: 'drag',\n                label: 'Photoreal surface location drag',\n                showViewshed: false,\n            });\n            document.body.appendChild(ring);\n        }\n        this._surfaceGrabRing = ring;\n        return ring;\n    }\n\n    _showSurfaceGrabRing(clientX, clientY, source = null) {\n        const ring = this._ensureSurfaceGrabRing();\n        if (!ring) return;\n        updateSceneLocationIndicator(ring, {\n            x: clientX,\n            y: clientY,\n            active: true,\n            photoreal: source === 'photo',\n        });\n    }\n\n    _showSurfaceGrabRingAtAnchor(fallbackX, fallbackY) {\n        const pivot = this.geoNav?.pivotPoint;\n        const rect = this.renderer?.domElement?.getBoundingClientRect?.();\n        if (!pivot || !rect || !this.camera) {\n            this._showSurfaceGrabRing(fallbackX, fallbackY, this._lastGeoHitSource);\n            return;\n        }\n        this.camera.updateMatrixWorld?.(true);\n        const projected = this._geoDragProjectedAnchor\n            || (this._geoDragProjectedAnchor = new THREE.Vector3());\n        projected.copy(pivot).project(this.camera);\n        if (!Number.isFinite(projected.x) || !Number.isFinite(projected.y)) {\n            this._showSurfaceGrabRing(fallbackX, fallbackY, this._lastGeoHitSource);\n            return;\n        }\n        this._showSurfaceGrabRing(\n            rect.left + ((projected.x + 1) * 0.5 * rect.width),\n            rect.top + ((1 - projected.y) * 0.5 * rect.height),\n            this._lastGeoHitSource\n        );\n    }\n\n    _hideSurfaceGrabRing() {\n        const ring = this._surfaceGrabRing;\n        if (!ring) return;\n        updateSceneLocationIndicator(ring, {\n            active: false,\n            photoreal: false,\n        });\n    }\n\n    _onGeoPointerMove(e) {\n        if (!this.geoNav.active || this.geoNav.pointerId !== e.pointerId) return;\n        const dx = e.clientX - this.geoNav.lastX;\n        const dy = e.clientY - this.geoNav.lastY;\n        if (!dx && !dy) return;\n\n        this.geoNav.lastX = e.clientX;\n        this.geoNav.lastY = e.clientY;\n\n        if (this.geoNav.action === 'drag') {\n            this._applyGeoDrag(e.clientX, e.clientY);\n            if (this.cameraMode === 'surface') {\n                // Position the marker from the immutable world anchor, not\n                // from the event. Any future constraint regression is then\n                // visible immediately instead of being hidden by the cursor.\n                this._showSurfaceGrabRingAtAnchor(e.clientX, e.clientY);\n            }\n        } else if (this.geoNav.action === 'surface-pan') {\n            this._applySurfaceTouchPan(dx, dy);\n            this._showSurfaceGrabRing(e.clientX, e.clientY, 'tangent');\n        } else if (this.geoNav.action === 'rotate') {\n            this._applyGeoRotate(dx, dy);\n        } else if (this.geoNav.action === 'orbit') {\n            // One-finger orbit in orbit mode on mobile (same as desktop left-click drag)\n            this._applyMobileOrbitDrag(e.clientX, e.clientY);\n        }\n    }\n\n    _applyMobileOrbitDrag(clientX, clientY) {\n        this._applyOrbitDrag(clientX, clientY);\n    }\n\n    _applySurfaceTouchPan(dx, dy) {\n        if (this.cameraMode !== 'surface' || (!dx && !dy)) return;\n\n        const up = this.surfaceState.up;\n        const east = this._vA;\n        const north = this._vB;\n        this.computeTangentBasis(up, east, north);\n\n        const yaw = this.surfaceState.yaw || 0;\n        const cosYaw = Math.cos(yaw);\n        const sinYaw = Math.sin(yaw);\n        const forward = this._vC\n            .copy(north)\n            .multiplyScalar(cosYaw)\n            .addScaledVector(east, sinYaw)\n            .normalize();\n        const right = this._vD\n            .copy(east)\n            .multiplyScalar(cosYaw)\n            .addScaledVector(north, -sinYaw)\n            .normalize();\n\n        const viewportHeight = Math.max(1, this.renderer?.domElement?.clientHeight || 1);\n        const altitude = Math.max(\n            this.SURFACE_EYE_HEIGHT,\n            this._airborneMSLGlideActive && Number.isFinite(this._airborneMSLGlideMsl)\n                ? this._airborneMSLGlideMsl\n                : Number.isFinite(this.surfaceAltitudeMeters)\n                    ? this.surfaceAltitudeMeters\n                : this.SURFACE_EYE_HEIGHT\n        );\n        const fovRad = THREE.MathUtils.degToRad(this.camera?.fov || 60);\n        const projectedMetersPerPixel = (2 * altitude * Math.tan(fovRad * 0.5)) / viewportHeight;\n        const metersPerPixel = Math.max(0.35, projectedMetersPerPixel)\n            * (Number.isFinite(this.NAV_DRAG_SPEED) ? this.NAV_DRAG_SPEED : 1);\n\n        // Map-style grab: pulling the scene right moves the camera left;\n        // pulling it down advances the camera along its current heading.\n        const move = this._look\n            .copy(forward)\n            .multiplyScalar(dy)\n            .addScaledVector(right, -dx);\n        if (move.lengthSq() < 1e-8) return;\n\n        const moveMeters = move.length() * metersPerPixel;\n        move.normalize();\n        this._resolvePhotoSurfaceMoveDirection(\n            move,\n            moveMeters,\n            up,\n            this._geoResolvedMove || (this._geoResolvedMove = new THREE.Vector3())\n        );\n        if (this._geoResolvedMove.lengthSq() < 1e-8) return;\n        move.copy(this._geoResolvedMove);\n        const surfaceRadius = this._getEllipsoidRadiusForDir(up);\n        const moveAngle = moveMeters * move.length() / Math.max(1, surfaceRadius);\n        const axis = this._target.crossVectors(up, move).normalize();\n        const nextUp = this._geoHit.copy(up).applyAxisAngle(axis, moveAngle).normalize();\n        this._reanchorUpPreserveOrientation(nextUp);\n    }\n\n    _onGeoPointerUp(e) {\n        if (!this.geoNav.active || this.geoNav.pointerId !== e.pointerId) return;\n        if (this.geoNav.action === 'drag' && this.cameraMode === 'surface') {\n            // Persist the exact release pose into terrain/altitude state before\n            // ordinary per-frame surface placement resumes.\n            this._syncSurfaceFromCamera({ preserveOrientation: false });\n        }\n        this.geoNav.active = false;\n        this.geoNav.action = null;\n        this.geoNav.pointerId = null;\n        this._resetGeoDragConstraint();\n        this._setSurfaceDragMSLLock(false);\n        this._hideSurfaceGrabRing();\n        try { this.renderer?.domElement.releasePointerCapture?.(e.pointerId); } catch { }\n    }\n\n    _applyGeoDrag(clientX, clientY) {\n        // The target delta and quaternion are one exact globe rotation from\n        // the current pose. Applying both (with no clamp, tangent projection,\n        // collision slide, or terrain rewrite) is what keeps the originally\n        // selected rendered point under an arbitrarily moved cursor.\n        const delta = this._getGeoDragTargetDelta(clientX, clientY, this._vC);\n        if (!delta) return;\n        this.camera.position.add(delta);\n        this.camera.quaternion.copy(this.geoNav.dragTargetQuaternion);\n        this.camera.updateMatrixWorld?.(true);\n\n        if (this.cameraMode === 'surface' && this.camera.position.lengthSq() > 1e-8) {\n            // Capture the transported orientation in surface-state terms so\n            // releasing the button cannot snap back to a pre-drag heading.\n            // Camera placement itself remains untouched until release.\n            this.setSurfaceFromDir(this.camera.position, true);\n            const ellipsoidR = this._getEllipsoidRadiusForDir(this.camera.position);\n            this.surfaceAltitudeMSL = this.camera.position.length() - ellipsoidR;\n            if (this._airborneMSLGlideActive) {\n                this._airborneMSLGlideMsl = this.surfaceAltitudeMSL;\n                this._surfaceAltitudeReference = 'msl';\n            }\n        }\n    }\n\n    _applyGeoRotate(dx, dy) {\n        if (!this.renderer) return;\n        const height = Math.max(1, this.renderer.domElement.clientHeight || 1);\n        const scale = (2 * Math.PI / height) * (Number.isFinite(this.NAV_ROTATE_SPEED) ? this.NAV_ROTATE_SPEED : 1);\n        const azimuth = -dx * scale;\n        const altitude = -dy * scale;\n\n        const pivot = this.geoNav.pivotPoint;\n        const pivotNormal = this.geoNav.pivotNormal;\n\n        this._rotateAroundPivot(pivot, pivotNormal, azimuth);\n\n        const viewDir = this._vA.copy(this.camera.position).sub(pivot).normalize();\n        const right = this._vB.copy(viewDir).cross(pivotNormal);\n        if (right.lengthSq() > 1e-8) {\n            right.normalize();\n            this._rotateAroundPivot(pivot, right, altitude);\n        }\n\n        this.camera.up.copy(pivotNormal);\n        this.camera.lookAt(pivot);\n        this.camera.updateMatrixWorld();\n        if (this.cameraMode === 'surface') {\n            this._syncSurfaceFromCamera();\n        }\n    }\n\n    _onPointerDown(e) {\n        if (this.isEditableTarget(e.target)) return;\n        if (e.pointerType === 'touch') {\n            this._onGeoTouchPointerDown(e);\n            return;\n        }\n        if (this.cameraMode === 'orbit' && e.button === 2 && !e.shiftKey) {\n            if (this._beginOrbitViewPivot(e.clientX, e.clientY, e.pointerId)) {\n                e.preventDefault();\n                this.renderer.domElement.setPointerCapture?.(e.pointerId);\n            }\n            return;\n        }\n        if (e.button === 1 || (e.shiftKey && (e.button === 0 || e.button === 2)) || (e.button === 2 && this.cameraMode === 'surface')) {\n            this._onGeoPointerDown(e);\n            return;\n        }\n        if (this.cameraMode === 'surface') {\n            if (e.button !== 0) return;\n            if (this.isPointerLocked()) return;\n            this._startPointerLockHold(e);\n            this.surfaceState.dragging = true;\n            this.surfaceState.lastX = e.clientX;\n            this.surfaceState.lastY = e.clientY;\n            this.renderer.domElement.setPointerCapture?.(e.pointerId);\n            return;\n        }\n\n        if (this.cameraMode !== 'orbit') return;\n        if (e.pointerType === 'mouse' && e.button !== 0) return;\n        if (e.shiftKey) return;\n\n        this.orbitState.pointers.set(e.pointerId, { x: e.clientX, y: e.clientY });\n        this.renderer.domElement.setPointerCapture?.(e.pointerId);\n        if (this.orbitState.pointers.size === 1) {\n            this._beginOrbitDrag(e.clientX, e.clientY, e.pointerId);\n        } else if (this.orbitState.pointers.size === 2) {\n            this.orbitState.dragging = false;\n            this.orbitState.pointerId = null;\n            this.orbitState.pinchDistance = this._getOrbitPointerDistance();\n        }\n    }\n\n    _onPointerMove(e) {\n        if (e.pointerType === 'touch') {\n            this._onGeoTouchPointerMove(e);\n            return;\n        }\n        if (this.orbitViewPivot?.dragging && this.orbitViewPivot.pointerId === e.pointerId) {\n            e.preventDefault();\n            this._applyOrbitViewPivotDrag(e.clientX, e.clientY);\n            return;\n        }\n        if (this.geoNav?.active) {\n            this._onGeoPointerMove(e);\n            return;\n        }\n        if (this.pointerLockState.holding) {\n            const dxHold = e.clientX - this.pointerLockState.holdX;\n            const dyHold = e.clientY - this.pointerLockState.holdY;\n            const limit = this.POINTER_LOCK_STILLNESS_PX;\n            if ((dxHold * dxHold + dyHold * dyHold) > limit * limit) {\n                this._cancelPointerLockHold();\n                return;\n            }\n            this._positionPointerLockRing(e.clientX, e.clientY);\n        }\n        if (this.isPointerLocked()) return;\n        if (this.cameraMode === 'surface') {\n            if (!this.surfaceState.dragging) return;\n            const dx = e.clientX - this.surfaceState.lastX;\n            const dy = e.clientY - this.surfaceState.lastY;\n            this.surfaceState.lastX = e.clientX;\n            this.surfaceState.lastY = e.clientY;\n\n            this.surfaceState.yaw -= dx * this.surfaceState.sens;\n            this.surfaceState.pitch += dy * this.surfaceState.sens;\n            this.surfaceState.pitch = THREE.MathUtils.clamp(this.surfaceState.pitch, -1.45, 1.45);\n            return;\n        }\n\n        if (this.cameraMode !== 'orbit') return;\n        const pointer = this.orbitState.pointers.get(e.pointerId);\n        if (!pointer) return;\n        pointer.x = e.clientX;\n        pointer.y = e.clientY;\n\n        if (this.orbitState.pointers.size >= 2) {\n            const nextDistance = this._getOrbitPointerDistance();\n            if (Number.isFinite(nextDistance) && Number.isFinite(this.orbitState.pinchDistance)) {\n                const ratio = this.orbitState.pinchDistance / Math.max(1, nextDistance);\n                const dist = this.camera.position.length();\n                const base = Number.isFinite(this.orbitZoomTarget) ? this.orbitZoomTarget : dist;\n                const minDist = this.controls?.minDistance ?? (PLANET_RADIUS + this.SURFACE_EYE_HEIGHT);\n                const maxDist = this.controls?.maxDistance ?? EARTH_ORBIT_MAX_DISTANCE_M;\n                this.orbitZoomTarget = THREE.MathUtils.clamp(base * ratio, minDist, maxDist);\n                this.orbitState.pinchDistance = nextDistance;\n            }\n            return;\n        }\n\n        if (!this.orbitState.dragging || this.orbitState.pointerId !== e.pointerId) return;\n        this._applyOrbitDrag(e.clientX, e.clientY);\n    }\n\n    _onPointerUp(e) {\n        if (e.pointerType === 'touch') {\n            this._onGeoTouchPointerUp(e);\n            return;\n        }\n        if (this.orbitViewPivot?.dragging && this.orbitViewPivot.pointerId === e.pointerId) {\n            this._endOrbitViewPivot();\n            try { this.renderer.domElement.releasePointerCapture?.(e.pointerId); } catch { }\n            return;\n        }\n        if (this.geoNav?.active) {\n            this._onGeoPointerUp(e);\n            return;\n        }\n        if (this.cameraMode === 'surface') {\n            this.surfaceState.dragging = false;\n            if (this.pointerLockState.holding && !this.isPointerLocked()) {\n                const elapsed = performance.now() - this.pointerLockState.holdStart;\n                if (elapsed >= this.POINTER_LOCK_HOLD_MS) {\n                    this._requestPointerLock();\n                }\n            }\n            this._cancelPointerLockHold();\n            try { this.renderer.domElement.releasePointerCapture?.(e.pointerId); } catch { }\n            return;\n        }\n\n        if (this.cameraMode !== 'orbit') return;\n        this.orbitState.pointers.delete(e.pointerId);\n        if (this.orbitState.pointerId === e.pointerId) {\n            this.orbitState.dragging = false;\n            this.orbitState.pointerId = null;\n        }\n        if (this.orbitState.pointers.size < 2) {\n            this.orbitState.pinchDistance = null;\n        }\n        if (this.orbitState.pointers.size === 1) {\n            const remaining = Array.from(this.orbitState.pointers.entries())[0];\n            if (remaining) {\n                const [pointerId, pos] = remaining;\n                this._beginOrbitDrag(pos.x, pos.y, pointerId);\n            }\n        }\n        try { this.renderer.domElement.releasePointerCapture?.(e.pointerId); } catch { }\n    }\n\n    _onPointerCancel(e) {\n        if (e.pointerType === 'touch') {\n            if (e.type === 'lostpointercapture'\n                && !this.geoNav?.touchPointers?.has?.(e.pointerId)) {\n                return;\n            }\n            this._resetTouchNavigationState();\n            return;\n        }\n        if (this.orbitViewPivot?.pointerId === e.pointerId) {\n            this._endOrbitViewPivot();\n        }\n        if (this.geoNav?.pointerId === e.pointerId) {\n            this.geoNav.active = false;\n            this.geoNav.action = null;\n            this.geoNav.pointerId = null;\n            this._resetGeoDragConstraint();\n            this._setSurfaceDragMSLLock(false);\n            this._hideSurfaceGrabRing();\n        }\n        if (this.surfaceState?.dragging) this.surfaceState.dragging = false;\n        if (this.pointerLockState?.holdPointerId === e.pointerId) {\n            this._cancelPointerLockHold();\n        }\n        this.orbitState?.pointers?.delete?.(e.pointerId);\n        try { this.renderer?.domElement.releasePointerCapture?.(e.pointerId); } catch { }\n    }\n\n    _onMouseMove(e) {\n        if (this.cameraMode !== 'surface') return;\n        if (!this.isPointerLocked()) return;\n        const dx = e.movementX || 0;\n        const dy = e.movementY || 0;\n        if (!dx && !dy) return;\n        this.surfaceState.yaw += dx * this.surfaceState.sens;\n        this.surfaceState.pitch -= dy * this.surfaceState.sens;\n        this.surfaceState.pitch = THREE.MathUtils.clamp(this.surfaceState.pitch, -1.45, 1.45);\n    }\n\n    _applySurfaceFovZoom(deltaY) {\n        if (!Number.isFinite(deltaY) || deltaY === 0) return;\n        const current = this.camera.fov;\n        const deltaAbs = Math.max(\n            this.SURFACE_FOV_SCROLL_MIN,\n            Math.min(this.SURFACE_FOV_SCROLL_MAX, Math.abs(deltaY) * this.SURFACE_FOV_SCROLL_SCALE)\n        );\n        const delta = Math.sign(deltaY) * deltaAbs;\n        const next = THREE.MathUtils.clamp(\n            current - delta,\n            this.SURFACE_FOV_MIN,\n            this.SURFACE_FOV_MAX\n        );\n        if (Math.abs(next - current) < 1e-4) return;\n        this.camera.fov = next;\n        this.camera.updateProjectionMatrix();\n    }\n\n    _surfaceScrollAltitudeStep(deltaY, baseAltitude = null, zoomScale = null) {\n        const magnitude = Math.min(120, Math.abs(deltaY || 0));\n        if (magnitude === 0) return 0;\n\n        const floor = this._getAltitudeClampMin();\n        const currentAltitude = Number.isFinite(baseAltitude)\n            ? baseAltitude\n            : (Number.isFinite(this.surfaceAltitudeMeters)\n                ? this.surfaceAltitudeMeters\n                : this.SURFACE_EYE_HEIGHT);\n        const altitude = Math.max(floor, currentAltitude);\n        const resolvedZoomScale = Number.isFinite(zoomScale)\n            ? zoomScale\n            : (Number.isFinite(this.NAV_ZOOM_SPEED) ? this.NAV_ZOOM_SPEED : 1);\n        const inputScale = (magnitude / 100) * resolvedZoomScale;\n        const coarseStep = Math.max(2, Math.min(altitude * 0.05, 2000)) * inputScale;\n        const fineControlMax = Number.isFinite(this.SURFACE_SCROLL_FINE_CONTROL_MAX_ALT)\n            ? this.SURFACE_SCROLL_FINE_CONTROL_MAX_ALT\n            : 100;\n\n        // At and above 100m retain the established 5%-of-altitude response.\n        // Below it, scale the 100m boundary step along a normalized exponential\n        // curve. The non-zero floor scale permits ascent from the surface while\n        // the target clamp remains the sole authority that prevents penetration.\n        if (altitude >= fineControlMax || fineControlMax <= floor) return coarseStep;\n\n        const normalizedAltitude = THREE.MathUtils.clamp(\n            (altitude - floor) / (fineControlMax - floor),\n            0,\n            1\n        );\n        const exponent = Math.max(0, Number.isFinite(this.SURFACE_SCROLL_SOFTEN_EXP)\n            ? this.SURFACE_SCROLL_SOFTEN_EXP\n            : 2.8);\n        const exponentialDenominator = Math.expm1(exponent);\n        const exponentialAltitude = exponentialDenominator > 1e-9\n            ? Math.expm1(exponent * normalizedAltitude) / exponentialDenominator\n            : normalizedAltitude;\n        const minimumScale = THREE.MathUtils.clamp(\n            Number.isFinite(this.SURFACE_SCROLL_SOFTEN_MIN_SCALE)\n                ? this.SURFACE_SCROLL_SOFTEN_MIN_SCALE\n                : 0.02,\n            0,\n            1\n        );\n        const fineScale = THREE.MathUtils.lerp(minimumScale, 1, exponentialAltitude);\n        const boundaryStep = Math.max(2, Math.min(fineControlMax * 0.05, 2000)) * inputScale;\n        return boundaryStep * fineScale;\n    }\n\n    _normalizeAltitudeWheelDelta(event) {\n        let delta = Number(event?.deltaY);\n        if (!Number.isFinite(delta)) return 0;\n        const mode = Number(event?.deltaMode) || 0;\n        if (mode === 1) delta *= 16;\n        else if (mode === 2) delta *= 800;\n        return THREE.MathUtils.clamp(delta, -120, 120);\n    }\n\n    // Accumulate intentional input, not frames: sparse ticks retain centimetre\n    // precision while a fast wheel/trackpad burst can escape street level.\n    _altitudeWheelAcceleration(deltaY, now = performance.now()) {\n        const direction = Math.sign(deltaY);\n        const elapsed = now - (this._altitudeWheelAccelerationAt ?? -Infinity);\n        const continuing = direction === this._altitudeWheelAccelerationDir\n            && elapsed >= 0 && elapsed < 240;\n        const energy = continuing\n            ? (this._altitudeWheelEnergy || 0) * Math.exp(-elapsed / 800)\n            : 0;\n        this._altitudeWheelEnergy = Math.min(1600, energy + Math.abs(deltaY));\n        if (!continuing) this._altitudeWheelSustainStart = now;\n        this._altitudeWheelAccelerationAt = now;\n        this._altitudeWheelAccelerationDir = direction;\n        return Math.min(128, 1 + (Math.max(0, this._altitudeWheelEnergy - 120) / 75) ** 2);\n    }\n\n    /**\n     * Surface wheel boost: gentle near the ground, aware of scroll speed.\n     * Speed (decayed wheel energy) gives a smooth response that is capped by\n     * altitude AGL (2.5x at street level, 24x by 400 m), so a quick flick\n     * near the ground stays small. Holding a fast scroll keeps accelerating\n     * (the sustain factor grows after 0.4 s), so you can still climb away\n     * quickly. The ceiling peaks at 16x mid-altitude and returns to the\n     * original 8x above 1 km.\n     */\n    _surfaceWheelBoost(altitude, now = performance.now()) {\n        const energy = this._altitudeWheelEnergy || 0;\n        const speed = 1 + Math.pow(Math.max(0, energy - 150) / 200, 1.5);\n        const start = this._altitudeWheelSustainStart;\n        const sustainMs = Number.isFinite(start) ? Math.max(0, now - start) : 0;\n        const sustain = 1 + Math.pow(Math.max(0, sustainMs - 400) / 300, 2);\n        const alt = Number.isFinite(altitude) ? altitude : 0;\n        const altitudeCap = THREE.MathUtils.lerp(2.5, 24, THREE.MathUtils.smoothstep(alt, 3, 400));\n        const ceiling = THREE.MathUtils.lerp(\n            THREE.MathUtils.lerp(8, 16, THREE.MathUtils.smoothstep(alt, 3, 100)),\n            8,\n            THREE.MathUtils.smoothstep(alt, 600, 1000),\n        );\n        return Math.max(1, Math.min(Math.min(speed, altitudeCap) * sustain, ceiling));\n    }\n\n    _cancelSurfaceScrollAltitude({ resetGesture = false } = {}) {\n        this._surfaceScrollAltitudeTarget = null;\n        this._surfaceScrollExitRequested = false;\n        if (resetGesture) {\n            this._altitudeWheelGestureDir = 0;\n            this._altitudeWheelGestureUntil = 0;\n            this._altitudeWheelReverseDelta = 0;\n            this._altitudeWheelEnergy = 0;\n            this._altitudeWheelAccelerationAt = null;\n            this._altitudeWheelAccelerationDir = 0;\n            this._altitudeWheelSustainStart = null;\n        }\n    }\n\n    _filterAltitudeWheelDelta(deltaY, now = null) {\n        if (!Number.isFinite(deltaY) || Math.abs(deltaY) < 0.25) return 0;\n        const timestamp = Number.isFinite(now)\n            ? now\n            : ((typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now());\n        const direction = Math.sign(deltaY);\n        const holdMs = Math.max(0, Number.isFinite(this.ALTITUDE_WHEEL_DIRECTION_HOLD_MS)\n            ? this.ALTITUDE_WHEEL_DIRECTION_HOLD_MS\n            : 90);\n\n        if (!this._altitudeWheelGestureDir\n            || timestamp >= (this._altitudeWheelGestureUntil || 0)\n            || direction === this._altitudeWheelGestureDir) {\n            this._altitudeWheelGestureDir = direction;\n            this._altitudeWheelGestureUntil = timestamp + holdMs;\n            this._altitudeWheelReverseDelta = 0;\n            return deltaY;\n        }\n\n        // Precision trackpads commonly emit a tiny opposite-sign tail while\n        // momentum settles. Do not let that reverse a still-active altitude\n        // gesture. A deliberate reversal either exceeds this short accumulator\n        // or is accepted automatically after the 90ms gesture window expires.\n        this._altitudeWheelReverseDelta = (this._altitudeWheelReverseDelta || 0) + Math.abs(deltaY);\n        const threshold = Math.max(1, Number.isFinite(this.ALTITUDE_WHEEL_REVERSAL_THRESHOLD)\n            ? this.ALTITUDE_WHEEL_REVERSAL_THRESHOLD\n            : 12);\n        if (this._altitudeWheelReverseDelta < threshold) return 0;\n\n        this._altitudeWheelGestureDir = direction;\n        this._altitudeWheelGestureUntil = timestamp + holdMs;\n        this._altitudeWheelReverseDelta = 0;\n        return deltaY;\n    }\n\n    _applySurfaceScrollAltitude(deltaSeconds) {\n        if (!Number.isFinite(this._surfaceScrollAltitudeTarget)) return false;\n        const current = Number.isFinite(this.surfaceAltitudeMeters)\n            ? this.surfaceAltitudeMeters\n            : this.SURFACE_EYE_HEIGHT;\n        const target = THREE.MathUtils.clamp(\n            this._surfaceScrollAltitudeTarget,\n            this._getAltitudeClampMin(),\n            this.SURFACE_ALTITUDE_MAX\n        );\n        const dt = THREE.MathUtils.clamp(\n            Number.isFinite(deltaSeconds) ? deltaSeconds : 1 / 60,\n            1 / 240,\n            0.1\n        );\n        const response = Math.max(0.02, Number.isFinite(this.SURFACE_SCROLL_RESPONSE_SEC)\n            ? this.SURFACE_SCROLL_RESPONSE_SEC\n            : 0.10);\n        const alpha = 1 - Math.exp(-dt / response);\n        let next = THREE.MathUtils.lerp(current, target, alpha);\n        if (Math.abs(target - next) < 0.01) next = target;\n        const altitudeDelta = next - current;\n        if (this._airborneMSLGlideActive && Number.isFinite(this._airborneMSLGlideMsl)) {\n            this._airborneMSLGlideMsl += altitudeDelta;\n            this.surfaceAltitudeMSL = this._airborneMSLGlideMsl;\n            this.surfaceAltitudeMeters = next;\n            if (altitudeDelta < 0 && next <= this._getAltitudeClampMin()) {\n                this._clearAirborneMSLGlide();\n            }\n        } else {\n            this.surfaceAltitudeMeters = next;\n            this._surfaceAltitudeReference = 'terrain';\n\n            const terrainR = this._terrainRadius || PLANET_RADIUS;\n            const ellipsoidR = this._getEllipsoidRadiusForDir(this.surfaceState.up);\n            const terrainElev = terrainR - ellipsoidR;\n            const cameraMsl = this._computeCameraMSL();\n            this.surfaceAltitudeMSL = Number.isFinite(cameraMsl)\n                ? cameraMsl + altitudeDelta\n                : terrainElev + next + this.SURFACE_TERRAIN_CLEARANCE;\n            this._activateAirborneMSLGlide(this.surfaceAltitudeMSL);\n        }\n\n        const direction = Math.sign(target - current);\n        if (direction !== 0) {\n            this._surfaceScrollHoldDir = direction;\n            const now = (typeof performance !== 'undefined' && performance.now)\n                ? performance.now()\n                : Date.now();\n            this._surfaceScrollHoldUntil = Math.max(this._surfaceScrollHoldUntil || 0, now + 80);\n        }\n\n        if (next === target) this._surfaceScrollAltitudeTarget = null;\n        if (this._surfaceScrollExitRequested\n            && next >= this.SURFACE_ALTITUDE_MAX * 0.95) {\n            this._surfaceScrollAltitudeTarget = null;\n            this._surfaceScrollExitRequested = false;\n            this.exitSurfaceMode();\n            return true;\n        }\n        return false;\n    }\n\n    _onWheel(e) {\n        if (this.cameraMode === 'toSurface' || this.cameraMode === 'toOrbit') {\n            return;\n        }\n        // Guard: drop noise events with effectively zero delta\n        const rawDeltaY = this._normalizeAltitudeWheelDelta(e);\n        if (Math.abs(rawDeltaY) < 0.25) return;\n        const zoomScale = Number.isFinite(this.NAV_ZOOM_SPEED) ? this.NAV_ZOOM_SPEED : 1;\n        if (this.cameraMode !== 'surface') {\n            this.surfaceZoomOutAccumulator = 0;\n            if (this.cameraMode === 'orbit' || this.cameraMode === 'transit') {\n                // Non-terra: OrbitControls handles zoom natively\n                if (this._bodyAnchor !== 'terra') return;\n                const deltaY = this._filterAltitudeWheelDelta(rawDeltaY);\n                if (deltaY === 0) return;\n                const reversed = this._altitudeWheelAccelerationDir\n                    && Math.sign(deltaY) !== this._altitudeWheelAccelerationDir;\n                const boost = Math.min(8, this._altitudeWheelAcceleration(deltaY));\n                if (reversed) this.orbitZoomTarget = null;\n                const dist = this.camera.position.length();\n                const base = Number.isFinite(this.orbitZoomTarget) ? this.orbitZoomTarget : dist;\n                this.orbitZoomTarget = this._getOrbitWheelDistanceTarget(deltaY, base, zoomScale * boost);\n            }\n            return;\n        }\n\n        if (this.isPointerLocked() && this.navProfile !== 'geospatial') {\n            this._applySurfaceFovZoom(rawDeltaY);\n            this.surfaceZoomOutAccumulator = 0;\n            return;\n        }\n\n        const deltaY = this._filterAltitudeWheelDelta(rawDeltaY);\n        if (deltaY === 0) return;\n        const reversed = this._altitudeWheelAccelerationDir\n            && Math.sign(deltaY) !== this._altitudeWheelAccelerationDir;\n        const wheelNow = performance.now();\n        this._altitudeWheelAcceleration(deltaY, wheelNow);\n        if (reversed) this._cancelSurfaceScrollAltitude();\n\n        // A wheel gesture takes altitude ownership immediately. Do not let the\n        // decaying Q/E velocity from a previous input write a second altitude\n        // in the same frame and create a visible direction reversal.\n        this._verticalSpeed = 0;\n        this._verticalDir = 0;\n\n        // Compute direction FIRST, then derive hold direction from it so\n        // they can never disagree. (Noise delta already filtered at top.)\n        const scrollOut = deltaY > 0; // positive deltaY = scroll out = ascend\n        const direction = scrollOut ? 1 : -1;\n\n        // Scroll behaves like Q/E — pure altitude change, smooth exit at ceiling\n        this._surfaceScrollHoldUntil = performance.now() + this.SURFACE_SCROLL_HOLD_MS;\n        this._surfaceScrollHoldDir = direction;\n        this._clearSurfaceAutoMSLHold();\n\n        const altitude = this.surfaceAltitudeMeters ?? this.SURFACE_EYE_HEIGHT;\n        const baseAltitude = Number.isFinite(this._surfaceScrollAltitudeTarget)\n            ? this._surfaceScrollAltitudeTarget\n            : altitude;\n        // Gentle near the ground, speed- and duration-aware (see _surfaceWheelBoost).\n        const altitudeBoost = this._surfaceWheelBoost(baseAltitude, wheelNow);\n        const step = this._surfaceScrollAltitudeStep(deltaY, baseAltitude, zoomScale * altitudeBoost);\n        const minAlt = this._getAltitudeClampMin();\n        const nextAlt = THREE.MathUtils.clamp(\n            baseAltitude + direction * step,\n            minAlt,\n            this.SURFACE_ALTITUDE_MAX\n        );\n        this._surfaceScrollAltitudeTarget = nextAlt;\n        if (!scrollOut) this._surfaceScrollExitRequested = false;\n        this._surfaceAltitudeReference = 'terrain';\n\n        // Exit only after the smoothed camera altitude reaches the ceiling;\n        // using the future target here would start the handoff prematurely.\n        if (scrollOut && nextAlt >= this.SURFACE_ALTITUDE_MAX * 0.95) {\n            this._surfaceScrollExitRequested = true;\n        }\n    }\n\n    _getOrbitPointerDistance() {\n        if (this.orbitState.pointers.size < 2) return null;\n        const points = Array.from(this.orbitState.pointers.values());\n        const dx = points[0].x - points[1].x;\n        const dy = points[0].y - points[1].y;\n        return Math.sqrt(dx * dx + dy * dy);\n    }\n\n    _beginOrbitDrag(clientX, clientY, pointerId) {\n        if (this._bodyAnchor !== 'terra') return false;\n        const dir = this._getOrbitDirFromClient(clientX, clientY, this.orbitState.lastDir);\n        if (!dir) return false;\n        this.orbitState.dragging = true;\n        this.orbitState.pointerId = pointerId;\n        this.orbitState.lastX = clientX;\n        this.orbitState.lastY = clientY;\n        this.orbitState.anchorDir.copy(dir);\n        return true;\n    }\n\n    _applyOrbitDrag(clientX, clientY) {\n        if (this._bodyAnchor !== 'terra') return;\n        const state = this.orbitState, dx = clientX - state.lastX, dy = clientY - state.lastY;\n        if (!Number.isFinite(dx) || !Number.isFinite(dy) || (!dx && !dy)) return;\n        const previous = this._getOrbitDirFromClient(state.lastX, state.lastY, state.lastDir);\n        const previousImpact = this._orbitDragMetrics?.impactRatio ?? Infinity;\n        const current = this._getOrbitDirFromClient(clientX, clientY, this._vA);\n        const impact = Math.max(previousImpact, this._orbitDragMetrics?.impactRatio ?? Infinity);\n        state.lastX = clientX; state.lastY = clientY;\n        if (!previous || !current) return;\n        this._orbitQuat.setFromUnitVectors(current, previous);\n\n        // Keep direct grabbing over the inner globe. Ease into screen-relative\n        // angular motion before the limb, where perspective ray/surface\n        // derivatives diverge. The sky has the same finite response everywhere.\n        const blend = THREE.MathUtils.smoothstep(impact, 0.45, 0.8);\n        if (blend > 0) {\n            const rect = this.renderer.domElement.getBoundingClientRect();\n            const distance = this.camera.position.length();\n            const scale = Math.min(0.01, Math.max(1e-6,\n                (distance / PLANET_RADIUS - 1) * 2 * Math.tan(this.camera.fov * Math.PI / 360)\n                / Math.max(1, rect.height)));\n            this._orbitScreenRight ||= new THREE.Vector3();\n            this._orbitScreenUp ||= new THREE.Vector3();\n            this._orbitScreenAxis ||= new THREE.Vector3();\n            this._orbitScreenQuat ||= new THREE.Quaternion();\n            this._orbitScreenRight.set(1,0,0).applyQuaternion(this.camera.quaternion);\n            this._orbitScreenUp.set(0,1,0).applyQuaternion(this.camera.quaternion);\n            this._orbitScreenAxis.copy(this._orbitScreenUp).multiplyScalar(-dx)\n                .addScaledVector(this._orbitScreenRight,-dy).normalize();\n            this._orbitScreenQuat.setFromAxisAngle(this._orbitScreenAxis,Math.hypot(dx,dy)*scale);\n            this._orbitQuat.slerp(this._orbitScreenQuat,blend);\n        }\n        this.camera.position.applyQuaternion(this._orbitQuat);\n        this.camera.up.applyQuaternion(this._orbitQuat);\n        this._ensureOrbitUp();\n        this.camera.lookAt(this._origin);\n        this._applyOrbitViewPivot();\n        this.camera.updateMatrixWorld();\n    }\n\n    _orbitNow() {\n        return typeof performance !== 'undefined' && typeof performance.now === 'function'\n            ? performance.now()\n            : Date.now();\n    }\n\n    _beginOrbitViewPivot(clientX, clientY, pointerId) {\n        if (this._bodyAnchor !== 'terra' || this.cameraMode !== 'orbit' || !this.camera) return false;\n        const state = this.orbitViewPivot;\n        if (!state) return false;\n        const now = this._orbitNow();\n        state.dragging = true;\n        state.pointerId = pointerId;\n        state.lastX = clientX;\n        state.lastY = clientY;\n        state.targetYaw = Number.isFinite(state.targetYaw) ? state.targetYaw : state.yaw || 0;\n        state.targetPitch = Number.isFinite(state.targetPitch) ? state.targetPitch : state.pitch || 0;\n        state.velocityYaw = 0;\n        state.velocityPitch = 0;\n        state.lastInteractionAt = now;\n        state.lastUpdateAt = now;\n        return true;\n    }\n\n    _applyOrbitViewPivotDrag(clientX, clientY) {\n        const state = this.orbitViewPivot;\n        if (!state?.dragging) return;\n        const dx = clientX - state.lastX;\n        const dy = clientY - state.lastY;\n        state.lastX = clientX;\n        state.lastY = clientY;\n        if (!dx && !dy) return;\n\n        const now = this._orbitNow();\n        const dt = Math.max(1 / 120, Math.min(0.12, (now - (state.lastInteractionAt || now)) / 1000));\n        const sens = Number.isFinite(this.ORBIT_VIEW_PIVOT_SENS)\n            ? this.ORBIT_VIEW_PIVOT_SENS\n            : 0.0022;\n        const prevTargetYaw = Number.isFinite(state.targetYaw) ? state.targetYaw : state.yaw || 0;\n        const prevTargetPitch = Number.isFinite(state.targetPitch) ? state.targetPitch : state.pitch || 0;\n\n        // Dragging the mouse right/down pivots the camera view left/up,\n        // giving a soft opposing look offset without moving orbit position.\n        const roll = state.roll || 0, cos = Math.cos(roll), sin = Math.sin(roll);\n        this._setOrbitViewPivotTarget(\n            prevTargetYaw + (dx * cos + dy * sin) * sens,\n            prevTargetPitch + (-dx * sin + dy * cos) * sens,\n            true,\n        );\n        const nextTargetYaw = Number.isFinite(state.targetYaw) ? state.targetYaw : 0;\n        const nextTargetPitch = Number.isFinite(state.targetPitch) ? state.targetPitch : 0;\n        const nextVelocityYaw = (nextTargetYaw - prevTargetYaw) / dt;\n        const nextVelocityPitch = (nextTargetPitch - prevTargetPitch) / dt;\n        state.velocityYaw = THREE.MathUtils.lerp(state.velocityYaw || 0, nextVelocityYaw, 0.48);\n        state.velocityPitch = THREE.MathUtils.lerp(state.velocityPitch || 0, nextVelocityPitch, 0.48);\n        state.lastInteractionAt = now;\n    }\n\n    _endOrbitViewPivot() {\n        const state = this.orbitViewPivot;\n        if (!state) return;\n        const now = this._orbitNow();\n        if (now - state.lastInteractionAt > 120) state.velocityYaw = state.velocityPitch = 0;\n        state.dragging = false;\n        state.pointerId = null;\n        state.lastInteractionAt = now;\n    }\n\n    _resetOrbitViewPivot() {\n        const state = this.orbitViewPivot;\n        if (!state) return;\n        state.dragging = false;\n        state.pointerId = null;\n        state.yaw = 0;\n        state.pitch = 0;\n        state.targetYaw = 0;\n        state.targetPitch = 0;\n        state.roll = 0;\n        state.targetRoll = 0;\n        state.velocityYaw = 0;\n        state.velocityPitch = 0;\n        state.lastInteractionAt = 0;\n        state.lastUpdateAt = 0;\n    }\n\n    _getOrbitViewPivotMaxAngle() {\n        const maxAngle = Number.isFinite(this.ORBIT_VIEW_PIVOT_MAX_ANGLE)\n            ? this.ORBIT_VIEW_PIVOT_MAX_ANGLE\n            : THREE.MathUtils.degToRad(90);\n        return Math.max(THREE.MathUtils.degToRad(5), maxAngle);\n    }\n\n    _limitOrbitViewPivotKeys(yawKey, pitchKey, soft = false) {\n        const state = this.orbitViewPivot;\n        if (!state) return;\n        const yaw = Number.isFinite(state[yawKey]) ? state[yawKey] : 0;\n        const pitch = Number.isFinite(state[pitchKey]) ? state[pitchKey] : 0;\n        const mag = Math.hypot(yaw, pitch);\n        const maxAngle = this._getOrbitViewPivotMaxAngle();\n        if (!Number.isFinite(mag) || mag <= 1e-9) return;\n\n        let limitedMag = maxAngle;\n        if (soft) {\n            const softStartRatio = THREE.MathUtils.clamp(\n                Number.isFinite(this.ORBIT_VIEW_PIVOT_SOFT_START)\n                    ? this.ORBIT_VIEW_PIVOT_SOFT_START\n                    : 0.82,\n                0.1,\n                0.98\n            );\n            const softStart = maxAngle * softStartRatio;\n            const softSpan = Math.max(1e-6, maxAngle - softStart);\n            if (mag <= softStart) return;\n            if (mag > softStart) {\n                limitedMag = softStart + softSpan * (1 - Math.exp(-(mag - softStart) / softSpan));\n                limitedMag = Math.min(maxAngle, limitedMag);\n            } else {\n                limitedMag = mag;\n            }\n        } else if (mag <= maxAngle) {\n            return;\n        }\n\n        const scale = limitedMag / mag;\n        state[yawKey] = yaw * scale;\n        state[pitchKey] = pitch * scale;\n    }\n\n    _setOrbitViewPivotTarget(yaw, pitch, soft = false) {\n        const state = this.orbitViewPivot;\n        if (!state) return;\n        state.targetYaw = Number.isFinite(yaw) ? yaw : 0;\n        state.targetPitch = Number.isFinite(pitch) ? pitch : 0;\n        this._limitOrbitViewPivotKeys('targetYaw', 'targetPitch', soft);\n    }\n\n    _applyOrbitViewPivot() {\n        const state = this.orbitViewPivot;\n        if (!state || !this.camera) return false;\n        if (Math.abs(state.yaw) < 1e-7 && Math.abs(state.pitch) < 1e-7 && Math.abs(state.roll || 0) < 1e-7) return false;\n        this.camera.rotateY(state.yaw);\n        this.camera.rotateX(state.pitch);\n        // Local Z is the current optical axis, even when looking away from\n        // Earth. Keep this separate from the transported orbital up frame.\n        this.camera.rotateZ(state.roll || 0);\n        this.camera.updateMatrixWorld(true);\n        return true;\n    }\n\n    _updateOrbitViewPivot(now = this._orbitNow()) {\n        const state = this.orbitViewPivot;\n        if (!state) return;\n\n        const lastUpdateAt = state.lastUpdateAt || now;\n        const dt = Math.max(0, Math.min(0.1, (now - lastUpdateAt) / 1000));\n        state.lastUpdateAt = now;\n\n        if (!Number.isFinite(state.targetYaw)) state.targetYaw = state.yaw || 0;\n        if (!Number.isFinite(state.targetPitch)) state.targetPitch = state.pitch || 0;\n        if (!Number.isFinite(state.velocityYaw)) state.velocityYaw = 0;\n        if (!Number.isFinite(state.velocityPitch)) state.velocityPitch = 0;\n\n        if (!state.dragging) {\n            const inertiaSec = Math.max(\n                0.05,\n                Number.isFinite(this.ORBIT_VIEW_PIVOT_INERTIA_SEC)\n                    ? this.ORBIT_VIEW_PIVOT_INERTIA_SEC\n                    : 0.70\n            );\n            const velocityMag = Math.hypot(state.velocityYaw, state.velocityPitch);\n            if (velocityMag > 1e-5 && dt > 0) {\n                const prevTargetYaw = state.targetYaw;\n                const prevTargetPitch = state.targetPitch;\n                this._setOrbitViewPivotTarget(\n                    state.targetYaw + state.velocityYaw * dt,\n                    state.targetPitch + state.velocityPitch * dt,\n                    true\n                );\n                const acceptedYaw = state.targetYaw - prevTargetYaw;\n                const acceptedPitch = state.targetPitch - prevTargetPitch;\n                const acceptedMag = Math.hypot(acceptedYaw, acceptedPitch);\n                const requestedMag = Math.hypot(state.velocityYaw * dt, state.velocityPitch * dt);\n                if (requestedMag > 1e-8 && acceptedMag < requestedMag * 0.35) {\n                    state.velocityYaw *= 0.35;\n                    state.velocityPitch *= 0.35;\n                }\n            }\n            const inertiaDamp = Math.exp(-dt / inertiaSec);\n            state.velocityYaw *= inertiaDamp;\n            state.velocityPitch *= inertiaDamp;\n            if (Math.abs(state.velocityYaw) < 1e-4) state.velocityYaw = 0;\n            if (Math.abs(state.velocityPitch) < 1e-4) state.velocityPitch = 0;\n        }\n\n        const recenterAngle = Number.isFinite(this.ORBIT_VIEW_PIVOT_RECENTER_ANGLE)\n            ? this.ORBIT_VIEW_PIVOT_RECENTER_ANGLE : THREE.MathUtils.degToRad(5);\n        const lookAngle = Math.acos(THREE.MathUtils.clamp(Math.cos(state.targetYaw) * Math.cos(state.targetPitch), -1, 1));\n        // A look-away pose is navigation intent, never an idle animation.\n        // Capture only a deliberate return near Earth, after release inertia\n        // has settled; elapsed time alone cannot recenter the camera.\n        if (!state.dragging && lookAngle <= recenterAngle\n            && Math.hypot(state.velocityYaw, state.velocityPitch) < 0.02) {\n            const returnSec = Math.max(\n                0.05,\n                Number.isFinite(this.ORBIT_VIEW_PIVOT_RETURN_SEC)\n                    ? this.ORBIT_VIEW_PIVOT_RETURN_SEC\n                    : 1.6\n            );\n            const blend = 1 - Math.exp(-dt / returnSec);\n            state.targetYaw = THREE.MathUtils.lerp(state.targetYaw, 0, blend);\n            state.targetPitch = THREE.MathUtils.lerp(state.targetPitch, 0, blend);\n            state.velocityYaw *= Math.exp(-dt / Math.max(0.05, returnSec * 0.4));\n            state.velocityPitch *= Math.exp(-dt / Math.max(0.05, returnSec * 0.4));\n            if (Math.abs(state.targetYaw) < 1e-5) state.targetYaw = 0;\n            if (Math.abs(state.targetPitch) < 1e-5) state.targetPitch = 0;\n        }\n\n        const responseSec = Math.max(\n            0.01,\n            Number.isFinite(this.ORBIT_VIEW_PIVOT_RESPONSE_SEC)\n                ? this.ORBIT_VIEW_PIVOT_RESPONSE_SEC\n                : 0.10\n        );\n        const followBlend = dt > 0 ? 1 - Math.exp(-dt / responseSec) : 1;\n        state.yaw = THREE.MathUtils.lerp(state.yaw || 0, state.targetYaw || 0, followBlend);\n        state.pitch = THREE.MathUtils.lerp(state.pitch || 0, state.targetPitch || 0, followBlend);\n        state.roll = THREE.MathUtils.lerp(state.roll || 0, state.targetRoll || 0, followBlend);\n        this._limitOrbitViewPivotKeys('yaw', 'pitch', false);\n        if (!state.dragging\n            && Math.abs(state.targetYaw) < 1e-5\n            && Math.abs(state.targetPitch) < 1e-5\n            && Math.abs(state.velocityYaw) < 1e-4\n            && Math.abs(state.velocityPitch) < 1e-4) {\n            state.targetYaw = 0;\n            state.targetPitch = 0;\n            state.velocityYaw = 0;\n            state.velocityPitch = 0;\n        }\n        this._applyOrbitViewPivot();\n    }\n\n    _ensureOrbitUp() {\n        const radius = this.camera.position.length();\n        if (!Number.isFinite(radius) || radius < 1e-6) return;\n        const forward = this._vC.copy(this.camera.position).multiplyScalar(-1/radius);\n        const up = this._vD.copy(this.camera.up);\n        up.addScaledVector(forward,-up.dot(forward));\n        if (up.lengthSq() < 1e-12) {\n            // A restored polar pose can have collinear up/forward. Preserve\n            // the existing view's right axis instead of choosing north, whose\n            // longitude/sign is undefined at the pole.\n            this._orbitUpRight ||= new THREE.Vector3();\n            this._orbitUpRight.set(1,0,0).applyQuaternion(this.camera.quaternion);\n            up.crossVectors(this._orbitUpRight,forward);\n            if(up.lengthSq()<1e-12){up.set(Math.abs(forward.y)<.9?0:1,Math.abs(forward.y)<.9?1:0,0);up.addScaledVector(forward,-up.dot(forward));}\n        }\n        this.camera.up.copy(up.normalize());\n    }\n\n    _getOrbitDirFromClient(clientX, clientY, out) {\n        if (!this.renderer || !this.camera || !Number.isFinite(clientX) || !Number.isFinite(clientY)) return null;\n        const rect = this.renderer.domElement.getBoundingClientRect();\n        if (!(rect.width > 0 && rect.height > 0)) return null;\n        this.camera.updateMatrixWorld();\n        this._orbitNdc.set((clientX-rect.left)/rect.width*2-1,1-(clientY-rect.top)/rect.height*2);\n        this._orbitRaycaster.setFromCamera(this._orbitNdc,this.camera);\n        this._orbitDragMetrics ||= {};\n        const projected = projectOrbitDragRay(this._orbitRaycaster.ray.origin,this._orbitRaycaster.ray.direction,\n            PLANET_RADIUS,out,this._orbitDragMetrics);\n        if (this._orbitDragMetrics.impactRatio < 0.8) {\n            const hit = rayEllipsoidIntersection(this._orbitRaycaster.ray.origin,\n                this._orbitRaycaster.ray.direction,this.triTree?.group || null);\n            if (hit) return out.copy(hit).normalize();\n        }\n        return projected;\n    }\n\n    _onKeyDown(e) {\n        if (this.isEditableTarget(e.target)) return;\n        const lookKey = { KeyR: 'r', KeyF: 'f', KeyZ: 'z', KeyX: 'x' }[e.code];\n        if (lookKey) {\n            if (e.ctrlKey || e.metaKey || e.altKey || e.isComposing || e.defaultPrevented\n                || this._externalCameraOverride || _isMetaverseSceneMode()\n                || (typeof window !== 'undefined' && window.__noclipMapMode === '2d')\n                || !['surface', 'orbit'].includes(this.cameraMode)) return;\n            if (!this.keyState.r && !this.keyState.f && !this.keyState.z && !this.keyState.x) {\n                this._keyboardLookLastAt = performance.now();\n            }\n            this.keyState[lookKey] = true;\n            e.preventDefault();\n            return;\n        }\n        if (this.cameraMode !== 'surface') return;\n        if (!e.code) return;\n\n        const key = e.code.toLowerCase();\n        if (key === 'keyw' || key === 'arrowup') {\n            this.keyState.w = true;\n            this.keyState.arrowup = true;\n            e.preventDefault();\n        }\n        if (key === 'keys' || key === 'arrowdown') {\n            this.keyState.s = true;\n            this.keyState.arrowdown = true;\n            e.preventDefault();\n        }\n        if (key === 'keya' || key === 'arrowleft') {\n            this.keyState.a = true;\n            this.keyState.arrowleft = true;\n            e.preventDefault();\n        }\n        if (key === 'keyd' || key === 'arrowright') {\n            this.keyState.d = true;\n            this.keyState.arrowright = true;\n            e.preventDefault();\n        }\n        if (key === 'keye') {\n            this.keyState.e = true;\n            e.preventDefault();\n        }\n        if (key === 'keyq') {\n            this.keyState.q = true;\n            e.preventDefault();\n        }\n        if (key === 'shiftleft' || key === 'shiftright') {\n            this.keyState.shift = true;\n            e.preventDefault();\n        }\n        if (key === 'space') {\n            this.keyState.space = true;\n            if (!this._isJumping && !this._jumpRequested) {\n                this._jumpRequested = true;\n            }\n            e.preventDefault();\n        }\n        if (key === 'controlleft' || key === 'controlright') {\n            this.keyState.ctrl = true;\n            this._isCrouching = true;\n            e.preventDefault();\n        }\n    }\n\n    _onKeyUp(e) {\n        if (!e.code) return;\n        const lookKey = { KeyR: 'r', KeyF: 'f', KeyZ: 'z', KeyX: 'x' }[e.code];\n        if (lookKey) { this.keyState[lookKey] = false; return; }\n        const key = e.code.toLowerCase();\n        if (key === 'keyw' || key === 'arrowup') {\n            this.keyState.w = false;\n            this.keyState.arrowup = false;\n        }\n        if (key === 'keys' || key === 'arrowdown') {\n            this.keyState.s = false;\n            this.keyState.arrowdown = false;\n        }\n        if (key === 'keya' || key === 'arrowleft') {\n            this.keyState.a = false;\n            this.keyState.arrowleft = false;\n        }\n        if (key === 'keyd' || key === 'arrowright') {\n            this.keyState.d = false;\n            this.keyState.arrowright = false;\n        }\n        if (key === 'keye') {\n            this.keyState.e = false;\n        }\n        if (key === 'keyq') {\n            this.keyState.q = false;\n        }\n        if (key === 'shiftleft' || key === 'shiftright') {\n            this.keyState.shift = false;\n        }\n        if (key === 'space') {\n            this.keyState.space = false;\n        }\n        if (key === 'controlleft' || key === 'controlright') {\n            this.keyState.ctrl = false;\n            this._isCrouching = false;\n        }\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Jump and movement state accessors for avatar system\n    // ──────────────────────────────────────────────────────────────\n\n    resetKeyboardLook() {\n        if (this.keyState) this.keyState.r = this.keyState.f = this.keyState.z = this.keyState.x = false;\n        this._keyboardLookLastAt = null;\n    }\n\n    _updateKeyboardLook(now = performance.now()) {\n        if (this._externalCameraOverride || _isMetaverseSceneMode()\n            || (typeof window !== 'undefined' && window.__noclipMapMode === '2d')\n            || (typeof document !== 'undefined' && (document.hidden || this.isEditableTarget(document.activeElement)))\n            || (this.cameraMode !== 'surface' && this.cameraMode !== 'orbit')) {\n            this.resetKeyboardLook(); return;\n        }\n        const previous = this._keyboardLookLastAt;\n        this._keyboardLookLastAt = now;\n        const dt = previous == null ? 0 : Math.max(0, Math.min(0.1, (now - previous) / 1000));\n        const k = this.keyState || {};\n        const pitch = ((k.r ? 1 : 0) - (k.f ? 1 : 0)) * dt * Math.PI / 3;\n        const yaw = ((k.x ? 1 : 0) - (k.z ? 1 : 0)) * dt * Math.PI / 3;\n        if (!pitch && !yaw) return;\n        if (this.cameraMode === 'surface') {\n            this.surfaceState.pitch = THREE.MathUtils.clamp((this.surfaceState.pitch || 0) + pitch, -1.45, 1.45);\n            const nextYaw = (this.surfaceState.yaw || 0) + yaw;\n            this.surfaceState.yaw = Math.atan2(Math.sin(nextYaw), Math.cos(nextYaw));\n            if (this._useDeviceOrientation) {\n                this._beginDeviceLookGesture();\n                this._deviceLookOffsetPitch = THREE.MathUtils.clamp((this._deviceLookOffsetPitch || 0) + pitch, -1.45, 1.45);\n                this._deviceLookOffsetYaw = THREE.MathUtils.clamp((this._deviceLookOffsetYaw || 0) - yaw, -Math.PI, Math.PI);\n            }\n        } else if (this.orbitViewPivot) {\n            // Local camera +Y rotation points left; compass yaw points right.\n            const state = this.orbitViewPivot;\n            this._setOrbitViewPivotTarget((state.targetYaw || 0) - yaw, (state.targetPitch || 0) + pitch);\n            state.velocityYaw = state.velocityPitch = 0;\n            state.lastInteractionAt = now;\n        }\n    }\n\n    /**\n     * Get current horizontal velocity\n     */\n    getSurfaceVelocity() {\n        return this._velocity.clone();\n    }\n\n    /**\n     * Get current horizontal speed (m/s)\n     */\n    getSurfaceSpeed() {\n        return this._speed;\n    }\n\n    /**\n     * Check if currently jumping\n     */\n    isJumping() {\n        return this._isJumping;\n    }\n\n    /**\n     * Check if currently crouching\n     */\n    isCrouching() {\n        return this._isCrouching || !!this._xrLocomotionInput?.crouch;\n    }\n\n    /**\n     * Check if grounded (not jumping and at eye height)\n     */\n    isGrounded() {\n        if (this._isJumping || this._airborneMSLGlideActive) return false;\n        const eyeHeight = this._getSurfaceFloorAltitude();\n        return Math.abs(this.surfaceAltitudeMeters - eyeHeight) < 0.5;\n    }\n\n    /**\n     * Update velocity tracking (call each frame)\n     */\n    _updateVelocityTracking(dt) {\n        const position = this._getCameraAnchor().position;\n        if (!this._prevCamPos) {\n            this._prevCamPos = position.clone();\n            return;\n        }\n\n        const invDt = 1 / Math.max(dt, 1e-5);\n        this._velocity.subVectors(position, this._prevCamPos).multiplyScalar(invDt);\n        this._speed = Math.hypot(this._velocity.x, this._velocity.z);\n        this._prevCamPos.copy(position);\n    }\n\n    /**\n     * Update jump and crouch physics (call each frame in surface mode)\n     */\n    _updateJumpPhysics(dt) {\n        const targetEyeHeight = this._getSurfaceFloorAltitude();\n        const oceanSwimming = Number.isFinite(this.surfaceAltitudeMeters)\n            && this.surfaceAltitudeMeters < targetEyeHeight\n            && this._isOceanForDir(this.surfaceState?.up);\n\n        // Underwater Q/E navigation is buoyancy-neutral. Ground jump/crouch\n        // physics must not pull the camera back to eye height every frame.\n        if (oceanSwimming) {\n            this._jumpRequested = false;\n            this._jumpVelocity = 0;\n            this._isJumping = false;\n            const swimFloor = this._getNavigationFloorAltitude(this.surfaceState?.up);\n            if (!Number.isFinite(this.surfaceAltitudeMeters) || this.surfaceAltitudeMeters < swimFloor) {\n                this.surfaceAltitudeMeters = swimFloor;\n            }\n            return;\n        }\n\n        if (this._airborneMSLGlideActive) {\n            this._jumpRequested = false;\n            this._jumpVelocity = 0;\n            this._isJumping = false;\n            return;\n        }\n\n        // Handle jump request\n        if (this._jumpRequested && !this._isJumping) {\n            // Only jump if close to ground level (not floating/flying)\n            if (Math.abs(this.surfaceAltitudeMeters - targetEyeHeight) < 0.5) {\n                this._jumpVelocity = this.JUMP_VELOCITY;\n                this._isJumping = true;\n            }\n            this._jumpRequested = false;\n        }\n\n        // Near the surface, releasing vertical flight hands altitude back to\n        // physical radial gravity. This applies to both photoreal contact and\n        // TriTree terrain because `surfaceAltitudeMeters` is measured above\n        // the active walkable floor in either provider. Deliberate flight\n        // above the capture band remains possible and a wheel gesture retains\n        // ownership until its short smoothing hold expires.\n        const verticalInput = !!(this.keyState?.q || this.keyState?.e || this._xrLocomotionInput?.vertical);\n        const gravityCaptureAlt = Math.max(\n            targetEyeHeight,\n            Number(this.SURFACE_GRAVITY_CAPTURE_ALT) || 8\n        );\n        const scrollOwnsAltitude = performance.now() < (this._surfaceScrollHoldUntil || 0);\n        const shouldFall = !verticalInput\n            && !scrollOwnsAltitude\n            && Number.isFinite(this.surfaceAltitudeMeters)\n            && this.surfaceAltitudeMeters > targetEyeHeight + 0.01\n            && this.surfaceAltitudeMeters <= gravityCaptureAlt;\n        if (shouldFall && !this._isJumping) {\n            this._jumpVelocity = Math.min(0, Number(this._jumpVelocity) || 0);\n            this._isJumping = true;\n        } else if (verticalInput && this._isJumping) {\n            // Q/E is an explicit thrust owner and must not fight the gravity\n            // integrator in the same frame.\n            this._jumpVelocity = 0;\n            this._isJumping = false;\n        }\n\n        // Apply jump physics\n        if (this._isJumping) {\n            const terminalVelocity = Math.max(1, Number(this.SURFACE_TERMINAL_VELOCITY) || 55);\n            this._jumpVelocity = Math.max(\n                -terminalVelocity,\n                this._jumpVelocity - this.GRAVITY * dt\n            );\n            this.surfaceAltitudeMeters += this._jumpVelocity * dt;\n\n            // Check if landed\n            if (this.surfaceAltitudeMeters <= targetEyeHeight) {\n                this.surfaceAltitudeMeters = targetEyeHeight;\n                this._jumpVelocity = 0;\n                this._isJumping = false;\n            }\n        } else {\n            // Smoothly interpolate to crouch/stand height when not jumping\n            // Only adjust if we're at ground level (not flying/floating)\n            if (Math.abs(this.surfaceAltitudeMeters - this.STAND_EYE_HEIGHT) < 1.0 ||\n                Math.abs(this.surfaceAltitudeMeters - this.CROUCH_EYE_HEIGHT) < 1.0) {\n                const crouchSpeed = 8.0; // Height transition speed (meters per second equivalent in lerp)\n                const alpha = 1 - Math.exp(-crouchSpeed * dt);\n                this.surfaceAltitudeMeters += (targetEyeHeight - this.surfaceAltitudeMeters) * alpha;\n            }\n        }\n\n        const minFloor = this._getSurfaceFloorAltitude();\n        if (!Number.isFinite(this.surfaceAltitudeMeters) || this.surfaceAltitudeMeters < minFloor) {\n            this.surfaceAltitudeMeters = minFloor;\n        }\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Event listener management\n    // ──────────────────────────────────────────────────────────────\n\n    attachEventListeners() {\n        this.renderer.domElement.style.touchAction = 'none';\n        this.renderer.domElement.addEventListener('contextmenu', this._onContextMenu);\n        this.renderer.domElement.addEventListener('pointerdown', this._onPointerDown);\n        this.renderer.domElement.addEventListener('pointermove', this._onPointerMove);\n        this.renderer.domElement.addEventListener('pointerup', this._onPointerUp);\n        this.renderer.domElement.addEventListener('pointercancel', this._onPointerCancel);\n        this.renderer.domElement.addEventListener('lostpointercapture', this._onPointerCancel);\n        this.renderer.domElement.addEventListener('wheel', this._onWheel, { passive: true });\n        window.addEventListener('mousemove', this._onMouseMove);\n        document.addEventListener('pointerlockchange', this._onPointerLockChange);\n        document.addEventListener('pointerlockerror', this._onPointerLockError);\n        window.addEventListener('keydown', this._onKeyDown);\n        window.addEventListener('keyup', this._onKeyUp);\n        window.addEventListener('blur', this._onKeyboardLookBlur);\n        document.addEventListener('focusin', this._onKeyboardLookFocus);\n        document.addEventListener('visibilitychange', this._onKeyboardLookVisibility);\n    }\n\n    detachEventListeners() {\n        this.resetKeyboardLook();\n        this.renderer.domElement.removeEventListener('contextmenu', this._onContextMenu);\n        this.renderer.domElement.removeEventListener('pointerdown', this._onPointerDown);\n        this.renderer.domElement.removeEventListener('pointermove', this._onPointerMove);\n        this.renderer.domElement.removeEventListener('pointerup', this._onPointerUp);\n        this.renderer.domElement.removeEventListener('pointercancel', this._onPointerCancel);\n        this.renderer.domElement.removeEventListener('lostpointercapture', this._onPointerCancel);\n        this.renderer.domElement.removeEventListener('wheel', this._onWheel);\n        window.removeEventListener('mousemove', this._onMouseMove);\n        document.removeEventListener('pointerlockchange', this._onPointerLockChange);\n        document.removeEventListener('pointerlockerror', this._onPointerLockError);\n        window.removeEventListener('keydown', this._onKeyDown);\n        window.removeEventListener('keyup', this._onKeyUp);\n        window.removeEventListener('blur', this._onKeyboardLookBlur);\n        document.removeEventListener('focusin', this._onKeyboardLookFocus);\n        document.removeEventListener('visibilitychange', this._onKeyboardLookVisibility);\n    }\n\n    /**\n     * Handle origin shift from floating origin system\n     * Called when the world is shifted to keep camera near origin\n     * @param {THREE.Vector3} shift - The shift amount applied\n     */\n    handleOriginShift(shift) {\n        // Update velocity tracking reference position\n        if (this._prevCamPos) {\n            this._prevCamPos.sub(shift);\n        }\n\n        // Update any cached positions that need adjustment\n        if (this._orbitReturnPose?.position) {\n            this._orbitReturnPose.position.sub(shift);\n        }\n\n        // Update geoNav pivot point if active\n        if (this.geoNav?.pivotPoint) {\n            this.geoNav.pivotPoint.sub(shift);\n        }\n    }\n\n    dispose() {\n        this.detachEventListeners();\n        this.camera = null;\n        this.renderer = null;\n        this.controls = null;\n        this.triTree = null;\n    }\n}\n","// Lightweight UI SFX helper (ported from hydra docs graph audio)\nlet audioCtx = null;\n\nconst ensureAudioCtx = () => {\n  const AudioCtx = window.AudioContext || window.webkitAudioContext || null;\n  if (!AudioCtx) return null;\n  if (!audioCtx) {\n    try {\n      audioCtx = new AudioCtx();\n    } catch (_) {\n      audioCtx = null;\n    }\n  }\n  if (audioCtx && audioCtx.state === 'suspended') {\n    audioCtx.resume().catch(() => { /* ignore */ });\n  }\n  return audioCtx;\n};\n\nconst playBlip = (frequency, durationMs, gainValue) => {\n  try {\n    const ctx = ensureAudioCtx();\n    if (!ctx) return;\n    const osc = ctx.createOscillator();\n    const gain = ctx.createGain();\n    osc.type = 'sine';\n    osc.frequency.value = frequency;\n    const now = ctx.currentTime;\n    const durationSec = Math.max(durationMs || 0, 1) / 1000;\n    const volume = Math.max(0.0001, gainValue ?? 0.04);\n    gain.gain.setValueAtTime(volume, now);\n    gain.gain.exponentialRampToValueAtTime(0.0001, now + durationSec);\n    osc.connect(gain).connect(ctx.destination);\n    osc.start(now);\n    osc.stop(now + durationSec);\n  } catch (_) {\n    /* ignore autoplay or audio errors */\n  }\n};\n\nconst playMoveBlip = () => playBlip(12000, 50, 0.03);\nconst playResizeBlip = () => playBlip(200, 100, 0.05);\n\nexport function getUiAudioSfx() {\n  return {\n    playBlip,\n    playMoveBlip,\n    playResizeBlip\n  };\n}\n","/**\n * HoverDispatcher — single pointermove listener with rAF-coalesced dispatch.\n *\n * Replaces the per-overlay raycaster + per-event getBoundingClientRect pattern\n * with a centralized dispatcher that:\n *\n *   1. Owns ONE passive `pointermove` listener on the renderer canvas.\n *   2. Stores only the latest event between frames.\n *   3. On each frameClock.onBeforeRender tick (i.e. inside the animation loop,\n *      after camera update, before render), if the latest event differs from\n *      the last dispatched event, builds a shared context and calls registered\n *      consumers exactly once per frame.\n *\n * The shared context contains:\n *   {\n *     event,        // the latest pointermove event\n *     raycaster,    // a single THREE.Raycaster, setFromCamera() called ONCE per dispatch\n *     camera,       // the active THREE.Camera passed to attach()\n *     canvasRect,   // getBoundingClientRect() called ONCE per dispatch (cached on ctx)\n *     ndc,          // THREE.Vector2 in normalized device coords\n *     frameIndex,   // monotonic frame counter from frameClock\n *   }\n *\n * Consumers register via:\n *\n *     const unregister = hoverDispatcher.register('myOverlay', (ctx) => {\n *         const hits = ctx.raycaster.intersectObjects(myGroup.children, true);\n *         // ...\n *     });\n *\n * Each consumer keeps its own intersectObjects call against its specific\n * group/recursive/instancing semantics — the dispatcher does NOT try to merge\n * raycasts across overlays. The win is:\n *   - One getBoundingClientRect per frame (was 4+ per mousemove)\n *   - One raycaster.setFromCamera per frame (was N, one per overlay)\n *   - One pointermove listener (was N, one per overlay)\n *   - At most one dispatch per rendered frame (was 1000+ per second)\n *\n * Migration: refactor/async/README.md#phase-1b\n */\n\nimport * as THREE from 'three';\nimport { onBeforeRender, getFrameState } from '../frameClock.js';\n\n/** @type {HoverDispatcher|null} */\nlet _instance = null;\n\nclass HoverDispatcher {\n  constructor() {\n    /** @type {Map<string, (ctx: any) => void>} */\n    this._consumers = new Map();\n\n    this._raycaster = new THREE.Raycaster();\n    this._ndc = new THREE.Vector2();\n\n    /** @type {HTMLElement|null} */\n    this._domElement = null;\n    /** @type {THREE.Camera|null} */\n    this._camera = null;\n\n    /** @type {PointerEvent|MouseEvent|null} */\n    this._latestEvent = null;\n    /** @type {PointerEvent|MouseEvent|null} */\n    this._lastDispatchedEvent = null;\n\n    this._frameUnsub = null;\n    this._attached = false;\n\n    // Stats\n    this._dispatches = 0;\n    this._eventsReceived = 0;\n    this._lastDispatchAt = 0;\n\n    this._onPointerMove = this._onPointerMove.bind(this);\n  }\n\n  /**\n   * Attach the listener to a DOM element and bind to the active camera.\n   * Safe to call multiple times — re-attach updates the bindings.\n   *\n   * @param {HTMLElement} domElement\n   * @param {THREE.Camera} camera\n   */\n  attach(domElement, camera) {\n    if (this._attached && this._domElement === domElement && this._camera === camera) {\n      return;\n    }\n    if (this._attached) this.detach();\n    this._domElement = domElement;\n    this._camera = camera;\n    if (domElement) {\n      domElement.addEventListener('pointermove', this._onPointerMove, { passive: true });\n    }\n    this._frameUnsub = onBeforeRender(() => this._dispatch());\n    this._attached = true;\n  }\n\n  /**\n   * Detach listeners and clear the latest-event cache. Consumers stay\n   * registered so a subsequent attach() resumes dispatch transparently.\n   */\n  detach() {\n    if (!this._attached) return;\n    if (this._domElement) {\n      this._domElement.removeEventListener('pointermove', this._onPointerMove);\n    }\n    if (this._frameUnsub) this._frameUnsub();\n    this._frameUnsub = null;\n    this._domElement = null;\n    this._camera = null;\n    this._latestEvent = null;\n    this._lastDispatchedEvent = null;\n    this._attached = false;\n  }\n\n  /**\n   * Update the active camera (e.g. after a camera swap).\n   * @param {THREE.Camera} camera\n   */\n  setCamera(camera) {\n    this._camera = camera;\n  }\n\n  /**\n   * Register a hover consumer.\n   *\n   * @param {string} id  stable identifier — repeat registrations replace\n   * @param {(ctx: { event, raycaster, camera, canvasRect, ndc, frameIndex }) => void} fn\n   * @returns {() => void} unregister function\n   */\n  register(id, fn) {\n    if (!id || typeof fn !== 'function') return () => {};\n    this._consumers.set(id, fn);\n    return () => this._consumers.delete(id);\n  }\n\n  /**\n   * Unregister by id. Returns true if a consumer was removed.\n   * @param {string} id\n   */\n  unregister(id) {\n    return this._consumers.delete(id);\n  }\n\n  /** @private */\n  _onPointerMove(e) {\n    this._latestEvent = e;\n    this._eventsReceived++;\n  }\n\n  /** @private */\n  _dispatch() {\n    const e = this._latestEvent;\n    if (!e || e === this._lastDispatchedEvent) return;\n    if (this._consumers.size === 0) return;\n    if (!this._domElement || !this._camera) return;\n\n    this._lastDispatchedEvent = e;\n    this._dispatches++;\n    this._lastDispatchAt = performance.now();\n\n    // Cache rect ONCE per dispatch — overlays read it from ctx.canvasRect.\n    const rect = this._domElement.getBoundingClientRect();\n    this._ndc.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;\n    this._ndc.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;\n    this._raycaster.setFromCamera(this._ndc, this._camera);\n\n    const ctx = {\n      event: e,\n      raycaster: this._raycaster,\n      camera: this._camera,\n      canvasRect: rect,\n      ndc: this._ndc,\n      frameIndex: getFrameState().frameIndex,\n    };\n\n    for (const [id, fn] of this._consumers) {\n      try {\n        fn(ctx);\n      } catch (err) {\n        if (typeof console !== 'undefined') {\n          console.warn(`[HoverDispatcher] consumer \"${id}\" threw`, err);\n        }\n      }\n    }\n  }\n\n  /** Dev-mode stats for window.__noclipAsync.debug() */\n  getStats() {\n    return {\n      attached: this._attached,\n      consumerCount: this._consumers.size,\n      consumerIds: Array.from(this._consumers.keys()),\n      dispatches: this._dispatches,\n      eventsReceived: this._eventsReceived,\n      lastDispatchAt: this._lastDispatchAt,\n    };\n  }\n}\n\n/**\n * Lazy singleton accessor.\n * @returns {HoverDispatcher}\n */\nexport function getHoverDispatcher() {\n  if (!_instance) _instance = new HoverDispatcher();\n  return _instance;\n}\n\n/** Test-only reset. */\nexport function _resetHoverDispatcherForTests() {\n  if (_instance) _instance.detach();\n  _instance = null;\n}\n","/**\n * WorkerPoolMetrics — per-worker counters and latency histograms.\n *\n * Kept separate from WorkerPool.js to honor the agent-friendly-code 300 LOC\n * budget. Counters are simple integers; latency is a fixed-bucket histogram.\n *\n * Buckets (ms): 0-1, 1-5, 5-25, 25-100, 100-500, 500+\n */\n\nconst _stats = new Map();\n\nconst BUCKETS = [\n  { name: '0-1ms',     limit: 1 },\n  { name: '1-5ms',     limit: 5 },\n  { name: '5-25ms',    limit: 25 },\n  { name: '25-100ms',  limit: 100 },\n  { name: '100-500ms', limit: 500 },\n  { name: '500ms+',    limit: Infinity },\n];\n\nfunction _slot(name) {\n  let s = _stats.get(name);\n  if (!s) {\n    s = {\n      submitted: 0,\n      results: 0,\n      errors: 0,\n      timeouts: 0,\n      lastLatencyMs: 0,\n      maxLatencyMs: 0,\n      latencyHistogram: BUCKETS.map((b) => ({ name: b.name, count: 0 })),\n    };\n    _stats.set(name, s);\n  }\n  return s;\n}\n\nexport function recordSubmit(name) {\n  _slot(name).submitted++;\n}\n\nexport function recordResult(name, latencyMs) {\n  const s = _slot(name);\n  s.results++;\n  s.lastLatencyMs = latencyMs;\n  if (latencyMs > s.maxLatencyMs) s.maxLatencyMs = latencyMs;\n  for (let i = 0; i < BUCKETS.length; i++) {\n    if (latencyMs <= BUCKETS[i].limit) {\n      s.latencyHistogram[i].count++;\n      return;\n    }\n  }\n}\n\nexport function recordError(name) {\n  _slot(name).errors++;\n}\n\nexport function recordTimeout(name) {\n  _slot(name).timeouts++;\n}\n\nexport function getMetrics(name) {\n  const s = _stats.get(name);\n  if (!s) return null;\n  return {\n    submitted: s.submitted,\n    results: s.results,\n    errors: s.errors,\n    timeouts: s.timeouts,\n    lastLatencyMs: Math.round(s.lastLatencyMs * 100) / 100,\n    maxLatencyMs: Math.round(s.maxLatencyMs * 100) / 100,\n    latencyHistogram: s.latencyHistogram.map((b) => ({ ...b })),\n  };\n}\n\n/** Test-only reset. */\nexport function _reset() {\n  _stats.clear();\n}\n","/**\n * WorkerPool — generic Web Worker RPC for the AsyncHarness.\n *\n * Spawns and manages module workers (one per worker name) and provides a\n * promise-based RPC API:\n *\n *     const result = await workerPool.run('parser-worker', 'parseJSON', { text });\n *\n * Workers are lazily spawned on first use. Use precreate(name) during idle\n * time to warm them and avoid the ~50ms cold-start cost on first request.\n *\n * Message convention (matches refactor/voice/voice-worker.js for consistency):\n *\n *   main → worker:  { requestId, action, payload, transfer? }\n *   worker → main:  { type: 'result'   | 'error' | 'progress',\n *                     requestId,\n *                     payload }\n *\n * Extension over voice-worker:\n *   { requestId, action: '__abort__' }  cancels an in-flight request.\n *   Workers are expected to honor abort by checking a per-requestId flag\n *   in long loops. (Not all workers need it; parser-worker does.)\n *\n * Each worker file lives at refactor/async/workers/<name>.js and uses the\n * Vite-canonical pattern (re: refactor/voice/VoiceSystem.js:1372):\n *\n *     new Worker(new URL('./<name>.js', import.meta.url), { type: 'module' });\n *\n * Migration: refactor/async/README.md#phase-2\n */\n\nimport * as metrics from './WorkerPoolMetrics.js';\n\nlet _nextRequestId = 1;\nfunction nextId() { return `r${_nextRequestId++}`; }\nconst MAX_PENDING_PER_WORKER = 32;\n\nclass WorkerHandle {\n  constructor(name) {\n    this.name = name;\n    /** @type {Worker|null} */ this.worker = null;\n    /** @type {Map<string, {resolve, reject, onProgress, timer}>} */\n    this.pending = new Map();\n    this.retryAt = 0;\n    this.failures = 0;\n  }\n\n  ensureSpawned() {\n    if (this.worker) return;\n    if (Date.now() < this.retryAt) throw new Error(`WorkerPool[${this.name}] recovery cooldown`);\n    try {\n      const worker = _createWorker(this.name);\n      this.worker = worker;\n      worker.addEventListener('message', (ev) => {\n        if (this.worker === worker) this._onMessage(ev);\n      });\n      for (const type of ['error', 'messageerror']) {\n        worker.addEventListener(type, (ev) => {\n          ev.preventDefault?.();\n          this._fail(worker, new Error(`WorkerPool[${this.name}] ${type}: ${ev.message || 'worker unavailable'}`));\n        });\n      }\n    } catch (error) {\n      this._fail(this.worker, error);\n      throw error;\n    }\n  }\n\n  _take(requestId) {\n    const slot = this.pending.get(requestId);\n    if (!slot) return null;\n    this.pending.delete(requestId);\n    clearTimeout(slot.timer);\n    slot.signal?.removeEventListener('abort', slot.onAbort);\n    return slot;\n  }\n\n  _fail(worker, error) {\n    if (this.worker !== worker) return;\n    this.worker = null;\n    this.retryAt = Date.now() + Math.min(30000, 1000 * 2 ** Math.min(this.failures++, 5));\n    try { worker?.terminate(); } catch {}\n    for (const id of this.pending.keys()) {\n      const slot = this._take(id);\n      metrics.recordError(this.name);\n      slot.reject(error);\n    }\n  }\n\n  _onMessage(ev) {\n    const data = ev.data;\n    if (!data || !data.requestId) return;\n    const slot = this.pending.get(data.requestId);\n    if (!slot) return;\n    if (data.type === 'progress') {\n      try { slot.onProgress?.(data.payload); } catch {}\n      return;\n    }\n    if (data.type !== 'result' && data.type !== 'error') return;\n    this._take(data.requestId);\n    if (data.type === 'result') {\n      this.failures = 0;\n      metrics.recordResult(this.name, performance.now() - slot.startedAt);\n      slot.resolve(data.payload);\n    } else if (data.type === 'error') {\n      metrics.recordError(this.name);\n      const err = new Error(data.payload?.message || 'WorkerPool: worker error');\n      err.workerName = this.name;\n      err.workerPayload = data.payload;\n      slot.reject(err);\n    }\n  }\n\n  run(action, payload, opts = {}) {\n    if (opts.signal?.aborted) return Promise.reject(new DOMException('aborted', 'AbortError'));\n    if (this.pending.size >= MAX_PENDING_PER_WORKER) {\n      return Promise.reject(new Error(`WorkerPool[${this.name}] admission limit reached`));\n    }\n    try { this.ensureSpawned(); } catch (error) { return Promise.reject(error); }\n    const requestId = nextId();\n    const transfer = Array.isArray(opts.transfer) ? opts.transfer : null;\n    const startedAt = performance.now();\n\n    metrics.recordSubmit(this.name);\n\n    return new Promise((resolve, reject) => {\n      const slot = { resolve, reject, onProgress: opts.onProgress || null, startedAt, timer: null, signal: opts.signal, onAbort: null };\n      const timeoutMs = Number.isFinite(opts.timeoutMs) ? opts.timeoutMs : 30000;\n      slot.timer = setTimeout(() => {\n        if (this.pending.has(requestId)) {\n          metrics.recordTimeout(this.name);\n          const err = new Error(`WorkerPool[${this.name}]:${action} timed out after ${timeoutMs}ms`);\n          err.workerName = this.name;\n          // A hung synchronous parse cannot process __abort__. Retire its\n          // generation, rejecting all dependent RPCs before permitting retry.\n          this._fail(this.worker, err);\n        }\n      }, timeoutMs);\n      this.pending.set(requestId, slot);\n\n      const signal = opts.signal || null;\n      if (signal) {\n        slot.onAbort = () => {\n          if (this._take(requestId)) {\n            try { this.worker?.postMessage({ requestId, action: '__abort__' }); } catch {}\n            reject(new DOMException('aborted', 'AbortError'));\n          }\n        };\n        signal.addEventListener('abort', slot.onAbort, { once: true });\n      }\n\n      try {\n        if (transfer) {\n          this.worker.postMessage({ requestId, action, payload }, transfer);\n        } else {\n          this.worker.postMessage({ requestId, action, payload });\n        }\n      } catch (err) {\n        this._take(requestId);\n        metrics.recordError(this.name);\n        reject(err);\n      }\n    });\n  }\n\n  terminate() {\n    for (const id of this.pending.keys()) {\n      const slot = this._take(id);\n      slot.reject(new Error(`WorkerPool[${this.name}] terminated`));\n    }\n    this.pending.clear();\n    if (this.worker) {\n      try { this.worker.terminate(); } catch {}\n      this.worker = null;\n    }\n  }\n}\n\n// Vite needs the literal URL inside the constructor to bundle worker imports.\nfunction _createWorker(name) {\n  switch (name) {\n    case 'parser-worker':\n      return new Worker(new URL('./parser-worker.js', import.meta.url), { type: 'module' });\n    case 'mvt-worker':\n      return new Worker(new URL('./mvt-worker.js', import.meta.url), { type: 'module' });\n    case 'boundary-worker':\n      return new Worker(new URL('./boundary-worker.js', import.meta.url), { type: 'module' });\n    default:\n      throw new Error(`WorkerPool: unknown worker \"${name}\"`);\n  }\n}\n\nclass WorkerPool {\n  constructor() {\n    /** @type {Map<string, WorkerHandle>} */\n    this._handles = new Map();\n  }\n\n  _handle(name) {\n    let h = this._handles.get(name);\n    if (!h) {\n      h = new WorkerHandle(name);\n      this._handles.set(name, h);\n    }\n    return h;\n  }\n\n  /**\n   * Run an action on a named worker.\n   *\n   * @param {string} name\n   * @param {string} action\n   * @param {any}    payload\n   * @param {{ transfer?: Transferable[], timeoutMs?: number, signal?: AbortSignal,\n   *           onProgress?: (p:any)=>void }} [opts]\n   */\n  run(name, action, payload, opts) {\n    return this._handle(name).run(action, payload, opts);\n  }\n\n  /** Pre-spawn a worker so the next run() call doesn't pay cold-start cost. */\n  precreate(name) {\n    try {\n      this._handle(name).ensureSpawned();\n    } catch (e) {\n      if (typeof console !== 'undefined') {\n        console.warn(`[WorkerPool] precreate(\"${name}\") failed:`, e?.message || e);\n      }\n    }\n  }\n\n  /** Terminate one or all workers. */\n  terminate(name) {\n    if (name) {\n      const h = this._handles.get(name);\n      if (h) { h.terminate(); this._handles.delete(name); }\n      return;\n    }\n    for (const [, h] of this._handles) h.terminate();\n    this._handles.clear();\n  }\n\n  getStats() {\n    const out = {};\n    for (const [name, h] of this._handles) {\n      out[name] = {\n        spawned: !!h.worker,\n        pending: h.pending.size,\n        maxPending: MAX_PENDING_PER_WORKER,\n        retryAfterMs: Math.max(0, h.retryAt - Date.now()),\n        ...metrics.getMetrics(name),\n      };\n    }\n    return out;\n  }\n}\n\nlet _instance = null;\n\n/** Lazy singleton accessor. */\nexport function getWorkerPool() {\n  if (!_instance) _instance = new WorkerPool();\n  return _instance;\n}\n\n/** Test-only reset. */\nexport function _resetWorkerPoolForTests() {\n  if (_instance) _instance.terminate();\n  _instance = null;\n  metrics._reset();\n}\n","/**\n * AsyncHarness — singleton facade over frame clock, scheduler, fetch queue,\n * worker pool, and hover dispatcher.\n *\n * Import this once from main.js (or scene bootstrap) to initialize the harness,\n * then any module can get the singleton via getAsyncHarness().\n *\n *   import { initAsyncHarness, getAsyncHarness } from 'refactor/async/AsyncHarness.js';\n *   initAsyncHarness({ enableDebugGlobals: true });\n *   ...\n *   const harness = getAsyncHarness();\n *   harness.budgetScheduler.rafCoalesce('myHover', () => { ... });\n *\n * **Phase 0**: only frameClock + BudgetScheduler are wired up.\n * workerPool, fetchQueue, hoverDispatcher land in later phases as null-safe\n * getters so callers can use optional chaining:\n *\n *   harness.workerPool?.run('parser-worker', 'parseJSON', {text});\n *\n * Feature flags (window.__noclipAsync.flags) — added as each phase lands:\n *   hoverThrottle       Phase 1a  (rAF coalesce of mousemove)\n *   hoverDispatcher     Phase 1b  (HoverDispatcher replaces per-overlay raycasts)\n *   workerGeocode       Phase 2   (Nominatim parse in worker)\n *   workerOverpass      Phase 3   (Overpass parse in worker)\n *   surfaceSampleOpt    Phase 4   (photo-tile spatial pre-filter)\n *   workerMVT           Phase 5   (MVT decode in worker)\n *   splitTimeBudgetMs   Phase 6   (TriTree time-budget yield; numeric, 0 = off)\n */\n\nimport * as frameClock from './frameClock.js';\nimport * as budgetScheduler from './scheduler/BudgetScheduler.js';\nimport { getHoverDispatcher } from './hover/HoverDispatcher.js';\nimport { getWorkerPool } from './workers/WorkerPool.js';\nimport { getFetchQueue } from './fetch/FetchQueue.js';\n\nconst _defaultFlags = {\n  hoverThrottle: true,      // Phase 1a default-on once landed\n  hoverDispatcher: false,   // Phase 1b default-off until verified\n  workerGeocode: true,      // Phase 2 default-on (inline parse fallback)\n  workerOverpass: true,     // Phase 3 default-on (inline parse fallback)\n  surfaceSampleOpt: false,  // Phase 4\n  workerMVT: true,          // Phase 5 default-on (inline VectorTile fallback)\n  splitTimeBudgetMs: 0,     // Phase 6 (numeric; 0 = disabled)\n};\n\n/** @type {AsyncHarness|null} */\nlet _instance = null;\n\nclass AsyncHarness {\n  constructor(opts = {}) {\n    this.frameClock = frameClock;\n    this.budgetScheduler = budgetScheduler;\n\n    // WorkerPool spawns workers lazily on first run() call. Wiring the\n    // singleton here gives callers a stable handle without forcing spawn.\n    /** @type {any} */ this.workerPool = getWorkerPool();\n\n    // FetchQueue is the single network entry point for migrated callers.\n    // We wire it to the worker pool so large JSON parses route off-thread.\n    /** @type {any} */ this.fetchQueue = getFetchQueue();\n    if (this.fetchQueue && typeof this.fetchQueue.setWorkerPool === 'function') {\n      this.fetchQueue.setWorkerPool(this.workerPool);\n    }\n\n    // HoverDispatcher is lazily instantiated on first access — modules that\n    // don't need hover (workers, headless tests) never pay the cost.\n    /** @type {any} */ this.hoverDispatcher = getHoverDispatcher();\n\n    // Feature flags — users can flip these at runtime via\n    // window.__noclipAsync.flags.<name> = true/false/<num>\n    this.flags = { ..._defaultFlags, ...(opts.flags || {}) };\n\n    // Dev-mode debug hook.\n    if (opts.enableDebugGlobals !== false && typeof globalThis !== 'undefined') {\n      globalThis.__noclipAsync = {\n        harness: this,\n        flags: this.flags,\n        debug: () => this.debug(),\n      };\n    }\n\n    // Warm the parser worker during browser idle so the first geocode call\n    // doesn't pay the ~50ms worker cold-start cost. Safe to call before any\n    // consumer asks for it; precreate is best-effort and never throws.\n    try {\n      budgetScheduler.deferUntilIdle(() => {\n        if (this.flags?.workerGeocode || this.flags?.workerOverpass) {\n          this.workerPool?.precreate?.('parser-worker');\n        }\n      }, 5000);\n    } catch {}\n  }\n\n  /**\n   * Read-only stats snapshot for dev debugging.\n   * Invoke from console as: window.__noclipAsync.debug()\n   */\n  debug() {\n    return {\n      frameClock: frameClock.getFrameClockStats(),\n      budgetScheduler: budgetScheduler.getBudgetSchedulerStats(),\n      workerPool: this.workerPool?.getStats?.() ?? null,\n      fetchQueue: this.fetchQueue?.getStats?.() ?? null,\n      hoverDispatcher: this.hoverDispatcher?.getStats?.() ?? null,\n      flags: { ...this.flags },\n    };\n  }\n\n  /**\n   * Called by animation-loop.js BEFORE renderer.render() so HoverDispatcher\n   * and other rafCoalesce consumers see fresh camera state.\n   *\n   * @param {number} now performance.now()\n   * @param {number} dt  seconds since last frame\n   */\n  tickBeforeRender(now, dt) {\n    frameClock.tickBeforeRender(now, dt);\n  }\n\n  /**\n   * Called by animation-loop.js AFTER renderer.render() + budget governor.\n   * @param {number} now              frame end time\n   * @param {number} frameBudgetMs    total frame cost\n   */\n  tickAfterRender(now, frameBudgetMs) {\n    frameClock.tickAfterRender(now, frameBudgetMs);\n  }\n}\n\n/**\n * Initialize the singleton. Call once from main bootstrap; safe to call\n * multiple times (subsequent calls return the existing instance).\n *\n * @param {{ flags?: Partial<typeof _defaultFlags>, enableDebugGlobals?: boolean }} [opts]\n * @returns {AsyncHarness}\n */\nexport function initAsyncHarness(opts = {}) {\n  if (_instance) return _instance;\n  _instance = new AsyncHarness(opts);\n  return _instance;\n}\n\n/**\n * Get the singleton. Returns null if initAsyncHarness() has not been called\n * yet — all call sites MUST handle this with optional chaining.\n *\n * @returns {AsyncHarness|null}\n */\nexport function getAsyncHarness() {\n  return _instance;\n}\n\n/**\n * Test-only helper to reset the singleton between unit tests.\n * DO NOT call from production code.\n */\nexport function _resetAsyncHarnessForTests() {\n  _instance = null;\n}\n","/**\n * Global event coordination for UI interactions\n */\n\nimport * as THREE from 'three';\nimport { PLANET_RADIUS, DEG2RAD, RAD2DEG, ELEVATION_EXAGGERATION } from './constants.js';\nimport {\n    raySphereIntersection,\n    rayEllipsoidIntersection,\n    worldPosToLatLonLocal,\n    dirToLatLonLocal,\n    computeLocalSunAngles,\n    latLonToLocalDir,\n    ellipsoidRadiusForLocalDir,\n    ellipsoidRadiusForWorldDir\n} from './geometry-utils.js';\nimport { getHudInfoStore } from './hud-info-store.js';\nimport { getUiAudioSfx } from './audio-sfx.js';\nimport { getAsyncHarness } from '../refactor/async/AsyncHarness.js';\nimport { rafCoalesce as asyncRafCoalesce, cancelRafCoalesce as asyncCancelRafCoalesce } from '../refactor/async/scheduler/BudgetScheduler.js';\n\nexport class EventManager {\n    constructor(renderer, camera, triTree, surfaceController, lightingSystem = null, moonSystem = null, geoJsonLayer = null, eventBus = null) {\n        this.renderer = renderer;\n        this.camera = camera;\n        this.triTree = triTree;\n        this.surfaceController = surfaceController;\n        this.lightingSystem = lightingSystem;\n        this.moonSystem = moonSystem;\n        this.geoJsonLayer = geoJsonLayer;\n        this.eventBus = eventBus || null;\n        this.geoJsonOverlayLayer = null;\n        this.geoJsonOverlayLevel = 0;\n        this.geoJsonLabelLayers = [];\n        this.hudStore = getHudInfoStore();\n\n        // Raycasting for events\n        this.clickRaycaster = new THREE.Raycaster();\n        this.clickNDC = new THREE.Vector2();\n\n        // Hex selection state\n        this.hexSelection = {\n            centerDir: null,\n            radius: 5 * DEG2RAD,\n            surfaceRadius: null\n        };\n        this._isShiftHeld = false;\n        this.enableShiftHoverSelection = false;\n        this._surfacePathActive = false; // Track if surface path was clicked\n        this._lastPointerEvent = null;\n        this._hoverLatLon = null;\n        this._hoverWorldPos = null;\n        this._hoverGeoPollIntervalMs = 1000;\n        this._hoverGeoPollDeltaDeg = 0.1;\n        this._hoverGeoLast = {\n            lat: null,\n            lon: null,\n            ts: 0,\n            country: null,\n            countryFeature: null,\n            subdivision: null\n        };\n        this._hoverGeoSoundLast = {\n            key: null,\n            ts: 0\n        };\n        this._lastHoverWeatherSummary = null;\n        this.weatherProvider = null;\n        this.buildingOverlay = null;\n        this.aircraftOverlay = null;\n        this.satelliteOverlay = null;\n        this.maritimeOverlay = null;\n        this.incidentOverlay = null;\n        this.overlaySubsystem = null;\n        this.onViewshedHoverChange = null;\n        this.onOverlayHoverChange = null;\n        this._viewshedHover = { key: null, id: null };\n        this._overlayHover = { overlayId: null, itemId: null };\n        this._viewshedHoverTmpPos = new THREE.Vector3();\n        this._viewshedHoverTmpDir = new THREE.Vector3();\n        this._viewshedHoverTmpQuat = new THREE.Quaternion();\n        this._viewshedHoverTmpCam = new THREE.Vector3();\n        this._viewshedHoverTmpCenter = new THREE.Vector3();\n        this._hudTargetKeys = [\n            'target.lat',\n            'target.lon',\n            'target.elev',\n            'target.agl',\n            'target.radius',\n            'target.country',\n            'target.admin',\n            'target.building',\n            'target.buildingAddr',\n            'target.buildingHeight',\n            'target.buildingLevels',\n            'target.sunElev',\n            'target.sunAz',\n            'target.sunInc',\n            'target.solarTime',\n            'target.moonElev',\n            'target.moonAz',\n            'target.weatherCond',\n            'target.weatherTemp',\n            'target.weatherClouds',\n            'target.weatherHumidity',\n            'target.weatherWind',\n            'target.weatherPrecip',\n            'target.weatherUpdated',\n            'target.aircraftModel',\n            'target.aircraftCallsign',\n            'target.aircraftId',\n            'target.aircraftAlt',\n            'target.aircraftSpeed',\n            'target.aircraftHeading',\n            'target.aircraftLat',\n            'target.aircraftLon',\n            'target.aircraftSource',\n            'target.satelliteName',\n            'target.satelliteId',\n            'target.satelliteType',\n            'target.satelliteAlt',\n            'target.satelliteLat',\n            'target.satelliteLon',\n            'target.satelliteSource',\n            'target.vesselName',\n            'target.vesselMmsi',\n            'target.vesselSpeed',\n            'target.vesselHeading',\n            'target.vesselLat',\n            'target.vesselLon',\n            'target.vesselStatus',\n            'target.vesselSource'\n        ];\n\n        // Double-tap detection for mobile\n        this._lastTapTime = 0;\n        this._lastTapPos = { x: 0, y: 0 };\n        this._doubleTapDelay = 300; // ms between taps to count as double-tap\n        this._doubleTapRadius = 30; // pixels - max distance between taps\n        this._suppressSurfaceTapUntil = 0;\n        this._touchTapGesture = null;\n        this._touchTapMoveTolerance = 14;\n\n        // Viewport height tracking\n        this.viewportHeight = window.innerHeight || 800;\n        this._lastClientWidth = 0;\n        this._lastClientHeight = 0;\n        this._lastRenderWidth = 0;\n        this._lastRenderHeight = 0;\n        this._resizeObserver = null;\n        this._resizeRaf = 0;\n\n        // Event handlers (bound methods)\n        this._onHexSelect = this._onHexSelect.bind(this);\n        this._onLatLonHover = this._onLatLonHover.bind(this);\n        this._onResize = this._onResize.bind(this);\n        this._scheduleResize = this._scheduleResize.bind(this);\n        this._onEscapeKey = this._onEscapeKey.bind(this);\n        this._onDoubleClick = this._onDoubleClick.bind(this);\n        this._onTouchStart = this._onTouchStart.bind(this);\n        this._onTouchMove = this._onTouchMove.bind(this);\n        this._onTouchEnd = this._onTouchEnd.bind(this);\n        this._onTouchCancel = this._onTouchCancel.bind(this);\n        this._onShiftKeyDown = this._onShiftKeyDown.bind(this);\n        this._onShiftKeyUp = this._onShiftKeyUp.bind(this);\n        this._onToggleSurfaceBall = this._onToggleSurfaceBall.bind(this);\n        this._handleHoverWeatherUpdate = this._handleHoverWeatherUpdate.bind(this);\n\n        // Callbacks (set externally)\n        this.onHexSelectionChange = null;  // Called when hex selection changes\n        this.onResizeCallback = null;       // Called after resize\n        this.onSidebarClose = null;         // Called when Escape pressed with sidebar open\n        this.onLODModeChange = null;        // Called when LOD mode changes\n        this.onEnterSurface = null;         // Called when entering surface mode\n\n        // Hover marker (pulsing cylinder)\n        this._hoverMarker = null;\n        this._initHoverMarker();\n\n        // Surface hex marker\n        this._surfaceHex = null;\n\n        // Surface link line (camera to hover)\n        this._surfaceLine = null;\n\n        // Surface path spheres (camera to hover)\n        this._surfacePathSpheres = [];\n\n        // Surface debug ball at hover point\n        this._surfaceBall = null;\n        this._surfaceBallEnabled = true;\n\n        // Tile edge highlighting\n        this._tileEdgeHighlight = null;\n        this._tileEdgeEnabled = false;\n        this._currentHighlightedTile = null;\n        this._edgeFadeProgress = 0;\n        this._edgeFadeTarget = 0;\n        this._edgeFadeSpeed = 5.0; // units per second\n        this._edgeColors = {\n            v0v1: '#ffffff',\n            v1v2: '#ff00ff',\n            v2v0: '#00ffff'\n        };\n        this._tileEdgeHighlightColor = '#ffffff';\n\n        // Edge direction arrows\n        this._edgeArrows = null; // Will hold { v0v1: arrow, v1v2: arrow, v2v0: arrow }\n        this._neighborArrows = []; // Array of arrows on neighbor tiles pointing back\n        this._vertexHelpers = []; // Array of vertex helper spheres for click-to-stitch mode\n\n        this._initTileEdgeToggle();\n    }\n\n    getHoverLatLon() {\n        if (!this._hoverLatLon) return null;\n        return { ...this._hoverLatLon };\n    }\n\n    getHoverWorldPosition() {\n        return this._hoverWorldPos ? this._hoverWorldPos.clone() : null;\n    }\n\n    setGeoJsonOverlayInfo({ layer, adminLevel } = {}) {\n        if (layer !== undefined) {\n            if (this.geoJsonOverlayLayer && this.geoJsonOverlayLayer !== layer) {\n                this.geoJsonOverlayLayer.clearHighlight?.();\n            }\n            this.geoJsonOverlayLayer = layer;\n        }\n        if (adminLevel !== undefined) {\n            this.geoJsonOverlayLevel = this._normalizeGeoJsonLevel(adminLevel);\n        }\n        if (this._hoverGeoLast) {\n            this._hoverGeoLast.ts = 0;\n            this._hoverGeoLast.country = null;\n            this._hoverGeoLast.subdivision = null;\n            this._hoverGeoLast.countryFeature = null;\n        }\n    }\n\n    setGeoJsonLabelLayers(layers = []) {\n        if (!Array.isArray(layers)) {\n            this.geoJsonLabelLayers = [];\n            return;\n        }\n        this.geoJsonLabelLayers = layers.filter(Boolean);\n    }\n\n    setWeatherProvider(provider) {\n        if (this.weatherProvider && this.weatherProvider.onHoverUpdate === this._handleHoverWeatherUpdate) {\n            this.weatherProvider.onHoverUpdate = null;\n        }\n        this.weatherProvider = provider || null;\n        if (this.weatherProvider) {\n            this.weatherProvider.onHoverUpdate = this._handleHoverWeatherUpdate;\n        }\n    }\n\n    setBuildingOverlay(overlay) {\n        this.buildingOverlay = overlay || null;\n    }\n\n    setAircraftOverlay(overlay) {\n        this.aircraftOverlay = overlay || null;\n    }\n\n    setSatelliteOverlay(overlay) {\n        this.satelliteOverlay = overlay || null;\n    }\n\n    setMaritimeOverlay(overlay) {\n        this.maritimeOverlay = overlay || null;\n    }\n\n    setIncidentOverlay(overlay) {\n        this.incidentOverlay = overlay || null;\n    }\n\n    setOverlaySubsystem(subsystem) {\n        this.overlaySubsystem = subsystem || null;\n    }\n\n    _applyWeatherSummary(prefix, summary) {\n        const hudStore = this.hudStore || getHudInfoStore();\n        const values = summary?.values || null;\n        const data = summary?.data || null;\n        const entries = [\n            ['weatherCond', 'condition'],\n            ['weatherTemp', 'temp'],\n            ['weatherClouds', 'clouds'],\n            ['weatherHumidity', 'humidity'],\n            ['weatherWind', 'wind'],\n            ['weatherPrecip', 'precip'],\n            ['weatherUpdated', 'updated']\n        ];\n\n        entries.forEach(([suffix, field]) => {\n            const key = `${prefix}.${suffix}`;\n            const hasValue = values && Object.prototype.hasOwnProperty.call(values, field);\n            hudStore.setValue(key, hasValue ? (values[field] ?? '--') : '--');\n            const hasData = data && Object.prototype.hasOwnProperty.call(data, field);\n            hudStore.setData(key, hasData ? (data[field] ?? null) : null);\n        });\n    }\n\n    _handleHoverWeatherUpdate(summary) {\n        if (!this._hoverLatLon) return;\n        this._lastHoverWeatherSummary = summary;\n        this._applyWeatherSummary('target', summary);\n    }\n\n    _formatLonLat(ll) {\n        const latStr = ll.latDeg >= 0\n            ? `${ll.latDeg.toFixed(4)}° N`\n            : `${Math.abs(ll.latDeg).toFixed(4)}° S`;\n        const lonStr = ll.lonDeg >= 0\n            ? `${ll.lonDeg.toFixed(4)}° E`\n            : `${Math.abs(ll.lonDeg).toFixed(4)}° W`;\n        return { latStr, lonStr };\n    }\n\n    _formatBuildingName(tags = {}) {\n        if (!tags) return '';\n        return tags.name\n            || tags['addr:housename']\n            || tags.amenity\n            || tags.shop\n            || (tags.building && tags.building !== 'yes' ? tags.building : '');\n    }\n\n    _formatAircraftModelName(modelUrl) {\n        if (!modelUrl) return '--';\n        const raw = String(modelUrl).split('/').pop() || String(modelUrl);\n        const trimmed = raw.replace(/\\.(glb|gltf)$/i, '');\n        return trimmed || '--';\n    }\n\n    _getCameraWorldPosition(out) {\n        if (!this.camera) return null;\n        if (this.camera.userData?.worldPosition) {\n            return out.copy(this.camera.userData.worldPosition);\n        }\n        return this.camera.getWorldPosition(out);\n    }\n\n    _distanceToObject(object, cameraPos) {\n        if (!object || !cameraPos) return null;\n        object.getWorldPosition(this._viewshedHoverTmpPos);\n        return this._viewshedHoverTmpPos.distanceTo(cameraPos);\n    }\n\n    _distanceToLatLon(lat, lon, radius, cameraPos) {\n        if (!Number.isFinite(lat) || !Number.isFinite(lon) || !cameraPos) return null;\n        const localDir = latLonToLocalDir(lat, lon);\n        if (!localDir) return null;\n        const worldDir = this._viewshedHoverTmpDir.copy(localDir);\n        if (this.triTree?.group) {\n            this.triTree.group.getWorldQuaternion(this._viewshedHoverTmpQuat);\n            worldDir.applyQuaternion(this._viewshedHoverTmpQuat);\n        }\n        worldDir.normalize();\n        const earthPos = this.triTree?.group\n            ? this.triTree.group.getWorldPosition(this._viewshedHoverTmpCenter)\n            : this._viewshedHoverTmpCenter.set(0, 0, 0);\n        const radiusValue = Number.isFinite(radius)\n            ? radius\n            : ellipsoidRadiusForLocalDir(localDir);\n        this._viewshedHoverTmpPos.copy(worldDir).multiplyScalar(radiusValue).add(earthPos);\n        return this._viewshedHoverTmpPos.distanceTo(cameraPos);\n    }\n\n    _resolveViewshedHoverId(type, entry) {\n        if (!entry) return null;\n        switch (type) {\n            case 'building':\n                return entry.id || null;\n            case 'aircraft':\n                return entry.rawId || entry.id || entry.callsign || null;\n            case 'satellite':\n                return entry.noradCatId || entry.id || entry.name || null;\n            case 'maritime':\n                return entry.mmsi || entry.id || entry.name || null;\n            case 'incident':\n                return entry.id || null;\n            case 'business':\n            case 'natural':\n            case 'infrastructure':\n                return entry.id || entry.key || entry.osmId || entry.name || null;\n            default:\n                return entry.id || null;\n        }\n    }\n\n    _updateViewshedHoverHighlight(hovered = {}) {\n        const hudStore = this.hudStore || getHudInfoStore();\n        if (!hudStore?.setListHighlight) return;\n        const cameraPos = this._getCameraWorldPosition(this._viewshedHoverTmpCam);\n        if (!cameraPos) return;\n        const candidates = [];\n        const addCandidate = (key, id, distance) => {\n            if (!id || !Number.isFinite(distance)) return;\n            candidates.push({ key, id: String(id), distance });\n        };\n\n        if (hovered.incident) {\n            const id = this._resolveViewshedHoverId('incident', hovered.incident);\n            const dist = this._distanceToObject(hovered.incident.object, cameraPos);\n            addCandidate('viewshed.incidents', id, dist);\n        }\n\n        if (hovered.aircraft) {\n            const id = this._resolveViewshedHoverId('aircraft', hovered.aircraft);\n            const localDir = latLonToLocalDir(hovered.aircraft.lat, hovered.aircraft.lon);\n            const baseRadius = localDir ? ellipsoidRadiusForLocalDir(localDir) : PLANET_RADIUS;\n            const altitude = Number.isFinite(hovered.aircraft.altitudeM) ? hovered.aircraft.altitudeM : 0;\n            const dist = this._distanceToObject(hovered.aircraft.object, cameraPos)\n                ?? this._distanceToLatLon(\n                    hovered.aircraft.lat,\n                    hovered.aircraft.lon,\n                    baseRadius + altitude,\n                    cameraPos\n                );\n            addCandidate('viewshed.aircraft', id, dist);\n        }\n\n        if (hovered.satellite) {\n            const id = this._resolveViewshedHoverId('satellite', hovered.satellite);\n            const localDir = latLonToLocalDir(hovered.satellite.lastLat, hovered.satellite.lastLon);\n            const baseRadius = localDir ? ellipsoidRadiusForLocalDir(localDir) : PLANET_RADIUS;\n            const altitude = Number.isFinite(hovered.satellite.lastAltM) ? hovered.satellite.lastAltM : 0;\n            const dist = this._distanceToObject(hovered.satellite.object, cameraPos)\n                ?? this._distanceToLatLon(\n                    hovered.satellite.lastLat,\n                    hovered.satellite.lastLon,\n                    baseRadius + altitude,\n                    cameraPos\n                );\n            addCandidate('viewshed.satellites', id, dist);\n        }\n\n        if (hovered.maritime) {\n            const id = this._resolveViewshedHoverId('maritime', hovered.maritime);\n            const dist = this._distanceToObject(hovered.maritime.object, cameraPos)\n                ?? this._distanceToLatLon(hovered.maritime.lat, hovered.maritime.lon, null, cameraPos);\n            addCandidate('viewshed.maritime', id, dist);\n        }\n\n        if (hovered.building) {\n            const id = this._resolveViewshedHoverId('building', hovered.building);\n            let dist = null;\n            const center = hovered.building.center || null;\n            if (center && Number.isFinite(center.lat) && Number.isFinite(center.lon)) {\n                const localDir = latLonToLocalDir(center.lat, center.lon);\n                if (localDir) {\n                    const worldDir = this._viewshedHoverTmpDir.copy(localDir);\n                    if (this.triTree?.group) {\n                        this.triTree.group.getWorldQuaternion(this._viewshedHoverTmpQuat);\n                        worldDir.applyQuaternion(this._viewshedHoverTmpQuat);\n                    }\n                    worldDir.normalize();\n                    const radius = this._computeSurfaceRadius(worldDir, null);\n                    dist = this._distanceToLatLon(center.lat, center.lon, radius, cameraPos);\n                }\n            }\n            addCandidate('viewshed.buildings', id, dist);\n        }\n\n        candidates.sort((a, b) => a.distance - b.distance);\n        const next = candidates.length ? candidates[0] : null;\n        const nextKey = next?.key || null;\n        const nextId = next?.id || null;\n        if (this._viewshedHover.key === nextKey && this._viewshedHover.id === nextId) return;\n        this._viewshedHover = { key: nextKey, id: nextId };\n        const listKeys = [\n            'viewshed.aircraft',\n            'viewshed.satellites',\n            'viewshed.maritime',\n            'viewshed.buildings',\n            'viewshed.businesses',\n            'viewshed.natural',\n            'viewshed.infrastructure',\n            'viewshed.incidents'\n        ];\n        listKeys.forEach((key) => {\n            const match = key === nextKey ? { id: nextId } : null;\n            hudStore.setListHighlight(key, match);\n        });\n        if (typeof this.onViewshedHoverChange === 'function') {\n            this.onViewshedHoverChange({ key: nextKey, id: nextId });\n        }\n    }\n\n    _updateOverlayHoverHighlight(hoveredItem) {\n        const overlayId = hoveredItem?.overlayEntry?.overlayId || null;\n        const itemId = hoveredItem?.itemId || hoveredItem?.data?.item_id || null;\n        const layerId = hoveredItem?.layerId || null;\n        if (this._overlayHover.overlayId === overlayId && this._overlayHover.itemId === itemId) return;\n        this._overlayHover = { overlayId, itemId };\n        const payload = { overlayId, itemId, layerId, item: hoveredItem?.data || null };\n        if (typeof this.onOverlayHoverChange === 'function') {\n            this.onOverlayHoverChange(payload);\n        }\n        if (this.eventBus?.emit) {\n            this.eventBus.emit('overlay:itemHover', payload);\n        }\n    }\n\n    _shouldUpdateHoverGeo(latDeg, lonDeg, now) {\n        const last = this._hoverGeoLast;\n        if (!last) return true;\n        const timestamp = Number.isFinite(now)\n            ? now\n            : (typeof performance !== 'undefined' ? performance.now() : Date.now());\n        const elapsed = timestamp - (last.ts || 0);\n        const deltaLat = Number.isFinite(last.lat) ? Math.abs(last.lat - latDeg) : Infinity;\n        const deltaLon = Number.isFinite(last.lon) ? Math.abs(last.lon - lonDeg) : Infinity;\n        const needsInterval = elapsed >= this._hoverGeoPollIntervalMs;\n        const needsDelta = deltaLat >= this._hoverGeoPollDeltaDeg || deltaLon >= this._hoverGeoPollDeltaDeg;\n        const needsSeed = !last.country && !last.subdivision;\n        return needsInterval || needsDelta || needsSeed;\n    }\n\n    _getCountryForLatLon(latDeg, lonDeg) {\n        if (!this.geoJsonLayer || typeof this.geoJsonLayer.getCountryAtLatLon !== 'function') return null;\n        return this.geoJsonLayer.getCountryAtLatLon(latDeg, lonDeg);\n    }\n\n    _getCountryFeatureForLatLon(latDeg, lonDeg) {\n        if (!this.geoJsonLayer || typeof this.geoJsonLayer.getFeatureAtLatLon !== 'function') return null;\n        return this.geoJsonLayer.getFeatureAtLatLon(latDeg, lonDeg);\n    }\n\n    _normalizeGeoJsonLevel(value) {\n        const numeric = Number.isFinite(value) ? value : Number.parseInt(value, 10);\n        if (!Number.isFinite(numeric) || numeric < 0) return 0;\n        return Math.min(numeric, 3);\n    }\n\n    _getSubdivisionForLatLon(latDeg, lonDeg) {\n        const layer = this.geoJsonOverlayLayer;\n        const level = this._normalizeGeoJsonLevel(this.geoJsonOverlayLevel);\n        if (!layer || level <= 0) return null;\n        if (layer.group && !layer.group.visible) return null;\n        if (typeof layer.getFeatureAtLatLon !== 'function') return null;\n        const feature = layer.getFeatureAtLatLon(latDeg, lonDeg);\n        if (!feature) return null;\n        const props = feature.properties || {};\n        const name = feature.name ||\n            props.shapeName ||\n            props.name ||\n            props.name_en ||\n            props.name_long ||\n            props.NAME_1 ||\n            props.NAME_2 ||\n            props.NAME_3 ||\n            props.NAME ||\n            null;\n        if (!name) return null;\n        const label = props.shapeType || props.adm_level || `ADM${level}`;\n        return { name, label, level, feature };\n    }\n\n    _formatCelestial(surfaceDir) {\n        if (!this.lightingSystem) return null;\n\n        // Get sun direction in ecliptic (world) frame\n        const sunDir = this.lightingSystem.getSunDirection();\n\n        // Convert to Earth-fixed (planet-local) frame for lat/lon metrics\n        const sunLocal = sunDir.clone();\n        const surfaceLocal = surfaceDir.clone();\n        if (this.triTree && this.triTree.group) {\n            const invQ = this.triTree.group.getWorldQuaternion(new THREE.Quaternion()).invert();\n            sunLocal.applyQuaternion(invQ);\n            surfaceLocal.applyQuaternion(invQ);\n        }\n\n        // computeLocalSunAngles expects both vectors in world (ecliptic) frame\n        // It internally transforms to equatorial frame for lat/lon consistency\n        const sunAngles = computeLocalSunAngles(surfaceDir, sunDir);\n\n        // Convert sun direction to lat/lon to find subsolar point\n        // dirToLatLon internally untilts from ecliptic to equatorial frame\n        const llSun = dirToLatLonLocal(sunLocal);\n        const subsolarLon = llSun.lonDeg;\n\n        // Convert surface direction to lat/lon\n        const ll = dirToLatLonLocal(surfaceLocal);\n\n        // Calculate local solar time from longitude difference\n        const deltaLon = ((ll.lonDeg - subsolarLon + 540) % 360) - 180; // [-180,180]\n        let localSolarTime = 12 - deltaLon / 15; // noon when deltaLon=0\n        if (localSolarTime < 0) localSolarTime += 24;\n        if (localSolarTime >= 24) localSolarTime -= 24;\n        const lstHours = Math.floor(localSolarTime);\n        const lstMinutes = Math.round((localSolarTime - lstHours) * 60);\n\n        // Moon angles (optional)\n        let moonElevDeg = null;\n        let moonAzDeg = null;\n        if (this.moonSystem && this.moonSystem.getDirection) {\n            // Moon direction is also in ecliptic frame\n            const moonDir = this.moonSystem.getDirection();\n            const moonAngles = computeLocalSunAngles(surfaceDir, moonDir);\n            moonElevDeg = moonAngles.altitude * RAD2DEG;\n            moonAzDeg = moonAngles.azimuth * RAD2DEG;\n        }\n\n        const sunElevDeg = sunAngles.altitude * RAD2DEG;\n        const sunAzDeg = sunAngles.azimuth * RAD2DEG;\n        const sunIncDeg = sunAngles.incidence * RAD2DEG;\n        const lstStr = `${String(lstHours).padStart(2, '0')}:${String(lstMinutes).padStart(2, '0')} LST`;\n\n        return {\n            sunElevDeg,\n            sunAzDeg,\n            sunIncDeg,\n            solarTime: lstStr,\n            moonElevDeg,\n            moonAzDeg\n        };\n    }\n\n    _initHoverMarker() {\n        if (!this.triTree || !this.triTree.group) return;\n        const geom = new THREE.RingGeometry(18, 30, 32);\n        // RingGeometry faces +Z; the hover placement quaternion maps local +Y\n        // onto the surface normal, so rotate the ring into the local XZ plane.\n        geom.rotateX(-Math.PI / 2);\n\n        const mat = new THREE.MeshBasicMaterial({\n            color: 0xffc466,\n            transparent: true,\n            opacity: 0.78,\n            depthWrite: false,\n            depthTest: false,\n            side: THREE.DoubleSide,\n            toneMapped: false\n        });\n\n        const mesh = new THREE.Mesh(geom, mat);\n        mesh.visible = false;\n        mesh.renderOrder = 5;\n        this._hoverMarker = mesh;\n        this.triTree.group.add(mesh);\n    }\n\n    _initTileEdgeToggle() {\n        const toggle = document.getElementById('tile-edge-highlight-toggle');\n        if (toggle) {\n            toggle.addEventListener('change', (e) => {\n                this._tileEdgeEnabled = e.target.checked;\n                if (!this._tileEdgeEnabled) {\n                    this._edgeFadeTarget = 0;\n                    this._hideEdgeArrows();\n                } else if (this._currentHighlightedTile) {\n                    this._updateEdgeArrows(this._currentHighlightedTile);\n                }\n            });\n        }\n\n        // Add listener for vertex metrics checkbox\n        const vertexMetricsToggle = document.getElementById('cfg-vertex-metrics');\n        if (vertexMetricsToggle) {\n            vertexMetricsToggle.addEventListener('change', () => {\n                // Refresh the neighbor panel display\n                if (this._currentHighlightedTile) {\n                    this._updateNeighborPanels(this._currentHighlightedTile);\n                }\n            });\n        }\n\n    }\n\n    _ensureTileEdgeHighlight() {\n        if (this._tileEdgeHighlight || !this.triTree || !this.triTree.group) return;\n\n        // Create white wireframe material for the tile highlight\n        const wireframeMat = new THREE.MeshBasicMaterial({\n            color: this._tileEdgeHighlightColor || 0xffffff,\n            wireframe: true,\n            transparent: true,\n            opacity: 0,\n            depthWrite: false,\n            depthTest: true\n        });\n\n        // Create an empty mesh that we'll update with the hovered tile's geometry\n        this._tileEdgeHighlight = new THREE.Mesh(new THREE.BufferGeometry(), wireframeMat);\n        this._tileEdgeHighlight.visible = false;\n        this._tileEdgeHighlight.renderOrder = 10;\n\n        this.triTree.group.add(this._tileEdgeHighlight);\n    }\n\n    _getEdgeColors() {\n        return this._edgeColors || {\n            v0v1: '#ffffff',\n            v1v2: '#ff00ff',\n            v2v0: '#00ffff'\n        };\n    }\n\n    setWireframeStyle({ accent, accentSoft, accentStrong, highlight } = {}) {\n        const nextColors = { ...this._getEdgeColors() };\n        if (accent) nextColors.v0v1 = accent;\n        if (accentStrong) nextColors.v1v2 = accentStrong;\n        if (accentSoft) nextColors.v2v0 = accentSoft;\n        this._edgeColors = nextColors;\n\n        if (highlight) this._tileEdgeHighlightColor = highlight;\n        if (this._tileEdgeHighlight?.material) {\n            this._tileEdgeHighlight.material.color.set(this._tileEdgeHighlightColor || 0xffffff);\n            this._tileEdgeHighlight.material.needsUpdate = true;\n        }\n\n        if (this._currentHighlightedTile && this._tileEdgeEnabled) {\n            this._updateEdgeArrows(this._currentHighlightedTile);\n        } else if (this._edgeArrows) {\n            const edgeColors = this._getEdgeColors();\n            for (const [edgeName, arrow] of Object.entries(this._edgeArrows)) {\n                const color = edgeColors[edgeName];\n                if (arrow?.line?.material?.color) arrow.line.material.color.set(color);\n                if (arrow?.cone?.material?.color) arrow.cone.material.color.set(color);\n            }\n        }\n\n        if (this._currentHighlightedTile) {\n            this._updateNeighborPanels(this._currentHighlightedTile);\n        }\n    }\n\n    _createEdgeArrows() {\n        if (this._edgeArrows || !this.triTree || !this.triTree.group) return;\n\n        const edgeColors = this._getEdgeColors();\n\n        this._edgeArrows = {};\n\n        for (const [edgeName, color] of Object.entries(edgeColors)) {\n            const dir = new THREE.Vector3(0, 1, 0);\n            const origin = new THREE.Vector3(0, 0, 0);\n            const length = 50; // Arrow length\n            const headLength = 15;\n            const headWidth = 10;\n\n            const arrow = new THREE.ArrowHelper(dir, origin, length, color, headLength, headWidth);\n            arrow.visible = false;\n            arrow.renderOrder = 11; // Render on top of wireframe\n\n            this._edgeArrows[edgeName] = arrow;\n            this.triTree.group.add(arrow);\n        }\n    }\n\n    _getEdgeMidpoint(tile, edgeName) {\n        if (!tile || !tile.positionAttr) return null;\n\n        const res = tile.resolution;\n        if (!Number.isFinite(res) || res < 0) return null;\n        const baseCount = tile.vertexCount || (tile.baseDirs ? tile.baseDirs.length / 3 : 0);\n        if (!baseCount) return null;\n\n        // Vertex indices for corners (same as in getCornerPosition)\n        // v2 = index 0, v1 = index res, v0 = last index\n        const v0Idx = baseCount - 1;\n        const v1Idx = res;\n        const v2Idx = 0;\n\n        // Get indices for each edge's endpoints\n        let idx1, idx2;\n        if (edgeName === 'v0v1') {\n            idx1 = v0Idx;\n            idx2 = v1Idx;\n        } else if (edgeName === 'v1v2') {\n            idx1 = v1Idx;\n            idx2 = v2Idx;\n        } else if (edgeName === 'v2v0') {\n            idx1 = v2Idx;\n            idx2 = v0Idx;\n        } else {\n            return null;\n        }\n\n        // Get positions of the two endpoints\n        const p1 = new THREE.Vector3(\n            tile.positionAttr.getX(idx1),\n            tile.positionAttr.getY(idx1),\n            tile.positionAttr.getZ(idx1)\n        );\n        const p2 = new THREE.Vector3(\n            tile.positionAttr.getX(idx2),\n            tile.positionAttr.getY(idx2),\n            tile.positionAttr.getZ(idx2)\n        );\n\n        // Calculate midpoint and project to sphere (SLERP for spherical interpolation)\n        const midpoint = new THREE.Vector3().lerpVectors(p1, p2, 0.5);\n        const radius = (p1.length() + p2.length()) / 2;\n        midpoint.normalize().multiplyScalar(radius);\n\n        return midpoint;\n    }\n\n    _getTileCenter(tile) {\n        const center = new THREE.Vector3(0, 0, 0);\n        if (tile && tile.mesh && tile.mesh.geometry) {\n            const posAttr = tile.positionAttr || tile.mesh.geometry.getAttribute('position');\n            if (posAttr) {\n                const baseCount = tile.vertexCount ||\n                    (tile.baseDirs ? tile.baseDirs.length / 3 : posAttr.count);\n                const count = Math.min(baseCount || 0, posAttr.count);\n                if (!count) return center;\n                // Average all vertex positions to get center\n                for (let i = 0; i < count; i++) {\n                    center.x += posAttr.getX(i);\n                    center.y += posAttr.getY(i);\n                    center.z += posAttr.getZ(i);\n                }\n                center.divideScalar(count);\n            }\n        }\n        return center;\n    }\n\n    _getEdgeLength(tile, edgeName) {\n        if (!tile || !tile.positionAttr) return 0;\n\n        const res = tile.resolution;\n        if (!Number.isFinite(res) || res < 0) return 0;\n        const baseCount = tile.vertexCount || (tile.baseDirs ? tile.baseDirs.length / 3 : 0);\n        if (!baseCount) return 0;\n\n        const v0Idx = baseCount - 1;\n        const v1Idx = res;\n        const v2Idx = 0;\n\n        let idx1, idx2;\n        if (edgeName === 'v0v1') {\n            idx1 = v0Idx;\n            idx2 = v1Idx;\n        } else if (edgeName === 'v1v2') {\n            idx1 = v1Idx;\n            idx2 = v2Idx;\n        } else if (edgeName === 'v2v0') {\n            idx1 = v2Idx;\n            idx2 = v0Idx;\n        } else {\n            return 0;\n        }\n\n        const p1 = new THREE.Vector3(\n            tile.positionAttr.getX(idx1),\n            tile.positionAttr.getY(idx1),\n            tile.positionAttr.getZ(idx1)\n        );\n        const p2 = new THREE.Vector3(\n            tile.positionAttr.getX(idx2),\n            tile.positionAttr.getY(idx2),\n            tile.positionAttr.getZ(idx2)\n        );\n\n        return p1.distanceTo(p2);\n    }\n\n    _updateEdgeArrows(tile) {\n        if (!tile || !this._tileEdgeEnabled) {\n            this._hideEdgeArrows();\n            return;\n        }\n\n        this._createEdgeArrows();\n        this._clearNeighborArrows();\n\n        const edgeColors = this._getEdgeColors();\n\n        // Get tile center\n        const center = this._getTileCenter(tile);\n\n        // Update primary arrows on hovered tile\n        for (const edgeName of ['v0v1', 'v1v2', 'v2v0']) {\n            const arrow = this._edgeArrows[edgeName];\n            if (!arrow) continue;\n\n            const midpoint = this._getEdgeMidpoint(tile, edgeName);\n            if (!midpoint) {\n                arrow.visible = false;\n                continue;\n            }\n\n            // Direction from center to edge midpoint\n            const direction = new THREE.Vector3().subVectors(midpoint, center).normalize();\n\n            // Position arrow at center\n            arrow.position.copy(center);\n            arrow.setDirection(direction);\n\n            // Adjust arrow length to reach edge midpoint\n            const distance = center.distanceTo(midpoint);\n            arrow.setLength(distance, distance * 0.3, distance * 0.2);\n\n            arrow.visible = true;\n\n            // Create reciprocal arrows on neighbor tiles\n            const neighbors = this.triTree && this.triTree.findEdgeNeighbors\n                ? this.triTree.findEdgeNeighbors(tile, edgeName)\n                : [];\n\n            console.log(`Edge ${edgeName}: found ${neighbors.length} neighbors`);\n\n            // Calculate adaptive threshold based on primary tile edge length\n            const edgeLength = this._getEdgeLength(tile, edgeName);\n            const distanceThreshold = Math.max(edgeLength * 0.6, 100); // 60% of edge length or 100 units minimum\n            console.log(`  Edge length: ${edgeLength.toFixed(2)}, distance threshold: ${distanceThreshold.toFixed(2)}`);\n\n            for (const neighbor of neighbors) {\n                const neighborCenter = this._getTileCenter(neighbor);\n                const neighborId = neighbor.getTileId ? neighbor.getTileId() : 'unknown';\n                const neighborLOD = neighbor.level ?? '?';\n\n                // Find which edge on the neighbor OVERLAPS with our edge\n                // Don't use midpoint distance - use geometric overlap check\n                let bestEdgeName = null;\n                let foundOverlap = false;\n\n                // Get corners of the primary tile's edge\n                const primaryV0 = tile.v0;\n                const primaryV1 = tile.v1;\n                const primaryV2 = tile.v2;\n\n                let edgeV0, edgeV1;\n                if (edgeName === 'v0v1') {\n                    edgeV0 = primaryV0;\n                    edgeV1 = primaryV1;\n                } else if (edgeName === 'v1v2') {\n                    edgeV0 = primaryV1;\n                    edgeV1 = primaryV2;\n                } else { // v2v0\n                    edgeV0 = primaryV2;\n                    edgeV1 = primaryV0;\n                }\n\n                // Check each neighbor edge for overlap with primary edge\n                const neighborEdges = [\n                    { name: 'v0v1', v0: neighbor.v0, v1: neighbor.v1 },\n                    { name: 'v1v2', v0: neighbor.v1, v1: neighbor.v2 },\n                    { name: 'v2v0', v0: neighbor.v2, v1: neighbor.v0 }\n                ];\n\n                for (const nEdge of neighborEdges) {\n                    // Use the tritree manager's overlap check if available\n                    if (this.triTree && this.triTree._edgesOverlap) {\n                        if (this.triTree._edgesOverlap(edgeV0, edgeV1, nEdge.v0, nEdge.v1)) {\n                            bestEdgeName = nEdge.name;\n                            foundOverlap = true;\n                            break;\n                        }\n                    }\n                }\n\n                console.log(`  Neighbor ${neighborId} (LOD ${neighborLOD}): overlap edge ${bestEdgeName}, found: ${foundOverlap}`);\n\n                // Only create arrow if we found an overlapping edge\n                if (bestEdgeName && foundOverlap) {\n                    const neighborMidpoint = this._getEdgeMidpoint(neighbor, bestEdgeName);\n                    const targetPoint = neighborMidpoint || midpoint;\n\n                    // Direction from neighbor center toward edge midpoint (pointing at shared edge)\n                    const neighborDirection = new THREE.Vector3().subVectors(targetPoint, neighborCenter).normalize();\n\n                    // Create arrow on neighbor tile\n                    const neighborArrow = new THREE.ArrowHelper(\n                        neighborDirection,\n                        neighborCenter,\n                        50,\n                        edgeColors[edgeName], // Use same color as primary arrow\n                        15,\n                        10\n                    );\n\n                    // Adjust arrow length\n                    const neighborDistance = neighborCenter.distanceTo(targetPoint);\n                    neighborArrow.setLength(neighborDistance, neighborDistance * 0.3, neighborDistance * 0.2);\n\n                    neighborArrow.renderOrder = 11;\n                    this.triTree.group.add(neighborArrow);\n                    this._neighborArrows.push(neighborArrow);\n\n                    console.log(`    ✓ Created neighbor arrow at`, neighborCenter, `pointing`, neighborDirection, `length ${neighborDistance.toFixed(2)}`);\n                } else {\n                    console.log(`    ✗ Skipped neighbor arrow (no overlapping edge found)`);\n                }\n            }\n        }\n    }\n\n    _clearNeighborArrows() {\n        if (!this._neighborArrows || !this.triTree || !this.triTree.group) return;\n\n        for (const arrow of this._neighborArrows) {\n            this.triTree.group.remove(arrow);\n            // Dispose of arrow geometry and material\n            if (arrow.line) {\n                if (arrow.line.geometry) arrow.line.geometry.dispose();\n                if (arrow.line.material) arrow.line.material.dispose();\n            }\n            if (arrow.cone) {\n                if (arrow.cone.geometry) arrow.cone.geometry.dispose();\n                if (arrow.cone.material) arrow.cone.material.dispose();\n            }\n        }\n        this._neighborArrows = [];\n    }\n\n    _hideEdgeArrows() {\n        if (this._edgeArrows) {\n            for (const arrow of Object.values(this._edgeArrows)) {\n                arrow.visible = false;\n            }\n        }\n        this._clearNeighborArrows();\n    }\n\n    _showVertexHelpers(tile) {\n        if (!tile || !this.triTree || !this.triTree.group) return;\n\n        // Clear any existing vertex helpers\n        this._hideVertexHelpers();\n\n        const edgeColors = this._getEdgeColors();\n\n        const edges = ['v0v1', 'v1v2', 'v2v0'];\n\n        // Process each edge of the selected tile\n        for (const edgeName of edges) {\n            const neighbors = this.triTree.findEdgeNeighbors ? this.triTree.findEdgeNeighbors(tile, edgeName) : [];\n\n            // Get vertices on this edge for the selected tile\n            const edgeVertices = this._getEdgeVerticesFromGeometry(tile, edgeName);\n            if (!edgeVertices || edgeVertices.length === 0) continue;\n\n            const edgeColor = edgeColors[edgeName];\n\n            // Add helpers for selected tile's edge vertices (always in edge color)\n            for (const vertex of edgeVertices) {\n                this._createVertexHelper(vertex, edgeColor);\n            }\n\n            // Add helpers for neighbor tiles' edge vertices\n            for (const neighbor of neighbors) {\n                const neighborEdgeVertices = this._getNeighborEdgeVerticesFromGeometry(neighbor, tile, edgeName);\n\n                if (neighborEdgeVertices && neighborEdgeVertices.length > 0) {\n                    const lodDelta = tile.level - neighbor.level;\n\n                    // Identify matched and free-floating vertices\n                    if (Math.abs(lodDelta) === 1) {\n                        for (const neighborVertex of neighborEdgeVertices) {\n                            const isMatched = this._hasMatchingVertex(neighborVertex, edgeVertices);\n                            const color = isMatched ? edgeColor : 0xffffff; // White for free-floating\n                            this._createVertexHelper(neighborVertex, color);\n                        }\n                    } else {\n                        // No LOD difference - show all neighbor vertices in edge color\n                        for (const neighborVertex of neighborEdgeVertices) {\n                            this._createVertexHelper(neighborVertex, edgeColor);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    _hideVertexHelpers() {\n        if (!this._vertexHelpers || !this.triTree || !this.triTree.group) return;\n\n        for (const helper of this._vertexHelpers) {\n            this.triTree.group.remove(helper);\n            if (helper.geometry) helper.geometry.dispose();\n            if (helper.material) helper.material.dispose();\n        }\n        this._vertexHelpers = [];\n    }\n\n    _createVertexHelper(position, color) {\n        if (!this.triTree || !this.triTree.group) return;\n\n        const sphereGeom = new THREE.SphereGeometry(25, 8, 8); // 10x larger sphere (was 2.5, now 25)\n        const sphereMat = new THREE.MeshBasicMaterial({\n            color: color,\n            transparent: true,\n            opacity: 0.9,\n            depthWrite: false\n        });\n        const sphere = new THREE.Mesh(sphereGeom, sphereMat);\n\n        // Offset slightly outward from surface\n        const offsetPos = position.clone().normalize().multiplyScalar(position.length() + 5);\n        sphere.position.copy(offsetPos);\n        sphere.renderOrder = 12; // Render on top of arrows\n\n        this.triTree.group.add(sphere);\n        this._vertexHelpers.push(sphere);\n    }\n\n    _getEdgeVerticesFromGeometry(tile, edgeName) {\n        if (!tile || !tile.positionAttr || tile.positionAttr.count === 0) return [];\n        if (!tile._edgeVertexIndices) return [];\n\n        // Map our edge naming to the tile's edge naming (v1v2 -> v2v1)\n        let tileEdgeName = edgeName;\n        if (edgeName === 'v1v2') {\n            tileEdgeName = 'v2v1';\n        }\n\n        // Get the indices for vertices on this edge\n        const indices = tile._edgeVertexIndices(tileEdgeName);\n        if (!indices || indices.length === 0) return [];\n\n        const positions = tile.positionAttr.array;\n        const vertices = [];\n\n        for (const idx of indices) {\n            if (idx >= 0 && idx < tile.positionAttr.count) {\n                const vertex = new THREE.Vector3(\n                    positions[idx * 3],\n                    positions[idx * 3 + 1],\n                    positions[idx * 3 + 2]\n                );\n                vertices.push(vertex);\n            }\n        }\n\n        return vertices;\n    }\n\n    _getNeighborEdgeVerticesFromGeometry(neighbor, primaryTile, primaryEdgeName) {\n        if (!neighbor || !this.triTree) return [];\n\n        // Find which edge on the neighbor overlaps with the primary edge\n        const primaryV0 = primaryTile.v0;\n        const primaryV1 = primaryTile.v1;\n        const primaryV2 = primaryTile.v2;\n\n        let edgeV0, edgeV1;\n        if (primaryEdgeName === 'v0v1') {\n            edgeV0 = primaryV0;\n            edgeV1 = primaryV1;\n        } else if (primaryEdgeName === 'v1v2') {\n            edgeV0 = primaryV1;\n            edgeV1 = primaryV2;\n        } else {\n            edgeV0 = primaryV2;\n            edgeV1 = primaryV0;\n        }\n\n        // Check each neighbor edge for overlap\n        const neighborEdges = [\n            { name: 'v0v1', v0: neighbor.v0, v1: neighbor.v1 },\n            { name: 'v1v2', v0: neighbor.v1, v1: neighbor.v2 },\n            { name: 'v2v0', v0: neighbor.v2, v1: neighbor.v0 }\n        ];\n\n        for (const nEdge of neighborEdges) {\n            if (this.triTree._edgesOverlap && this.triTree._edgesOverlap(edgeV0, edgeV1, nEdge.v0, nEdge.v1)) {\n                return this._getEdgeVerticesFromGeometry(neighbor, nEdge.name);\n            }\n        }\n\n        return [];\n    }\n\n    _hasMatchingVertex(vertex, neighborVertices) {\n        if (!neighborVertices || neighborVertices.length === 0) return false;\n\n        const tolerance = 5.0; // Increased tolerance for matching\n        for (const neighborVertex of neighborVertices) {\n            if (vertex.distanceTo(neighborVertex) < tolerance) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    _performStitching(tile) {\n        if (!tile || !this.triTree) {\n            console.log('[Stitch] No tile or triTree');\n            return;\n        }\n\n        // Manual clickstitch uses the same seam injection as auto stitching, but hard-locks edges.\n        console.log(`[Stitch] ========== CLICK DETECTED - STARTING STITCH ==========`);\n        console.log(`[Stitch] Tile: ${tile.getTileId ? tile.getTileId() : 'unknown'} (LOD ${tile.level})`);\n\n        const edges = ['v0v1', 'v1v2', 'v2v0'];\n        let totalStitched = 0;\n\n        for (const edgeName of edges) {\n            const neighborInfos = this.triTree.getEdgeNeighborInfos\n                ? this.triTree.getEdgeNeighborInfos(tile, edgeName)\n                : [];\n            console.log(`[Stitch] Edge ${edgeName}: Found ${neighborInfos.length} neighbors`);\n\n            for (const neighborInfo of neighborInfos) {\n                const neighbor = neighborInfo.tile;\n                const neighborEdgeName = neighborInfo.edgeName;\n                if (!neighbor) continue;\n\n                const lodDelta = tile.level - neighbor.level;\n                console.log(`[Stitch]   Neighbor: ${neighbor.getTileId ? neighbor.getTileId() : 'unknown'} (LOD ${neighbor.level}), delta: ${lodDelta}`);\n\n                let authorityTile;\n                let authorityEdge;\n                let targetTile;\n                let targetEdge;\n\n                if (lodDelta === 0) {\n                    const tileCompleteness = (typeof tile.getEdgeElevationCompleteness === 'function')\n                        ? tile.getEdgeElevationCompleteness(edgeName)\n                        : 0.0;\n                    const neighborCompleteness = (typeof neighbor.getEdgeElevationCompleteness === 'function')\n                        ? neighbor.getEdgeElevationCompleteness(neighborEdgeName)\n                        : 0.0;\n\n                    let neighborIsAuthority = false;\n                    if (neighborCompleteness > tileCompleteness) {\n                        neighborIsAuthority = true;\n                    } else if (tileCompleteness > neighborCompleteness) {\n                        neighborIsAuthority = false;\n                    } else {\n                        const tileId = tile.getTileId ? tile.getTileId() : '';\n                        const neighborId = neighbor.getTileId ? neighbor.getTileId() : '';\n                        neighborIsAuthority = (neighborId < tileId);\n                    }\n\n                    if (neighborIsAuthority) {\n                        authorityTile = neighbor;\n                        authorityEdge = neighborEdgeName;\n                        targetTile = tile;\n                        targetEdge = edgeName;\n                        console.log(`[Stitch]   -> Will adjust clicked tile to match neighbor`);\n                    } else {\n                        authorityTile = tile;\n                        authorityEdge = edgeName;\n                        targetTile = neighbor;\n                        targetEdge = neighborEdgeName;\n                        console.log(`[Stitch]   -> Will adjust neighbor to match clicked tile`);\n                    }\n                } else {\n                    // Different LOD - higher LOD tile gets adjusted to match lower LOD\n                    authorityTile = lodDelta > 0 ? neighbor : tile;  // Lower LOD is authority\n                    authorityEdge = lodDelta > 0 ? neighborEdgeName : edgeName;\n                    targetTile = lodDelta > 0 ? tile : neighbor;     // Higher LOD is target\n                    targetEdge = lodDelta > 0 ? edgeName : neighborEdgeName;\n                    console.log(`[Stitch]   -> Will adjust higher LOD tile: L${targetTile.level} to match lower LOD tile: L${authorityTile.level}`);\n                }\n\n                const authorityRange = (authorityTile === tile)\n                    ? (neighborInfo.originRange || null)\n                    : (neighborInfo.neighborRange || null);\n                const stitched = this.triTree.stitchEdgeFromAuthority\n                    ? this.triTree.stitchEdgeFromAuthority(\n                        targetTile,\n                        targetEdge,\n                        authorityTile,\n                        authorityEdge,\n                        'hard',\n                        'manual',\n                        authorityRange ? { authorityRange, canonical: true } : null\n                    )\n                    : 0;\n                totalStitched += stitched;\n            }\n        }\n\n        console.log(`[Stitch] ========== COMPLETE: ${totalStitched} vertices adjusted ==========`);\n    }\n\n    _updateTileEdgeGeometry(tile) {\n        if (!tile || !tile.mesh || !tile.mesh.geometry || !this._tileEdgeHighlight) return;\n\n        const geometry = tile.mesh.geometry;\n        const posAttr = geometry.getAttribute('position');\n        if (!posAttr) return;\n\n        // Clone the geometry to create an independent copy\n        const clonedGeom = geometry.clone();\n        const clonedPosAttr = clonedGeom.getAttribute('position');\n        if (!clonedPosAttr) return;\n\n        // Offset all vertices outward by 0.01 units (radially from planet center)\n        const offsetAmount = 0.01;\n        const count = clonedPosAttr.count;\n\n        for (let i = 0; i < count; i++) {\n            // Get current vertex position\n            const x = clonedPosAttr.getX(i);\n            const y = clonedPosAttr.getY(i);\n            const z = clonedPosAttr.getZ(i);\n\n            // Calculate direction from planet center (radial direction)\n            const length = Math.sqrt(x * x + y * y + z * z);\n            if (length > 0) {\n                // Normalize and offset outward\n                const scale = (length + offsetAmount) / length;\n                clonedPosAttr.setXYZ(i, x * scale, y * scale, z * scale);\n            }\n        }\n\n        clonedPosAttr.needsUpdate = true;\n        clonedGeom.computeBoundingSphere();\n\n        // Replace the highlight mesh geometry with the cloned, offset geometry\n        if (this._tileEdgeHighlight.geometry) {\n            this._tileEdgeHighlight.geometry.dispose();\n        }\n        this._tileEdgeHighlight.geometry = clonedGeom;\n        this._tileEdgeHighlight.visible = true;\n    }\n\n    updateTileEdgeFade(dt) {\n        if (!this._tileEdgeHighlight) return;\n\n        // Animate fade progress towards target\n        const delta = this._edgeFadeTarget - this._edgeFadeProgress;\n        if (Math.abs(delta) > 0.001) {\n            const step = this._edgeFadeSpeed * dt;\n            if (Math.abs(delta) < step) {\n                this._edgeFadeProgress = this._edgeFadeTarget;\n            } else {\n                this._edgeFadeProgress += Math.sign(delta) * step;\n            }\n\n            // Update wireframe material opacity\n            if (this._tileEdgeHighlight.material) {\n                this._tileEdgeHighlight.material.opacity = this._edgeFadeProgress;\n            }\n\n            this._tileEdgeHighlight.visible = this._edgeFadeProgress > 0.001;\n        }\n    }\n\n    _ensureSurfaceHex() {\n        if (this._surfaceHex || !this.triTree || !this.triTree.group) return;\n        const radius = 50;\n        const shape = new THREE.Shape();\n        for (let i = 0; i < 6; i++) {\n            const a = (Math.PI / 3) * i + Math.PI / 6;\n            const x = Math.cos(a) * radius;\n            const y = Math.sin(a) * radius;\n            if (i === 0) shape.moveTo(x, y);\n            else shape.lineTo(x, y);\n        }\n        shape.closePath();\n\n        const geom = new THREE.ShapeGeometry(shape);\n        const mat = new THREE.MeshBasicMaterial({\n            color: 0xffc857,\n            transparent: true,\n            opacity: 0.6,\n            depthWrite: false,\n            side: THREE.DoubleSide\n        });\n        const mesh = new THREE.Mesh(geom, mat);\n        mesh.visible = false;\n        mesh.renderOrder = 6;\n        this._surfaceHex = mesh;\n        this.triTree.group.add(mesh);\n    }\n\n    _ensureSurfaceLine() {\n        if (this._surfaceLine || !this.triTree || !this.triTree.group) return;\n        const geom = new THREE.BufferGeometry().setFromPoints([new THREE.Vector3(), new THREE.Vector3()]);\n        const mat = new THREE.LineBasicMaterial({\n            color: 0xffc857,\n            transparent: true,\n            opacity: 0.7,\n            depthWrite: false\n        });\n        const line = new THREE.Line(geom, mat);\n        line.visible = false;\n        line.renderOrder = 7;\n        this._surfaceLine = line;\n        this.triTree.group.add(line);\n    }\n\n    _ensureSurfacePathSpheres(count) {\n        if (!this.triTree || !this.triTree.group) return;\n        const current = this._surfacePathSpheres.length;\n        const needed = Math.max(0, count - current);\n        for (let i = 0; i < needed; i++) {\n            const geom = new THREE.SphereGeometry(3, 12, 12);\n            const mat = new THREE.MeshBasicMaterial({\n                color: 0xffc857,\n                transparent: true,\n                opacity: 0.8,\n                depthWrite: false\n            });\n            const mesh = new THREE.Mesh(geom, mat);\n            mesh.visible = false;\n            mesh.renderOrder = 7;\n            this.triTree.group.add(mesh);\n            this._surfacePathSpheres.push(mesh);\n        }\n    }\n\n    _ensureSurfaceBall() {\n        if (this._surfaceBall || !this.triTree || !this.triTree.group) return;\n        const geom = new THREE.SphereGeometry(5, 16, 16); // diameter ~10 units\n        const mat = new THREE.MeshBasicMaterial({\n            color: 0xffffff,\n            transparent: true,\n            opacity: 0.85,\n            depthWrite: false\n        });\n        const mesh = new THREE.Mesh(geom, mat);\n        mesh.visible = false;\n        mesh.renderOrder = 8;\n        this._surfaceBall = mesh;\n        this.triTree.group.add(mesh);\n    }\n\n    _getTerrainIntersectionFromEvent(e, detailed = false) {\n        if (!this.renderer || !this.camera) return null;\n        const rect = this.renderer.domElement.getBoundingClientRect();\n        const ndc = this.clickNDC;\n        ndc.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;\n        ndc.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;\n        this.clickRaycaster.setFromCamera(ndc, this.camera);\n\n        // Photorealistic tile group is in a separate scene graph from triTree.\n        // Raycast against it FIRST so surface hover captures building/terrain\n        // heights instead of falling through to ellipsoid sea level.\n        const photoGroup = this.surfaceController?.photoTileGroup;\n        if (photoGroup && this.surfaceController?.getSurfacePointFromClient) {\n            const point = this.surfaceController.getSurfacePointFromClient(e.clientX, e.clientY);\n            if (point) {\n                return detailed\n                    ? { point: point.clone(), object: null, source: this.surfaceController._lastGeoHitSource || 'photo' }\n                    : point.clone();\n            }\n        }\n\n        const meshes = (this.triTree && Array.isArray(this.triTree.visibleMeshes))\n            ? this.triTree.visibleMeshes.filter(m => m && m.visible && m.geometry)\n            : [];\n        if (meshes.length) {\n            for (const m of meshes) m.updateMatrixWorld(true);\n            const hits = this.clickRaycaster.intersectObjects(meshes, true);\n            if (hits && hits.length) {\n                return detailed ? hits[0] : hits[0].point.clone();\n            }\n        }\n        return null;\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Helper functions\n    // ──────────────────────────────────────────────────────────────\n\n    isEditableTarget(el) {\n        if (!el) return false;\n        const tag = (el.tagName || '').toLowerCase();\n        if (tag === 'input' || tag === 'textarea' || tag === 'select') return true;\n        if (el.isContentEditable) return true;\n        if (el.getAttribute && el.getAttribute('contenteditable') === 'true') return true;\n        return false;\n    }\n\n    getSphereIntersectionFromEvent(e) {\n        const rect = this.renderer.domElement.getBoundingClientRect();\n        const x = ((e.clientX - rect.left) / rect.width) * 2 - 1;\n        const y = -((e.clientY - rect.top) / rect.height) * 2 + 1;\n        this.clickNDC.set(x, y);\n\n        this.clickRaycaster.setFromCamera(this.clickNDC, this.camera);\n        const planetGroup = this.triTree?.group || null;\n        return rayEllipsoidIntersection(\n            this.clickRaycaster.ray.origin,\n            this.clickRaycaster.ray.direction,\n            planetGroup\n        ) || raySphereIntersection(\n            this.clickRaycaster.ray.origin,\n            this.clickRaycaster.ray.direction\n        );\n    }\n\n    _updateHexFromEvent(e) {\n        if (!e) return false;\n        if (this.surfaceController && this.surfaceController.isInSurfaceMode()) return false;\n        const terrainHit = this._getTerrainIntersectionFromEvent(e, true);\n        const hit = terrainHit?.point || this.getSphereIntersectionFromEvent(e);\n        if (!hit) return false;\n        const dir = hit.clone().normalize();\n        const radius = this._computeHexRadius(dir, terrainHit);\n        const surfaceRadius = this._computeSurfaceRadius(dir, terrainHit);\n        this.setHexSelection(dir, radius, surfaceRadius);\n        return true;\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Hex selection\n    // ──────────────────────────────────────────────────────────────\n\n    _clampHexRadius(rad) {\n        const MIN_RAD = 1e-6; // ~6 m arc length\n        const MAX_RAD = 0.5;  // ~28.6°\n        if (!Number.isFinite(rad)) return 5 * DEG2RAD;\n        return THREE.MathUtils.clamp(rad, MIN_RAD, MAX_RAD);\n    }\n\n    _computeTileMinEdgeAngle(tile) {\n        if (!tile || !tile.baseDirs || !tile.geometry) return null;\n        if (Number.isFinite(tile._cachedMinEdgeAngle)) return tile._cachedMinEdgeAngle;\n        const indexAttr = tile.geometry.getIndex();\n        if (!indexAttr) return null;\n        const base = tile.baseDirs;\n        const tmpA = new THREE.Vector3();\n        const tmpB = new THREE.Vector3();\n        let minEdge = Infinity;\n        const faceCount = indexAttr.count / 3;\n        for (let f = 0; f < faceCount; f++) {\n            const i0 = indexAttr.getX(f * 3 + 0);\n            const i1 = indexAttr.getX(f * 3 + 1);\n            const i2 = indexAttr.getX(f * 3 + 2);\n            tmpA.set(base[i0 * 3 + 0], base[i0 * 3 + 1], base[i0 * 3 + 2]);\n            tmpB.set(base[i1 * 3 + 0], base[i1 * 3 + 1], base[i1 * 3 + 2]);\n            const e0 = Math.acos(THREE.MathUtils.clamp(tmpA.dot(tmpB), -1, 1));\n            tmpB.set(base[i2 * 3 + 0], base[i2 * 3 + 1], base[i2 * 3 + 2]);\n            const e1 = Math.acos(THREE.MathUtils.clamp(tmpA.dot(tmpB), -1, 1));\n            const v1 = new THREE.Vector3(base[i1 * 3 + 0], base[i1 * 3 + 1], base[i1 * 3 + 2]);\n            const e2 = Math.acos(THREE.MathUtils.clamp(v1.dot(tmpB), -1, 1));\n            minEdge = Math.min(minEdge, e0, e1, e2);\n        }\n        if (!Number.isFinite(minEdge) || minEdge === Infinity) return null;\n        tile._cachedMinEdgeAngle = minEdge;\n        return minEdge;\n    }\n\n    _computeHexRadius(dir, terrainHit) {\n        if (!this.triTree) return null;\n        const tileFromHit = terrainHit?.object?.userData?.tile || null;\n        const tile = tileFromHit\n            || (dir && typeof this.triTree.findLeafTileForWorldDir === 'function'\n                ? this.triTree.findLeafTileForWorldDir(dir)\n                : null);\n        if (!tile || !tile.baseDirs || !tile.geometry) return null;\n\n        const base = tile.baseDirs;\n        const indexAttr = tile.geometry.getIndex();\n        if (!indexAttr) return null;\n\n        let faceIndex = terrainHit?.faceIndex;\n        let minEdge = null;\n\n        if (Number.isInteger(faceIndex)) {\n            const idx0 = indexAttr.getX(faceIndex * 3 + 0);\n            const idx1 = indexAttr.getX(faceIndex * 3 + 1);\n            const idx2 = indexAttr.getX(faceIndex * 3 + 2);\n\n            const v0 = new THREE.Vector3(base[idx0 * 3 + 0], base[idx0 * 3 + 1], base[idx0 * 3 + 2]);\n            const v1 = new THREE.Vector3(base[idx1 * 3 + 0], base[idx1 * 3 + 1], base[idx1 * 3 + 2]);\n            const v2 = new THREE.Vector3(base[idx2 * 3 + 0], base[idx2 * 3 + 1], base[idx2 * 3 + 2]);\n\n            const e0 = Math.acos(THREE.MathUtils.clamp(v0.dot(v1), -1, 1));\n            const e1 = Math.acos(THREE.MathUtils.clamp(v1.dot(v2), -1, 1));\n            const e2 = Math.acos(THREE.MathUtils.clamp(v2.dot(v0), -1, 1));\n            minEdge = Math.min(e0, e1, e2);\n        } else {\n            minEdge = this._computeTileMinEdgeAngle(tile);\n        }\n\n        if (!Number.isFinite(minEdge) || minEdge <= 0) return null;\n        return this._clampHexRadius(minEdge);\n    }\n\n    _computeSurfaceRadius(dir, terrainHit) {\n        if (terrainHit?.point) {\n            const len = terrainHit.point.length();\n            if (Number.isFinite(len)) return len;\n        }\n        if (!dir || !this.triTree) return null;\n        if (typeof this.triTree.sampleTerrainRadiusForDir === 'function') {\n            const r = this.triTree.sampleTerrainRadiusForDir(dir);\n            if (Number.isFinite(r)) return r;\n        }\n        if (typeof this.triTree.getSurfaceRadiusAtDir === 'function') {\n            const r = this.triTree.getSurfaceRadiusAtDir(dir);\n            if (Number.isFinite(r)) return r;\n        }\n        return null;\n    }\n\n    setHexSelection(dir, radiusOverride = null, surfaceRadius = null) {\n        if (dir) {\n            this.hexSelection.centerDir = dir.clone().normalize();\n            const r = Number.isFinite(radiusOverride) ? radiusOverride : 5 * DEG2RAD;\n            this.hexSelection.radius = this._clampHexRadius(r);\n            this.hexSelection.surfaceRadius = Number.isFinite(surfaceRadius) ? surfaceRadius : null;\n        } else {\n            this.hexSelection.centerDir = null;\n            this.hexSelection.surfaceRadius = null;\n        }\n\n        // Notify callback\n        if (typeof this.onHexSelectionChange === 'function') {\n            this.onHexSelectionChange(this.hexSelection);\n        }\n    }\n\n    getHexSelection() {\n        return this.hexSelection;\n    }\n\n    _onHexSelect(e) {\n        if (e.button !== 0) return;\n        if (this.isEditableTarget(e.target)) return;\n\n        if (this._trySelectGeoJsonLabel(e)) return;\n\n        // Original hex selection behavior (requires shift key)\n        if (!e.shiftKey) return;\n\n        // Handle surface mode - activate surface path\n        if (this.surfaceController && this.surfaceController.getCameraMode() === 'surface') {\n            this._surfacePathActive = true;\n            return;\n        }\n\n        const terrainHit = this._getTerrainIntersectionFromEvent(e, true);\n        const hit = terrainHit?.point || this.getSphereIntersectionFromEvent(e);\n        if (hit) {\n            const dir = hit.clone().normalize();\n            const radius = this._computeHexRadius(dir, terrainHit);\n            const surfaceRadius = this._computeSurfaceRadius(dir, terrainHit);\n            this.setHexSelection(dir, radius, surfaceRadius);\n            // Shift-click in orbit should no longer teleport to surface.\n        }\n    }\n\n    _trySelectGeoJsonLabel(e) {\n        if (!this.eventBus?.emit || !this.renderer || !this.camera) return false;\n        if (!this.geoJsonLabelLayers || !this.geoJsonLabelLayers.length) return false;\n        if (!Number.isFinite(e?.clientX) || !Number.isFinite(e?.clientY)) return false;\n        const rect = this.renderer.domElement.getBoundingClientRect();\n        const x = ((e.clientX - rect.left) / rect.width) * 2 - 1;\n        const y = -((e.clientY - rect.top) / rect.height) * 2 + 1;\n        this.clickNDC.set(x, y);\n        this.clickRaycaster.setFromCamera(this.clickNDC, this.camera);\n\n        let best = null;\n        for (const layer of this.geoJsonLabelLayers) {\n            if (!layer || typeof layer.pickLabel !== 'function') continue;\n            const hit = layer.pickLabel(this.clickRaycaster, this.camera);\n            if (!hit?.entry) continue;\n            if (!best || hit.distance < best.distance) {\n                best = hit;\n            }\n        }\n        if (!best?.entry) return false;\n        this.eventBus.emit('scene:geojson-label-toggle', best.entry);\n        e.preventDefault?.();\n        e.stopPropagation?.();\n        return true;\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Lat/lon hover display\n    // ──────────────────────────────────────────────────────────────\n\n    _onLatLonHover(e) {\n        const hudStore = this.hudStore || getHudInfoStore();\n        if (!hudStore) return;\n\n        this._lastPointerEvent = e;\n        const inSurfaceMode = this.surfaceController && this.surfaceController.isInSurfaceMode();\n\n        // Space objects remain hoverable when this ray misses Earth's terrain.\n        if(this.satelliteOverlay){\n            const rect=this.renderer.domElement.getBoundingClientRect();\n            this.clickNDC.set((e.clientX-rect.left)/rect.width*2-1,1-(e.clientY-rect.top)/rect.height*2);\n            this.clickRaycaster.setFromCamera(this.clickNDC,this.camera);\n            this.satelliteOverlay.updateHover(this.clickRaycaster,this.camera,{pointer:{x:e.clientX,y:e.clientY},rect});\n        }\n\n        if(this.aircraftOverlay?.catalog){\n            const rect=this.renderer.domElement.getBoundingClientRect();\n            this.clickNDC.set((e.clientX-rect.left)/rect.width*2-1,1-(e.clientY-rect.top)/rect.height*2);\n            this.clickRaycaster.setFromCamera(this.clickNDC,this.camera);\n            this.aircraftOverlay.updateHover(this.clickRaycaster,this.camera,{pointer:{x:e.clientX,y:e.clientY},rect});\n        }\n\n        // Hover position (orbit + surface)\n        let hit = null;\n        let groundElev = null;\n        let groundR = null;\n        // Prefer terrain intersections (gives face info for hex sizing); fall back to sphere\n        const terrainHit = this._getTerrainIntersectionFromEvent(e, true);\n        if (inSurfaceMode) {\n            hit = terrainHit?.point || this.getSphereIntersectionFromEvent(e);\n        } else {\n            hit = terrainHit?.point || this.getSphereIntersectionFromEvent(e);\n        }\n        if (!hit && inSurfaceMode) {\n            const surfacePos = this.surfaceController.getSurfacePosition();\n            if (surfacePos) {\n                hit = surfacePos.clone();\n                groundR = surfacePos.length();\n                const ellipsoidR = ellipsoidRadiusForWorldDir(surfacePos, this.triTree?.group);\n                groundElev = (groundR - ellipsoidR) / (ELEVATION_EXAGGERATION || 1);\n            }\n        }\n\n        if (this.enableShiftHoverSelection) {\n            const shiftActive = this._isShiftHeld || e.shiftKey;\n            if (shiftActive && hit) {\n                const dir = hit.clone().normalize();\n                const radius = this._computeHexRadius(dir, terrainHit);\n                const surfaceRadius = this._computeSurfaceRadius(dir, terrainHit);\n                this.setHexSelection(dir, radius, surfaceRadius);\n            }\n        }\n\n        if (hit) {\n            const ll = worldPosToLatLonLocal(hit, this.triTree?.group);\n            if (ll) {\n                const { latStr, lonStr } = this._formatLonLat(ll);\n                const now = typeof performance !== 'undefined' ? performance.now() : Date.now();\n                const shouldUpdateGeo = this._shouldUpdateHoverGeo(ll.latDeg, ll.lonDeg, now);\n                let countryFeature = this._hoverGeoLast?.countryFeature || null;\n                let country = this._hoverGeoLast?.country || null;\n                let subdivision = this._hoverGeoLast?.subdivision || null;\n\n                if (shouldUpdateGeo) {\n                    countryFeature = this._getCountryFeatureForLatLon(ll.latDeg, ll.lonDeg);\n                    country = countryFeature?.name || null;\n                    subdivision = this._getSubdivisionForLatLon(ll.latDeg, ll.lonDeg);\n                    this._hoverGeoLast = {\n                        lat: ll.latDeg,\n                        lon: ll.lonDeg,\n                        ts: now,\n                        country,\n                        countryFeature,\n                        subdivision\n                    };\n                }\n                const hoverRadius = hit.length();\n                const hoverEllipsoidRadius = ellipsoidRadiusForWorldDir(hit, this.triTree?.group);\n                const hoverElevation = Number.isFinite(hoverRadius) && Number.isFinite(hoverEllipsoidRadius)\n                    ? hoverRadius - hoverEllipsoidRadius\n                    : groundElev;\n                const photoRoot = this.surfaceController?.photoTileGroup || null;\n                let hitOwner = terrainHit?.object || null;\n                let photorealHit = false;\n                while (hitOwner) {\n                    if (photoRoot && hitOwner === photoRoot) {\n                        photorealHit = true;\n                        break;\n                    }\n                    hitOwner = hitOwner.parent;\n                }\n                this._hoverLatLon = {\n                    lat: ll.latDeg,\n                    lon: ll.lonDeg,\n                    elevation_m: Number.isFinite(hoverElevation) ? hoverElevation : null,\n                    surface_radius_m: Number.isFinite(hoverRadius) ? hoverRadius : null,\n                    surface_source: photorealHit\n                        ? 'photoreal'\n                        : (terrainHit?.point ? 'terrain' : 'ellipsoid'),\n                    observed_at_ms: Date.now(),\n                    country: country || null,\n                    adminLevel: subdivision?.level ?? null,\n                    subdivision: subdivision?.name || null\n                };\n                this._hoverWorldPos = hit.clone();\n                if (groundR === null &&\n                    this.triTree && typeof this.triTree.findLeafTileForWorldDir === 'function') {\n                    const dir = hit.clone().normalize();\n                    const leaf = this.triTree.findLeafTileForWorldDir(dir);\n                    if (leaf && leaf.mesh && leaf.mesh.visible) {\n                        const hits = this.clickRaycaster.intersectObject(leaf.mesh, false);\n                        if (hits && hits.length && hits[0].point) {\n                            groundR = hits[0].point.length();\n                            const ellipsoidR = ellipsoidRadiusForWorldDir(hits[0].point, this.triTree?.group);\n                            groundElev = (groundR - ellipsoidR) / (ELEVATION_EXAGGERATION || 1);\n                        }\n                    }\n                }\n                const cameraWorldPos = this._getCameraWorldPosition(this._viewshedHoverTmpCam);\n                const camLen = cameraWorldPos\n                    ? cameraWorldPos.length()\n                    : (this.camera?.position?.length?.() ?? NaN);\n                const controllerAgl = this.surfaceController?.getSurfaceAltitudeMeters?.();\n                const agl = inSurfaceMode\n                    ? ((Number.isFinite(groundR) && Number.isFinite(camLen))\n                        ? (camLen - groundR)\n                        : (Number.isFinite(controllerAgl) ? controllerAgl : null))\n                    : null;\n                const formatMeters = (value) => Number.isFinite(value) ? `${value.toFixed(1)} m` : '--';\n                const formatDeg = (value) => Number.isFinite(value) ? `${value.toFixed(1)}°` : '--';\n                const formatSpeed = (value) => {\n                    if (!Number.isFinite(value)) return '--';\n                    if (value >= 1000) {\n                        return `${(value / 1000).toFixed(2)} km/s`;\n                    }\n                    return `${value.toFixed(value < 10 ? 2 : value < 100 ? 1 : 0)} m/s`;\n                };\n                const celestial = this._formatCelestial(hit.clone().normalize());\n                const adminLabel = subdivision?.label || (Number.isFinite(subdivision?.level) ? `ADM${subdivision.level}` : '');\n                const adminValue = subdivision?.name\n                    ? `${adminLabel ? `${adminLabel} ` : ''}${subdivision.name}`\n                    : '--';\n\n                this._maybePlayGeoHoverSound(country, subdivision);\n\n                hudStore.setValue('target.lat', latStr);\n                hudStore.setValue('target.lon', lonStr);\n                hudStore.setValue('target.elev', formatMeters(groundElev));\n                hudStore.setValue('target.agl', formatMeters(agl));\n                hudStore.setValue('target.radius', formatMeters(groundR));\n                hudStore.setValue('target.country', country || '--');\n                hudStore.setValue('target.admin', adminValue);\n\n                let hoveredBuilding = null;\n                let hoveredAircraft = null;\n                let hoveredSatellite = null;\n                let hoveredMaritime = null;\n                let hoveredIncident = null;\n                let hoveredOverlayItem = null;\n\n                // Building hover updates\n                if (this.buildingOverlay) {\n                    this.buildingOverlay.updateHover(this.clickRaycaster, this.camera, { pointer: { x: e.clientX, y: e.clientY } });\n                    hoveredBuilding = this.buildingOverlay.getHoveredBuilding();\n                    if (hoveredBuilding) {\n                        const bldgName = this._formatBuildingName(hoveredBuilding.tags);\n                        hudStore.setValue('target.building', bldgName || '--');\n                        hudStore.setValue('target.buildingAddr', hoveredBuilding.address || '--');\n                        // Format height with units, levels as integer\n                        const heightStr = Number.isFinite(hoveredBuilding.height)\n                            ? `${hoveredBuilding.height.toFixed(1)}m`\n                            : '--';\n                        const levelsStr = Number.isFinite(hoveredBuilding.levels)\n                            ? String(hoveredBuilding.levels)\n                            : '--';\n                        hudStore.setValue('target.buildingHeight', heightStr);\n                        hudStore.setValue('target.buildingLevels', levelsStr);\n                        hudStore.setData('target.building', hoveredBuilding);\n                        hudStore.setData('target.buildingAddr', hoveredBuilding.address || null);\n                        hudStore.setData('target.buildingHeight', hoveredBuilding.height || null);\n                        hudStore.setData('target.buildingLevels', hoveredBuilding.levels || null);\n                    } else {\n                        hudStore.setValue('target.building', '--');\n                        hudStore.setValue('target.buildingAddr', '--');\n                        hudStore.setValue('target.buildingHeight', '--');\n                        hudStore.setValue('target.buildingLevels', '--');\n                        hudStore.setData('target.building', null);\n                        hudStore.setData('target.buildingAddr', null);\n                        hudStore.setData('target.buildingHeight', null);\n                        hudStore.setData('target.buildingLevels', null);\n                    }\n                } else {\n                    hudStore.setValue('target.building', '--');\n                    hudStore.setValue('target.buildingAddr', '--');\n                    hudStore.setValue('target.buildingHeight', '--');\n                    hudStore.setValue('target.buildingLevels', '--');\n                    hudStore.setData('target.building', null);\n                    hudStore.setData('target.buildingAddr', null);\n                    hudStore.setData('target.buildingHeight', null);\n                    hudStore.setData('target.buildingLevels', null);\n                }\n\n                const clearAircraftTarget = () => {\n                    hudStore.setValue('target.aircraftModel', '--');\n                    hudStore.setValue('target.aircraftCallsign', '--');\n                    hudStore.setValue('target.aircraftId', '--');\n                    hudStore.setValue('target.aircraftAlt', '--');\n                    hudStore.setValue('target.aircraftSpeed', '--');\n                    hudStore.setValue('target.aircraftHeading', '--');\n                    hudStore.setValue('target.aircraftLat', '--');\n                    hudStore.setValue('target.aircraftLon', '--');\n                    hudStore.setValue('target.aircraftSource', '--');\n                    hudStore.setData('target.aircraftModel', null);\n                    hudStore.setData('target.aircraftCallsign', null);\n                    hudStore.setData('target.aircraftId', null);\n                    hudStore.setData('target.aircraftAlt', null);\n                    hudStore.setData('target.aircraftSpeed', null);\n                    hudStore.setData('target.aircraftHeading', null);\n                    hudStore.setData('target.aircraftLat', null);\n                    hudStore.setData('target.aircraftLon', null);\n                    hudStore.setData('target.aircraftSource', null);\n                };\n\n                const clearSatelliteTarget = () => {\n                    hudStore.setValue('target.satelliteName', '--');\n                    hudStore.setValue('target.satelliteId', '--');\n                    hudStore.setValue('target.satelliteType', '--');\n                    hudStore.setValue('target.satelliteAlt', '--');\n                    hudStore.setValue('target.satelliteLat', '--');\n                    hudStore.setValue('target.satelliteLon', '--');\n                    hudStore.setValue('target.satelliteSource', '--');\n                    hudStore.setData('target.satelliteName', null);\n                    hudStore.setData('target.satelliteId', null);\n                    hudStore.setData('target.satelliteType', null);\n                    hudStore.setData('target.satelliteAlt', null);\n                    hudStore.setData('target.satelliteLat', null);\n                    hudStore.setData('target.satelliteLon', null);\n                    hudStore.setData('target.satelliteSource', null);\n                };\n\n                const clearMaritimeTarget = () => {\n                    hudStore.setValue('target.vesselName', '--');\n                    hudStore.setValue('target.vesselMmsi', '--');\n                    hudStore.setValue('target.vesselSpeed', '--');\n                    hudStore.setValue('target.vesselHeading', '--');\n                    hudStore.setValue('target.vesselLat', '--');\n                    hudStore.setValue('target.vesselLon', '--');\n                    hudStore.setValue('target.vesselStatus', '--');\n                    hudStore.setValue('target.vesselSource', '--');\n                    hudStore.setData('target.vesselName', null);\n                    hudStore.setData('target.vesselMmsi', null);\n                    hudStore.setData('target.vesselSpeed', null);\n                    hudStore.setData('target.vesselHeading', null);\n                    hudStore.setData('target.vesselLat', null);\n                    hudStore.setData('target.vesselLon', null);\n                    hudStore.setData('target.vesselStatus', null);\n                    hudStore.setData('target.vesselSource', null);\n                };\n\n                if (this.aircraftOverlay) {\n                    this.aircraftOverlay.updateHover(this.clickRaycaster);\n                    hoveredAircraft = this.aircraftOverlay.getHoveredAircraft?.();\n                    if (hoveredAircraft && Number.isFinite(hoveredAircraft.lat) && Number.isFinite(hoveredAircraft.lon)) {\n                        const acLatLon = this._formatLonLat({ latDeg: hoveredAircraft.lat, lonDeg: hoveredAircraft.lon });\n                        const modelLabel = hoveredAircraft.aircraftType\n                            || this._formatAircraftModelName(this.aircraftOverlay.modelUrl);\n                        hudStore.setValue('target.aircraftModel', modelLabel);\n                        hudStore.setValue('target.aircraftCallsign', hoveredAircraft.callsign || '--');\n                        hudStore.setValue('target.aircraftId', hoveredAircraft.rawId || '--');\n                        hudStore.setValue('target.aircraftAlt', formatMeters(hoveredAircraft.altitudeM));\n                        hudStore.setValue('target.aircraftSpeed', formatSpeed(hoveredAircraft.velocityMps));\n                        hudStore.setValue('target.aircraftHeading', formatDeg(hoveredAircraft.headingDeg));\n                        hudStore.setValue('target.aircraftLat', acLatLon.latStr);\n                        hudStore.setValue('target.aircraftLon', acLatLon.lonStr);\n                        hudStore.setValue('target.aircraftSource', hoveredAircraft.source || '--');\n                        hudStore.setData('target.aircraftModel', hoveredAircraft.aircraftType || this.aircraftOverlay.modelUrl || null);\n                        hudStore.setData('target.aircraftCallsign', hoveredAircraft.callsign || null);\n                        hudStore.setData('target.aircraftId', hoveredAircraft.rawId || null);\n                        hudStore.setData('target.aircraftAlt', hoveredAircraft.altitudeM ?? null);\n                        hudStore.setData('target.aircraftSpeed', hoveredAircraft.velocityMps ?? null);\n                        hudStore.setData('target.aircraftHeading', hoveredAircraft.headingDeg ?? null);\n                        hudStore.setData('target.aircraftLat', hoveredAircraft.lat ?? null);\n                        hudStore.setData('target.aircraftLon', hoveredAircraft.lon ?? null);\n                        hudStore.setData('target.aircraftSource', hoveredAircraft.source || null);\n                    } else {\n                        clearAircraftTarget();\n                    }\n                } else {\n                    clearAircraftTarget();\n                }\n\n                if (this.satelliteOverlay) {\n                    hoveredSatellite = this.satelliteOverlay.getHoveredSatellite?.();\n                    if (hoveredSatellite && Number.isFinite(hoveredSatellite.lastLat) && Number.isFinite(hoveredSatellite.lastLon)) {\n                        const satLatLon = this._formatLonLat({ latDeg: hoveredSatellite.lastLat, lonDeg: hoveredSatellite.lastLon });\n                        const altitude = Number.isFinite(hoveredSatellite.lastAltM) ? hoveredSatellite.lastAltM : null;\n                        const altitudeLabel = Number.isFinite(altitude)\n                            ? (altitude >= 10000 ? `${(altitude / 1000).toFixed(1)} km` : `${altitude.toFixed(0)} m`)\n                            : '--';\n                        hudStore.setValue('target.satelliteName', hoveredSatellite.name || '--');\n                        hudStore.setValue('target.satelliteId', hoveredSatellite.noradCatId ?? hoveredSatellite.id ?? '--');\n                        hudStore.setValue('target.satelliteType', hoveredSatellite.objectType || '--');\n                        hudStore.setValue('target.satelliteAlt', altitudeLabel);\n                        hudStore.setValue('target.satelliteLat', satLatLon.latStr);\n                        hudStore.setValue('target.satelliteLon', satLatLon.lonStr);\n                        hudStore.setValue('target.satelliteSource', hoveredSatellite.source || '--');\n                        hudStore.setData('target.satelliteName', hoveredSatellite.name || null);\n                        hudStore.setData('target.satelliteId', hoveredSatellite.noradCatId ?? hoveredSatellite.id ?? null);\n                        hudStore.setData('target.satelliteType', hoveredSatellite.objectType || null);\n                        hudStore.setData('target.satelliteAlt', altitude ?? null);\n                        hudStore.setData('target.satelliteLat', hoveredSatellite.lastLat ?? null);\n                        hudStore.setData('target.satelliteLon', hoveredSatellite.lastLon ?? null);\n                        hudStore.setData('target.satelliteSource', hoveredSatellite.source || null);\n                    } else {\n                        clearSatelliteTarget();\n                    }\n                } else {\n                    clearSatelliteTarget();\n                }\n\n                if (this.maritimeOverlay) {\n                    this.maritimeOverlay.updateHover(this.clickRaycaster);\n                    hoveredMaritime = this.maritimeOverlay.getHoveredVessel?.();\n                    if (hoveredMaritime && Number.isFinite(hoveredMaritime.lat) && Number.isFinite(hoveredMaritime.lon)) {\n                        const vesselLatLon = this._formatLonLat({ latDeg: hoveredMaritime.lat, lonDeg: hoveredMaritime.lon });\n                        const heading = Number.isFinite(hoveredMaritime.headingDeg) ? hoveredMaritime.headingDeg : hoveredMaritime.courseDeg;\n                        hudStore.setValue('target.vesselName', hoveredMaritime.name || '--');\n                        hudStore.setValue('target.vesselMmsi', hoveredMaritime.mmsi || hoveredMaritime.id || '--');\n                        hudStore.setValue('target.vesselSpeed', formatSpeed(hoveredMaritime.speedMps));\n                        hudStore.setValue('target.vesselHeading', formatDeg(heading));\n                        hudStore.setValue('target.vesselLat', vesselLatLon.latStr);\n                        hudStore.setValue('target.vesselLon', vesselLatLon.lonStr);\n                        hudStore.setValue('target.vesselStatus', hoveredMaritime.navStatus || '--');\n                        hudStore.setValue('target.vesselSource', hoveredMaritime.source || '--');\n                        hudStore.setData('target.vesselName', hoveredMaritime.name || null);\n                        hudStore.setData('target.vesselMmsi', hoveredMaritime.mmsi || hoveredMaritime.id || null);\n                        hudStore.setData('target.vesselSpeed', hoveredMaritime.speedMps ?? null);\n                        hudStore.setData('target.vesselHeading', heading ?? null);\n                        hudStore.setData('target.vesselLat', hoveredMaritime.lat ?? null);\n                        hudStore.setData('target.vesselLon', hoveredMaritime.lon ?? null);\n                        hudStore.setData('target.vesselStatus', hoveredMaritime.navStatus || null);\n                        hudStore.setData('target.vesselSource', hoveredMaritime.source || null);\n                    } else {\n                        clearMaritimeTarget();\n                    }\n                } else {\n                    clearMaritimeTarget();\n                }\n\n                if (this.incidentOverlay) {\n                    this.incidentOverlay.updateHover?.(this.clickRaycaster);\n                    hoveredIncident = this.incidentOverlay.getHoveredIncident?.() || null;\n                }\n\n                if (this.overlaySubsystem?.updateHover) {\n                    hoveredOverlayItem = this.overlaySubsystem.updateHover(this.clickRaycaster);\n                }\n\n                this._updateViewshedHoverHighlight({\n                    building: hoveredBuilding,\n                    aircraft: hoveredAircraft,\n                    satellite: hoveredSatellite,\n                    maritime: hoveredMaritime,\n                    incident: hoveredIncident\n                });\n                this._updateOverlayHoverHighlight(hoveredOverlayItem);\n\n                hudStore.setValue('target.sunElev', celestial ? formatDeg(celestial.sunElevDeg) : '--');\n                hudStore.setValue('target.sunAz', celestial ? formatDeg(celestial.sunAzDeg) : '--');\n                hudStore.setValue('target.sunInc', celestial ? formatDeg(celestial.sunIncDeg) : '--');\n                hudStore.setValue('target.solarTime', celestial?.solarTime || '--');\n                hudStore.setValue('target.moonElev', celestial ? formatDeg(celestial.moonElevDeg) : '--');\n                hudStore.setValue('target.moonAz', celestial ? formatDeg(celestial.moonAzDeg) : '--');\n\n                hudStore.setData('target.lat', ll.latDeg);\n                hudStore.setData('target.lon', ll.lonDeg);\n                hudStore.setData('target.elev', groundElev);\n                hudStore.setData('target.agl', agl);\n                hudStore.setData('target.radius', groundR);\n                hudStore.setData('target.country', country || null);\n                let adminData = null;\n                if (subdivision) {\n                    adminData = { ...subdivision };\n                    delete adminData.feature;\n                }\n                hudStore.setData('target.admin', adminData);\n                hudStore.setData('target.sunElev', celestial?.sunElevDeg ?? null);\n                hudStore.setData('target.sunAz', celestial?.sunAzDeg ?? null);\n                hudStore.setData('target.sunInc', celestial?.sunIncDeg ?? null);\n                hudStore.setData('target.solarTime', celestial?.solarTime ?? null);\n                hudStore.setData('target.moonElev', celestial?.moonElevDeg ?? null);\n                hudStore.setData('target.moonAz', celestial?.moonAzDeg ?? null);\n\n                if (this.weatherProvider?.setHoverTarget && shouldUpdateGeo) {\n                    this.weatherProvider.setHoverTarget(ll.latDeg, ll.lonDeg);\n                }\n                const weatherSummary = this.weatherProvider?.getHudWeatherSummary?.('hover')\n                    || this._lastHoverWeatherSummary\n                    || null;\n                this._applyWeatherSummary('target', weatherSummary);\n\n                const allowHighlight = !inSurfaceMode &&\n                    this.geoJsonOverlayLayer &&\n                    this.geoJsonOverlayLayer.group &&\n                    this.geoJsonOverlayLayer.group.visible;\n                if (allowHighlight) {\n                    const highlightFeature = subdivision?.feature || countryFeature;\n                    this.geoJsonOverlayLayer.setHighlightFeature?.(highlightFeature);\n                } else {\n                    this.geoJsonOverlayLayer?.clearHighlight?.();\n                }\n\n                // Update tile metrics using the same raycast result\n                this._updateTileMetrics(terrainHit);\n\n                // Move hover marker\n                if (this._hoverMarker && hit) {\n                    const normal = hit.clone().normalize();\n                    const h = this._hoverMarker.geometry?.parameters?.height || 0;\n                    const offset = normal.clone().multiplyScalar(h * 0.5);\n                    this._hoverMarker.position.copy(hit).add(offset);\n                    const q = new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 1, 0), normal);\n                    this._hoverMarker.setRotationFromQuaternion(q);\n                    this._hoverMarker.visible = true;\n                }\n\n                // Surface path spheres (shift+click in surface mode)\n                if (inSurfaceMode && this._surfacePathActive) {\n                    this._ensureSurfaceLine();\n                    this._ensureSurfacePathSpheres(25);\n                    this._ensureSurfaceBall();\n                    const worldPos = this.camera?.userData?.worldPosition;\n                    const camPos = this.camera\n                        ? (worldPos ? worldPos.clone() : this.camera.position.clone())\n                        : null;\n                    const startDir = camPos ? camPos.clone().normalize() : null;\n                    const endDir = hit.clone().normalize();\n                    const radius = hit.length(); // use target radius for path height\n                    const theta = startDir && startDir.lengthSq() > 0 ? startDir.angleTo(endDir) : 0;\n                    const straightLen = camPos ? camPos.distanceTo(hit) : 0;\n                    const arcLength = Math.max(theta * radius, straightLen, 1); // ensure non-zero path length\n\n                    const distances = [];\n                    for (let d = 1; d <= 10; d++) distances.push(d);\n                    const midSeg = [20, 40, 60, 80, 100];\n                    distances.push(...midSeg);\n                    const farSeg = [250, 500, 750, 1000];\n                    distances.push(...farSeg);\n                    const usable = distances.filter(d => d <= arcLength + 0.1);\n                    if (!usable.length) usable.push(arcLength * 0.5); // ensure at least one point\n                    this._ensureSurfacePathSpheres(usable.length);\n\n                    for (let i = 0; i < this._surfacePathSpheres.length; i++) {\n                        const sphere = this._surfacePathSpheres[i];\n                        if (i >= usable.length || !startDir || theta === 0) {\n                            sphere.visible = false;\n                            continue;\n                        }\n                        const dist = usable[i];\n                        const t = Math.max(0, Math.min(1, dist / arcLength));\n                        const dir = new THREE.Vector3();\n                        const sinTheta = Math.sin(theta);\n                        const w1 = Math.sin((1 - t) * theta) / sinTheta;\n                        const w2 = Math.sin(t * theta) / sinTheta;\n                        dir.copy(startDir).multiplyScalar(w1).addScaledVector(endDir, w2);\n                        dir.normalize();\n                        const pos = dir.multiplyScalar(radius + 1.6); // hover above terrain\n                        sphere.position.copy(pos);\n                        const opacity = THREE.MathUtils.lerp(0.9, 0.2, t);\n                        if (sphere.material) {\n                            sphere.material.opacity = opacity;\n                            sphere.material.needsUpdate = true;\n                        }\n                        sphere.visible = true;\n                    }\n\n                    // Place debug ball at hover point\n                    if (this._surfaceBall && this._surfaceBallEnabled) {\n                        this._surfaceBall.position.copy(hit);\n                        this._surfaceBall.visible = true;\n                    } else if (this._surfaceBall) {\n                        this._surfaceBall.visible = false;\n                    }\n                } else {\n                    if (this._surfaceHex) this._surfaceHex.visible = false;\n                    if (this._surfaceLine) this._surfaceLine.visible = false;\n                    if (this._surfacePathSpheres.length) {\n                        for (const s of this._surfacePathSpheres) s.visible = false;\n                    }\n                    if (this._surfaceBall) this._surfaceBall.visible = false;\n                }\n            }\n        } else {\n            this._hudTargetKeys.forEach((key) => {\n                hudStore.setValue(key, null);\n                hudStore.setData(key, null);\n            });\n            this.weatherProvider?.clearHoverTarget?.();\n            this.buildingOverlay?.clearHover?.();\n            this.aircraftOverlay?.clearHover?.();\n            this.maritimeOverlay?.clearHover?.();\n            this.incidentOverlay?.clearHover?.();\n            this._updateViewshedHoverHighlight();\n            this._updateOverlayHoverHighlight(null);\n            this._hoverLatLon = null;\n            this._hoverWorldPos = null;\n            if (this._hoverMarker) this._hoverMarker.visible = false;\n            this.geoJsonOverlayLayer?.clearHighlight?.();\n            if (this._surfaceHex) this._surfaceHex.visible = false;\n            if (this._surfaceLine) this._surfaceLine.visible = false;\n            if (this._surfacePathSpheres.length) {\n                for (const s of this._surfacePathSpheres) s.visible = false;\n            }\n            if (this._surfaceBall) this._surfaceBall.visible = false;\n        }\n    }\n\n    _maybePlayGeoHoverSound(country, subdivision) {\n        const name = country || null;\n        const adminName = subdivision?.name || null;\n        const adminLevel = Number.isFinite(subdivision?.level) ? subdivision.level : null;\n        if (!name && !adminName) return;\n\n        const key = `${name || 'none'}|${adminLevel ?? 'none'}|${adminName || 'none'}`;\n        const now = typeof performance !== 'undefined' ? performance.now() : Date.now();\n        const last = this._hoverGeoSoundLast || { key: null, ts: 0 };\n        if (last.key === key && (now - (last.ts || 0)) < 250) return;\n\n        const inSurfaceMode = this.surfaceController?.isInSurfaceMode?.() || false;\n        if (!inSurfaceMode) {\n            this._hoverGeoSoundLast = { key, ts: now };\n            const audio = getUiAudioSfx();\n            audio.playMoveBlip();\n        }\n    }\n\n    _updateTileMetrics(terrainHit) {\n        const hudStore = this.hudStore || getHudInfoStore();\n\n        // Extract tile from the raycast hit object\n        let tile = null;\n        if (terrainHit && terrainHit.object && terrainHit.object.userData && terrainHit.object.userData.tile) {\n            tile = terrainHit.object.userData.tile;\n        }\n\n        if (!tile) {\n            // Clear all tile metrics\n            hudStore.setValue('tile.id', '--');\n            hudStore.setValue('tile.lod', '--');\n            hudStore.setValue('tile.path', '--');\n            hudStore.setValue('tile.imgZoom', '--');\n            hudStore.setValue('tile.imgSize', '--');\n            hudStore.setValue('tile.imgBytes', '--');\n            hudStore.setValue('tile.elevReady', '--');\n            hudStore.setValue('tile.elevActive', '--');\n\n            // Fade out edge highlight\n            if (this._tileEdgeEnabled) {\n                this._currentHighlightedTile = null;\n                this._edgeFadeTarget = 0;\n            }\n            return;\n        }\n\n        // Update edge highlighting\n        if (this._tileEdgeEnabled) {\n            this._ensureTileEdgeHighlight();\n\n            // Check if we're hovering a different tile\n            if (this._currentHighlightedTile !== tile) {\n                this._currentHighlightedTile = tile;\n                this._updateTileEdgeGeometry(tile);\n                this._updateEdgeArrows(tile);\n                this._edgeFadeTarget = 1.0; // Fade in\n\n            }\n        } else {\n            // Edge highlighting disabled, fade out\n            if (this._currentHighlightedTile !== null) {\n                this._currentHighlightedTile = null;\n                this._edgeFadeTarget = 0;\n                this._hideEdgeArrows();\n                this._hideVertexHelpers();\n            }\n        }\n\n        // Tile ID (geohash-like identifier)\n        if (typeof tile.getTileId === 'function') {\n            hudStore.setValue('tile.id', tile.getTileId());\n        } else {\n            hudStore.setValue('tile.id', '--');\n        }\n\n        // LOD level\n        hudStore.setValue('tile.lod', String(tile.level));\n\n        // Child path from root\n        if (typeof tile._getChildPath === 'function') {\n            const path = tile._getChildPath();\n            hudStore.setValue('tile.path', path || 'root');\n        } else {\n            hudStore.setValue('tile.path', '--');\n        }\n\n        // Imagery zoom level\n        hudStore.setValue('tile.imgZoom',\n            tile.imageryZoom !== undefined && tile.imageryZoom !== null\n                ? String(tile.imageryZoom)\n                : '--'\n        );\n\n        // Imagery atlas size (tiles)\n        hudStore.setValue('tile.imgSize',\n            tile.imageryAtlasW && tile.imageryAtlasH\n                ? `${tile.imageryAtlasW}x${tile.imageryAtlasH}`\n                : '--'\n        );\n\n        // Imagery byte size\n        if (typeof tile.getImageryByteSize === 'function') {\n            const bytes = tile.getImageryByteSize();\n            if (bytes > 0) {\n                const kb = bytes / 1024;\n                const mb = kb / 1024;\n                if (mb >= 1) {\n                    hudStore.setValue('tile.imgBytes', `${mb.toFixed(2)} MB`);\n                } else {\n                    hudStore.setValue('tile.imgBytes', `${kb.toFixed(0)} KB`);\n                }\n            } else {\n                hudStore.setValue('tile.imgBytes', '--');\n            }\n        } else {\n            hudStore.setValue('tile.imgBytes', '--');\n        }\n\n        const vertexCount = Number.isFinite(tile.vertexCount) ? tile.vertexCount : 0;\n        const fetchStats = (typeof tile.getElevationFetchStats === 'function')\n            ? tile.getElevationFetchStats()\n            : {\n                done: Number.isFinite(tile.elevationDone) ? tile.elevationDone : 0,\n                expected: Number.isFinite(tile.elevationExpected) ? tile.elevationExpected : 0,\n                ratio: 0\n            };\n        if (fetchStats.expected > 0) {\n            fetchStats.ratio = fetchStats.done / fetchStats.expected;\n        } else if (vertexCount > 0) {\n            fetchStats.ratio = Math.min(1, fetchStats.done / vertexCount);\n        }\n        const visualStats = (typeof tile.getElevationVisualStats === 'function')\n            ? tile.getElevationVisualStats()\n            : null;\n\n        let elevLabel = '--';\n        if (vertexCount > 0) {\n            const expected = fetchStats.expected > 0 ? fetchStats.expected : vertexCount;\n            const done = Math.min(fetchStats.done, expected);\n            const ratio = expected > 0 ? (done / expected) : 0;\n            elevLabel = `${done}/${expected} ${(ratio * 100).toFixed(0)}%`;\n            if (visualStats && Number.isFinite(visualStats.done) && visualStats.done > done) {\n                elevLabel += ` (visual ${visualStats.done}/${vertexCount})`;\n            }\n        } else if (visualStats && Number.isFinite(visualStats.done) && visualStats.done > 0) {\n            elevLabel = `${visualStats.done} visual`;\n        }\n        hudStore.setValue('tile.elevReady', elevLabel);\n\n        let activeEntry = null;\n        const activeTiles = this.triTree?.activeElevationTiles;\n        if (Array.isArray(activeTiles)) {\n            activeEntry = activeTiles.find(entry => entry?.tile === tile) || null;\n        }\n        const forced = !!tile._elevForceFetch;\n        let activeLabel = activeEntry ? 'Yes' : 'No';\n        if (activeEntry && Number.isFinite(activeEntry.priority)) {\n            activeLabel = `Yes P${Math.round(activeEntry.priority)}`;\n        }\n        if (forced) {\n            activeLabel = activeEntry ? `${activeLabel} F` : 'Force';\n        }\n        hudStore.setValue('tile.elevActive', activeLabel);\n\n        // Update detailed neighbor panels\n        this._updateNeighborPanels(tile);\n    }\n\n    _getLODColor(level) {\n        // Color gradient based on LOD level\n        const colors = [\n            '#ff0000', // L0 - Red\n            '#ff4400', // L1 - Red-Orange\n            '#ff8800', // L2 - Orange\n            '#ffcc00', // L3 - Yellow-Orange\n            '#ffff00', // L4 - Yellow\n            '#88ff00', // L5 - Yellow-Green\n            '#00ff00', // L6 - Green\n            '#00ff88', // L7 - Green-Cyan\n            '#00ffff', // L8 - Cyan\n            '#0088ff', // L9 - Cyan-Blue\n            '#0000ff', // L10 - Blue\n            '#4400ff', // L11 - Blue-Violet\n            '#8800ff', // L12 - Violet\n            '#ff00ff', // L13 - Magenta\n            '#ff0088'  // L14+ - Magenta-Red\n        ];\n        return colors[Math.min(level, colors.length - 1)];\n    }\n\n    _updateNeighborPanels(tile) {\n        const container = document.getElementById('neighbors-container');\n        if (!container) return;\n\n        // Find or create the content container (separate from title with checkbox)\n        let contentContainer = container.querySelector('.neighbor-content');\n        if (!contentContainer) {\n            contentContainer = document.createElement('div');\n            contentContainer.className = 'neighbor-content';\n            container.appendChild(contentContainer);\n        }\n\n        if (!tile) {\n            contentContainer.innerHTML = '<div style=\"padding: 8px; color: #888; font-size: 10px;\">No tile selected</div>';\n            return;\n        }\n\n        // Check if vertex metrics are enabled\n        const showVertexMetrics = document.getElementById('cfg-vertex-metrics')?.checked || false;\n\n        // Edge colors matching the arrows\n        const edgeColors = this._getEdgeColors();\n\n        const edges = ['v0v1', 'v1v2', 'v2v0'];\n\n        // Build new neighbor display content (WITHOUT title - it's preserved in DOM)\n        let html = '<div style=\"max-height: 300px; overflow-y: auto; overflow-x: hidden;\">';\n\n        // Add tile's own info at top with edge vertex counts\n        const tileId = tile.getTileId ? tile.getTileId() : '--';\n        const tileLod = tile.level ?? '--';\n        const tileColor = this._getLODColor(tile.level);\n        html += `<div style=\"margin-bottom: 12px; padding: 8px; background: rgba(255,255,255,0.05); border-radius: 4px;\">`;\n        html += `<div style=\"font-size: 9px; color: #888; margin-bottom: 4px;\">SELECTED TILE</div>`;\n        html += `<div style=\"font-size: 11px; color: ${tileColor}; font-weight: 600;\">${tileId}</div>`;\n        html += `<div style=\"font-size: 9px; color: #666; margin-top: 2px;\">LOD: ${tileLod}</div>`;\n\n        // Show edge vertex counts if enabled\n        if (showVertexMetrics) {\n            html += `<div style=\"margin-top: 6px; padding-top: 6px; border-top: 1px solid rgba(255,255,255,0.1);\">`;\n            for (const edgeName of edges) {\n                const vtxCount = tile.getEdgeVertexCount ? tile.getEdgeVertexCount(edgeName) : 0;\n                const color = edgeColors[edgeName];\n                html += `<div style=\"font-size: 9px; color: #888; display: flex; justify-content: space-between; margin-bottom: 2px;\">`;\n                html += `<span style=\"color: ${color};\">${edgeName}:</span>`;\n                html += `<span style=\"color: #aaa; font-weight: 600;\">${vtxCount} vtx</span>`;\n                html += `</div>`;\n            }\n            html += `</div>`;\n        }\n\n        html += `</div>`;\n\n        for (const edgeName of edges) {\n            // Find neighbors on-demand using tritree manager\n            const neighbors = this.triTree && this.triTree.findEdgeNeighbors\n                ? this.triTree.findEdgeNeighbors(tile, edgeName)\n                : [];\n\n            if (neighbors.length === 0) continue;\n\n            const color = edgeColors[edgeName];\n\n            // Create a vertical stack for this edge\n            html += `<div style=\"margin-top: 8px; border-left: 3px solid ${color}; padding-left: 8px;\">`;\n            html += `<div style=\"font-size: 9px; color: ${color}; font-weight: 600; margin-bottom: 4px; text-transform: uppercase; letter-spacing: 0.1em;\">${edgeName}</div>`;\n\n            // Stack neighbors vertically\n            for (const neighbor of neighbors) {\n                const neighborId = neighbor.getTileId ? neighbor.getTileId() : '--';\n                const neighborLod = neighbor.level ?? '--';\n                const neighborLodColor = this._getLODColor(neighbor.level);\n                const delta = typeof neighbor.level === 'number' ? neighbor.level - tile.level : 0;\n                const deltaStr = delta > 0 ? `+${delta}` : String(delta);\n\n                // Color code delta\n                let deltaColor = '#fff';\n                if (delta > 1) deltaColor = '#ff6b6b'; // Red\n                else if (delta < -1) deltaColor = '#ffa500'; // Orange\n                else if (delta === 0) deltaColor = '#4ecdc4'; // Cyan\n\n                // Abbreviated ID\n                let shortId = neighborId;\n                const match = neighborId.match(/L(\\d+)-(.*)$/);\n                if (match) {\n                    const level = match[1];\n                    const path = match[2];\n                    const shortPath = path.length > 8 ? '...' + path.slice(-8) : path;\n                    shortId = `L${level}-${shortPath}`;\n                }\n\n                // Get vertex count for this neighbor's matching edge (if metrics enabled)\n                let neighborVtxCount = 0;\n                if (showVertexMetrics && neighbor.getEdgeVertexCount) {\n                    // Find which edge on the neighbor matches this edge\n                    // Use the stored edge info from _edgeNeighborMap\n                    const tileEdgeKey = `${tile.getTileId()}_${edgeName}`;\n                    const neighborInfos = this.triTree._edgeNeighborMap?.get(tileEdgeKey);\n                    const neighborInfo = neighborInfos?.find(info => info.tile === neighbor);\n                    if (neighborInfo) {\n                        neighborVtxCount = neighbor.getEdgeVertexCount(neighborInfo.edgeName);\n                    }\n                }\n\n                html += `<div style=\"font-size: 10px; margin-bottom: 2px; display: flex; gap: 6px; align-items: center;\">`;\n                html += `<span style=\"color: #94a3b8; flex: 1; overflow: hidden; text-overflow: ellipsis;\" title=\"${neighborId}\">${shortId}</span>`;\n                html += `<span style=\"color: ${neighborLodColor}; font-size: 9px; font-weight: 600;\">L${neighborLod}</span>`;\n                html += `<span style=\"color: ${deltaColor}; font-size: 9px; font-weight: 600; min-width: 24px; text-align: right;\">${deltaStr}</span>`;\n                if (showVertexMetrics) {\n                    html += `<span style=\"color: #888; font-size: 9px; min-width: 36px; text-align: right;\">${neighborVtxCount}v</span>`;\n                }\n                html += `</div>`;\n            }\n\n            html += `</div>`;\n        }\n\n        html += '</div>'; // Close scrollable container\n\n        // Update only the content container, preserving the title with checkbox\n        contentContainer.innerHTML = html;\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Window resize\n    // ──────────────────────────────────────────────────────────────\n\n    _onResize() {\n        const container = this.renderer.domElement.parentElement;\n        if (!container) return;\n\n        const w = container.clientWidth;\n        const h = container.clientHeight;\n        if (w <= 0 || h <= 0) return;\n        const renderScale = this.sceneInitializer?.renderScale || 1.0;\n        const renderWidth = Math.floor(w * renderScale);\n        const renderHeight = Math.floor(h * renderScale);\n        const sizeUnchanged = w === this._lastClientWidth &&\n            h === this._lastClientHeight &&\n            renderWidth === this._lastRenderWidth &&\n            renderHeight === this._lastRenderHeight;\n        if (sizeUnchanged) return;\n\n        this._lastClientWidth = w;\n        this._lastClientHeight = h;\n        this._lastRenderWidth = renderWidth;\n        this._lastRenderHeight = renderHeight;\n\n        this.viewportHeight = h;\n        this.camera.aspect = w / h;\n        this.camera.updateProjectionMatrix();\n\n        // Keep canvas CSS at full container size, but render buffer at 75%\n        this.renderer.domElement.style.width = '100%';\n        this.renderer.domElement.style.height = '100%';\n        this.renderer.setSize(renderWidth, renderHeight, false);\n\n        // Resize post-processing targets (bloom, atmosphere depth, etc.)\n        if (this.sceneInitializer?.handleResize) {\n            this.sceneInitializer.handleResize();\n        }\n\n        // Notify callback\n        if (typeof this.onResizeCallback === 'function') {\n            this.onResizeCallback(w, h);\n        }\n    }\n\n    _scheduleResize() {\n        if (this._resizeRaf) return;\n        const raf = typeof requestAnimationFrame === 'function'\n            ? requestAnimationFrame\n            : (fn) => setTimeout(fn, 16);\n        this._resizeRaf = raf(() => {\n            this._resizeRaf = 0;\n            this._onResize();\n        });\n    }\n\n    getViewportHeight() {\n        return this.viewportHeight;\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Keyboard events\n    // ──────────────────────────────────────────────────────────────\n\n    _onEscapeKey(e) {\n        if (this.isEditableTarget(e.target)) return;\n        if (e.code === 'Escape') {\n            const sidebar = document.getElementById('sidebar');\n            if (sidebar && sidebar.classList.contains('open')) {\n                if (typeof this.onSidebarClose === 'function') {\n                    this.onSidebarClose();\n                }\n                e.preventDefault();\n            }\n        }\n    }\n\n    _onShiftKeyDown(e) {\n        if (this.isEditableTarget(e.target)) return;\n        if (e.code !== 'ShiftLeft' && e.code !== 'ShiftRight') return;\n        if (this._isShiftHeld) return;\n        this._isShiftHeld = true;\n        if (!this.enableShiftHoverSelection) return;\n        // Only update hex selection in ORBIT mode; surface mode uses beads\n        if (!this.surfaceController || !this.surfaceController.isInSurfaceMode()) {\n            if (this._lastPointerEvent) {\n                this._updateHexFromEvent(this._lastPointerEvent);\n            }\n        }\n    }\n\n    _onShiftKeyUp(e) {\n        if (this.isEditableTarget(e.target)) return;\n        if (e.code !== 'ShiftLeft' && e.code !== 'ShiftRight') return;\n        if (!this._isShiftHeld) return;\n        this._isShiftHeld = false;\n        this._surfacePathActive = false; // Deactivate surface path\n        if (!this.enableShiftHoverSelection) return;\n        // Only clear hex selection in ORBIT mode; surface mode beads hide automatically\n        if (!this.surfaceController || !this.surfaceController.isInSurfaceMode()) {\n            this.setHexSelection(null);\n        }\n    }\n\n    _onToggleSurfaceBall(e) {\n        if (this.isEditableTarget(e.target)) return;\n        if (e.code !== 'KeyY') return;\n        this._surfaceBallEnabled = !this._surfaceBallEnabled;\n        if (!this._surfaceBallEnabled && this._surfaceBall) {\n            this._surfaceBall.visible = false;\n        }\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Double-click to enter surface mode\n    // ──────────────────────────────────────────────────────────────\n\n    /**\n     * Track the complete touch sequence so a finger lifted from a pinch can\n     * never masquerade as one half of a double tap.\n     */\n    _onTouchStart(e) {\n        if (this.isEditableTarget(e.target)) return;\n        if (!this._touchTapGesture || this._touchTapGesture.activeIds.size === 0) {\n            this._touchTapGesture = {\n                activeIds: new Set(),\n                starts: new Map(),\n                maxPointers: 0,\n                moved: false,\n            };\n        }\n        const gesture = this._touchTapGesture;\n        for (const touch of Array.from(e.changedTouches || [])) {\n            gesture.activeIds.add(touch.identifier);\n            gesture.starts.set(touch.identifier, {\n                x: touch.clientX,\n                y: touch.clientY,\n            });\n        }\n        gesture.maxPointers = Math.max(\n            gesture.maxPointers,\n            e.touches?.length || gesture.activeIds.size\n        );\n        if (gesture.maxPointers > 1) {\n            this._lastTapTime = 0;\n            this._lastTapPos = { x: 0, y: 0 };\n        }\n    }\n\n    _onTouchMove(e) {\n        const gesture = this._touchTapGesture;\n        if (!gesture || gesture.moved) return;\n        const toleranceSq = this._touchTapMoveTolerance * this._touchTapMoveTolerance;\n        for (const touch of Array.from(e.touches || [])) {\n            const start = gesture.starts.get(touch.identifier);\n            if (!start) continue;\n            const dx = touch.clientX - start.x;\n            const dy = touch.clientY - start.y;\n            if (dx * dx + dy * dy > toleranceSq) {\n                gesture.moved = true;\n                this._lastTapTime = 0;\n                this._lastTapPos = { x: 0, y: 0 };\n                break;\n            }\n        }\n    }\n\n    _onTouchCancel() {\n        this._touchTapGesture = null;\n        this._lastTapTime = 0;\n        this._lastTapPos = { x: 0, y: 0 };\n    }\n\n    _onTouchEnd(e) {\n        if (Date.now() <= this._suppressSurfaceTapUntil) {\n            this._suppressSurfaceTapUntil = 0;\n            this._touchTapGesture = null;\n            this._lastTapTime = 0;\n            this._lastTapPos = { x: 0, y: 0 };\n            e.preventDefault?.();\n            return;\n        }\n        if (this.isEditableTarget(e.target)) return;\n\n        const gesture = this._touchTapGesture;\n        for (const touch of Array.from(e.changedTouches || [])) {\n            gesture?.activeIds?.delete?.(touch.identifier);\n        }\n        const completed = (e.touches?.length || 0) === 0;\n        const isTap = !!(\n            completed\n            && gesture\n            && gesture.maxPointers === 1\n            && gesture.moved !== true\n            && e.changedTouches?.length === 1\n        );\n        if (completed) this._touchTapGesture = null;\n        if (!isTap) {\n            if (completed) {\n                this._lastTapTime = 0;\n                this._lastTapPos = { x: 0, y: 0 };\n            }\n            return;\n        }\n\n        const touch = e.changedTouches[0];\n        const now = Date.now();\n        const timeSinceLastTap = now - this._lastTapTime;\n        const dx = touch.clientX - this._lastTapPos.x;\n        const dy = touch.clientY - this._lastTapPos.y;\n        const distance = Math.sqrt(dx * dx + dy * dy);\n\n        // Check if this is a double-tap (within time and distance threshold)\n        if (timeSinceLastTap < this._doubleTapDelay && distance < this._doubleTapRadius) {\n            // Double-tap detected! Trigger surface mode entry\n            console.log('[TOUCH] Double-tap detected at', touch.clientX, touch.clientY);\n            e.preventDefault();\n            e.stopPropagation?.();\n\n            // Create a synthetic event object for _onDoubleClick\n            const syntheticEvent = {\n                clientX: touch.clientX,\n                clientY: touch.clientY,\n                target: e.target,\n                preventDefault: () => e.preventDefault(),\n                stopPropagation: () => e.stopPropagation?.()\n            };\n\n            this._onDoubleClick(syntheticEvent);\n\n            // Reset tap tracking to prevent triple-tap triggering another action\n            this._lastTapTime = 0;\n            this._lastTapPos = { x: 0, y: 0 };\n        } else {\n            // Single tap, update tracking\n            this._lastTapTime = now;\n            this._lastTapPos = { x: touch.clientX, y: touch.clientY };\n        }\n    }\n\n    _onDoubleClick(e) {\n        if (this.isEditableTarget(e.target)) return;\n        if (!this.surfaceController || !this.camera) return;\n        const mode = typeof this.surfaceController.getCameraMode === 'function'\n            ? this.surfaceController.getCameraMode()\n            : null;\n        if (mode && mode !== 'orbit') return;\n        if (this.surfaceController.isInSurfaceMode && this.surfaceController.isInSurfaceMode()) return;\n\n        // Check for celestial body hits (moon, sun, earth sphere) before terrain\n        const bodyHit = this._getCelestialBodyHit(e);\n        if (bodyHit) {\n            e.preventDefault?.();\n            e.stopPropagation?.();\n            this.surfaceController.transitionToBody(bodyHit);\n            return;\n        }\n\n        const terrainHit = this._getTerrainIntersectionFromEvent(e, true);\n        const hit = terrainHit?.point || this.getSphereIntersectionFromEvent(e);\n        if (!hit) return;\n\n        e.preventDefault?.();\n        e.stopPropagation?.();\n\n        // If currently anchored to a non-earth body and double-clicking earth terrain,\n        // transition back to earth\n        const currentAnchor = this.surfaceController.getBodyAnchor?.();\n        if (currentAnchor && currentAnchor !== 'terra') {\n            this.surfaceController.transitionToBody('terra');\n            return;\n        }\n\n        const dir = hit.clone().normalize();\n        this.surfaceController.enterSurfaceAt(dir, {\n            transitionDurationMs: this.surfaceController.DOUBLE_CLICK_SURFACE_TRANSITION_MS ?? 1000\n        });\n        if (typeof this.onEnterSurface === 'function') {\n            this.onEnterSurface(dir);\n        }\n    }\n\n    suppressSurfaceTapGesture(durationMs = 750) {\n        const duration = Number.isFinite(durationMs) ? Math.max(0, durationMs) : 750;\n        this._suppressSurfaceTapUntil = Date.now() + duration;\n        this._touchTapGesture = null;\n        this._lastTapTime = 0;\n        this._lastTapPos = { x: 0, y: 0 };\n    }\n\n    /**\n     * Raycast against moon and sun meshes; also detect earth-sphere when not anchored to earth.\n     * Returns body name ('luna'|'sol'|'terra') or null.\n     */\n    _getCelestialBodyHit(e) {\n        const rect = this.renderer.domElement.getBoundingClientRect();\n        const x = ((e.clientX - rect.left) / rect.width) * 2 - 1;\n        const y = -((e.clientY - rect.top) / rect.height) * 2 + 1;\n        this.clickNDC.set(x, y);\n        this.clickRaycaster.setFromCamera(this.clickNDC, this.camera);\n\n        const currentAnchor = this.surfaceController?.getBodyAnchor?.() || 'terra';\n        const ray = this.clickRaycaster.ray;\n        const hits = [];\n\n        // Test Moon\n        if (this.moonSystem?.moonMesh) {\n            const moonPos = this.moonSystem.moonMesh.position;\n            const moonR = this.moonSystem.moonMesh.geometry?.parameters?.radius;\n            if (moonPos && moonR) {\n                const dist = this._raySphereTest(ray, moonPos, moonR);\n                if (dist !== null) hits.push({ body: 'luna', dist });\n            }\n        }\n\n        // Test Sun (use lighting system's DirectionalLight position as proxy)\n        if (this.lightingSystem?.sun) {\n            const sunPos = this.lightingSystem.sun.position;\n            // Use a generous clickable radius (actual sun radius is enormous but\n            // visually it appears small at 1 AU distance)\n            const sunClickR = sunPos.length() * 0.01; // ~1% of distance as click target\n            const dist = this._raySphereTest(ray, sunPos, sunClickR);\n            if (dist !== null) hits.push({ body: 'sol', dist });\n        }\n\n        // If currently anchored to non-earth body, allow clicking earth sphere to return\n        if (currentAnchor !== 'terra') {\n            const earthHit = raySphereIntersection(ray.origin, ray.direction);\n            if (earthHit) {\n                const dist = ray.origin.distanceTo(earthHit);\n                hits.push({ body: 'terra', dist });\n            }\n        }\n\n        if (hits.length === 0) return null;\n\n        // Don't transition to the body we're already anchored to\n        hits.sort((a, b) => a.dist - b.dist);\n        for (const h of hits) {\n            if (h.body !== currentAnchor) return h.body;\n        }\n        return null;\n    }\n\n    /**\n     * Ray-sphere intersection test. Returns distance or null.\n     */\n    _raySphereTest(ray, center, radius) {\n        const oc = new THREE.Vector3().subVectors(ray.origin, center);\n        const b = oc.dot(ray.direction);\n        const c = oc.dot(oc) - radius * radius;\n        const discriminant = b * b - c;\n        if (discriminant < 0) return null;\n        const sqrtD = Math.sqrt(discriminant);\n        const t1 = -b - sqrtD;\n        const t2 = -b + sqrtD;\n        if (t2 < 0) return null; // behind camera\n        return t1 >= 0 ? t1 : t2;\n    }\n\n    // ──────────────────────────────────────────────────────────────\n    // Event listener management\n    // ──────────────────────────────────────────────────────────────\n\n    enable() {\n        // Hex selection (Shift+click)\n        this.renderer.domElement.addEventListener('pointerdown', this._onHexSelect);\n\n        // Lat/lon hover display — three install paths in order of preference:\n        //   Phase 1b: HoverDispatcher (centralized pointermove + frame dispatch)\n        //   Phase 1a: rafCoalesce wrapper (per-instance, throttled to 1/frame)\n        //   Legacy:   raw mousemove listener (unthrottled, baseline)\n        //\n        // All three call the same _onLatLonHover. The progression centralizes\n        // the rect/NDC/raycaster cache so future overlays can register their\n        // own consumers and read from ctx instead of recomputing.\n        //\n        // Migration: refactor/async/README.md\n        const harness = getAsyncHarness();\n        const hoverDispatcher = harness?.hoverDispatcher || null;\n        const useDispatcher = !!(hoverDispatcher && harness?.flags?.hoverDispatcher);\n        const useThrottle = !!(harness?.flags?.hoverThrottle !== false);\n\n        if (useDispatcher) {\n            hoverDispatcher.attach(this.renderer.domElement, this.camera);\n            this._hoverUnregister = hoverDispatcher.register('eventManager:latLonHover', (ctx) => {\n                // Backward compat: consumer fn calls the existing event-driven\n                // handler. Future commits can refactor _onLatLonHover to read\n                // ctx.raycaster / ctx.canvasRect / ctx.ndc directly.\n                if (ctx && ctx.event) this._onLatLonHover(ctx.event);\n            });\n        } else if (useThrottle) {\n            this._pendingMousemoveEvent = null;\n            this._mousemoveCoalesced = (e) => {\n                this._pendingMousemoveEvent = e;\n                asyncRafCoalesce('eventManager:latLonHover', () => {\n                    const pending = this._pendingMousemoveEvent;\n                    this._pendingMousemoveEvent = null;\n                    if (pending) this._onLatLonHover(pending);\n                });\n            };\n            this._mousemoveListenerOpts = { passive: true };\n            this.renderer.domElement.addEventListener(\n                'mousemove',\n                this._mousemoveCoalesced,\n                this._mousemoveListenerOpts\n            );\n        } else {\n            // [ASYNC-BLOCKER:1] Unthrottled mousemove at 1000Hz+\n            // Migration: refactor/async/README.md#phase-1a\n            // Final fallback when both flags are disabled.\n            this.renderer.domElement.addEventListener('mousemove', this._onLatLonHover);\n        }\n\n        // Double-click to enter surface\n        this.renderer.domElement.addEventListener('dblclick', this._onDoubleClick);\n\n        // Double-tap for mobile. Classification owns the whole gesture so\n        // pinch/drag completions never enter surface mode.\n        this.renderer.domElement.addEventListener('touchstart', this._onTouchStart, { passive: true });\n        this.renderer.domElement.addEventListener('touchmove', this._onTouchMove, { passive: true });\n        this.renderer.domElement.addEventListener('touchend', this._onTouchEnd, { passive: false });\n        this.renderer.domElement.addEventListener('touchcancel', this._onTouchCancel, { passive: true });\n\n        // Window/container resize. Some browser maximize/title-bar paths update\n        // the canvas container without a reliable edge-drag style resize event.\n        window.addEventListener('resize', this._scheduleResize);\n        window.visualViewport?.addEventListener?.('resize', this._scheduleResize);\n        if (!this._resizeObserver && typeof ResizeObserver !== 'undefined') {\n            const resizeTarget = this.renderer?.domElement?.parentElement;\n            if (resizeTarget) {\n                this._resizeObserver = new ResizeObserver(() => this._scheduleResize());\n                this._resizeObserver.observe(resizeTarget);\n            }\n        }\n        this._scheduleResize();\n\n        // Escape key\n        window.addEventListener('keydown', this._onEscapeKey);\n        window.addEventListener('keydown', this._onShiftKeyDown);\n        window.addEventListener('keyup', this._onShiftKeyUp);\n        window.addEventListener('keydown', this._onToggleSurfaceBall);\n    }\n\n    disable() {\n        this.renderer.domElement.removeEventListener('pointerdown', this._onHexSelect);\n        // Tear down whichever hover install path enable() chose.\n        if (this._hoverUnregister) {\n            this._hoverUnregister();\n            this._hoverUnregister = null;\n            // Leave HoverDispatcher attached — other consumers may be using it.\n        } else if (this._mousemoveCoalesced) {\n            this.renderer.domElement.removeEventListener(\n                'mousemove',\n                this._mousemoveCoalesced,\n                this._mousemoveListenerOpts\n            );\n            asyncCancelRafCoalesce('eventManager:latLonHover');\n            this._mousemoveCoalesced = null;\n            this._mousemoveListenerOpts = null;\n            this._pendingMousemoveEvent = null;\n        } else {\n            this.renderer.domElement.removeEventListener('mousemove', this._onLatLonHover);\n        }\n        this.renderer.domElement.removeEventListener('dblclick', this._onDoubleClick);\n        this.renderer.domElement.removeEventListener('touchstart', this._onTouchStart);\n        this.renderer.domElement.removeEventListener('touchmove', this._onTouchMove);\n        this.renderer.domElement.removeEventListener('touchend', this._onTouchEnd);\n        this.renderer.domElement.removeEventListener('touchcancel', this._onTouchCancel);\n        this._touchTapGesture = null;\n        window.removeEventListener('resize', this._scheduleResize);\n        window.visualViewport?.removeEventListener?.('resize', this._scheduleResize);\n        if (this._resizeObserver) {\n            this._resizeObserver.disconnect();\n            this._resizeObserver = null;\n        }\n        if (this._resizeRaf) {\n            const cancel = typeof cancelAnimationFrame === 'function'\n                ? cancelAnimationFrame\n                : clearTimeout;\n            cancel(this._resizeRaf);\n            this._resizeRaf = 0;\n        }\n        window.removeEventListener('keydown', this._onEscapeKey);\n        window.removeEventListener('keydown', this._onShiftKeyDown);\n        window.removeEventListener('keyup', this._onShiftKeyUp);\n        window.removeEventListener('keydown', this._onToggleSurfaceBall);\n    }\n\n    dispose() {\n        this.disable();\n        this.renderer = null;\n        this.camera = null;\n        this.triTree = null;\n        this.surfaceController = null;\n    }\n}\n"],"names":["DEG2RAD","RAD2DEG","WGS84_SEMI_MAJOR_AXIS","WGS84_SEMI_MINOR_AXIS","EARTH_RADIUS_M","PLANET_RADIUS","SUN_RADIUS_M","SUN_EARTH_DISTANCE_M","MOON_RADIUS_M","MOON_DISTANCE_M","CAMERA_NEAR","CAMERA_FAR","EARTH_ORBIT_MAX_DISTANCE_M","VIEW_ALTITUDE_MIN_M","VIEW_ALTITUDE_MAX_M","ALT_30K_UNITS","ALT_10K_UNITS","ELEVATION_EXAGGERATION","MAX_TILE_LEVEL","WAYBACK_ROOT","WAYBACK_WMTS_CAPABILITIES_PATH","WAYBACK_WMTS_ROOT_PATH","isUnsafeCrossOriginWaybackProxy","hasBackendOverride","backendBase","getBackendApiBase","backendUrl","backendHost","pageHost","shouldUseWaybackProxy","isLocalRuntime","buildWaybackUrl","path","normalized","resolveBackendApiUrl","WAYBACK_WMTS_CAPABILITIES","DEFAULT_WAYBACK_VERSION","AXIAL_TILT_DEG","AXIAL_TILT_RAD","ATMOSPHERE_HEIGHT_M","ATMOSPHERE_RADIUS_M","RAYLEIGH_SCALE_HEIGHT_M","MIE_SCALE_HEIGHT_M","BETA_RAYLEIGH","BETA_MIE","MIE_G","EARTH_PRIME_MERIDIAN_OFFSET_RAD","DEFAULT_FORWARDER","WMTS_ROOT","UNTILT_AXIS","THREE.Vector3","UNTILT_QUAT","THREE.Quaternion","_tmpDir","_tmpQuat","_ellipsoidTmpDir","_ellipsoidTmpQuat","_ellipsoidTmpOrigin","_ellipsoidTmpDir2","_ellipsoidTmpPos","_ellipsoidTmpQuat2","WGS84_A2","WGS84_B2","WGS84_E2","WGS84_ONE_MINUS_E2","computeLocalSunAngles","surfaceDir","sunDir","up","sunEq","worldUp","east","north","alt","THREE.MathUtils","az","incidence","dirToLatLonLocal","dir","target","rxz","lat","lon","worldPosToLatLonLocal","vec","planetGroup","latLonToLocalDir","latDeg","lonDeg","adjustedLon","x","y","z","ellipsoidRadiusForLocalDir","xx","yy","denom","ellipsoidRadiusForWorldDir","raySphereIntersection","origin","radius","o","d","b","c","disc","t","rayEllipsoidIntersection","a","worldPos","invA","invB","ox","oy","oz","dx","dy","dz","A","B","C","sqrtDisc","hitLocal","geodesicDistanceWGS84","lat1Deg","lon1Deg","lat2Deg","lon2Deg","f","phi1","phi2","L","U1","U2","sinU1","cosU1","sinU2","cosU2","lambda","lambdaPrev","iter","sinSigma","cosSigma","sigma","sinAlpha","cosSqAlpha","cos2SigmaM","sinLambda","cosLambda","t1","t2","meanR","dLat","dLon","sinDLat","sinDLon","hav","uSq","deltaSigma","geodesicDestinationWGS84","bearingDeg","distanceM","alpha1","sinAlpha1","cosAlpha1","sigma1","sigmaPrev","tmp","lon2","geodesicBearing","interpolateGreatCircle","start","end","steps","s","_normalisePoint","e","lam1","lam2","sinPhi1","cosPhi1","sinPhi2","cosPhi2","cosDLam","cosD","out","i","sinD","phi","lam","p","lonLatToTileCoords","MAX_LAT","EPS","latRad","n","cx","cy","updateAttributeInPlace","geometry","name","array","itemSize","existing","THREE.BufferAttribute","updateTrailAttributes","specs","sameShape","spec","attr","sameFootprint","local","direction","photorealInteriorState","controller","worldPosition","_a","_b","sequence","_c","flight","center","skin","PhotorealInteriorRenderer","THREE.Scene","THREE.Color","THREE.BufferGeometry","THREE.Float32BufferAttribute","THREE.ShaderMaterial","solid","THREE.Mesh","renderer","camera","XRSurfaceRig","rig","THREE.PerspectiveCamera","key","THREE.Matrix4","forward","viewerTransform","yaw","xr","rigApplied","frame","calibratedNow","space","pose","eyes","eye","HUD_CORNERS","HUD_GROUPS","HUD_ITEMS","index","HUD_ITEM_MAP","item","HUD_DEFAULT_PINS","acc","normalizeHudPins","pins","corner","HudInfoStore","root","suspended","next","el","set","value","formatted","items","list","prev","idx","highlight","containers","elements","flush","handle","container","meta","frag","line","metaEntry","color","matchById","matchByIndex","clean","hudInfoStoreInstance","getHudInfoStore","options","RAD","J1970","J2000","toJulian","date","toDays","siderealTime","days","lng","calculateSunPosition","observer","Observer","equator","Equator","horizon","Horizon","getSunDirectionVector","pos","getEarthRotationAngleUTC","gmst","twoPi","angle","setPlanetFrameEuler","result","CelestialFrame","THREE.Euler","timeMs","r","Rotation_EQJ_EQD","theta","SiderealTime","equatorialDirection","raDegrees","decDegrees","ra","dec","properMotionVector","muRa","muDec","scale","julianYearsSinceJ2000","ms","_beforeRenderSubs","_afterRenderSubs","_state","onBeforeRender","cb","onAfterRender","tickBeforeRender","now","dt","tickAfterRender","frameBudgetMs","getFrameState","getFrameClockStats","_pending","_subscribed","_ensureSubscribed","drain","fn","rafCoalesce","cancelRafCoalesce","_schedulerPostTask","priority","yieldToEventLoop","resolve","yieldIfOverBudget","frameStartMs","budgetMs","runChunked","iterable","processFn","opts","signal","chunkStart","_requestIdle","deferUntilIdle","timeoutMs","timer","nextFrame","getBudgetSchedulerStats","CANONICAL_EDGES","EDGE_INDEX_REVERSED","PARENT_EDGE_TO_CHILD","CHILD_EDGE_TO_PARENT","INTERNAL_SIBLING","EDGE_NAME_ALIASES","clamp01","splitRange","t0","half","mid","formatRootIndex","normalizeEdgeName","edgeName","getEdgeIndexReversed","canonical","getParentEdgeForChildEdge","childSlot","mapping","getEdgeEndpoints","tile","getChildSlot","getChildPath","current","slot","getRootIndex","formatTileKey","rootIndex","level","pathStr","edgeReverseFlag","a0","a1","b0","b1","costAligned","pointOnArc","v0","v1","tolerance","pN","v0N","v1N","normal","angle_v0_v1","angle_v0_p","angle_p_v1","defaultEdgesOverlap","v0A","v1A","v0B","v1B","normalA","normalB","v0B_on_A","v1B_on_A","v0A_on_B","v1A_on_B","bPointsOnA","aPointsOnB","EdgeStitchTopology","rootTiles","tiles","tileA","edgeNameA","entry","edgeA","found","tileB","edgeNameB","edgeB","reverse","mapA","mapB","canonicalEdge","currentEdge","flip","halfPath","cursor","internal","neighborPath","external","range","rootMap","rootNeighbor","neighborEdge","descendEdge","effectiveHalf","childInfo","originRange","reason","neighborRange","indexReversed","imageryAvgSampler","TWO_PI","WIREFRAME_EVEREST_M","WIREFRAME_MIN_DEPTH_M","WIREFRAME_BELOW_MIN_OPACITY","WIREFRAME_LINE_OPACITY","wireframeMaterials","wireframeStyleState","_geometryPool","_GEOMETRY_POOL_MAX_PER_RES","acquirePooledGeometry","resolution","pool","releasePooledGeometry","geom","posAttr","clearPooledGeometries","disposed","ellipsoidRadiusForDir","radiusFromElevation","baseRadius","elevMeters","elev","elevationFromRadius","wireframeVertexShader","wireframeFillFragmentShader","wireframeLineFragmentShader","getWireframeFillMaterial","THREE.DoubleSide","getWireframeLineMaterial","getImageryAvgSampler","size","canvas","ctx","setTilesPendingNormals","setWireframeStyle","style","raw","uniforms","fadeInActiveTiles","crossfadeActiveTiles","registerFadeInTile","registerCrossfadeTile","updateTileFadeIns","rootTile","toRemove","updateTileCrossfades","polygonSignedArea2D","points","area","j","_buildingTmpVec3D","TriTile","v2","parent","elevationClient","a2","material","enabled","startTime","mid01","mid12","mid20","childLevel","baseRes","resPerLevel","override","res","vertexCount","vertices","dirs","baseRadii","indexArray","cz","maxLocalRadiusSq","k","w0","w1","w2","px","py","pz","len","v3","localX","localY","localZ","vIdx","indexOffset","rowStart","rowLen","nextRowStart","positionArray","baseDirArray","THREE.DynamicDrawUsage","THREE.Sphere","tmpDir","resolveOcean","expectAll","intendedCount","i3","ocean","mask","alreadyDone","inSurfaceMode","_d","extrusions","payload","positions","floatCount","baseCount","extraPositions","extraFloatCount","extraVertexCount","baseFloatCount","basePositions","nextPositions","positionAttr","baseIndexArray","baseIndexCount","nextIndex","buildings","buildingCount","debugLogs","baseDirs","backSide","_f","_e","THREE.BackSide","basePosArray","sampleTileRadiusForDir","dirX","dirY","dirZ","bestDot","bestRadius","dot","newPositions","newIndices","wallTriangleCount","roofTriangleCount","building","height","footprint","quat","basePos","embed","footprintCount","dirSamples","groundVerts","topVerts","invalid","tileMinR","tileMaxR","pt","wx","wy","wz","wLen","dIdx","sampleR","hasTileSample","tileMaxRadius","tileMinRadius","surfaceOffset","embedFloor","embedFromTile","effectiveEmbed","groundR","topR","gIdx","baseLen","baseRx","baseRy","baseRz","groundStart","topStart","g0x","g0y","g0z","g1x","g1y","g1z","t1x","t1y","t1z","ax","ay","bx","by","bz","nx","ny","nz","edgeLen","ex","ey","ez","midWx","midWy","midWz","midLen","rx","ry","rz","roofShape","THREE.Vector2","roofTris","THREE.ShapeUtils","tri","cxp","cyp","czp","abx","aby","abz","acx","acy","acz","addedVertexCount","posArray","idxArray","currentPos","totalCount","existingUv2","uv2Array","uv2Attr","uvArray","sumSin","sumCos","lonRad","refLonRad","refLonDeg","delta","u","v","uvAttr","maskArray","maskAttr","spanMeters","forceRebuild","edgeNames","edgeIndices","skirtVertexCount","sum","edge","expectedIndexCount","waterAttr","indices","sources","vertexOffset","edgeLength","top0","top1","bottom0","bottom1","surfacePositions","skirtPositions","surfaceUv","surfaceUv2","skirtUv","skirtUv2","surfaceWater","skirtWater","depth","sourceIndex","source3","target3","isBottom","worldX","worldY","worldZ","hasDeferred","hasMissing","flushPending","allowMorph","directUpdated","flushed","count","done","seeded","expected","doneRaw","expectedSafe","ratio","seededOnly","visualDone","state","fillMask","edgeCache","deferredEdges","needsFullFetch","label","offset","includePhotogramOffset","values","clampedStart","clampedEnd","span","rawCount","i0","i1","tt","cache","activeMask","maskArr","cleared","getIndex","ii","edges","bit","checkEdge","tm","infos","info","neighbor","hashCorner","maxLevel","maxNeighborLevel","fetchedCount","elevations","hasState","fallback","output","authorityElevations","neighborInfo","nFine","nAuthority","lockMode","stitchReason","blendAlpha","updatedCount","pos_t","baseElev","originalElev","maxPerCall","fullFetch","registered","checked","hasRecord","parentRes","mapped","heights","valid","validCount","markDone","maxSamples","limit","applied","safeElev","p0","p1","p2","j0","overflow","fi","fj","maxI","maxJ","idxA","idxB","idxC","wA","wB","wC","idxD","wD","iRound","jRound","eps","doneOnly","avg","ij","maxUpdates","updated","minNeighbors","epsilon","allowSeededFill","useDoneNeighbors","missing","isDone","isSeeded","isEdgeVertex","neighbors","addNeighbor","jj","nIdx","hits","fill","parentFill","allowEdges","updateLimit","avgDone","avgAny","fallbackAvg","stallMs","maxWait","currentNow","last","sampled","samples","weighted","total","sample","base","doneMask","hasSeeded","hasAuthoritativeEdgeData","child","childRes","hasData","childIdx","atlasZoom","inherited","imageryManager","map","image","width","allowInherited","inheritedZoom","hasMap","hasBinding","fallbackLevel","lowLodFallback","minX","minY","wTiles","hTiles","tileSize","atlasWidth","atlasHeight","coords","alignedMinX","halfPixelU","halfPixelV","refCx","minCx","maxCx","atlasCenter","wrapShift","tileMin","tileMax","bestMinX","bestOverlap","bestCenterDist","shift","candidateMinX","candidateMaxX","overlap","candidateCenter","centerRef","centerDist","minU","maxU","minV","maxV","sx","sw","sy","sh","sampleSize","sampler","data","g","cornerCoords","meanAngle","atlasMinXUv","atlasMinXStored","vertexIndex","cellX","cellY","targetMaterial","hadPreviousImagery","prevAtlasKey","prevInheritedKey","prevTexture","prevInheritedTexture","prevManager","alreadyRetainingNewAtlas","baseMaterial","treeManager","mat","baseRaycast","raycaster","intersects","restore","matEntry","pendingInherited","pendingManager","pendingHoldManager","pendingHoldKey","visible","elapsed","progress","eased","newTexture","prevUvOffset","prevUvScale","currentTex","manager","minCoverageRatio","bestChild","bestZoom","zoom","coverageRatio","clampedMinCoverage","targetZoom","padTiles","useAutoCoverage","maxSpan","minCy","maxCy","cxTile","maxX","maxY","spanX","spanY","maxAllowed","required","reqW","reqH","reqArea","atlasMinY","atlasMaxY","overlapY","atlasMinX","atlasMaxX","shiftCandidates","overlapX","shiftedMin","shiftedMax","candidate","overlapArea","tree","defaultMaxAtlasTiles","maxAtlasTiles","minZoom","candidates","hasZoom","hasVersion","baseChild","baseZoom","childZoom","versionId","startZoom","bounds","seq","mosaic","rules","materialInstance","wireMat","wireMesh","group","preserveLowLod","adoptedMosaic","stack","syncMorph","isStitchedVertex","preserveStitch","holdUpdate","didMorph","maxApply","speed","step","pending","remove","filled","preservePhotogram","offsets","resOverride","imageryConfig","config","requestPriority","requestContextKey","requestRing","autoCoverage","snapshotAtlas","rootZoom","stableZoom","effectiveZoom","nextZoom","pendingStallMs","nowMsStart","pendingAgeAtStartMs","pendingRequestedZoom","pendingVersionMatches","hasUVs","currentZoom","alreadyHigherOrEqual","vxCount","prepareCoords","cached","coordsLocal","atlasData","snapshotZoom","snapshotMinX","snapshotMinY","snapshotW","snapshotH","uvMinX","finalCoords","maxSpanAllowed","requestMinX","requestMaxX","requestMinXCanonical","requestMaxXCanonical","atlasKey","nowMs","pendingAgeNowMs","clearPendingRequest","hadRenderableCoverage","cachedUv","wrapN","cellN","hasLiveAtlas","shouldShowLoading","tex","retryImmediately","retryZoom","retryConfig","retry","err","cornerName","e0","e1","e2","centroid","vx","vy","vz","vertex","edgeV0","edgeV1","angle_v0_v","angle_v_v1","neighborIds","bytesPerTile","createIcosahedronTiles","verts","faces","i2","RENDER_CADENCE_JITTER_TOLERANCE_MS","ALTITUDE_TAPE_SCALE","seaLevelDatum","msl","resolveAltitudeHudPresentation","inSurface","agl","underwater","finite","AnimationLoop","modeLabel","cadenceMs","frameDiscard","discardThreshold","time","_now","immersiveXR","stereoPresenting","fixedMs","hud","altimeter","metersPerPixel","autoScrollZonePx","maxAutoSpeed","altitudeBoostStartRatio","altitudeBoostMax","orbitExitEpsilon","getAltitudeLiftScale","altitude","maxAltitude","ascending","maybeTransitionOrbitAtMax","getOverflow","clientY","rect","updateAutoTarget","strength","currentAlt","maxAlt","liftScale","stepAuto","alpha","minAlt","nextAlt","_h","_g","stopDrag","pointerId","event","pitchLadder","degreesPerPixel","deltaDeg","nextPitch","compass","nextYaw","lines","ticks","tick","abs","km","decimals","heading","prefix","summary","suffix","field","hasValue","elapsedMs","thresholdMs","effectiveThreshold","dtRaw","frameCpuStarted","completedBefore","frameFailed","error","_i","earthRotation","cameraMode","observerPos","_k","_j","_m","_l","_r","_n","_o","_q","_p","surfacePos","frameIntervalHintMs","_t","_s","elevationQueue","_u","tileBudget","msBudget","nowFn","morphStart","processed","geometryFinalizeQueue","_v","finalizeStart","normalsComputed","normalsStart","normalsMsBudget","_x","_w","_z","_y","asyncTickBefore","camWorldPos","_B","_A","_D","_C","_F","_E","_H","_G","_J","_I","_K","_N","_L","_M","renderNow","asyncTickAfter","_O","_P","previousRotation","appliedRotation","cfg","frameIntervalMs","fps","minToggleIntervalMs","canToggle","recoverThreshold","frameCpuMs","frameWaitMs","longTaskDelta","isLikelyThrottled","isLikelyGPUBound","renderDt","fpsRounded","tileUsage","emergencyMode","stageLevel","stagePctRaw","stagePct","showStage","stageLabel","stageBar","waitThresholdMs","maxElevationMorphTilesPerFrame","maxGeometryFinalizeTilesPerFrame","maxElevationMorphMsPerFrame","maxGeometryFinalizeMsPerFrame","maxNormalsPerFrame","maxNormalsMsPerFrame","_dt","_fps","minInterval","lodStats","imageryStats","elevStats","renderInfo","visibilityState","hasFocus","guard","visibilityOk","waitMs","cpuMs","longTaskBlocked","cpuBlocked","waitBlocked","intervalBlocked","badFrame","active","keepSceneLowFps","keepTerrainLowFps","stats","gov","gstats","timeInfo","hours","minutes","seconds","year","month","day","utcDate","targetPos","vDir","cameraPos","ll","offsetMs","localDate","pad","localYear","localMonth","localDay","localHours","localMinutes","localSeconds","latlonStr","navOverride","hasOverride","body","lunar","navLat","navLon","navWeather","paintDom","pointerLocked","mode","prevMode","telemetry","cameraR","surfaceUp","hasSurfaceDir","ellipsoidR","localDir","exag","cameraMsl","controllerMsl","altitudeTape","measuredSurfaceAgl","groundElevGeom","groundElev","seabed","altitudePresentation","actualAltitudeTape","orbitBody","orbitalInstruments","sampledOrbit","orbitPose","pitchDeg","headingDeg","fovDeg","showFov","anchorMinimumToEdge","val","rounded","unitsPerLine","lineSpacing","majorEvery","min","max","labelFormatter","baseIndex","edgeShift","edgeIndexShift","configuredHalfHeight","windowHeight","visibleHalfHeight","edgeSpanPx","edgeBlend","offsetIndex","lineIndex","lineValue","isMajor","isHorizon","overlay","nearKm","midKm","ringMetersEl","ringCapsEl","imgCapsEl","stageEl","pctRaw","pct","lvl","targetDir","viewDir","hit","camPos","underTile","underRingEl","status","cap","elevEl","elevRatio","elevPct","elevNearEl","elevMidEl","elevFarEl","worldQuat","tileCenter","ring","fmt","mgr","baseCfg","frac","wrapped","isCardinal","TileVisibilityTracker","focusDir","metadata","maxCount","face","childPath","distance","distancePriority","angleDeg","lerp","minMax","arr","mn","mx","buildSAT","src","w","h","sat","row","yOff","yPrev","srcOff","boxBlurFromSAT","W","y0","y1","sy0","sy1","x0","x1","sx0","sx1","D","normalize01","sobelGXGY","gxOut","gyOut","magOut","y2","a00","a01","a02","a10","a12","a20","a21","a22","gx","gy","estimateSunFromIllum","illum","mag","sumX","sumY","sumM","m","wgt","conf","computeFieldsAtRes","img","illumRadiusPx","iw","ih","logL","veg","dom","satL","refl","satR","blurS","blurB","rS","rB","dog","sunEst","canopyFromShadows","F","params","vegThr","shThr","maxLenPx","canopyBlurPx","sunElDeg","meanIll","SH_SCALE","dark","casterLen","sun","maxLen","stepInc","fx","fy","ix","iy","elRad","tanEl","hRaw","invMax","lenN","shaped","satH","canopy","satV","vegD","sampleBilinear","tx","ty","upsampleTo","low","wL","hL","wT","hT","yL","xL","buildHeightFieldFromImage","usedLevels","normalizeMode","sizes","weights","outH","fullCanvas","sunEstCoarse","autoSun","azNorm","manualSun","li","illumR","canopyParams","embossStep","coarseBoost","detailGain","shadowMicro","dirMicro","canopyScale","domeStrength","dome","extraBlur","pass","doTileNormalize","smoothPasses","rawMin","rawMax","sampleHeightField","heightField","DEFAULT_CONFIG","clampNumber","safeInt","buildConfigHash","getTileId","getTileUvBounds","extractTileCanvas","mapResolution","PhotogrammetryManager","merged","jobs","minValue","maxValue","prevMin","prevMax","changed","skipTile","imageryKey","tileScale","maxRes","minRes","minElev","completeness","invertConfig","targetRes","cacheKey","tileCanvas","invert","clampMeters","cacheEntry","ringStats","ringStatsChanged","update","gMin","gMax","edgeFade","expectedCount","invRes","uLocal","vLocal","hNorm","weight","minW","maxEntries","entries","TriTreeManager","scene","THREE.Group","THREE.MeshStandardMaterial","THREE.Raycaster","ringMidLod","worldQ","camDir","horizonRad","minRad","marginRadBase","maxRad","orbitMaxRad","surfaceMarginRad","surfaceViewshedRad","orbitMarginRad","orbitViewshedRad","referenceDir","vFovRad","aspect","hFovRad","viewHalfFovRad","marginRad","viewEdgeRad","anchorDeg","viewFalloffEndRad","hysteresisRad","_altUnits","altMeters","minLevel","altScale","altFactor","levelFromAlt","stageMin","stageMax","frameNow","ringCaps","midCap","farCap","near","upStep","downStep","downHysteresis","upCooldownMs","downCooldownMs","lastAdvance","nextNear","minScale","maxScale","targetMs","desiredScale","currentScale","lerpRate","surfacePosition","altMaxLod","stageCurrent","renderMaxLod","prefetchBias","elevationMaxLevel","imageryMinZoom","imageryMaxZoom","lodRatio","imageryCap","viewportHeight","fovRad","pixelScale","circumference","centerDir","baseTileBudget","baseSplitBudget","baseMergeBudget","baseImageryBudget","baseStageMaxLod","perf","handler","minLOD","maxLOD","cooldownMs","cullAngleDeg","focusAngleDeg","instantRampEnabled","instantRampCooldownMs","instantRampDownCooldownMs","instantRampUpStep","instantRampDownStep","instantRampDownHysteresis","viewCullEnabled","viewBufferDeg","peripheralLodDrop","viewCenterImageryBoost","removedCount","cleanupTile","nearLOD","farLOD","falloffPower","startDeg","marginDeg","power","coarseReadyRatio","tileReadyRatio","minVisibleTiles","coarseMaxLevel","flag","splitBudget","mergeBudget","lodMutationMsPerFrame","imageryPreparationMsPerFrame","emaAlpha","dropLerp","riseLerp","maxZoom","boost","newBoost","oldBoost","seen","batch","roots","wasEnabled","nowEnabled","altUnits","focusWorld","altBucket","newMaterial","prevMap","physicsSystem","addedCount","mesh","colliderData","removed","applyToMaterial","position","minXRaw","tileId","match","digit","childIndex","maxTiles","maxKeys","focusWorldDir","tileLimit","keyLimit","seenKeys","seenTileIds","focusLocalDir","parsed","score","aLevel","collectedTiles","imageryZoom","meshIdx","tileIdx","applyImagery","forceVisible","applyElevationFromCache","imageryCfg","snap","snapZoom","snapMinX","snapMinY","snapW","snapH","hasSnapshotAtlas","useSnapshotAtlas","snapMinXCanonical","minCoverage","queue","restored","initialBudget","perFrameBudget","deferRemainder","bLevel","filtered","blockedAncestors","ancestryOrder","immediateLimit","immediateCount","n0","n1","n2","bestRootDot","bestChildDot","worldDir","startR","intersectMeshRadius","prevVisible","leaf","hitR","visibleMeshes","meshes","dist","tileDirWorld","tileAngularRadius","angularPad","edgeAngle","surfaceRadius","arcDist","effective","far","tier","caps","nearDist","farDist","nearLod","farLod","falloff","seededRatio","threshold","ring0TileCount","ring0ReadyCount","aUnderfoot","bUnderfoot","aFocus","bFocus","aViewWeight","bViewWeight","aRing","bRing","aPriority","bPriority","includeRoot","violations","offenders","postOrderCheck","hasVisibleInSubtree","id","camDistOrPos","camDist","targetDeg","targetLevel","perFrame","contextKey","hasRenderableMap","hasAtlasBinding","baseConfig","request","underfoot","focus","edgeDistance","nearRadius","immediateNear","fallbackState","managerCfg","tileQueue","atlasQueue","maxQueuedTileRequests","maxQueuedAtlasRequests","tileQueueRatio","atlasQueueRatio","currentTileLoads","maxConcurrentTileLoads","currentAtlasBuilds","maxConcurrentAtlasBuilds","tileLoadRatio","atlasLoadRatio","pressureScore","hardQueuePressure","wasActive","shouldEnable","shouldDisable","scoreText","ringOrOptions","isBlankOpt","clampedTarget","requestZoom","hasImagery","isBlank","resolvedRing","pendingZoom","pendingAgeMs","visibleSince","treatAsUnderfoot","gap","minCoverZoom","coverZoom","maxRing","ringStartCap","backpressureState","zoomDrop","minBackpressureZoom","tileRadius","tileCenterWorld","dotF","surfaceRing","camAngle","surfaceEdgeAngle","surfaceEdgeDistance","containsCameraSubpoint","viewMetric","nearMeters","nearWeight","viewWeight","surfaceCap","farAngle","ringZoomCap","effectiveRingCap","since","ageMs","upgradeMs","minCap","maxCap","policyMin","policyMax","halfFov","bufferRad","centerAngle","apparentRadius","toTile","physicalRadius","safeHalfFov","dotCam","viewshedRad","maxAngle","dotThreshold","hysteresis","inViewport","metric","buffer","effectiveFalloffRad","dotView","angleToView","visibleTiles","spatialIndex","edgeCorners","tileEdgeKey","sibling","otherEdges","otherEdgeName","otherCorners","tileCentroid","searchRadius","other","neighborTile","visibleSet","resolveNeighbor","descriptor","parentEdge","mapChildEdgeToParent","resolved","neighborEdgeName","cellSize","cellKey","testPos","cellTiles","childTile","childEdge","edgesB","tileKey","authorityTile","authorityEdgeName","targetTile","targetEdgeName","minAuthority","skipTarget","maxBlend","minBlend","authorityCompleteness","targetCompleteness","targetFactor","authorityRange","edgeBit","tileById","activeEdgeMaskByTile","seamCount","edgeKey","lastUnderscore","primaryTile","coarseTile","fineTile","coarseEdgeName","fineEdgeName","fineId","coarseId","seamKey","stitchCount","getAuthorityRange","buildOptions","lodDelta","edgeOptions","neighborPairs","force","grace","toDelete","plannedTileCount","entryUnderCap","tileUnderCap","graceMs","retainElevation","pressure","tilesToSplit","hasViolation","coarseData","fineIndices","isPositionMode","cost","costRev","fineStartIdx","fineEndIdx","fineStart","fineEnd","c0","c1","fineStartH","fineEndH","reversed","screenPixels","policyRenderMax","surfaceStageCap","desired","sse","maxSSE","mergeRatio","angleToFocus","stageFocusRad","distanceCap","floor","levelFromPatch","patch","dotP","angleToPatch","dotFocus","tanHalfFov","focalLength","approx","cosFactor","localAlt","decay","camPosResolved","rawStartRad","startRad","tileDir","bufferT","drop","perfEnabled","prevSurfaceMode","elevationCascadeEnabled","stageActive","coarseCap","policy","targetMax","baseCap","nearCap","posDelta","rotDelta","focusDelta","worldDelta","modeChanged","poseChanged","idleExpired","fastPosThresh","basePreloadPending","modeScale","motionScale","adaptiveSplitScale","effectiveSplitBudget","effectiveMergeBudgetBase","effectiveImageryBudget","effectiveTileBudget","tileRatio","imageryPressure","retirementRatio","throttle","focusLeafTile","forceImageryReset","imageryFocusDir","prevDir","prevAlt","prevSurface","dirDeltaDeg","altJump","surfaceChanged","fastSweep","hardDir","hardAlt","hiddenLeafTilesForElevation","tilesToMerge","tilesToLoadImagery","coarseImageryEnqueued","HYST","imageryAppliedCount","imageryVisibleCount","imageryBudget","imageryFullCoverage","imageryBackpressureState","mergesDone","splitsDone","pressureFactor","splitMin","imageryMin","splitScale","imageryScale","camPosSurface","underfootLeafTile","underfootLineage","focusLineage","elevationMergeGraceMs","hasRecentElevationProgress","lastProgress","isMergeProtectedTile","stageRingLimit","fallbackCoverageLevel","tileHasRenderableImagery","tileHasVisibleCoverage","tileHasSplitCoverage","visit","suppressVisibility","bypassUnderfootCulling","allChildrenReady","parentHasImagery","anyDescendantVisible","parentSuppressedUntil","parentHoldSuppressed","holdParent","parentAlt","childThreshold","canMerge","mergeDueToDistance","mergeDueToDesired","allowParentVisible","suppressChildren","surfaceViewMetric","inCameraViewshed","inBufferedViewshed","viewEdgeAngle","inStageFocus","inNearRing","forceUnderfoot","centerRingLimit","inCenterFetchRing","cascadeAllowsRefine","forceNearRings","allowVisible","hasLiveMap","shouldAnimate","needsUpgrade","needsUvRefresh","needs","nearRingTile","camPosForRing","tileDirForRing","allowPendingOverride","clearPending","isUnderfoot","isFocus","ringPriority","levelPriority","centerPriority","parentDirWorld","parentRing","parentPriority","parentZ","localThreshold","forceMinLevel","canSplitByPixels","shouldSplit","distanceToTile","stageReady","stageTileCount","stageProgressSum","stageReadyCount","fullTileCount","fullTileReadyCount","retryBudget","stageTiles","retryScale","perTile","added","readyRatio","ratioReady","fullReady","centricFetchMode","coarseCascadePhase","canSetSchedulingProfile","targetMode","currentProfile","anchor","maxDist","distanceReset","angleReset","forceCount","missingCount","coverageEntries","coverageTileSet","coverageTiles","allRetryBudget","baseBudget","tileCount","tileReadyThreshold","coarseReadyThreshold","coarseReadyTiles","coarseTotalTiles","centerFullFetchRingLimit","inElevationViewshed","shouldForceFullFetch","forceFocus","centerCandidate","expectedFromTile","hasMissingFromTile","fullFetchGateOpen","centerPriorityTile","authoritativeMissing","budget","visibleAgeMs","visibleCount","orbitTileCount","baseTileScan","baseCandidateMax","perTileLimit","visibleScale","forceScale","candidateMax","pressureScale","activeTiles","pushTile","ringBoosts","levelWeight","coarseLevelCap","distClamp","ringBoost","viewBoost","levelScore","tilePriorityMap","centerPriorityActive","queueTile","combinedPriority","ringBuckets","baseMaxActiveTiles","maxActiveTiles","remainingBudget","ringWeights","nearBudget","midBudget","farBudget","bucket","remaining","orbitTiles","cosLimit","canAdvance","cooldownElapsed","prevLOD","tilesNeedingImagery","isFullCoverageOrbit","imageryApplied","bootstrapApplied","loadedTiles","imageryPrepareStart","imageryPrepareBudgetMs","imageryPrepareBudgetExceeded","bootstrapBudgetCap","bootstrapBudget","bootstrapMinPriority","bootstrapCandidates","bootstrapSeen","tileCfg","tileState","targetImageryZoom","tileIsBlank","tileRing","rescueApplied","rescueBudget","rescueCandidates","tileUsageRatio","emergencyThreshold","lodLoopStartMs","lodTimeBudgetMs","emergencyMergeScale","effectiveMergeBudget","parentRenderable","anyChildRenderable","mergedTileVisible","maxSplitsPossible","splitLimit","resurrected","childrenInherited","parentCanHold","shouldDetectNeighbors","needsNeighborBuild","neighborsRebuilt","staleCollidersRemoved","nextVisible","elevationStats","refCount","setupCallback","updatedTile","originalPrepareChildren","contactResolution","object","node","finestSurfaceContactHits","curvedSurfaceGroundRadius","referenceR","slopeDot","centers","rays","basis","fit","matrix","pivot","evaluate","coeff","maxGradient","best","omit","_","inliers","refined","CENTER","AVERAGE","SAH","NOT_INTERSECTED","INTERSECTED","CONTAINED","PRIMITIVE_INTERSECT_COST","TRAVERSAL_COST","BYTES_PER_NODE","UINT32_PER_NODE","IS_LEAFNODE_FLAG","LEAFNODE_MASK_32","FLOAT32_EPSILON","SKIP_GENERATION","DEFAULT_OPTIONS","arrayToBox","nodeIndex32","getLongestEdgeIndex","splitDimIdx","splitDist","expandByPrimitiveBounds","startIndex","primitiveBounds","tCenter","tHalf","tMin","tMax","computeSurfaceArea","d0","d1","d2","IS_LEAF","n16","uint16Array","OFFSET","n32","uint32Array","COUNT","LEFT_NODE","RIGHT_NODE","relativeOffset","SPLIT_AXIS","getBounds","centroidTarget","minx","miny","minz","maxx","maxy","maxz","cminx","cminy","cminz","cmaxx","cmaxy","cmaxz","boundsOffset","hx","lx","hy","ly","hz","lz","BIN_COUNT","SWEEP_COUNT","binCounts","binBounds","binRightBounds","leftBounds","rightBounds","sweepOrder","sweepRightBounds","expandBoundsAt","computeSurfaceAreaAt","getOptimalSplit","nodeBoundingData","centroidBoundingData","strategy","axis","getAverage","rootSurfaceArea","bestCost","cStart","cEnd","axisLeft","binWidth","leftCount","rightCount","leftProb","rightProb","binIndex","binCount","partition","stride","split","left","right","axisOffset","l","tb","MAX_POINTER","_nodeBounds","_centroidBounds","buildTree","bvh","loadRange","maxDepth","verbose","targetLeafSize","_strictLeafSize","onProgress","useSharedArrayBuffer","partitionBuffer","partitionStride","BufferConstructor","float32Array","nodeCount","reachedMaxDepth","splitNode","triggerProgress","primitivesProcessed","writeLeaf","node32","node16","nodeIndex","mustSplit","splitOffset","relativeRightIndex","buildPackedTree","rootRanges","firstRange","lastRange","fullRange","PrimitivePool","getNewPrimitive","primitives","primitive","_BufferStack","prevBuffer","BufferStack","_box1","_box2","boxStack","boxPool","Box3","shapecast","intersectsBounds","intersectsRange","boundsTraverseOrder","nodeOffset","shapecastTraverse","length","intersectsBoundsFunc","intersectsRangeFunc","nodeScoreFunc","nodeIndexOffset","nodeIndex16","getLeftOffset","getRightEndOffset","c2","score1","score2","box1","box2","temp","isC1Leaf","c1Intersection","c1StopTraversal","isC2Leaf","c2Intersection","c2StopTraversal","_bufferStack1","_bufferStack2","_boxPool","_leftBox1","_rightBox1","_leftBox2","_rightBox2","_active","bvhcast","otherBvh","matrixToLocal","intersectsRanges","otherRoots","nodeOffset1","nodeOffset2","invMat","Matrix4","il","localBox","jl","_traverse","node1Index32","node2Index32","matrix2to1","matrix1to2","intersectsRangesFunc","node1IndexOffset","node2IndexOffset","depth1","depth2","currBox","bufferStack1","bufferStack2","float32Array1","uint32Array1","uint16Array1","float32Array2","uint32Array2","uint16Array2","node1Index16","node2Index16","isLeaf1","isLeaf2","newBox","cl1","cr1","intersectCl1","intersectCr1","cl2","cr2","leftIntersects","rightIntersects","BVHTraversalHelper","traversing","node32Index","node16Index","walk","callback","isLeaf","splitAxis","_tempBox","_tempBuffer","BVH","targetBuffer","minZ","maxZ","indirectBuffer","totalNodes","rootCount","leftMin","leftMax","rightMin","rightMax","callbacks","intersectsPrimitive","scratchPrimitive","iterate","originalIntersectsRange","contained","shapecastFunc","isSharedArrayBufferSupported","getVertexCount","geo","getTriCount","getIndexArray","ensureIndex","BufferAttribute","getFullPrimitiveRange","primitiveCount","drawRange","getPrimitiveGroupRanges","getRootPrimitiveRanges","primitiveRanges","ranges","drawRangeStart","drawRangeEnd","events","groupStart","groupCount","groupEnd","activeGroups","lastPos","newPos","generateIndirectBuffer","useUint32","byteCount","GeometryBVH","primitiveStride","SeparatingAxisBounds","Vector3","box","boxMin","boxMax","closestPointLineToLine","dir1","dir2","v02","l1","l2","v10","v32","d0232","d3210","d3232","d0210","closestPointsSegmentToSegment","paramResult","Vector2","temp1","temp2","target1","target2","closestPoint","closestPoint2","sphereIntersectTriangle","closestPointTemp","projectedPointTemp","planeTemp","Plane","lineTemp","Line3","sphere","triangle","plane","pp","componentKeys","ZERO_EPSILON","ZERO_EPSILON_SQR","isNearZero","ExtendedTriangle","Triangle","args","satAxes","satBounds","axis0","sab0","axis1","sab1","axis2","sab2","axis3","sab3","lengthAB","lengthBC","lengthCA","point1","point2","segment","distSq","closestDistanceSq","startDist","endDist","nexti","saTri2","cachedSatBounds","cachedSatBounds2","tmpVec","tempDir","edge1","edge2","tempPoint","bounds1","bounds2","coplanarIntersectsTriangle","self","suppressLog","planeNormal","satBounds1","satAxes1","sb","sa","satBounds2","satAxes2","findSingleBounds","aProj","bProj","cProj","aDist","bDist","cDist","findIntersectionLineBounds","abDist","acDist","intersectTriangleSegment","degenerateTriangle","intersectTrianglePoint","point","intersectSegmentPoint","segmentTri","pointTri","handleDegenerateCases","segment1","segment2","delta1","delta2","startDelta","z1","z2","plane1","plane2","a1Dist","b1Dist","c1Dist","a1b1Dist","a1c1Dist","a2Dist","b2Dist","c2Dist","a2b2Dist","a2c2Dist","intersectionLine","componentIndex","maxComponent","comp1","a1Proj","b1Proj","c1Proj","a2Proj","b2Proj","c2Proj","cornerFields","line1","line2","lineTarget","otherVec","thisVec","f11","f12","f21","f22","OrientedBox","minVec","pi","alignedSatBounds","aabbBounds","saTri","pointsArr","cachedAxis","triSatBounds","triSatAxes","sa1","sa2","xyzFields","segments1","segments2","threshold2","nextIndex2","index2","f1","f2","f3","ExtendedTrianglePoolBase","ExtendedTrianglePool","closestPointToPoint","minThreshold","maxThreshold","minThresholdSq","maxThresholdSq","closestDistanceTriIndex","triIndex","closestDistance","IS_GT_REVISION_169","REVISION","IS_LT_REVISION_161","_vA","_vB","_vC","_uvA","_uvB","_uvC","_normalA","_normalB","_normalC","_intersectionPoint","checkIntersection","ray","pA","pB","pC","side","intersect","BackSide","DoubleSide","checkBufferGeometryIntersection","uv","uv1","intersection","barycoord","getSide","materialOrSide","intersectTri","intersections","triOffset","groups","firstIndex","materialIndex","setTriangle","ta","tc","tempV1","tempV2","tempV3","tempUV1","tempUV2","tempUV3","getTriangleHitPointInfo","triangleIndex","uvs","firstVertexIndex","intersectTris","_indirectBuffer","intersectClosestTri","iterateOverTriangles","intersectsTriangleFunc","refit","nodeIndices","indexArr","byteOffset","forceChildren","includesLeft","includesRight","leftNodeId","rightNodeId","traverseLeft","traverseRight","leftChange","rightChange","didChange","left_i","right_i","minLeftValue","maxLeftValue","minRightValue","maxRightValue","intersectsNodeBounds","tmin","tmax","tymin","tymax","tzmin","tzmax","invdirx","invdiry","invdirz","intersectTris_indirect","vi","intersectClosestTri_indirect","iterateOverTriangles_indirect","raycast","_raycast","leftIndex","rightIndex","_xyzFields","raycastFirst","_raycastFirst","xyzAxis","leftToRight","c1Result","c2Result","boundingBox","triangle2","invertedMat","obb","obb2","intersectsGeometry","otherGeometry","geometryToBvh","_intersectsGeometry","cachedObb","thisGeometry","thisIndex","thisPos","otherIndex","otherPos","otherTriangleCount","tempMatrix","temp3","temp4","closestPointToGeometry","tempTarget1","tempTargetDest1","tempTarget2","tempTargetDest2","closestDistanceOtherTriIndex","otherOffset","otherCount","triCount","refit_indirect","raycast_indirect","raycastFirst_indirect","intersectsGeometry_indirect","ti","closestPointToGeometry_indirect","ti2","convertRaycastIntersect","_obb","_ray","Ray","_direction","_inverseMatrix","_worldScale","_getters","MeshBVH","rootData","indexAttribute","fixupVersion0","newIndex","tri3","ai","bi","ci","posArr","bufferOffset","getters","writeOffset","boundsIndexOffset","halfExtents","el2","scaleFactor","FrontSide","raycastFunc","closestResult","raycastFirstFunc","geomToMesh","intersectsGeometryFunc","intersectsTriangles","triangle1","indexAttr1","positionAttr1","assignTriangle1","indexAttr2","positionAttr2","assignTriangle2","iterateOverDoubleTriangles","offset1","count1","offset2","count2","nodeIndex1","nodeIndex2","originalIntersectsRanges","boxToMesh","_linePool","_intersectPointOnRay","_intersectPointOnSegment","_box","_vec","LineSegmentsBVH","indexAttr","vertCount","iterateOverLines","matrixWorld","firstHitOnly","localThresholdSq","closestHit","LineLoopBVH","LineBVH","intersectsPointFunc","_pointPool","PointsBVH","pointIndex","iterateOverPoints","rayPointDistanceSq","intersectPoint","prim","_geometry","BufferGeometry","_matrix","_sphere","Sphere","_mesh","Mesh","_geometryRange","ObjectBVH","objectSet","collectObjects","objects","idBits","idMask","compositeId","getObjectId","getInstanceId","primitiveBuffer","iterateOverObjects","includeInstances","localIntersects","instanceId","geometryId","geometryRange","inverseMatrixWorld","precise","shrinkToSphere","getPreciseBounds","instanceCount","maxInstanceCount","foundInstances","_v0","_v1","_v2","_localPoint","_axes","SkinnedMeshBVH","actualTri","resUv","resUv1","resNormal","BVHRootHelper","Object3D","frustum","boundsTree","positionArrays","boundsCount","indexLength","posOffset","targetDepth","displayParents","posIndex","boundingData","terminate","xVal","yVal","zVal","BVHHelper","Group","edgeMaterial","LineBasicMaterial","meshMaterial","MeshBasicMaterial","drawInfo","totalRoots","displayEdges","source","children","MeshBVHHelper","getElementSize","isTypedArray","getRootExtremes","offsetOrSplit","l0","surfaceArea","getBVHExtremes","estimateMemoryInBytes","obj","traversed","bytes","curr","validateBounds","depthStack","tempBuffer","passes","isContained","getJSONStructure","IS_REVISION_166","_raycastFunctions","Line","LineSegments","LineLoop","Points","BatchedMesh","_batchIntersects","acceleratedRaycast","acceleratedBatchedMeshRaycast","raycastFunction","boundsTrees","drawRanges","oldBoundsTree","oldDrawRange","computeBoundsTree","type","disposeBoundsTree","computeBatchedBoundsTree","geometryCount","disposeBatchedBoundsTree","countToStringFormat","countToFormat","RedFormat","RGFormat","RGBAFormat","countToIntFormat","RedIntegerFormat","RGIntegerFormat","RGBAIntegerFormat","VertexAttributeTexture","DataTexture","NearestFilter","overrideItemSize","originalItemSize","originalCount","originalBufferCons","targetType","finalStride","FloatType","UnsignedIntType","IntType","format","normalizeValue","targetBufferCons","internalFormat","UnsignedByteType","ByteType","ShortType","UnsignedShortType","dimension","dataArray","originalNormalized","UIntVertexAttributeTexture","IntVertexAttributeTexture","FloatVertexAttributeTexture","MeshBVHUniformStruct","bvhToTextures","dereferenceIndex","bvhBounds","bvhContents","unpacked","boundsTexture","contentsTexture","boundsDimension","boundsArray","contentsDimension","contentsArray","boundsIndex","mergedLeafCount","rightNodeIndex","_positionVector","_normalVector","_tangentVector","_tangentVector4","Vector4","_morphVector","_temp","_skinIndex","_skinWeight","_boneMatrix","validateAttributes","attr1","attr2","sameCount","sameNormalized","sameType","sameItemSize","createAttributeClone","countOverride","cons","copyAttributeContents","targetOffset","io","addScaledMatrix","targetArray","matrixArray","boneNormalTransform","skeleton","bones","boneInverses","boneIndex","applyMorphTarget","morphData","morphInfluences","morphTargetsRelative","influence","morphAttribute","mergeBufferGeometries","geometries","targetGeometry","isIndexed","useGroups","updateIndex","skipAttributes","attributesUsed","attributes","attributesCount","forceUpdateIndex","indexCount","targetIndex","attrList","targetAttribute","checkTypedArrayEquality","invertGeometry","GeometryDiff","boneMatrices","StaticGeometryGenerator","finalMeshes","materials","_intermediateGeometry","_diffMap","diff","attrs","applyWorldTransforms","includeNormal","includeTangent","targetAttributes","tangent","morphPosition","morphNormal","morphTangent","normalMatrix","Matrix3","common_functions","bvh_distance_functions","bvh_ray_functions","bvh_struct_definitions","shaderStructs","BVHShaderGLSL.bvh_struct_definitions","shaderDistanceFunction","BVHShaderGLSL.bvh_distance_functions","shaderIntersectFunction","BVHShaderGLSL.common_functions","BVHShaderGLSL.bvh_ray_functions","EPSILON","SurfaceCapsuleCollider","foot","motion","inverse","localStart","localEnd","localDelta","first","iteration","closing","wall","bump","vertical","into","correction","capsule","stepHeight","lift","ceiling","landing","baseProgress","ground","projectOrbitDragRay","metrics","impact","publications","invalidatePhotorealSamplingMatrices","publishPhotorealSamplingMatrices","xrFrame","previous","SVG_NS","normalizeLocatorHeading","clampLocatorFov","fov","createCrosshairMotion","random","between","buildViewshedSectorPath","safeRadius","pointAt","degrees","radians","appendClass","element","names","createSceneLocationIndicator","documentRef","variant","className","showViewshed","locator","radar","svg","circle","sector","core","crosshair","arm","updateSceneLocationIndicator","photoreal","headingKey","fovKey","DeviceSensors","snapshot","gestureNeeded","targetYawDeg","currentHeadingDeg","deltaRad","qDelta","beta","gamma","isUpright","isNotRolled","q","deg","ang","deviceFwd","deviceUp","horizLen","pitch","camRight","camRightLen","roll","rad","hdg","oHead","incl","worldVec","SensorCtor","sensor","magNorm","world","headingRaw","finalHeading","aNorm","axn","ayn","azn","my","mz","horiz","sr","cr","sp","cp","mxComp","myComp","headingRad","deviceSensorsInstance","getDeviceSensors","_isMetaverseSceneMode","PHOTO_CONTACT_REUSE_RADIUS_M","WALK_HEIGHT_MAX_SLOPE","WALK_HEIGHT_SETTLE_MPS","WALK_NO_CLIP_M","WALK_FALL_MPS","SurfaceController","controls","triTree","THREE.Object3D","delay","startsAt","duration","deviceQuat","yawOffset","pitchOffset","upComp","fwdT","ready","lookDir","outEast","outNorth","upDir","preserveLook","flatDir","newUp","presentationOnlyRoot","rayOrigin","rayDir","farLimitOverride","farLimit","tmpCenter","tmpClosest","modelSeq","bs","worldRadius","projectedT","maxOffset","highestR","sourceMaterial","radialNormalDot","THREE.Matrix3","mutateCache","allowCachedFallback","_preferCandidates","surface","providerOnly","walkableVerified","visibleSkinRadius","floorR","collisionFloorR","localPosition","commandedAgl","targetR","calibrationPending","requireFreshPhotoHit","photoR","isTileReliable","leafTile","withinBounds","hitTile","rawRadius","STILL_DEADBAND_M","STILL_MOVE_M2","movementIntent","geoStill","stillAnchor","localPos","hugSurface","tau","directAltitudeInput","maxDelta","terrainElevRaw","minAltitude","rate","alphaAlt","terrainElev","altitudeForMSL","activeMSL","clampedAlt","standHeight","crouchHeight","minClearance","resolver","seaHeight","nearby","elevation","isOcean","commanded","surfaceFloor","centerSkinR","terrainR","eyeHeight","cacheAge","movedSq","directionStable","distanceCovered","cameraWorldPos","labelWorldPos","segmentLength","renderFrame","sourceWorldPos","listenerWorldPos","reflectionPoint","midpoint","groundRay","THREE.Ray","reflectedDistance","excessDistance","fromWorld","toWorld","maxDistance","moveDir","moveMeters","bodyRadius","bodyHeight","solver","grounded","down","signature","samePoint","clearance","previousPosition","proposedPosition","motionDistance","validHits","referenceGroundR","maxStepUp","stepUp","ceilingR","bestCenter","bestFallback","nearestOffset","allowSupportedRise","perRay","residualToleranceM","minimumAxisSpanM","fitThree","x2","determinant","minE","maxE","minN","maxN","maxOffsetM","eastSpanM","northSpanM","interceptSum","centerR","supportArea","centerToleranceM","centerGroundR","centerResidualM","residualM","absoluteMin","baseMin","useSample","keyboard","mobileX","mobileY","mobile","coasting","geoTranslation","seedPos","frameDirection","commandedAlt","stationary","cachedAt","cachedAge","HOLD_STALE_MS","STATIONARY_SAMPLE_DEADBAND_M","NEAR_GROUND_SNAP_ALT_M","footprintRadiusM","limitSq","invalidated","smoothedGround","rawGround","syncAltitude","oceanDir","commandedAltitude","minR","dir0","ellR","sanityMin","photoClearance","bodyClearance","clamped","needsFootprintSeed","nearGroundContact","currentCenterSkinR","targetContactR","safeTerrainR","baseClearance","radiusNow","floorAlt","enterAlt","exitAlt","externalOwnerToken","minFloorPhoto","aglTarget","ellipsoidRPhoto","anchorPhoto","anchorPosition","walkingTopologyActive","contactGround","contactProbe","oceanSwimming","groundForPlacement","mslOwnsPlacement","rPhoto","useDeviceOrientation","posPhoto","postGateR","minFloor","terrainBasisR","minRadius","clampedMsl","dolly","viewerOffset","trackedEyeHeight","floorRadius","nextAltitude","targetRadius","radiusDelta","input","xrCamera","rightDir","moveX","moveZ","altitudeFactor","movement","vertMove","endPos","endQuat","nextMode","durationMs","radialArc","pathFacing","arcLiftMeters","dur","startDir","endDir","arcQuat","stepQuat","aheadA","aheadE","aheadStepQuat","aheadRadius","aheadPos","pathObject","THREE.Camera","departureBlend","arrivalBlend","anchorPos","upVec","savedPitch","minDist","tRaw","terrainRadius","planetQuat","finalTerrainR","preserveAltitude","transitionDurationMs","targetAltitudeMeters","travelArcLiftMeters","enteringFromSurface","keepAltitude","camRadius","rawAlt","currentRadius","currentAltitude","orbitExitAltitude","cameraUp","currentUp","scaled","deltaY","baseDistance","zoomScale","minDistance","baseAltitude","damping","factor","transitCooldown","cooldownActive","currentDistance","targetDistance","deltaSeconds","response","accel","decel","baseAlt","deltaTime","moveForward","moveBackward","moveLeft","moveRight","xrVertical","moveUp","moveDown","shiftHeld","wantsVerticalBoost","verticalAccel","verticalDirection","targetVerticalSpeed","verticalRateBase","appliedDir","altitudeDelta","minGlideMsl","maxGlideMsl","forwardComp","rightComp","hasMoveInput","moveInputMagnitude","holdProgress","holdMultiplier","speedAltitude","targetSpeed","moveRateBase","cosYaw","sinYaw","northMove","eastMove","surfaceR","moveAngle","nextUp","profile","forwardMeters","rightMeters","requestedHorizontalMeters","upMeters","yawRadians","pitchRadians","appliedHorizontalMeters","horizontalMeters","requestedDirection","resolvedDirection","admittedMeters","altitudeBefore","altitudeAfter","bodyName","currentAnchorPos","orbitDist","bt","preserveOrientation","preserveMSL","posRadius","flightMsl","flightGroundR","photoGroundSample","photoGroundRadius","computedMsl","targetAlt","clientX","defaultFar","queryLimit","roundoffGuard","photoHit","nav","relativeOrigin","sphereHit","newPivotDir","pivotDir","relativeCamera","baseR","cameraPosition","acceptedSurfaceR","highestCenterR","nearestHighestR","CLUSTER_TOLERANCE_M","clusterEnd","clusterSize","forceWalkableCalibration","SHORT_TTL_MS","LONG_TTL_MS","contactReuseM2","horizontalDistSq","geometryChangedSinceSample","ttl","SAMPLE_OFFSETS","tmpPt","nearWalkingSurface","walkableReferenceR","needsSupportedCenterRevalidation","MAX_EXPECTED_ELEVATION_M","MIN_EXPECTED_ELEVATION_M","dE","dN","isCenterSample","hitCountBeforeRay","worldNormal","hasContinuityGround","centerHit","aglCommand","hold","followRate","sampleRadii","sorted","movedM","cachedAgl","directCommand","idleFlight","intervalMs","minRadiusM","maxRadiusM","reportedAgl","ringM","minElevation","maxElevation","probe","rayDirection","hitNormal","centerRadius","preferredMsl","targetMsl","resolvedAlt","lockMinAlt","explicitMSL","computedMSL","hadLock","baseline","holdMs","minMsl","maxMsl","corrected","owner","token","tag","locked","wantsRotate","wantsDrag","action","nextDist","pointers","nextId","previousDistance","nextDistance","minimum","dollyOffset","pts","gesture","sens","cos","sin","fovEl","fallbackX","fallbackY","projected","projectedMetersPerPixel","move","azimuth","pivotNormal","dxHold","dyHold","pointer","deltaAbs","magnitude","resolvedZoomScale","inputScale","coarseStep","fineControlMax","normalizedAltitude","exponent","exponentialDenominator","exponentialAltitude","minimumScale","fineScale","continuing","energy","sustainMs","sustain","altitudeCap","resetGesture","timestamp","rawDeltaY","wheelNow","scrollOut","altitudeBoost","previousImpact","blend","prevTargetYaw","prevTargetPitch","nextTargetYaw","nextTargetPitch","nextVelocityYaw","nextVelocityPitch","yawKey","pitchKey","soft","limitedMag","softStartRatio","softStart","softSpan","lastUpdateAt","inertiaSec","acceptedYaw","acceptedPitch","acceptedMag","requestedMag","inertiaDamp","recenterAngle","lookAngle","returnSec","responseSec","followBlend","lookKey","invDt","targetEyeHeight","swimFloor","verticalInput","gravityCaptureAlt","scrollOwnsAltitude","terminalVelocity","audioCtx","ensureAudioCtx","AudioCtx","playBlip","frequency","gainValue","osc","gain","durationSec","volume","playMoveBlip","playResizeBlip","getUiAudioSfx","_instance","HoverDispatcher","domElement","getHoverDispatcher","_stats","BUCKETS","_slot","recordSubmit","recordResult","latencyMs","recordError","recordTimeout","getMetrics","_nextRequestId","MAX_PENDING_PER_WORKER","WorkerHandle","worker","_createWorker","ev","requestId","metrics.recordError","metrics.recordResult","transfer","startedAt","metrics.recordSubmit","reject","metrics.recordTimeout","WorkerPool","metrics.getMetrics","getWorkerPool","_defaultFlags","AsyncHarness","frameClock","budgetScheduler","getFetchQueue","budgetScheduler.deferUntilIdle","frameClock.getFrameClockStats","budgetScheduler.getBudgetSchedulerStats","frameClock.tickBeforeRender","frameClock.tickAfterRender","initAsyncHarness","getAsyncHarness","EventManager","surfaceController","lightingSystem","moonSystem","geoJsonLayer","eventBus","layer","adminLevel","layers","provider","subsystem","hudStore","latStr","lonStr","tags","modelUrl","earthPos","radiusValue","hovered","addCandidate","nextKey","hoveredItem","overlayId","itemId","layerId","deltaLat","deltaLon","needsInterval","needsDelta","needsSeed","numeric","feature","props","sunLocal","surfaceLocal","invQ","sunAngles","subsolarLon","localSolarTime","lstHours","lstMinutes","moonElevDeg","moonAzDeg","moonDir","moonAngles","sunElevDeg","sunAzDeg","sunIncDeg","lstStr","THREE.RingGeometry","THREE.MeshBasicMaterial","toggle","vertexMetricsToggle","wireframeMat","accent","accentSoft","accentStrong","nextColors","edgeColors","arrow","headLength","headWidth","THREE.ArrowHelper","v0Idx","v1Idx","v2Idx","idx1","idx2","distanceThreshold","neighborCenter","neighborId","neighborLOD","bestEdgeName","foundOverlap","primaryV0","primaryV1","primaryV2","neighborEdges","nEdge","targetPoint","neighborDirection","neighborArrow","neighborDistance","edgeVertices","edgeColor","neighborEdgeVertices","neighborVertex","helper","sphereGeom","THREE.SphereGeometry","sphereMat","offsetPos","tileEdgeName","primaryEdgeName","neighborVertices","totalStitched","neighborInfos","authorityEdge","targetEdge","tileCompleteness","neighborCompleteness","neighborIsAuthority","stitched","clonedGeom","clonedPosAttr","offsetAmount","shape","THREE.Shape","THREE.ShapeGeometry","THREE.LineBasicMaterial","THREE.Line","needed","detailed","ndc","terrainHit","tmpA","tmpB","minEdge","faceCount","faceIndex","idx0","radiusOverride","shouldUpdateGeo","countryFeature","country","subdivision","hoverRadius","hoverEllipsoidRadius","hoverElevation","photoRoot","hitOwner","photorealHit","camLen","controllerAgl","formatMeters","formatDeg","formatSpeed","celestial","adminLabel","adminValue","hoveredBuilding","hoveredAircraft","hoveredSatellite","hoveredMaritime","hoveredIncident","hoveredOverlayItem","bldgName","heightStr","levelsStr","clearAircraftTarget","clearSatelliteTarget","clearMaritimeTarget","acLatLon","modelLabel","satLatLon","altitudeLabel","vesselLatLon","adminData","weatherSummary","highlightFeature","straightLen","arcLength","distances","midSeg","farSeg","usable","sinTheta","opacity","_R","_Q","_T","_S","_V","_U","adminName","kb","mb","fetchStats","visualStats","elevLabel","activeEntry","forced","activeLabel","colors","contentContainer","showVertexMetrics","html","tileLod","tileColor","vtxCount","neighborLod","neighborLodColor","deltaStr","deltaColor","shortId","shortPath","neighborVtxCount","renderScale","renderWidth","renderHeight","raf","sidebar","touch","toleranceSq","completed","isTap","timeSinceLastTap","syntheticEvent","bodyHit","currentAnchor","moonPos","moonR","sunPos","sunClickR","earthHit","oc","discriminant","sqrtD","harness","hoverDispatcher","useDispatcher","useThrottle","asyncRafCoalesce","resizeTarget","asyncCancelRafCoalesce"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,ECE7BC,GAAmC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,ECFnCC,GAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","x_google_ignoreList":[17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70]}