@rr0/ufoathome 0.57.1 → 0.57.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -991,8 +991,10 @@ weather timeline from zero; seeking and pausing reproduce the same field. Covera
991
991
  fraction of the generated horizontal field occupied by cloud, independently of characteristic
992
992
  cloud size and optical density.
993
993
 
994
- `SceneElement.setCloudRendering("volume")` selects volumetric rendering. `"surface"` remains the default
995
- and is available for comparison on the existing development page, under the cloud test controls.
994
+ Volumetric rendering is the default, for recordings written before there were layers too (their
995
+ cover, base and darkness are adapted into one layer). `SceneElement.setCloudRendering("surface")`
996
+ selects the lightweight flat deck, available for comparison on the development page under the cloud
997
+ test controls.
996
998
  The thick layers use a 64³ byte noise texture, shared within a renderer, 48 view samples and up to
997
999
  three light samples per occupied view sample. Continuous weather changes update uniforms without
998
1000
  recreating meshes or textures. Cirrus still use the lightweight surface renderer.
@@ -5910,7 +5910,7 @@ void main()
5910
5910
  `+i.vertexShader,i.vertexShader=i.vertexShader.replace("#include <project_vertex>",`#include <project_vertex>
5911
5911
  cloudPoint = (modelMatrix * vec4(transformed, 1.0)).xyz - cameraPosition;`);let r=`varying vec3 cloudPoint;
5912
5912
  `,a="";t.forEach((o,c)=>{const l=`cloud${c}_`;for(const[h,u]of Object.entries(o.uniforms))i.uniforms[l+h]=u;r+=m3(l),a+=`diffuseColor.a *= ${l}transmissionAt(normalize(cloudPoint), length(cloudPoint));
5913
- `}),i.fragmentShader=r+i.fragmentShader,i.fragmentShader=i.fragmentShader.replace("#include <opaque_fragment>",a+"#include <opaque_fragment>")},e.needsUpdate=!0}meshes=new Map;signatures=new Map;extents=new Map;placed=[];frame;direction=new C;up=new C;lookAt=new Xe;vertex=new C;centre=new C;right=new C;above=new C;set(e,t){this.placed=e,this.frame=t;const n=new Set(e.map(i=>i.sourceId));for(const[i,r]of this.meshes)n.has(i)||(this.dispose(r),this.meshes.delete(i),this.signatures.delete(i),this.extents.delete(i));for(const i of e){let r=this.meshes.get(i.sourceId);r||(r=new Ye(new Vi(1,1,Yn.SEGMENTS,Yn.SEGMENTS),new Fi({transparent:!0,depthWrite:!1,depthTest:!0,fog:!1,toneMapped:!1})),this.configureCloudMaterial(r.material),r.frustumCulled=!1,r.layers.set(zm),this.scene.add(r),this.meshes.set(i.sourceId,r)),r.renderOrder=Pb+i.renderOrder,r.visible=!i.hidden&&i.shape.transparency<1,r.visible&&this.paint(r,i,t)}}place(e,t,n){const i=this.frame;if(i)for(const r of this.placed){const a=this.meshes.get(r.sourceId);if(!a||!a.visible)continue;const o=this.extents.get(r.sourceId);if(!o)continue;const{bounds:c}=r.shape;let l=c.x+c.width/2,h=c.y+c.height/2,u=!0;if(r.aim){const d=n(Yn.directionOf(r.aim,this.direction));d&&Math.abs(d.ndcX)<Yn.FURTHEST_NDC&&Math.abs(d.ndcY)<Yn.FURTHEST_NDC?(l=(d.ndcX+1)/2*i.canvasWidthPx,h=(1-d.ndcY)/2*i.canvasHeightPx):u=!1}u?this.curve(a,e,t,i,o,l,h,r.distanceM):this.flat(a,e,i,o,r.distanceM)}}static FURTHEST_NDC=4;curve(e,t,n,i,r,a,o,c){const l=a-r.width/2,h=o-r.height/2,u=e.geometry.attributes.position,d=Yn.SEGMENTS;let f=0;for(let p=0;p<=d;p++){const v=h+p/d*r.height;for(let g=0;g<=d;g++){const m=l+g/d*r.width;n(m/i.canvasWidthPx*2-1,-(v/i.canvasHeightPx*2-1),this.direction),this.vertex.copy(t.position).addScaledVector(this.direction,c),u.setXYZ(f++,this.vertex.x,this.vertex.y,this.vertex.z)}}u.needsUpdate=!0,e.matrixAutoUpdate=!1,e.matrix.identity(),e.matrixWorldNeedsUpdate=!0,e.scale.set(mt.sizeMAt(c,i.projection.pxToDeg(r.width)),mt.sizeMAt(c,i.projection.pxToDeg(r.height)),1)}flat(e,t,n,i,r){const a=e.geometry.attributes.position,o=Yn.SEGMENTS,c=mt.sizeMAt(r,n.projection.pxToDeg(i.width)),l=mt.sizeMAt(r,n.projection.pxToDeg(i.height));this.up.set(0,1,0).applyQuaternion(t.quaternion),this.centre.copy(t.position).addScaledVector(this.direction,r),this.lookAt.lookAt(t.position,this.centre,this.up),this.right.setFromMatrixColumn(this.lookAt,0),this.above.setFromMatrixColumn(this.lookAt,1);let h=0;for(let u=0;u<=o;u++){const d=.5-u/o;for(let f=0;f<=o;f++){const p=f/o-.5;this.vertex.copy(this.centre).addScaledVector(this.right,p*c).addScaledVector(this.above,d*l),a.setXYZ(h++,this.vertex.x,this.vertex.y,this.vertex.z)}}a.needsUpdate=!0,e.matrixAutoUpdate=!1,e.matrix.identity(),e.matrixWorldNeedsUpdate=!0,e.scale.set(c,l,1)}static SEGMENTS=16;static directionOf(e,t){const n=e.azimuthDeg*Math.PI/180,i=e.altitudeDeg*Math.PI/180;return t.set(Math.sin(n)*Math.cos(i),Math.sin(i),-Math.cos(n)*Math.cos(i))}get any(){for(const e of this.meshes.values())if(e.visible)return!0;return!1}get furthestM(){return this.placed.reduce((e,t)=>Math.max(e,t.distanceM),0)}paint(e,t,n){const{shape:i}=t,r=Xl.paintExtent(i);this.extents.set(t.sourceId,r);const a=Yn.signatureOf(i,n);if(this.signatures.get(t.sourceId)===a&&e.material.map)return;this.signatures.set(t.sourceId,a);const o=Math.min(n.scale,Ib/Math.max(r.width,r.height,1)),c=Math.max(1,Math.ceil(r.width*o)),l=Math.max(1,Math.ceil(r.height*o)),h=e.material.map,u=h?.image??document.createElement("canvas"),d=u.width!==c||u.height!==l;d&&(u.width=c,u.height=l);const f=u.getContext("2d");if(!f)return;f.clearRect(0,0,c,l);const p=new Xl(f);if(p.setStarPoints(n.starPoints),p.setRoll(n.rollRad),p.paintInto(i,r,o),h&&!d){h.needsUpdate=!0;return}h?.dispose();const v=new yi(u);v.colorSpace=Cn,v.minFilter=_t,v.generateMipmaps=!1,e.material.map=v,e.material.needsUpdate=!0}static signatureOf(e,t){const{bounds:n}=e;return JSON.stringify([e.kind,Math.round(n.width*10),Math.round(n.height*10),e.color,e.angle,e.transparency,e.haloScale,e.blur??0,e.brightness??0,e.kind==="polygon"?e.points:void 0,t.scale,t.starPoints,t.rollRad])}dispose(e){e.removeFromParent(),e.geometry.dispose(),e.material.map?.dispose(),e.material.dispose()}clear(){for(const e of this.meshes.values())this.dispose(e);this.meshes.clear(),this.signatures.clear(),this.extents.clear(),this.placed=[]}}function Lb(s,e){return JSON.stringify(s.cloudLayers)===JSON.stringify(e.cloudLayers)&&s.cloudCover===e.cloudCover&&s.cloudDarkness===e.cloudDarkness&&s.cloudBaseM===e.cloudBaseM&&s.highCloudCover===e.highCloudCover&&s.iceCrystalAlignment===e.iceCrystalAlignment&&s.lowerCloudCover===e.lowerCloudCover&&s.precipitationType===e.precipitationType&&s.precipitationIntensity===e.precipitationIntensity&&s.windDirectionDeg===e.windDirectionDeg&&s.windSpeed===e.windSpeed&&s.storm===e.storm}const Ro=900,Rl=1,Tf=.5,oa=900,Nb=6371e3,Ob=3e4;function Rf(s){const e=Math.sqrt(2*Nb*Math.max(s,0));return Math.max(oa,Math.min(e,Ob))}const Dl=.5,Df=850,Ub=.03,Do=850,Cl=4,Cf=1.5,Pf=-1,Fb=6,pu=-4,If=.2,Co=2600,zb=.97,kb=.38,Lf=pu,Bb=3,Hb=.15,Gb=.6,Vb=40,Wb=30,Xb=[0,45,90,135,180,225,270,315],qb={en:["N","NE","E","SE","S","SW","W","NW"],fr:["N","NE","E","SE","S","SO","O","NO"]},Yb=["en","fr"],Kb=880,Pl=40,$b=60,Zb=10,Jb=1,Qb=150,jb=55,eE=.5,tE=2.05,Nf=.265,Of=[[0,0],...Array.from({length:8},(s,e)=>{const t=e*Math.PI/4;return[Math.cos(t)*Nf,Math.sin(t)*Nf]})],Il=700,Ll=250/1e3,nE=12,Uf=5,Nl=6,Ms=[.92,.92,.95],Ol=[.15,.15,.19],Ff={snow:{fallSpeedMPerS:2,size:.3,color:new ce(1,1,1),driftSensitivity:1,radiusM:25,topYM:20,opacity:.75,poolSize:2400},hail:{fallSpeedMPerS:14,size:.5,color:new ce(.95,.98,1),driftSensitivity:.25,radiusM:25,topYM:10,opacity:.95,poolSize:1200}},hr=0,Ul=0,iE=150,zf=3e3,ea=20,sE=15,kf=hr,rE=40,Bf=1,aE=9;function Hf(s){return Bf+(aE-Bf)*s}const oE=new ce(.75,.82,.92),cE=10,lE=.5;function hE(s){return dc(s/cE,lE,1)}const cr=200,Gf=.18,Vf=.32,uE=.35,dE=new ce(.85,.9,.98),Wf=5,Xf=.85,qf=.01;function Fl(s,e){return Math.round(s*(qf+(1-qf)*e))}const Yf=230,Kf=.7,$f=.05,fE=.6,pE=.7,mE=.15,Zf=.35,gE=3,vE=1/12,xE=.5,Jf=8,Qf=25,jf=.12,ME={Venus:new ce(1,.96,.85),Mars:new ce(1,.55,.4),Jupiter:new ce(.95,.87,.72),Saturn:new ce(.92,.86,.68)};class ci{renderer;scene=new xc;phenomena=new Yn(this.scene);camera;celestialGroup=new an;skyMesh;groundMesh;terrainMesh;terrainProviders;terrainOrigin;terrainBuildToken=0;terrainAttribution;decorModelProvider=Db[0].create();decorModelToken=0;decorModelCredits=new Map;starTiers=[];bodyMeshes=new Map;hitAreas=new Map;glareSprites=new Map;decorObjects=[];decorGroups=new Map;decorReferencePose;decorCurrentPose;decorTime=0;celestialLight=new jv(16777215,0);celestialLightTarget=new yt;skyLight=new Kv(16777215,0,0);streetlightLights=new Map;compassSprites=[];showCompass=!1;compassHovered=!1;compassForced=!1;animationFrameId=null;raycaster=new ol;weather=ip;observerElevationM=0;groundRadius=oa;terrainRadius=oa;cloudRendering="surface";layeredClouds;cloudLayerOffsetsM={};cloudOffsetM=new C;cloudFieldOffset=new C;cloudMesh;cirrusMesh;cirrusMaterial;cirrusUniforms;cloudMaterial;cloudUniforms;precipitationPoints;precipitationPositions;precipitationPhase;precipitationSpeedJitter;precipitationWobbleFreqJitter;precipitationWobbleAmpJitter;precipitationBounceRemaining;precipitationBounceHeight;precipitationBounceDuration;precipitationBounceVelX;precipitationBounceVelZ;precipitationUniforms;rainSystem;rainSplashSystem;rainCameraDirection=new C;rainLastVerticalFacing=-1;rainViewportSize=new Pe;lightningArmed=!1;nextLightningAtS=null;lightningFlashRemainingS=0;baseFogColor=[0,0,0];lastSunPosition;lensFlare;sunCloudTransmission=1;sunUnhiddenFraction=1;lensFlareArtifactIntensity=0;sunWorldPosition=new C;sunVisible=!1;lensFlareScratch=new C;sunOcclusionRaycaster=new ol;sunOcclusionDirectionScratch=new C;sunOcclusionRightScratch=new C;sunOcclusionUpScratch=new C;ufoOcclusionRaycaster=new ol;projectionKind="rectilinear";starPoints=0;namedStars=[];equidistantPass;depthOfFieldPass;exposureAccumulation;exposureInstants=1;get developingExposure(){return this.exposureInstants>1&&this.exposureInstantAt!==void 0}static EXPOSURE_BUDGET_MS=12;exposureFrameId=null;exposureInstantsDone=0;exposureInstantAt;restatingExposure=!1;lensOptics;instrumentMagnitudeGain=0;meteorSystem;cometTail;iceHalos;rainbow;skyGlow;cometKey;onLightningFlash;constructor(e,t=Kg(),n){this.renderer=new a3({canvas:e,antialias:!0}),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio||1,2)),this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=ca,this.camera=new Sn(60,e.width/Math.max(e.height,1),.1,Ro*1.2),this.camera.position.set(0,1.6,0),this.terrainProviders=t,this.onLightningFlash=n,this.celestialLight.shadow.mapSize.set(1024,1024),this.celestialLight.shadow.camera.left=-120,this.celestialLight.shadow.camera.right=120,this.celestialLight.shadow.camera.top=120,this.celestialLight.shadow.camera.bottom=-120,this.celestialLight.shadow.camera.near=1,this.celestialLight.shadow.camera.far=1e3,this.celestialLight.shadow.bias=-.0015,this.celestialLight.target=this.celestialLightTarget,this.scene.add(this.celestialLight,this.celestialLightTarget,this.skyLight),this.scene.add(this.celestialGroup)}get currentTerrainAttribution(){return this.terrainAttribution}resize(e,t){this.renderer.setSize(e,t,!1),this.camera.aspect=e/Math.max(t,1),this.camera.updateProjectionMatrix(),this.render()}setCloudRendering(e){e!==this.cloudRendering&&(this.cloudRendering=e,this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.buildClouds(),this.buildCirrus(),this.render())}setCloudOffset(e,t={}){this.cloudOffsetM.set(e.x,0,e.z),this.cloudLayerOffsetsM=t,this.layeredClouds?.setOffsets(e,t),this.cloudFieldOffset.set(e.x*Ll,0,e.z*Ll);for(const n of[this.cloudUniforms,this.cirrusUniforms])n?.fieldOffset.value.copy(this.cloudFieldOffset);this.iceHalos?.setCloudOffset(this.layeredClouds?.cirrusMask?.offset??this.cloudFieldOffset)}setObserverPose(e){const t=((e.rollDeg??0)+this.gaitOffset.rollDeg)*Tn,n=(e.pitchDeg+this.lookPitchDeg+this.gaitOffset.pitchDeg)*Tn;if(e.headingDeg!==void 0?this.camera.rotation.set(n,-(e.headingDeg+this.lookYawDeg+this.gaitOffset.yawDeg)*Tn,t,"YXZ"):this.camera.rotation.set(n,this.camera.rotation.y,t,"YXZ"),e.elevationM!==this.observerElevationM&&(this.observerElevationM=e.elevationM,this.syncCloudLayer(),Math.abs(Rf(e.elevationM)-this.groundRadius)>1&&(this.buildGround(),this.celestialGroup.scale.setScalar(this.groundRadius/oa),this.camera.far=Math.max(Ro*1.2,this.groundRadius*2.5),this.camera.updateProjectionMatrix())),this.terrainMesh&&this.terrainOrigin&&e.lat!==void 0&&e.lng!==void 0){const i=rn(this.terrainOrigin.lat,this.terrainOrigin.lng,e.lat,e.lng);this.terrainMesh.position.x=i.x,this.terrainMesh.position.z=i.z}this.poseCameraY=this.groundYUnder(0,0)+1.6+e.elevationM,this.camera.position.y=this.poseCameraY,this.celestialGroup.position.y=this.camera.position.y,this.camera.fov!==e.fovDeg&&(this.camera.fov=e.fovDeg,this.camera.updateProjectionMatrix(),this.updateCompassScale())}setTerrainProviders(e){this.terrainProviders=e,this.disposeMesh(this.terrainMesh),this.terrainMesh=void 0,this.terrainOrigin=void 0,this.terrainAttribution=void 0,this.applyGroundDepthWrite(),this.terrainBuildToken++}setTerrainOrigin(e,t,n){if(e===void 0||t===void 0)return;const i=this.groundRadius;if(this.terrainOrigin&&Math.abs(this.terrainRadius-i)<i*.1){const{x:c,z:l}=rn(e,t,this.terrainOrigin.lat,this.terrainOrigin.lng);if(Math.sqrt(c*c+l*l)<Qb*(i/oa))return}const r=this.terrainOrigin,a=this.terrainRadius;this.terrainOrigin={lat:e,lng:t},this.terrainRadius=i;const o=++this.terrainBuildToken;JS(e,t,this.terrainProviders,i).then(({mesh:c,attribution:l})=>{if(o!==this.terrainBuildToken)return;const h=this.terrainMesh,u=r?rn(e,t,r.lat,r.lng):void 0;h&&u&&Math.hypot(u.x,u.z)<=a&&(c.position.y=h.position.y+this.groundYOfPatch(h,u.x,u.z)),this.disposeMesh(this.terrainMesh),c.renderOrder=Jb,this.terrainMesh=c,this.terrainAttribution=l,this.scene.add(c),this.applyGroundDepthWrite(),this.decorCurrentPose&&(this.setObserverPose(this.decorCurrentPose),this.updateDecorAnchoring(this.decorReferencePose,this.decorCurrentPose,this.decorTime)),this.render(),n?.()}).catch(c=>{console.warn("Terrain build failed, keeping the flat ground fallback:",c),n?.()})}setShowCompass(e){this.showCompass!==e&&(this.showCompass=e,this.disposeCompassLabels(),e&&this.buildCompassLabels(),this.render())}applyLensFlareTint(e){if(!this.lensFlare)return;const t=jb*this.sunCloudTransmission;this.lensFlare.uniforms.uColorGain.value.setRGB(t*e[0],t*e[1],t*e[2]),this.applyDazzleStrength()}applyDazzleStrength(){if(!this.lensFlare)return;const e=this.lastSunPosition?.altitudeDeg??-90,t=k3(e)*this.sunCloudTransmission*this.sunUnhiddenFraction,n=vs(e);this.lensFlare.uniforms.uDazzleColour.value.setRGB(n[0],n[1],n[2]),this.lensFlare.uniforms.uVeilStrength.value=tE**2*Math.max(0,t)}setCompassHovered(e){this.compassHovered!==e&&(this.compassHovered=e,this.updateCompassVisibility())}setCompassForced(e){this.compassForced!==e&&(this.compassForced=e,this.updateCompassVisibility())}updateCompassVisibility(){const e=this.compassHovered||this.compassForced;for(const t of this.compassSprites)t.visible=e;this.render()}setWeather(e){Lb(this.weather,e)||(this.weather=e,this.buildClouds(),this.buildCirrus(),this.buildPrecipitation(),this.lightningArmed=e.storm&&e.cloudDarkness>=xE,this.lightningArmed||(this.nextLightningAtS=null,this.lightningFlashRemainingS=0,this.restoreFogColor()),this.syncAnimationLoop(),this.render())}setDecor(e){if(this.decorObjects!==e){this.decorObjects=e,this.decorModelToken++,this.decorModelCredits.clear();for(const t of this.decorGroups.values())t.removeFromParent(),Jt.dispose(t);this.decorGroups.clear(),this.streetlightLights.clear();for(const t of e){const n=Jt.build(t,t.lit??!1);this.scene.add(n),this.decorGroups.set(t.id,n),t.kind==="streetlight"&&this.addStreetlightLight(t.id,n),this.loadDecorModel(t,this.decorModelToken)}this.celestialLight.castShadow=this.decorGroups.size>0}}setDecorModelProvider(e){this.decorModelProvider=e;const t=this.decorObjects;this.decorObjects=[],this.setDecor(t)}get currentDecorModelCredits(){return[...this.decorModelCredits.values()]}async loadDecorModel(e,t){const n=e.model;if(!(!n||!Jt.usesModel(e)))try{const i=n.url?void 0:n.id?await this.decorModelProvider.entry(n.id):void 0,r=n.url??i?.url,a=n.credit??i?.credit;if(!r||!a)return;const o=await Cb(r);if(t!==this.decorModelToken)return;const c=this.decorGroups.get(e.id);if(!c)return;Jt.applyModel(c,e,o,{headingOffsetDeg:n.headingOffsetDeg??i?.headingOffsetDeg,depictedSizeM:i?.sizeM}),this.decorModelCredits.set(e.id,a),this.render()}catch(i){console.warn(`Keeping the built-in shape for decor "${e.id}":`,i)}}updateDecorAnchoring(e,t,n=0){this.decorReferencePose=e,this.decorCurrentPose=t,this.decorTime=n;const i=e?.lat!==void 0&&e.lng!==void 0&&t?.lat!==void 0&&t?.lng!==void 0?rn(e.lat,e.lng,t.lat,t.lng):{x:0,z:0},r=this.decorObjects.find(l=>l.witnessSide!==void 0&&cp(l.kind));r||(i.x-=this.gaitOffset.eastM,i.z+=this.gaitOffset.northM,this.camera.position.y=this.poseCameraY+this.gaitOffset.upM,this.celestialGroup.position.y=this.camera.position.y);const a={x:0,z:0};let o=0;if(r){const l=Jt.occupantView(r),h=-(r.headingDeg??0)*Tn,u=l.x*Math.cos(h)+l.z*Math.sin(h),d=-l.x*Math.sin(h)+l.z*Math.cos(h),f=r.eastM+i.x,p=-r.northM+i.z;a.x=-(f+u),a.z=-(p+d),this.camera.position.y=this.groundYUnder(f,p)+l.eyeY,this.camera.rotation.set(this.indoorLookPitchDeg*Tn,-(l.headingDeg+this.indoorLookYawDeg)*Tn,0,"YXZ")}for(const l of this.decorObjects){const h=this.decorGroups.get(l.id);if(!h)continue;const u=vu(l,n),d=u.eastM+i.x+a.x,f=-u.northM+i.z+a.z;if(h.position.set(d,this.groundUnderFootprint(l,d,f,u.headingDeg)+u.altitudeM,f),l.kind==="crop"){const p=Math.hypot(d,f);h.visible=p<=iE}if(u.headingDeg!==void 0&&(h.rotation.y=-u.headingDeg*Tn),l.kind==="crop"&&h.visible){const p=this.terrainMesh,v=[p?.geometry.uuid,d-(p?.position.x??0),f-(p?.position.z??0),h.position.y-(p?.position.y??0),u.headingDeg,u.altitudeM].map(g=>typeof g=="number"?g.toFixed(4):g).join(":");h.userData.cropGroundKey!==v&&(Jt.fitCropToGround(h,(g,m)=>this.groundYUnder(g,m)+u.altitudeM),h.userData.cropGroundKey=v)}o=Math.max(o,h.position.distanceTo(this.camera.position))}const c=Math.max(Ro*1.2,this.groundRadius*2.5,o*1.2);Math.abs(this.camera.far-c)>1&&(this.camera.far=c,this.camera.updateProjectionMatrix())}groundYUnder(e,t){const n=this.terrainMesh;return n?n.position.y+this.groundYOfPatch(n,e-n.position.x,t-n.position.z):Ul}groundYOfPatch(e,t,n){const i=e.geometry.getAttribute("position"),r=Math.round(Math.sqrt(i.count));if(r<2||r*r!==i.count)return Ul;const a=i.getX(0),o=i.getX(r-1),c=i.getZ(0),l=i.getZ((r-1)*r),h=dc((t-a)/(o-a)*(r-1),0,r-1),u=dc((n-c)/(l-c)*(r-1),0,r-1);if(!Number.isFinite(h)||!Number.isFinite(u))return Ul;const d=Math.min(Math.floor(h),r-2),f=Math.min(Math.floor(u),r-2),p=h-d,v=u-f,g=(S,w)=>i.getY(S*r+w),m=g(f,d),E=g(f,d+1),b=g(f+1,d),_=g(f+1,d+1);return p+v<=1?m+(E-m)*p+(b-m)*v:_+(b-_)*(1-p)+(E-_)*(1-v)}groundUnderFootprint(e,t,n,i){return Jt.groundUnderFootprint(e,t,n,i,(r,a)=>this.groundYUnder(r,a))}lookYawDeg=0;lookPitchDeg=0;poseCameraY=1.6;setGait(e){this.gaitOffset=e}gaitOffset={eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0};setLookOffset(e,t){this.lookYawDeg=e,this.lookPitchDeg=t}indoorLookYawDeg=0;indoorLookPitchDeg=0;setIndoorLook(e,t){this.indoorLookYawDeg=e,this.indoorLookPitchDeg=t}updateDecorLitState(e,t=0){for(const n of this.decorObjects){const i=this.decorGroups.get(n.id);if(i&&n.lights?.length&&Jt.setLights(i,n.lights,e,i.position.distanceTo(this.camera.position),t),n.kind!=="streetlight"&&n.kind!=="vehicle")continue;const r=this.decorGroups.get(n.id);if(!r)continue;const a=Og(n,e);Jt.setLit(r,n.kind,a);const o=this.streetlightLights.get(n.id);o&&(o.visible=a)}}addStreetlightLight(e,t){const n=Jt.bodyOf(t),i=n.children.find(a=>a.userData.emissive);if(!i)return;const r=new Jv(16764006,Vb,Wb);r.position.copy(i.position).multiply(n.scale),r.castShadow=!0,r.shadow.mapSize.set(512,512),r.shadow.bias=-.002,t.add(r),this.streetlightLights.set(e,r)}setAstronomy(e){const t=Xh(e.sun.altitudeDeg),n=t.horizon;this.baseFogColor=n,this.lastSunPosition=e.sun,this.buildSky(e.sun),this.buildGround(),this.updateCloudLighting(e.sun,n),this.updateCelestialLight(e,t.zenith,n);const i=sm(e.sun.altitudeDeg,this.instrumentMagnitudeGain);this.buildStars(e.stars,i),this.setBodyMesh("sun",e.sun,Cl,new ce(1,.96,.88),e.sun.magnitude),this.setMoonMesh(e.moon,i),this.buildPlanets(e.planets,i),this.buildComet(e.comet,i),this.buildIceHalos(e.sun,e.moon),this.buildRainbow(e.sun,e.moon),this.buildSkyGlow(e,t.zenith),this.scene.fog=new Pu(new ce(...n),this.groundRadius*.2,this.groundRadius),this.syncAnimationLoop(),this.render()}updateCelestialLight(e,t,n){this.skyLight.color.setRGB(t[0],t[1],t[2]),this.skyLight.groundColor.setRGB(n[0],n[1],n[2]),this.skyLight.intensity=Gb;const i=e.sun.altitudeDeg>=Lf,r=!i&&e.moon.altitudeDeg>=Lf;if(!i&&!r){this.celestialLight.intensity=0;return}const a=i?e.sun:e.moon,{x:o,y:c,z:l}=fn(a.altitudeDeg,a.azimuthDeg,Do);this.celestialLight.position.set(o,c,l);const h=vs(a.altitudeDeg);this.celestialLight.color.setRGB(h[0],h[1],h[2]);const u=Math.max(0,Math.sin(Math.max(a.altitudeDeg,0)*Tn));this.celestialLight.intensity=(i?Bb:Hb)*u,this.celestialLight.castShadow=this.decorGroups.size>0}setMeteorShower(e,t,n){this.meteorSystem||(this.meteorSystem=new Kt,this.celestialGroup.add(this.meteorSystem.object)),this.meteorSystem.setShower(e,t,n)}get meteorSchedule(){return this.meteorSystem?.schedule??[]}meteorMidpoint(e){return this.meteorSystem?.midpointOf(e)}updateMeteors(e){this.meteorSystem?.update(e)}setInstrument(e){this.projectionKind=e.projection;const t=Ht.starPointsOf(e),n=Ht.flareArtifactsOf(e);t===this.starPoints&&n===this.lensFlareArtifactIntensity||(this.starPoints=t,this.lensFlareArtifactIntensity=n,this.lensFlare&&(this.lensFlare.uniforms.uStarPoints.value=t,this.lensFlare.uniforms.uFlareIntensity.value=n),this.render())}setInstrumentGain(e){this.instrumentMagnitudeGain=Number.isFinite(e)?e:0}render(){this.restatingExposure||(this.renderOnce(),this.developingExposure&&this.startExposure())}setExposure(e,t){const n=t?Math.max(1,Math.round(e)):1;if(n===this.exposureInstants&&(n===1||t===this.exposureInstantAt)){this.exposureInstantAt=t;return}this.exposureInstants=n,this.exposureInstantAt=t,n===1&&(this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0),this.render()}renderOnce(e){const t=this.usableEquidistantPass();this.phenomena.setCloudLayers(this.layeredClouds?.volumes??[]),this.phenomena.place(this.camera,(r,a,o)=>this.directionAtScreenPoint(r,a,o),r=>this.screenPointOf(r));const n=this.phenomena.furthestM*1.2;n>this.camera.far&&(this.camera.far=n,this.camera.updateProjectionMatrix());const i=this.renderer.getRenderTarget();if(!t){this.updateLensFlarePosition();const r=this.usableDepthOfFieldPass();r?.setEncodesOutput(e===void 0),this.skyGlow?.setDestinationEncoded(e===void 0&&!r),e&&this.renderer.setRenderTarget(e),r?r.render(this.renderer,this.scene,this.camera,()=>this.renderPhenomenaPass()):(this.renderer.render(this.scene,this.camera),this.renderPhenomenaPass()),e&&this.renderer.setRenderTarget(i);return}t.setEncodesOutput(e===void 0),this.skyGlow?.setDestinationEncoded(!1),e&&this.renderer.setRenderTarget(e),t.render(this.renderer,this.scene,this.camera,this.camera.fov,()=>this.updateLensFlarePosition(),()=>this.renderPhenomenaPass()),e&&this.renderer.setRenderTarget(i)}renderPhenomenaPass(){if(!this.phenomena.any)return;const e=this.renderer.autoClear,t=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,this.renderer.clearDepth();for(const n of this.decorObjects){const i=this.decorGroups.get(n.id);i&&ci.markDecorDepth(i,n.kind!=="crop")}this.camera.layers.set(Rl),this.scene.overrideMaterial=this.decorDepthMaterial,this.renderer.render(this.scene,this.camera),this.scene.overrideMaterial=null,this.camera.layers.set(zm),this.renderer.render(this.scene,this.camera),this.camera.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=t}decorDepthMaterial=new Fi({colorWrite:!1});static markDecorDepth(e,t){e.traverse(n=>{if(!(n instanceof Ye))return;const i=Array.isArray(n.material)?n.material[0]:n.material;t&&i.depthWrite!==!1&&i.blending!==Qn?n.layers.enable(Rl):n.layers.disable(Rl)})}startExposure(){this.cancelExposure();const e=this.renderer.getDrawingBufferSize(new Pe),t=Math.max(1,Math.round(e.x)),n=Math.max(1,Math.round(e.y));this.exposureAccumulation||(this.exposureAccumulation=new v3(t,n)),this.exposureAccumulation.resize(t,n),this.exposureAccumulation.open(this.renderer),this.exposureInstantsDone=0,this.exposureFrameId=requestAnimationFrame(()=>this.developExposure())}developExposure(){this.exposureFrameId=null;const e=this.exposureInstantAt,t=this.exposureAccumulation;if(!e||!t)return;const n=1/this.exposureInstants,i=performance.now()+ci.EXPOSURE_BUDGET_MS;do this.restateAt(e,this.exposureInstantsDone),this.renderOnce(t.instantTarget),t.add(this.renderer,n),this.exposureInstantsDone++;while(this.exposureInstantsDone<this.exposureInstants&&performance.now()<i);this.restateAt(e,0),t.develop(this.renderer,this.exposureInstants/this.exposureInstantsDone),this.exposureInstantsDone<this.exposureInstants&&(this.exposureFrameId=requestAnimationFrame(()=>this.developExposure()))}restateAt(e,t){this.restatingExposure=!0;try{e(t)}finally{this.restatingExposure=!1}}cancelExposure(){this.exposureFrameId!==null&&(cancelAnimationFrame(this.exposureFrameId),this.exposureFrameId=null)}setLensOptics(e){const t=this.lensOptics;this.lensOptics=e,(t===void 0!=(e===void 0)||t&&e&&(t.focalLengthMm!==e.focalLengthMm||t.fNumber!==e.fNumber||t.focusDistance!==e.focusDistance||t.frameHeightMm!==e.frameHeightMm))&&(e&&this.depthOfFieldPass&&this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.render())}usableDepthOfFieldPass(){const e=this.lensOptics;if(!e)return;const t=this.renderer.getDrawingBufferSize(new Pe),n=Math.max(1,Math.round(t.x)),i=Math.max(1,Math.round(t.y));return this.depthOfFieldPass||(this.depthOfFieldPass=new da(n,i)),this.depthOfFieldPass.resize(n,i),this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.depthOfFieldPass}usableEquidistantPass(){if(this.projectionKind!=="equidistant")return;const e=this.renderer.getDrawingBufferSize(new Pe);if(ua.supports(this.camera.fov,e.x/Math.max(e.y,1)))return this.equidistantPass?this.equidistantPass.resize(e.x,e.y):this.equidistantPass=new ua(e.x,e.y),this.equidistantPass}aimAtScreenPoint(e,t,n){const i=this.projectionKind==="equidistant"?this.equidistantPass:void 0;if(!i){e.setFromCamera(new Pe(t,n),this.camera);return}const r=i.directionFor(t,n,this.camera.fov);this.camera.updateMatrixWorld(),e.ray.origin.setFromMatrixPosition(this.camera.matrixWorld),e.ray.direction.set(r.x,r.y,r.z).applyQuaternion(this.camera.quaternion).normalize(),e.camera=this.camera}pickCloudAt(e,t){return this.layeredClouds?.pickInstance(this.cloudDirectionAt(e,t))}cloudDirectionAt(e,t){return this.directionAtScreenPoint(e,t,new C)}directionAtScreenPoint(e,t,n){return this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),n.copy(this.ufoOcclusionRaycaster.ray.direction)}screenPointOf(e){this.camera.updateMatrixWorld();const t=this.screenPointScratch.copy(e).applyQuaternion(this.screenPointQuaternion.copy(this.camera.quaternion).invert());if(t.z>=0)return;const n=this.renderer.getDrawingBufferSize(this.screenPointSize),i=n.x/Math.max(n.y,1);if(this.projectionKind==="equidistant"&&this.equidistantPass)return ua.ndcFor(t,this.camera.fov,i);const r=Math.tan(this.camera.fov/2*Tn);return{ndcX:t.x/-t.z/(i*r),ndcY:t.y/-t.z/r}}screenPointScratch=new C;screenPointQuaternion=new us;screenPointSize=new Pe;updateLensFlarePosition(){const e=this.lensFlare;if(!e)return;if(!this.sunVisible){e.mesh.visible=!1;return}if(this.camera.updateMatrixWorld(),this.lensFlareScratch.copy(this.sunWorldPosition).applyMatrix4(this.camera.matrixWorldInverse),this.lensFlareScratch.z>0){e.mesh.visible=!1;return}const t=this.sunVisibleFraction();if(t<=0){e.mesh.visible=!1;return}e.mesh.visible=!0,this.sunUnhiddenFraction=t,this.applyDazzleStrength();const n=this.lensFlareScratch.copy(this.sunWorldPosition).project(this.camera);e.uniforms.uLensPosition.value.set(n.x,n.y);const i=this.renderer.domElement.width,r=this.renderer.domElement.height;e.uniforms.uResolution.value.set(i,r),e.uniforms.uTanHalfFov.value=Math.tan(this.camera.fov*Math.PI/360)}sunVisibleFraction(){let e=0;for(const t of Of)this.isSunOccluded(t[0],t[1])||e++;return e/Of.length}raycastableDecor(){const e=[];for(const t of this.decorObjects){if(t.kind==="crop")continue;const n=this.decorGroups.get(t.id);n&&e.push(n)}return e}isSunOccluded(e=0,t=0){this.scene.updateMatrixWorld();const n=[];this.groundMesh&&n.push(this.groundMesh),this.terrainMesh&&n.push(this.terrainMesh);for(const o of this.raycastableDecor())n.push(o);if(n.length===0)return!1;const i=this.sunOcclusionDirectionScratch.copy(this.sunWorldPosition).sub(this.camera.position),r=i.length();if(i.normalize(),e!==0||t!==0){const o=Math.PI/180,c=this.sunOcclusionRightScratch.set(i.z,0,-i.x);c.lengthSq()<1e-9&&c.set(1,0,0),c.normalize();const l=this.sunOcclusionUpScratch.crossVectors(c,i).normalize();i.addScaledVector(c,e*o).addScaledVector(l,t*o).normalize()}this.sunOcclusionRaycaster.set(this.camera.position,i);const a=this.sunOcclusionRaycaster.intersectObjects(n,!0)[0];return a!==void 0&&a.distance<r}setPhenomena(e,t){this.phenomena.set(e,t)}decorDistancesAt(e,t,n){this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=Tf;let i,r;for(const a of this.decorObjects){if(a.kind==="crop")continue;const o=this.decorGroups.get(a.id);if(!o)continue;const c=this.ufoOcclusionRaycaster.intersectObject(o,!0)[0];c&&(a.occludesSourceIds?.includes(n)?i=i===void 0?c.distance:Math.max(i,c.distance):r=r===void 0?c.distance:Math.min(r,c.distance))}return{behindM:i,inFrontM:r}}pickBodyAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const n=[...this.hitAreas.entries()],i=this.raycaster.intersectObjects(n.map(([,r])=>r))[0];if(i&&!this.groundHides(e,t))return n.find(([,r])=>r===i.object)?.[0]}pickStarAt(e,t){if(this.namedStars.length===0)return;this.aimAtScreenPoint(this.raycaster,e,t);const n=this.raycaster.ray.direction,i=Math.cos(Ub*this.camera.fov*Math.PI/180);let r,a=i;for(const o of this.namedStars){const c=o.direction.dot(n);c>a&&(a=c,r={star:o.star,altitudeDeg:o.altitudeDeg})}return r&&this.groundHides(e,t)?void 0:r}groundHides(e,t){const n=[this.terrainMesh,this.groundMesh].filter(i=>i!==void 0);return n.length===0?!1:(this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=Tf,this.ufoOcclusionRaycaster.intersectObjects(n,!0).length>0)}pickDecorAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const n=[...this.decorGroups.entries()],i=this.raycaster.intersectObjects(n.map(([,a])=>a),!0)[0];if(!i)return;let r=i.object;for(;r&&!n.some(([,a])=>a===r);)r=r.parent;return n.find(([,a])=>a===r)?.[0]}dispose(){this.stopTwinkle(),this.phenomena.clear(),this.terrainBuildToken++,this.disposeMesh(this.skyMesh),this.disposeMesh(this.groundMesh),this.disposeMesh(this.terrainMesh),this.disposeCloudSystem(),this.disposeCirrus(),this.disposePrecipitationPoints(),this.disposeRain(),this.disposeStarTiers(),this.meteorSystem?.dispose(),this.meteorSystem=void 0,this.iceHalos?.dispose(),this.iceHalos=void 0,this.rainbow?.dispose(),this.rainbow=void 0,this.skyGlow?.dispose(),this.skyGlow=void 0,this.depthOfFieldPass?.dispose(),this.depthOfFieldPass=void 0,this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0,this.cometTail?.dispose(),this.cometTail=void 0;for(const e of this.bodyMeshes.values())this.disposeMesh(e);this.bodyMeshes.clear();for(const e of[...this.hitAreas.keys()])this.disposeHitArea(e);for(const e of[...this.glareSprites.keys()])this.disposeGlare(e);this.disposeCompassLabels();for(const e of this.decorGroups.values())Jt.dispose(e);this.decorGroups.clear(),this.streetlightLights.clear(),this.lensFlare&&(this.lensFlare.mesh.removeFromParent(),this.lensFlare.mesh.geometry.dispose(),this.lensFlare.mesh.material.dispose(),this.lensFlare=void 0),this.renderer.dispose()}animationsRunning=!1;startTwinkle(){if(this.animationFrameId!==null||!this.needsAnimationLoop())return;let e;const t=n=>{const i=e===void 0?0:Math.min((n-e)/1e3,vE);e=n,this.updateTwinkle(n/1e3),this.updatePrecipitation(n/1e3,i),this.updateRain(i),this.updateLightning(n/1e3,i),this.lensFlare&&(this.lensFlare.uniforms.uTime.value=n/1e3),this.developingExposure||this.render(),this.animationFrameId=requestAnimationFrame(t)};this.animationFrameId=requestAnimationFrame(t)}setAnimationsRunning(e){e!==this.animationsRunning&&(this.animationsRunning=e,e?this.nextLightningAtS=null:this.lightningFlashRemainingS>0&&(this.lightningFlashRemainingS=0,this.restoreFogColor()),this.syncAnimationLoop(),e||this.render())}stopTwinkle(){this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}restoreFogColor(){this.scene.fog&&this.scene.fog.color.setRGB(...this.baseFogColor)}needsAnimationLoop(){return this.animationsRunning&&(this.starTiers.length>0||this.precipitationPoints!==void 0||this.rainSystem!==void 0||this.lightningArmed||this.lensFlare!==void 0&&this.sunVisible)}syncAnimationLoop(){this.needsAnimationLoop()?this.startTwinkle():this.stopTwinkle()}buildSky(e){this.disposeMesh(this.skyMesh);const t=new cn(Ro,32,16),n=t.attributes.position,i=[];for(let a=0;a<n.count;a++){const{altitudeDeg:o,azimuthDeg:c}=_3(n.getX(a),n.getY(a),n.getZ(a)),l=R3(o,c,e.azimuthDeg,e.altitudeDeg);i.push(l[0],l[1],l[2])}t.setAttribute("color",new bt(i,3));const r=new Fi({vertexColors:!0,side:Ft,fog:!1,depthWrite:!1});this.skyMesh=new Ye(t,r),this.skyMesh.renderOrder=-1,this.celestialGroup.add(this.skyMesh)}buildGround(){this.disposeMesh(this.groundMesh),this.groundRadius=Rf(this.observerElevationM);const e=new Nu(this.groundRadius,48),t=new Ta({color:new ce(Dl,Dl,Dl),fog:!0});this.groundMesh=new Ye(e,t),this.groundMesh.rotation.x=-Math.PI/2,this.groundMesh.position.y=0,this.groundMesh.receiveShadow=!0,this.scene.add(this.groundMesh),this.applyGroundDepthWrite()}applyGroundDepthWrite(){const e=this.groundMesh?.material;if(!e)return;const t=this.terrainMesh===void 0;e.depthWrite!==t&&(e.depthWrite=t,e.needsUpdate=!0)}cloudTransmission(e){const t=fn(e.altitudeDeg,e.azimuthDeg,1);if(this.layeredClouds)return this.layeredClouds.transmissionAt(t);let n=1;const i=this.lowerCloudCover();i>0&&(n*=1-Ct.alphaAt(t,Math.abs(this.cloudLayerOffset()),i,this.cloudFieldOffset)*zb);const r=this.weather.highCloudCover??0;return r>0&&(n*=1-Ct.alphaAt(t,Co,r)*kb),Math.max(0,Math.min(1,n))}setBodyMesh(e,t,n,i,r){if(this.disposeMesh(this.bodyMeshes.get(e)),this.disposeHitArea(e),this.disposeGlare(e),t.altitudeDeg<pu){this.bodyMeshes.delete(e),e==="sun"&&(this.sunVisible=!1);return}const{x:a,y:o,z:c}=fn(t.altitudeDeg,t.azimuthDeg,Do),l=vs(t.altitudeDeg),h=this.cloudTransmission(t),u=new ce(i.r*l[0]*h,i.g*l[1]*h,i.b*l[2]*h),d=new cn(n,16,16),f=new Fi({color:u,fog:!1}),p=new Ye(d,f);p.position.set(a,o,c),this.celestialGroup.add(p),this.bodyMeshes.set(e,p),this.setHitArea(e,a,o,c,n);const v=r-2.5*Math.log10(Math.max(h,.001));if(e==="sun"&&(this.sunCloudTransmission=h),e!=="sun"&&this.setGlare(e,a,o,c,v,u),e==="sun"){this.sunVisible=!0;const g=this.celestialGroup.scale.x;this.sunWorldPosition.set(a*g,o*g+this.celestialGroup.position.y,c*g),this.lensFlare||(this.lensFlare=ub(),this.lensFlare.uniforms.uOpacity.value=eE,this.lensFlare.uniforms.uFlareIntensity.value=this.lensFlareArtifactIntensity,this.lensFlare.uniforms.uStarPoints.value=this.starPoints,this.scene.add(this.lensFlare.mesh)),this.applyLensFlareTint(l)}}setMoonMesh(e,t){const n="moon";if(this.disposeMesh(this.bodyMeshes.get(n)),this.disposeHitArea(n),this.disposeGlare(n),e.magnitude>t||e.altitudeDeg<pu){this.bodyMeshes.delete(n);return}const{x:i,y:r,z:a}=fn(e.altitudeDeg,e.azimuthDeg,Do),o=vs(e.altitudeDeg),c=new ce(o[0],o[1],o[2]),l=new ia({map:DE(e.phase),color:c,fog:!1}),h=new Ja(l);h.position.set(i,r,a);const u=Cl*2;h.scale.set(u,u,1),this.celestialGroup.add(h),this.bodyMeshes.set(n,h),this.setHitArea(n,i,r,a,Cl),this.setGlare(n,i,r,a,e.magnitude,c)}setHitArea(e,t,n,i,r){const a=new ia({transparent:!0,opacity:0,depthTest:!1,depthWrite:!1,fog:!1}),o=new Ja(a);o.position.set(t,n,i);const c=r*Fb;o.scale.set(c,c,1),this.celestialGroup.add(o),this.hitAreas.set(e,o)}disposeHitArea(e){const t=this.hitAreas.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.hitAreas.delete(e))}setGlare(e,t,n,i,r,a){const o=P3(r);if(o<=0){this.disposeGlare(e);return}const c=N3(o),l=this.glareSprites.get(e),h=l??new Ja(new ia({map:RE(),transparent:!0,blending:Qn,depthWrite:!1,fog:!1}));h.material.color.copy(a),h.material.opacity=F3(o),h.position.set(t,n,i),h.scale.set(c*2,c*2,1),l||(this.celestialGroup.add(h),this.glareSprites.set(e,h))}disposeGlare(e){const t=this.glareSprites.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.glareSprites.delete(e))}buildComet(e,t){const n=e&&`comet:${e.id}`;if(!e||!n||e.magnitude>t){this.disposeComet();return}this.cometKey&&this.cometKey!==n&&this.disposeComet();const i=gl(e.magnitude,t),r=vl(i);this.cometKey=n,this.setBodyMesh(n,e.position,Cf*(.5+.5*i),new ce(r,r,r),e.magnitude),this.cometTail||(this.cometTail=new Rn(Do),this.celestialGroup.add(this.cometTail.object)),this.cometTail.set(e.position,e.tailEnd,i)}buildIceHalos(e,t){this.iceHalos||(this.iceHalos=new oi,this.iceHalos.setCloudOffset(this.cloudFieldOffset),this.iceHalos.onReady=()=>this.render(),this.celestialGroup.add(this.iceHalos.object));const n=this.highCloudCover(),i=this.layeredClouds?.cirrusMask;if(this.iceHalos.setCloudOffset(i?.offset??this.cloudFieldOffset),n===void 0){this.iceHalos.update({x:0,y:1,z:0},-1,0,[1,1,1],{cover:0,layerHeight:Co},0);return}const r=this.lowerCloudCover(),a=et.deckLitUntilDeg(et.DECK_HEIGHT_M),o=e.altitudeDeg>-a?e:t,c=et.strength(n,r,o.altitudeDeg,a)*(o===e?1:If),{x:l,y:h,z:u}=fn(o.altitudeDeg,o.azimuthDeg,1),d=vs(o.altitudeDeg);this.iceHalos.update({x:l,y:h,z:u},o.altitudeDeg,c,[d[0],d[1],d[2]],{cover:i?.cover??n,layerHeight:i?.layerHeight??Co},i?.iceCrystalAlignment??this.weather.iceCrystalAlignment??.65)}buildRainbow(e,t){this.rainbow||(this.rainbow=new fa,this.celestialGroup.add(this.rainbow.object));const n=this.weather.precipitationType==="rain"?this.weather.precipitationIntensity:0,i=e.altitudeDeg>0,r=i?e:t,a=this.lowerCloudCover(),o=If*yn.moonlightShare(t.magnitude),c=yn.strength(n,a,r.altitudeDeg)*(i?1:o);if(c<=0){this.rainbow.update({x:0,y:1,z:0},0,[1,1,1],!0);return}const{x:l,y:h,z:u}=fn(r.altitudeDeg,r.azimuthDeg,1),d=vs(r.altitudeDeg);this.rainbow.update({x:l,y:h,z:u},c,[d[0],d[1],d[2]],i)}buildSkyGlow(e,t){if(!e.frame){this.skyGlow?.hide();return}this.skyGlow||(this.skyGlow=new Xn,this.skyGlow.onReady=()=>this.render(),this.celestialGroup.add(this.skyGlow.object));const{date:n,observer:i}=e.frame,r=qn.galactic(n,i),a=ci.directionOf(r.centre),o=ci.directionOf(r.rotation),c=ci.directionOf(r.pole),l=new ke().set(a.x,a.y,a.z,o.x,o.y,o.z,c.x,c.y,c.z),h=ci.directionOf(qn.eclipticPole(n,i)),u=ci.directionOf(e.sun),d=u.clone().addScaledVector(h,-u.dot(h)).normalize();this.skyGlow.update({galactic:l,eclipticPole:h,sunLongitude:d,sunDirection:u,sunAltitudeDeg:e.sun.altitudeDeg,moon:{direction:ci.directionOf(e.moon),altitudeDeg:e.moon.altitudeDeg,phaseAngleDeg:Ze.phaseAngleOf(e.moon.phase.illuminatedFraction)},skyColor:new C(t[0],t[1],t[2])})}static directionOf(e){const{x:t,y:n,z:i}=fn(e.altitudeDeg,e.azimuthDeg,1);return new C(t,n,i).normalize()}disposeComet(){this.cometTail?.set(void 0,void 0,0),this.cometKey&&(this.disposeMesh(this.bodyMeshes.get(this.cometKey)),this.bodyMeshes.delete(this.cometKey),this.disposeHitArea(this.cometKey),this.disposeGlare(this.cometKey),this.cometKey=void 0)}buildPlanets(e,t){const n=new Set(["sun","moon",...this.cometKey?[this.cometKey]:[]]);for(const i of e){if(i.magnitude>t)continue;n.add(i.body);const r=gl(i.magnitude,t),a=vl(r),o=ME[i.body]??new ce(1,1,1),c=new ce(o.r*a,o.g*a,o.b*a),l=Cf*(.5+.5*r);this.setBodyMesh(i.body,i.position,l,c,i.magnitude)}for(const i of[...this.bodyMeshes.keys()])n.has(i)||(this.disposeMesh(this.bodyMeshes.get(i)),this.bodyMeshes.delete(i),this.disposeHitArea(i),this.disposeGlare(i))}buildStars(e,t){if(this.disposeStarTiers(),this.namedStars=[],!e||e.catalog.count===0){this.syncAnimationLoop();return}const{catalog:n,date:i,observer:r}=e,a=zl(1337),o=[];for(let c=0;c<n.count;c++){const l=n.mag[c];if(l>t)break;const{altitudeDeg:h,azimuthDeg:u}=Cr(n.ra[c],n.dec[c],i,r);if(h<Pf)continue;const{x:d,y:f,z:p}=fn(h,u,Df);o.push({x:d,y:f,z:p,brightness:gl(l,t),phase:a()*Math.PI*2,speedFactor:.7+a()*.6})}for(const c of XS){if(c.mag>t)continue;const{altitudeDeg:l,azimuthDeg:h}=Cr(c.raHours,c.decDeg,i,r);if(l<Pf)continue;const{x:u,y:d,z:f}=fn(l,h,Df);this.namedStars.push({star:c,direction:new C(u,d,f).normalize(),altitudeDeg:l})}this.starTiers=am.map((c,l)=>{const h=o.filter(b=>H3(b.brightness)===l),u=new Float32Array(h.length*3),d=new Float32Array(h.length),f=new Float32Array(h.length),p=new Float32Array(h.length);h.forEach((b,_)=>{u[_*3]=b.x,u[_*3+1]=b.y,u[_*3+2]=b.z,d[_]=b.brightness,f[_]=b.phase,p[_]=b.speedFactor});const v=new Et;v.setAttribute("position",new dt(u,3));const g=new dt(new Float32Array(h.length*3),3);v.setAttribute("color",g);const m=new kp({vertexColors:!0,size:c.size,sizeAttenuation:!1,fog:!1});ws.apply(m);const E=new Go(v,m);return this.celestialGroup.add(E),{points:E,colorAttribute:g,brightness:d,phase:f,speedFactor:p}}),this.updateTwinkle(0),this.startTwinkle()}updateTwinkle(e){for(const t of this.starTiers){const n=t.colorAttribute.array;for(let i=0;i<t.brightness.length;i++){const r=W3(t.brightness[i],{phase:t.phase[i],speedFactor:t.speedFactor[i]},e),a=vl(t.brightness[i])*r;n[i*3]=a,n[i*3+1]=a,n[i*3+2]=a}t.colorAttribute.needsUpdate=!0}}buildClouds(){if(this.cloudRendering==="volume"||this.weather.cloudLayers!==void 0){this.layeredClouds||(this.disposeCloudSystem(),this.layeredClouds=new g3(this.celestialGroup,Il,this.cloudRendering)),this.disposeCirrus(),this.layeredClouds.update(this.weather,this.observerElevationM+1.6),this.layeredClouds.setOffsets(this.cloudOffsetM,this.cloudLayerOffsetsM),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}this.disposeCloudSystem();const e=this.lowerCloudCover();if(e<=0)return;const t=this.weather.cloudDarkness,n=new ce(Ms[0]+(Ol[0]-Ms[0])*t,Ms[1]+(Ol[1]-Ms[1])*t,Ms[2]+(Ol[2]-Ms[2])*t),{material:i,uniforms:r}=Bh(n,e,Math.abs(this.cloudLayerOffset()));this.cloudMaterial=i,this.cloudUniforms=r,r.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);const a=Hh(Il);this.cloudMesh=new Ye(a,i),this.cloudLayerOffset()<0&&(this.cloudMesh.scale.y=-1),this.cloudMesh.renderOrder=Uf,this.celestialGroup.add(this.cloudMesh)}lowerCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(e=>e.type!=="cirrus").reduce((e,t)=>e*(1-t.coverage),1):this.weather.lowerCloudCover??this.weather.cloudCover}highCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(e=>e.type==="cirrus").reduce((e,t)=>e*(1-t.coverage),1):this.weather.highCloudCover}buildCirrus(){if(this.disposeCirrus(),this.layeredClouds)return;const e=this.weather.highCloudCover??0;if(e<=0)return;const{material:t,uniforms:n}=Bh(new ce(...Ms),e,Co,1);this.cirrusMaterial=t,this.cirrusUniforms=n,n.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.cirrusMesh=new Ye(Hh(Il*1.04),t),this.cirrusMesh.renderOrder=Uf-1,this.celestialGroup.add(this.cirrusMesh)}disposeCirrus(){this.cirrusMesh&&(this.cirrusMesh.removeFromParent(),this.cirrusMesh.geometry.dispose()),this.cirrusMaterial?.dispose(),this.cirrusMesh=void 0,this.cirrusMaterial=void 0,this.cirrusUniforms=void 0}syncCloudLayer(){this.layeredClouds?.update(this.weather,this.observerElevationM+1.6);const e=this.cloudLayerOffset();this.cloudUniforms&&(this.cloudUniforms.layerHeight.value=Math.abs(e)),this.cloudMesh&&(this.cloudMesh.scale.y=e<0?-1:1)}cloudLayerOffset(){const t=((this.weather.cloudBaseM??1e3)-this.observerElevationM)*Ll;return Math.sign(t||1)*Math.max(Math.abs(t),nE)}updateCloudLighting(e,t){const n=[this.cloudUniforms,this.cirrusUniforms].filter(l=>l!==void 0);if(n.length===0&&!this.layeredClouds)return;const{x:i,y:r,z:a}=fn(e.altitudeDeg,e.azimuthDeg,1),o=vs(e.altitudeDeg),c=Math.max(0,Math.sin(Math.max(e.altitudeDeg,0)*Tn));this.layeredClouds?.setLighting(new C(i,r,a),new ce(o[0]*c,.96*o[1]*c,.88*o[2]*c),new ce(...t),new ce(...t));for(const l of n)l.sunDir.value.set(i,r,a),l.sunColor.value.setRGB(o[0]*c,.96*o[1]*c,.88*o[2]*c),l.ambientColor.value.setRGB(t[0],t[1],t[2])}disposeCloudSystem(){this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.cloudMesh&&(this.cloudMesh.removeFromParent(),this.cloudMesh.geometry.dispose()),this.cloudMaterial?.dispose(),this.cloudMesh=void 0,this.cloudMaterial=void 0,this.cloudUniforms=void 0}disposePrecipitationPoints(){this.precipitationPoints&&(this.precipitationPoints.removeFromParent(),this.precipitationPoints.geometry.dispose(),this.precipitationPoints.material.dispose()),this.precipitationPoints=void 0,this.precipitationPositions=void 0,this.precipitationPhase=void 0,this.precipitationSpeedJitter=void 0,this.precipitationWobbleFreqJitter=void 0,this.precipitationWobbleAmpJitter=void 0,this.precipitationBounceRemaining=void 0,this.precipitationBounceHeight=void 0,this.precipitationBounceDuration=void 0,this.precipitationBounceVelX=void 0,this.precipitationBounceVelZ=void 0,this.precipitationUniforms=void 0}buildPrecipitation(){this.disposePrecipitationPoints(),this.disposeRain();const e=this.weather.precipitationType;if(e==="none")return;if(e==="rain"){this.buildRain();return}const t=Ff[e],n=t.poolSize,i=zl(9001),r=new Float32Array(n*3),a=new Float32Array(n),o=new Float32Array(n),c=new Float32Array(n),l=new Float32Array(n),h=new Float32Array(n),u=new Float32Array(n),d=new Float32Array(n),f=new Float32Array(n),p=new Float32Array(n);for(let b=0;b<n;b++){const _=i()*Math.PI*2,S=i()*t.radiusM;r[b*3]=Math.cos(_)*S,r[b*3+1]=hr+i()*(t.topYM-hr),r[b*3+2]=Math.sin(_)*S,a[b]=i()*Math.PI*2,o[b]=.7+i()*.6,c[b]=.6+i()*.8,l[b]=.4+i()*1.2}const v=new Et;v.setAttribute("position",new dt(r,3)),v.setDrawRange(0,Fl(n,this.weather.precipitationIntensity));const g={uSize:{value:t.size},uScale:{value:.5*this.renderer.domElement.height},uOpacity:{value:t.opacity},uColor:{value:t.color},uHazeColor:{value:new ce(...this.baseFogColor)},uTexture:{value:_E(e)},uNearFocusDistance:{value:Wf},uHazeDistance:{value:t.radiusM*Xf}},m=new wt({uniforms:g,vertexShader:AE,fragmentShader:TE,transparent:!0,depthWrite:!1});this.precipitationUniforms=g;const E=new Go(v,m);E.renderOrder=Nl,this.scene.add(E),this.precipitationPoints=E,this.precipitationPositions=r,this.precipitationPhase=a,this.precipitationSpeedJitter=o,this.precipitationWobbleFreqJitter=c,this.precipitationWobbleAmpJitter=l,this.precipitationBounceRemaining=h,this.precipitationBounceHeight=u,this.precipitationBounceDuration=d,this.precipitationBounceVelX=f,this.precipitationBounceVelZ=p}updatePrecipitation(e,t){if(!this.precipitationPoints||!this.precipitationPositions||!this.precipitationPhase||!this.precipitationSpeedJitter||(this.precipitationUniforms?.uHazeColor.value.setRGB(...this.baseFogColor),t<=0))return;const n=this.weather.precipitationType;if(n==="none"||n==="rain")return;const i=Ff[n],r=this.weather.windDirectionDeg*Tn,a=Math.sin(r)*this.weather.windSpeed*i.driftSensitivity,o=-Math.cos(r)*this.weather.windSpeed*i.driftSensitivity,c=this.precipitationPositions,l=this.precipitationPhase,h=this.precipitationSpeedJitter,u=this.precipitationWobbleFreqJitter,d=this.precipitationWobbleAmpJitter,f=this.precipitationBounceRemaining,p=this.precipitationBounceHeight,v=this.precipitationBounceDuration,g=this.precipitationBounceVelX,m=this.precipitationBounceVelZ,E=n==="snow"&&u&&d,b=n==="hail"&&f&&p&&v&&g&&m;for(let _=0,S=0;_<c.length;_+=3,S++){if(b&&f[S]>0){if(f[S]-=t,f[S]<=0){const x=Math.random()*Math.PI*2,A=Math.sqrt(Math.random())*i.radiusM;c[_]=Math.cos(x)*A,c[_+1]=i.topYM,c[_+2]=Math.sin(x)*A,f[S]=0}else{const x=1-f[S]/v[S];c[_+1]=hr+Math.sin(Math.PI*x)*p[S],c[_]=Io(c[_]+(a+g[S])*t,i.radiusM),c[_+2]=Io(c[_+2]+(o+m[S])*t,i.radiusM)}continue}let w=0,R=0;if(E){const x=fE*u[S],A=pE*d[S];w=Math.sin(e*x*Math.PI*2+l[S])*A,R=Math.sin(e*x*Math.PI*2+l[S]+Math.PI/2)*A}if(c[_]+=(a+w)*t,c[_+1]-=i.fallSpeedMPerS*h[S]*t,c[_+2]+=(o+R)*t,c[_]=Io(c[_],i.radiusM),c[_+2]=Io(c[_+2],i.radiusM),c[_+1]<hr){if(b){p[S]=Zf*(.2+Math.random()*1.6),v[S]=mE*(.5+Math.random()),f[S]=v[S];const P=Math.random()*Math.PI*2,D=gE*(p[S]/Zf);g[S]=Math.cos(P)*D,m[S]=Math.sin(P)*D,c[_+1]=hr;continue}const x=Math.random()*Math.PI*2,A=Math.sqrt(Math.random())*i.radiusM;c[_]=Math.cos(x)*A,c[_+1]=i.topYM,c[_+2]=Math.sin(x)*A}}this.precipitationPoints.geometry.attributes.position.needsUpdate=!0}buildRain(){const e=Hf(this.weather.precipitationIntensity);this.rainSystem=ob({count:zf,radiusM:ea,heightM:sE,bottomYM:kf,overallSpeed:rE,color:oE,opacity:.85,visibleCount:Fl(zf,this.weather.precipitationIntensity),speedStreak:hE(e),pixelSize:Yf,seed:9001,nearFocusDistanceM:Wf,hazeDistanceM:ea*Xf,hazeColor:new ce(...this.baseFogColor)}),this.rainLastVerticalFacing=-1,this.syncRainSlant(),this.rainSystem.points.renderOrder=Nl,this.scene.add(this.rainSystem.points),this.buildRainSplashes()}buildRainSplashes(){const e=zl(4242),t=new Float32Array(cr*3),n=new Float32Array(cr),i=new Float32Array(cr),r=new Float32Array(cr);for(let h=0;h<cr;h++){const u=e()*Math.PI*2,d=Math.sqrt(e())*ea;t[h*3]=Math.cos(u)*d,t[h*3+1]=kf,t[h*3+2]=Math.sin(u)*d,i[h]=Po(Gf,Vf),n[h]=e()*i[h],r[h]=n[h]/i[h]}const a=new Et;a.setAttribute("position",new dt(t,3));const o=new dt(r,1);a.setAttribute("aLife",o),a.setDrawRange(0,Fl(cr,this.weather.precipitationIntensity));const c=new wt({uniforms:{uMaxSize:{value:uE},uScale:{value:.5*this.renderer.domElement.height},uColor:{value:dE},uTexture:{value:bE()}},vertexShader:EE,fragmentShader:wE,transparent:!0,depthWrite:!1}),l=new Go(a,c);l.renderOrder=Nl,this.scene.add(l),this.rainSplashSystem={points:l,positions:t,life:n,duration:i,lifeAttribute:o}}disposeRain(){this.rainSystem&&(this.rainSystem.points.removeFromParent(),this.rainSystem.points.geometry.dispose(),this.rainSystem.points.material.dispose()),this.rainSystem=void 0,this.disposeRainSplashes()}disposeRainSplashes(){this.rainSplashSystem&&(this.rainSplashSystem.points.removeFromParent(),this.rainSplashSystem.points.geometry.dispose(),this.rainSplashSystem.points.material.dispose()),this.rainSplashSystem=void 0}syncRainSlant(){const e=this.rainSystem;if(!e)return;const t=this.weather.windDirectionDeg*Tn;e.uniforms.uDropVelocity.value.set(Math.sin(t)*this.weather.windSpeed,-Hf(this.weather.precipitationIntensity),-Math.cos(t)*this.weather.windSpeed);const n=this.renderer.getSize(this.rainViewportSize);e.uniforms.uAspect.value=n.x/Math.max(n.y,1)}updateRain(e){const t=this.rainSystem;if(!t)return;t.uniforms.uTime.value+=e,t.uniforms.uHazeColor.value.setRGB(...this.baseFogColor);const n=this.weather.windDirectionDeg*Tn,i=Math.sin(n)*this.weather.windSpeed,r=-Math.cos(n)*this.weather.windSpeed,a=ea,o=l=>(l%(a*2)+a*3)%(a*2)-a;t.uniforms.uWindOffset.value.set(o(t.uniforms.uWindOffset.value.x+i*e),o(t.uniforms.uWindOffset.value.y+r*e)),this.syncRainSlant(),this.camera.getWorldDirection(this.rainCameraDirection);const c=Math.abs(this.rainCameraDirection.y);if(Math.abs(c-this.rainLastVerticalFacing)>.001){this.rainLastVerticalFacing=c;const l=Kf+(1-Kf)*(1-c),h=$f+(1-$f)*(1-c);t.uniforms.uUvSquash.value=h,t.uniforms.uPixelSize.value=Yf*l*(.5+.5*h)}this.updateRainSplashes(e)}updateRainSplashes(e){const t=this.rainSplashSystem;if(!t||e<=0)return;const{positions:n,life:i,duration:r,lifeAttribute:a}=t,o=a.array;for(let c=0,l=0;c<n.length;c+=3,l++){if(i[l]+=e,i[l]>=r[l]){const h=Math.random()*Math.PI*2,u=Math.sqrt(Math.random())*ea;n[c]=Math.cos(h)*u,n[c+2]=Math.sin(h)*u,r[l]=Po(Gf,Vf),i[l]=0}o[l]=i[l]/r[l]}t.points.geometry.attributes.position.needsUpdate=!0,a.needsUpdate=!0}updateLightning(e,t){if(this.lightningArmed){if(this.lightningFlashRemainingS>0){this.lightningFlashRemainingS=Math.max(0,this.lightningFlashRemainingS-t);const n=this.lightningFlashRemainingS/jf;this.scene.fog&&this.scene.fog.color.setRGB(this.baseFogColor[0]+(1-this.baseFogColor[0])*n,this.baseFogColor[1]+(1-this.baseFogColor[1])*n,this.baseFogColor[2]+(1-this.baseFogColor[2])*n);return}if(this.nextLightningAtS===null){this.nextLightningAtS=e+Po(Jf,Qf);return}e>=this.nextLightningAtS&&(this.lightningFlashRemainingS=jf,this.nextLightningAtS=e+Po(Jf,Qf),this.onLightningFlash?.())}}buildCompassLabels(){const e=gu(navigator.languages,Yb),t=qb[e];this.compassSprites=Xb.map((n,i)=>{const r=t[i],a=new ia({map:CE(r),depthTest:!1,fog:!1}),o=new Ja(a),{x:c,y:l,z:h}=fn(0,n,Kb);return o.position.set(c,l,h),o.scale.set(Pl,Pl,1),o.renderOrder=Zb,o.visible=this.compassHovered||this.compassForced,this.celestialGroup.add(o),o}),this.updateCompassScale()}updateCompassScale(){const e=this.camera.fov*Math.PI/360,t=$b*Math.PI/360,n=Pl*Math.tan(e)/Math.tan(t);for(const i of this.compassSprites)i.scale.set(n,n,1)}disposeCompassLabels(){for(const e of this.compassSprites)e.removeFromParent(),e.material.map?.dispose(),e.material.dispose();this.compassSprites=[]}disposeStarTiers(){for(const e of this.starTiers)this.disposeMesh(e.points);this.starTiers=[]}disposeMesh(e){if(!e)return;e.removeFromParent(),"geometry"in e&&e.geometry.dispose();const t=e.material;for(const n of Array.isArray(t)?t:[t]){const i=n.map;i&&i.dispose(),n.dispose()}}}const Tn=Math.PI/180;function dc(s,e,t){return Math.max(e,Math.min(t,s))}function Po(s,e){return s+Math.random()*(e-s)}function Io(s,e){return(s%(e*2)+e*3)%(e*2)-e}let Lo,No;function _E(s){switch(s){case"snow":return yE();case"hail":return SE()}}function yE(){if(Lo)return Lo;const s=64,e=document.createElement("canvas");e.width=s,e.height=s;const t=e.getContext("2d"),n=t.createRadialGradient(s/2,s/2,0,s/2,s/2,s/2);return n.addColorStop(0,"rgba(255,255,255,0.95)"),n.addColorStop(.5,"rgba(255,255,255,0.55)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,s,s),Lo=new yi(e),Lo}function SE(){if(No)return No;const s=64,e=document.createElement("canvas");e.width=s,e.height=s;const t=e.getContext("2d"),n=t.createRadialGradient(s/2,s/2,0,s/2,s/2,s/2);return n.addColorStop(0,"rgba(255,255,255,1)"),n.addColorStop(.55,"rgba(255,255,255,0.95)"),n.addColorStop(.8,"rgba(255,255,255,0.4)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,s,s),No=new yi(e),No}let Oo;function bE(){if(Oo)return Oo;const s=64,e=document.createElement("canvas");e.width=s,e.height=s;const t=e.getContext("2d"),n=t.createRadialGradient(s/2,s/2,0,s/2,s/2,s/2);return n.addColorStop(0,"rgba(255,255,255,0)"),n.addColorStop(.4,"rgba(255,255,255,0)"),n.addColorStop(.6,"rgba(255,255,255,0.9)"),n.addColorStop(.8,"rgba(255,255,255,0.25)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,s,s),Oo=new yi(e),Oo}const EE=`
5913
+ `}),i.fragmentShader=r+i.fragmentShader,i.fragmentShader=i.fragmentShader.replace("#include <opaque_fragment>",a+"#include <opaque_fragment>")},e.needsUpdate=!0}meshes=new Map;signatures=new Map;extents=new Map;placed=[];frame;direction=new C;up=new C;lookAt=new Xe;vertex=new C;centre=new C;right=new C;above=new C;set(e,t){this.placed=e,this.frame=t;const n=new Set(e.map(i=>i.sourceId));for(const[i,r]of this.meshes)n.has(i)||(this.dispose(r),this.meshes.delete(i),this.signatures.delete(i),this.extents.delete(i));for(const i of e){let r=this.meshes.get(i.sourceId);r||(r=new Ye(new Vi(1,1,Yn.SEGMENTS,Yn.SEGMENTS),new Fi({transparent:!0,depthWrite:!1,depthTest:!0,fog:!1,toneMapped:!1})),this.configureCloudMaterial(r.material),r.frustumCulled=!1,r.layers.set(zm),this.scene.add(r),this.meshes.set(i.sourceId,r)),r.renderOrder=Pb+i.renderOrder,r.visible=!i.hidden&&i.shape.transparency<1,r.visible&&this.paint(r,i,t)}}place(e,t,n){const i=this.frame;if(i)for(const r of this.placed){const a=this.meshes.get(r.sourceId);if(!a||!a.visible)continue;const o=this.extents.get(r.sourceId);if(!o)continue;const{bounds:c}=r.shape;let l=c.x+c.width/2,h=c.y+c.height/2,u=!0;if(r.aim){const d=n(Yn.directionOf(r.aim,this.direction));d&&Math.abs(d.ndcX)<Yn.FURTHEST_NDC&&Math.abs(d.ndcY)<Yn.FURTHEST_NDC?(l=(d.ndcX+1)/2*i.canvasWidthPx,h=(1-d.ndcY)/2*i.canvasHeightPx):u=!1}u?this.curve(a,e,t,i,o,l,h,r.distanceM):this.flat(a,e,i,o,r.distanceM)}}static FURTHEST_NDC=4;curve(e,t,n,i,r,a,o,c){const l=a-r.width/2,h=o-r.height/2,u=e.geometry.attributes.position,d=Yn.SEGMENTS;let f=0;for(let p=0;p<=d;p++){const v=h+p/d*r.height;for(let g=0;g<=d;g++){const m=l+g/d*r.width;n(m/i.canvasWidthPx*2-1,-(v/i.canvasHeightPx*2-1),this.direction),this.vertex.copy(t.position).addScaledVector(this.direction,c),u.setXYZ(f++,this.vertex.x,this.vertex.y,this.vertex.z)}}u.needsUpdate=!0,e.matrixAutoUpdate=!1,e.matrix.identity(),e.matrixWorldNeedsUpdate=!0,e.scale.set(mt.sizeMAt(c,i.projection.pxToDeg(r.width)),mt.sizeMAt(c,i.projection.pxToDeg(r.height)),1)}flat(e,t,n,i,r){const a=e.geometry.attributes.position,o=Yn.SEGMENTS,c=mt.sizeMAt(r,n.projection.pxToDeg(i.width)),l=mt.sizeMAt(r,n.projection.pxToDeg(i.height));this.up.set(0,1,0).applyQuaternion(t.quaternion),this.centre.copy(t.position).addScaledVector(this.direction,r),this.lookAt.lookAt(t.position,this.centre,this.up),this.right.setFromMatrixColumn(this.lookAt,0),this.above.setFromMatrixColumn(this.lookAt,1);let h=0;for(let u=0;u<=o;u++){const d=.5-u/o;for(let f=0;f<=o;f++){const p=f/o-.5;this.vertex.copy(this.centre).addScaledVector(this.right,p*c).addScaledVector(this.above,d*l),a.setXYZ(h++,this.vertex.x,this.vertex.y,this.vertex.z)}}a.needsUpdate=!0,e.matrixAutoUpdate=!1,e.matrix.identity(),e.matrixWorldNeedsUpdate=!0,e.scale.set(c,l,1)}static SEGMENTS=16;static directionOf(e,t){const n=e.azimuthDeg*Math.PI/180,i=e.altitudeDeg*Math.PI/180;return t.set(Math.sin(n)*Math.cos(i),Math.sin(i),-Math.cos(n)*Math.cos(i))}get any(){for(const e of this.meshes.values())if(e.visible)return!0;return!1}get furthestM(){return this.placed.reduce((e,t)=>Math.max(e,t.distanceM),0)}paint(e,t,n){const{shape:i}=t,r=Xl.paintExtent(i);this.extents.set(t.sourceId,r);const a=Yn.signatureOf(i,n);if(this.signatures.get(t.sourceId)===a&&e.material.map)return;this.signatures.set(t.sourceId,a);const o=Math.min(n.scale,Ib/Math.max(r.width,r.height,1)),c=Math.max(1,Math.ceil(r.width*o)),l=Math.max(1,Math.ceil(r.height*o)),h=e.material.map,u=h?.image??document.createElement("canvas"),d=u.width!==c||u.height!==l;d&&(u.width=c,u.height=l);const f=u.getContext("2d");if(!f)return;f.clearRect(0,0,c,l);const p=new Xl(f);if(p.setStarPoints(n.starPoints),p.setRoll(n.rollRad),p.paintInto(i,r,o),h&&!d){h.needsUpdate=!0;return}h?.dispose();const v=new yi(u);v.colorSpace=Cn,v.minFilter=_t,v.generateMipmaps=!1,e.material.map=v,e.material.needsUpdate=!0}static signatureOf(e,t){const{bounds:n}=e;return JSON.stringify([e.kind,Math.round(n.width*10),Math.round(n.height*10),e.color,e.angle,e.transparency,e.haloScale,e.blur??0,e.brightness??0,e.kind==="polygon"?e.points:void 0,t.scale,t.starPoints,t.rollRad])}dispose(e){e.removeFromParent(),e.geometry.dispose(),e.material.map?.dispose(),e.material.dispose()}clear(){for(const e of this.meshes.values())this.dispose(e);this.meshes.clear(),this.signatures.clear(),this.extents.clear(),this.placed=[]}}function Lb(s,e){return JSON.stringify(s.cloudLayers)===JSON.stringify(e.cloudLayers)&&s.cloudCover===e.cloudCover&&s.cloudDarkness===e.cloudDarkness&&s.cloudBaseM===e.cloudBaseM&&s.highCloudCover===e.highCloudCover&&s.iceCrystalAlignment===e.iceCrystalAlignment&&s.lowerCloudCover===e.lowerCloudCover&&s.precipitationType===e.precipitationType&&s.precipitationIntensity===e.precipitationIntensity&&s.windDirectionDeg===e.windDirectionDeg&&s.windSpeed===e.windSpeed&&s.storm===e.storm}const Ro=900,Rl=1,Tf=.5,oa=900,Nb=6371e3,Ob=3e4;function Rf(s){const e=Math.sqrt(2*Nb*Math.max(s,0));return Math.max(oa,Math.min(e,Ob))}const Dl=.5,Df=850,Ub=.03,Do=850,Cl=4,Cf=1.5,Pf=-1,Fb=6,pu=-4,If=.2,Co=2600,zb=.97,kb=.38,Lf=pu,Bb=3,Hb=.15,Gb=.6,Vb=40,Wb=30,Xb=[0,45,90,135,180,225,270,315],qb={en:["N","NE","E","SE","S","SW","W","NW"],fr:["N","NE","E","SE","S","SO","O","NO"]},Yb=["en","fr"],Kb=880,Pl=40,$b=60,Zb=10,Jb=1,Qb=150,jb=55,eE=.5,tE=2.05,Nf=.265,Of=[[0,0],...Array.from({length:8},(s,e)=>{const t=e*Math.PI/4;return[Math.cos(t)*Nf,Math.sin(t)*Nf]})],Il=700,Ll=250/1e3,nE=12,Uf=5,Nl=6,Ms=[.92,.92,.95],Ol=[.15,.15,.19],Ff={snow:{fallSpeedMPerS:2,size:.3,color:new ce(1,1,1),driftSensitivity:1,radiusM:25,topYM:20,opacity:.75,poolSize:2400},hail:{fallSpeedMPerS:14,size:.5,color:new ce(.95,.98,1),driftSensitivity:.25,radiusM:25,topYM:10,opacity:.95,poolSize:1200}},hr=0,Ul=0,iE=150,zf=3e3,ea=20,sE=15,kf=hr,rE=40,Bf=1,aE=9;function Hf(s){return Bf+(aE-Bf)*s}const oE=new ce(.75,.82,.92),cE=10,lE=.5;function hE(s){return dc(s/cE,lE,1)}const cr=200,Gf=.18,Vf=.32,uE=.35,dE=new ce(.85,.9,.98),Wf=5,Xf=.85,qf=.01;function Fl(s,e){return Math.round(s*(qf+(1-qf)*e))}const Yf=230,Kf=.7,$f=.05,fE=.6,pE=.7,mE=.15,Zf=.35,gE=3,vE=1/12,xE=.5,Jf=8,Qf=25,jf=.12,ME={Venus:new ce(1,.96,.85),Mars:new ce(1,.55,.4),Jupiter:new ce(.95,.87,.72),Saturn:new ce(.92,.86,.68)};class ci{renderer;scene=new xc;phenomena=new Yn(this.scene);camera;celestialGroup=new an;skyMesh;groundMesh;terrainMesh;terrainProviders;terrainOrigin;terrainBuildToken=0;terrainAttribution;decorModelProvider=Db[0].create();decorModelToken=0;decorModelCredits=new Map;starTiers=[];bodyMeshes=new Map;hitAreas=new Map;glareSprites=new Map;decorObjects=[];decorGroups=new Map;decorReferencePose;decorCurrentPose;decorTime=0;celestialLight=new jv(16777215,0);celestialLightTarget=new yt;skyLight=new Kv(16777215,0,0);streetlightLights=new Map;compassSprites=[];showCompass=!1;compassHovered=!1;compassForced=!1;animationFrameId=null;raycaster=new ol;weather=ip;observerElevationM=0;groundRadius=oa;terrainRadius=oa;cloudRendering="volume";layeredClouds;cloudLayerOffsetsM={};cloudOffsetM=new C;cloudFieldOffset=new C;cloudMesh;cirrusMesh;cirrusMaterial;cirrusUniforms;cloudMaterial;cloudUniforms;precipitationPoints;precipitationPositions;precipitationPhase;precipitationSpeedJitter;precipitationWobbleFreqJitter;precipitationWobbleAmpJitter;precipitationBounceRemaining;precipitationBounceHeight;precipitationBounceDuration;precipitationBounceVelX;precipitationBounceVelZ;precipitationUniforms;rainSystem;rainSplashSystem;rainCameraDirection=new C;rainLastVerticalFacing=-1;rainViewportSize=new Pe;lightningArmed=!1;nextLightningAtS=null;lightningFlashRemainingS=0;baseFogColor=[0,0,0];lastSunPosition;lensFlare;sunCloudTransmission=1;sunUnhiddenFraction=1;lensFlareArtifactIntensity=0;sunWorldPosition=new C;sunVisible=!1;lensFlareScratch=new C;sunOcclusionRaycaster=new ol;sunOcclusionDirectionScratch=new C;sunOcclusionRightScratch=new C;sunOcclusionUpScratch=new C;ufoOcclusionRaycaster=new ol;projectionKind="rectilinear";starPoints=0;namedStars=[];equidistantPass;depthOfFieldPass;exposureAccumulation;exposureInstants=1;get developingExposure(){return this.exposureInstants>1&&this.exposureInstantAt!==void 0}static EXPOSURE_BUDGET_MS=12;exposureFrameId=null;exposureInstantsDone=0;exposureInstantAt;restatingExposure=!1;lensOptics;instrumentMagnitudeGain=0;meteorSystem;cometTail;iceHalos;rainbow;skyGlow;cometKey;onLightningFlash;constructor(e,t=Kg(),n){this.renderer=new a3({canvas:e,antialias:!0}),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio||1,2)),this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=ca,this.camera=new Sn(60,e.width/Math.max(e.height,1),.1,Ro*1.2),this.camera.position.set(0,1.6,0),this.terrainProviders=t,this.onLightningFlash=n,this.celestialLight.shadow.mapSize.set(1024,1024),this.celestialLight.shadow.camera.left=-120,this.celestialLight.shadow.camera.right=120,this.celestialLight.shadow.camera.top=120,this.celestialLight.shadow.camera.bottom=-120,this.celestialLight.shadow.camera.near=1,this.celestialLight.shadow.camera.far=1e3,this.celestialLight.shadow.bias=-.0015,this.celestialLight.target=this.celestialLightTarget,this.scene.add(this.celestialLight,this.celestialLightTarget,this.skyLight),this.scene.add(this.celestialGroup)}get currentTerrainAttribution(){return this.terrainAttribution}resize(e,t){this.renderer.setSize(e,t,!1),this.camera.aspect=e/Math.max(t,1),this.camera.updateProjectionMatrix(),this.render()}setCloudRendering(e){e!==this.cloudRendering&&(this.cloudRendering=e,this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.buildClouds(),this.buildCirrus(),this.render())}setCloudOffset(e,t={}){this.cloudOffsetM.set(e.x,0,e.z),this.cloudLayerOffsetsM=t,this.layeredClouds?.setOffsets(e,t),this.cloudFieldOffset.set(e.x*Ll,0,e.z*Ll);for(const n of[this.cloudUniforms,this.cirrusUniforms])n?.fieldOffset.value.copy(this.cloudFieldOffset);this.iceHalos?.setCloudOffset(this.layeredClouds?.cirrusMask?.offset??this.cloudFieldOffset)}setObserverPose(e){const t=((e.rollDeg??0)+this.gaitOffset.rollDeg)*Tn,n=(e.pitchDeg+this.lookPitchDeg+this.gaitOffset.pitchDeg)*Tn;if(e.headingDeg!==void 0?this.camera.rotation.set(n,-(e.headingDeg+this.lookYawDeg+this.gaitOffset.yawDeg)*Tn,t,"YXZ"):this.camera.rotation.set(n,this.camera.rotation.y,t,"YXZ"),e.elevationM!==this.observerElevationM&&(this.observerElevationM=e.elevationM,this.syncCloudLayer(),Math.abs(Rf(e.elevationM)-this.groundRadius)>1&&(this.buildGround(),this.celestialGroup.scale.setScalar(this.groundRadius/oa),this.camera.far=Math.max(Ro*1.2,this.groundRadius*2.5),this.camera.updateProjectionMatrix())),this.terrainMesh&&this.terrainOrigin&&e.lat!==void 0&&e.lng!==void 0){const i=rn(this.terrainOrigin.lat,this.terrainOrigin.lng,e.lat,e.lng);this.terrainMesh.position.x=i.x,this.terrainMesh.position.z=i.z}this.poseCameraY=this.groundYUnder(0,0)+1.6+e.elevationM,this.camera.position.y=this.poseCameraY,this.celestialGroup.position.y=this.camera.position.y,this.camera.fov!==e.fovDeg&&(this.camera.fov=e.fovDeg,this.camera.updateProjectionMatrix(),this.updateCompassScale())}setTerrainProviders(e){this.terrainProviders=e,this.disposeMesh(this.terrainMesh),this.terrainMesh=void 0,this.terrainOrigin=void 0,this.terrainAttribution=void 0,this.applyGroundDepthWrite(),this.terrainBuildToken++}setTerrainOrigin(e,t,n){if(e===void 0||t===void 0)return;const i=this.groundRadius;if(this.terrainOrigin&&Math.abs(this.terrainRadius-i)<i*.1){const{x:c,z:l}=rn(e,t,this.terrainOrigin.lat,this.terrainOrigin.lng);if(Math.sqrt(c*c+l*l)<Qb*(i/oa))return}const r=this.terrainOrigin,a=this.terrainRadius;this.terrainOrigin={lat:e,lng:t},this.terrainRadius=i;const o=++this.terrainBuildToken;JS(e,t,this.terrainProviders,i).then(({mesh:c,attribution:l})=>{if(o!==this.terrainBuildToken)return;const h=this.terrainMesh,u=r?rn(e,t,r.lat,r.lng):void 0;h&&u&&Math.hypot(u.x,u.z)<=a&&(c.position.y=h.position.y+this.groundYOfPatch(h,u.x,u.z)),this.disposeMesh(this.terrainMesh),c.renderOrder=Jb,this.terrainMesh=c,this.terrainAttribution=l,this.scene.add(c),this.applyGroundDepthWrite(),this.decorCurrentPose&&(this.setObserverPose(this.decorCurrentPose),this.updateDecorAnchoring(this.decorReferencePose,this.decorCurrentPose,this.decorTime)),this.render(),n?.()}).catch(c=>{console.warn("Terrain build failed, keeping the flat ground fallback:",c),n?.()})}setShowCompass(e){this.showCompass!==e&&(this.showCompass=e,this.disposeCompassLabels(),e&&this.buildCompassLabels(),this.render())}applyLensFlareTint(e){if(!this.lensFlare)return;const t=jb*this.sunCloudTransmission;this.lensFlare.uniforms.uColorGain.value.setRGB(t*e[0],t*e[1],t*e[2]),this.applyDazzleStrength()}applyDazzleStrength(){if(!this.lensFlare)return;const e=this.lastSunPosition?.altitudeDeg??-90,t=k3(e)*this.sunCloudTransmission*this.sunUnhiddenFraction,n=vs(e);this.lensFlare.uniforms.uDazzleColour.value.setRGB(n[0],n[1],n[2]),this.lensFlare.uniforms.uVeilStrength.value=tE**2*Math.max(0,t)}setCompassHovered(e){this.compassHovered!==e&&(this.compassHovered=e,this.updateCompassVisibility())}setCompassForced(e){this.compassForced!==e&&(this.compassForced=e,this.updateCompassVisibility())}updateCompassVisibility(){const e=this.compassHovered||this.compassForced;for(const t of this.compassSprites)t.visible=e;this.render()}setWeather(e){Lb(this.weather,e)||(this.weather=e,this.buildClouds(),this.buildCirrus(),this.buildPrecipitation(),this.lightningArmed=e.storm&&e.cloudDarkness>=xE,this.lightningArmed||(this.nextLightningAtS=null,this.lightningFlashRemainingS=0,this.restoreFogColor()),this.syncAnimationLoop(),this.render())}setDecor(e){if(this.decorObjects!==e){this.decorObjects=e,this.decorModelToken++,this.decorModelCredits.clear();for(const t of this.decorGroups.values())t.removeFromParent(),Jt.dispose(t);this.decorGroups.clear(),this.streetlightLights.clear();for(const t of e){const n=Jt.build(t,t.lit??!1);this.scene.add(n),this.decorGroups.set(t.id,n),t.kind==="streetlight"&&this.addStreetlightLight(t.id,n),this.loadDecorModel(t,this.decorModelToken)}this.celestialLight.castShadow=this.decorGroups.size>0}}setDecorModelProvider(e){this.decorModelProvider=e;const t=this.decorObjects;this.decorObjects=[],this.setDecor(t)}get currentDecorModelCredits(){return[...this.decorModelCredits.values()]}async loadDecorModel(e,t){const n=e.model;if(!(!n||!Jt.usesModel(e)))try{const i=n.url?void 0:n.id?await this.decorModelProvider.entry(n.id):void 0,r=n.url??i?.url,a=n.credit??i?.credit;if(!r||!a)return;const o=await Cb(r);if(t!==this.decorModelToken)return;const c=this.decorGroups.get(e.id);if(!c)return;Jt.applyModel(c,e,o,{headingOffsetDeg:n.headingOffsetDeg??i?.headingOffsetDeg,depictedSizeM:i?.sizeM}),this.decorModelCredits.set(e.id,a),this.render()}catch(i){console.warn(`Keeping the built-in shape for decor "${e.id}":`,i)}}updateDecorAnchoring(e,t,n=0){this.decorReferencePose=e,this.decorCurrentPose=t,this.decorTime=n;const i=e?.lat!==void 0&&e.lng!==void 0&&t?.lat!==void 0&&t?.lng!==void 0?rn(e.lat,e.lng,t.lat,t.lng):{x:0,z:0},r=this.decorObjects.find(l=>l.witnessSide!==void 0&&cp(l.kind));r||(i.x-=this.gaitOffset.eastM,i.z+=this.gaitOffset.northM,this.camera.position.y=this.poseCameraY+this.gaitOffset.upM,this.celestialGroup.position.y=this.camera.position.y);const a={x:0,z:0};let o=0;if(r){const l=Jt.occupantView(r),h=-(r.headingDeg??0)*Tn,u=l.x*Math.cos(h)+l.z*Math.sin(h),d=-l.x*Math.sin(h)+l.z*Math.cos(h),f=r.eastM+i.x,p=-r.northM+i.z;a.x=-(f+u),a.z=-(p+d),this.camera.position.y=this.groundYUnder(f,p)+l.eyeY,this.camera.rotation.set(this.indoorLookPitchDeg*Tn,-(l.headingDeg+this.indoorLookYawDeg)*Tn,0,"YXZ")}for(const l of this.decorObjects){const h=this.decorGroups.get(l.id);if(!h)continue;const u=vu(l,n),d=u.eastM+i.x+a.x,f=-u.northM+i.z+a.z;if(h.position.set(d,this.groundUnderFootprint(l,d,f,u.headingDeg)+u.altitudeM,f),l.kind==="crop"){const p=Math.hypot(d,f);h.visible=p<=iE}if(u.headingDeg!==void 0&&(h.rotation.y=-u.headingDeg*Tn),l.kind==="crop"&&h.visible){const p=this.terrainMesh,v=[p?.geometry.uuid,d-(p?.position.x??0),f-(p?.position.z??0),h.position.y-(p?.position.y??0),u.headingDeg,u.altitudeM].map(g=>typeof g=="number"?g.toFixed(4):g).join(":");h.userData.cropGroundKey!==v&&(Jt.fitCropToGround(h,(g,m)=>this.groundYUnder(g,m)+u.altitudeM),h.userData.cropGroundKey=v)}o=Math.max(o,h.position.distanceTo(this.camera.position))}const c=Math.max(Ro*1.2,this.groundRadius*2.5,o*1.2);Math.abs(this.camera.far-c)>1&&(this.camera.far=c,this.camera.updateProjectionMatrix())}groundYUnder(e,t){const n=this.terrainMesh;return n?n.position.y+this.groundYOfPatch(n,e-n.position.x,t-n.position.z):Ul}groundYOfPatch(e,t,n){const i=e.geometry.getAttribute("position"),r=Math.round(Math.sqrt(i.count));if(r<2||r*r!==i.count)return Ul;const a=i.getX(0),o=i.getX(r-1),c=i.getZ(0),l=i.getZ((r-1)*r),h=dc((t-a)/(o-a)*(r-1),0,r-1),u=dc((n-c)/(l-c)*(r-1),0,r-1);if(!Number.isFinite(h)||!Number.isFinite(u))return Ul;const d=Math.min(Math.floor(h),r-2),f=Math.min(Math.floor(u),r-2),p=h-d,v=u-f,g=(S,w)=>i.getY(S*r+w),m=g(f,d),E=g(f,d+1),b=g(f+1,d),_=g(f+1,d+1);return p+v<=1?m+(E-m)*p+(b-m)*v:_+(b-_)*(1-p)+(E-_)*(1-v)}groundUnderFootprint(e,t,n,i){return Jt.groundUnderFootprint(e,t,n,i,(r,a)=>this.groundYUnder(r,a))}lookYawDeg=0;lookPitchDeg=0;poseCameraY=1.6;setGait(e){this.gaitOffset=e}gaitOffset={eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0};setLookOffset(e,t){this.lookYawDeg=e,this.lookPitchDeg=t}indoorLookYawDeg=0;indoorLookPitchDeg=0;setIndoorLook(e,t){this.indoorLookYawDeg=e,this.indoorLookPitchDeg=t}updateDecorLitState(e,t=0){for(const n of this.decorObjects){const i=this.decorGroups.get(n.id);if(i&&n.lights?.length&&Jt.setLights(i,n.lights,e,i.position.distanceTo(this.camera.position),t),n.kind!=="streetlight"&&n.kind!=="vehicle")continue;const r=this.decorGroups.get(n.id);if(!r)continue;const a=Og(n,e);Jt.setLit(r,n.kind,a);const o=this.streetlightLights.get(n.id);o&&(o.visible=a)}}addStreetlightLight(e,t){const n=Jt.bodyOf(t),i=n.children.find(a=>a.userData.emissive);if(!i)return;const r=new Jv(16764006,Vb,Wb);r.position.copy(i.position).multiply(n.scale),r.castShadow=!0,r.shadow.mapSize.set(512,512),r.shadow.bias=-.002,t.add(r),this.streetlightLights.set(e,r)}setAstronomy(e){const t=Xh(e.sun.altitudeDeg),n=t.horizon;this.baseFogColor=n,this.lastSunPosition=e.sun,this.buildSky(e.sun),this.buildGround(),this.updateCloudLighting(e.sun,n),this.updateCelestialLight(e,t.zenith,n);const i=sm(e.sun.altitudeDeg,this.instrumentMagnitudeGain);this.buildStars(e.stars,i),this.setBodyMesh("sun",e.sun,Cl,new ce(1,.96,.88),e.sun.magnitude),this.setMoonMesh(e.moon,i),this.buildPlanets(e.planets,i),this.buildComet(e.comet,i),this.buildIceHalos(e.sun,e.moon),this.buildRainbow(e.sun,e.moon),this.buildSkyGlow(e,t.zenith),this.scene.fog=new Pu(new ce(...n),this.groundRadius*.2,this.groundRadius),this.syncAnimationLoop(),this.render()}updateCelestialLight(e,t,n){this.skyLight.color.setRGB(t[0],t[1],t[2]),this.skyLight.groundColor.setRGB(n[0],n[1],n[2]),this.skyLight.intensity=Gb;const i=e.sun.altitudeDeg>=Lf,r=!i&&e.moon.altitudeDeg>=Lf;if(!i&&!r){this.celestialLight.intensity=0;return}const a=i?e.sun:e.moon,{x:o,y:c,z:l}=fn(a.altitudeDeg,a.azimuthDeg,Do);this.celestialLight.position.set(o,c,l);const h=vs(a.altitudeDeg);this.celestialLight.color.setRGB(h[0],h[1],h[2]);const u=Math.max(0,Math.sin(Math.max(a.altitudeDeg,0)*Tn));this.celestialLight.intensity=(i?Bb:Hb)*u,this.celestialLight.castShadow=this.decorGroups.size>0}setMeteorShower(e,t,n){this.meteorSystem||(this.meteorSystem=new Kt,this.celestialGroup.add(this.meteorSystem.object)),this.meteorSystem.setShower(e,t,n)}get meteorSchedule(){return this.meteorSystem?.schedule??[]}meteorMidpoint(e){return this.meteorSystem?.midpointOf(e)}updateMeteors(e){this.meteorSystem?.update(e)}setInstrument(e){this.projectionKind=e.projection;const t=Ht.starPointsOf(e),n=Ht.flareArtifactsOf(e);t===this.starPoints&&n===this.lensFlareArtifactIntensity||(this.starPoints=t,this.lensFlareArtifactIntensity=n,this.lensFlare&&(this.lensFlare.uniforms.uStarPoints.value=t,this.lensFlare.uniforms.uFlareIntensity.value=n),this.render())}setInstrumentGain(e){this.instrumentMagnitudeGain=Number.isFinite(e)?e:0}render(){this.restatingExposure||(this.renderOnce(),this.developingExposure&&this.startExposure())}setExposure(e,t){const n=t?Math.max(1,Math.round(e)):1;if(n===this.exposureInstants&&(n===1||t===this.exposureInstantAt)){this.exposureInstantAt=t;return}this.exposureInstants=n,this.exposureInstantAt=t,n===1&&(this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0),this.render()}renderOnce(e){const t=this.usableEquidistantPass();this.phenomena.setCloudLayers(this.layeredClouds?.volumes??[]),this.phenomena.place(this.camera,(r,a,o)=>this.directionAtScreenPoint(r,a,o),r=>this.screenPointOf(r));const n=this.phenomena.furthestM*1.2;n>this.camera.far&&(this.camera.far=n,this.camera.updateProjectionMatrix());const i=this.renderer.getRenderTarget();if(!t){this.updateLensFlarePosition();const r=this.usableDepthOfFieldPass();r?.setEncodesOutput(e===void 0),this.skyGlow?.setDestinationEncoded(e===void 0&&!r),e&&this.renderer.setRenderTarget(e),r?r.render(this.renderer,this.scene,this.camera,()=>this.renderPhenomenaPass()):(this.renderer.render(this.scene,this.camera),this.renderPhenomenaPass()),e&&this.renderer.setRenderTarget(i);return}t.setEncodesOutput(e===void 0),this.skyGlow?.setDestinationEncoded(!1),e&&this.renderer.setRenderTarget(e),t.render(this.renderer,this.scene,this.camera,this.camera.fov,()=>this.updateLensFlarePosition(),()=>this.renderPhenomenaPass()),e&&this.renderer.setRenderTarget(i)}renderPhenomenaPass(){if(!this.phenomena.any)return;const e=this.renderer.autoClear,t=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,this.renderer.clearDepth();for(const n of this.decorObjects){const i=this.decorGroups.get(n.id);i&&ci.markDecorDepth(i,n.kind!=="crop")}this.camera.layers.set(Rl),this.scene.overrideMaterial=this.decorDepthMaterial,this.renderer.render(this.scene,this.camera),this.scene.overrideMaterial=null,this.camera.layers.set(zm),this.renderer.render(this.scene,this.camera),this.camera.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=t}decorDepthMaterial=new Fi({colorWrite:!1});static markDecorDepth(e,t){e.traverse(n=>{if(!(n instanceof Ye))return;const i=Array.isArray(n.material)?n.material[0]:n.material;t&&i.depthWrite!==!1&&i.blending!==Qn?n.layers.enable(Rl):n.layers.disable(Rl)})}startExposure(){this.cancelExposure();const e=this.renderer.getDrawingBufferSize(new Pe),t=Math.max(1,Math.round(e.x)),n=Math.max(1,Math.round(e.y));this.exposureAccumulation||(this.exposureAccumulation=new v3(t,n)),this.exposureAccumulation.resize(t,n),this.exposureAccumulation.open(this.renderer),this.exposureInstantsDone=0,this.exposureFrameId=requestAnimationFrame(()=>this.developExposure())}developExposure(){this.exposureFrameId=null;const e=this.exposureInstantAt,t=this.exposureAccumulation;if(!e||!t)return;const n=1/this.exposureInstants,i=performance.now()+ci.EXPOSURE_BUDGET_MS;do this.restateAt(e,this.exposureInstantsDone),this.renderOnce(t.instantTarget),t.add(this.renderer,n),this.exposureInstantsDone++;while(this.exposureInstantsDone<this.exposureInstants&&performance.now()<i);this.restateAt(e,0),t.develop(this.renderer,this.exposureInstants/this.exposureInstantsDone),this.exposureInstantsDone<this.exposureInstants&&(this.exposureFrameId=requestAnimationFrame(()=>this.developExposure()))}restateAt(e,t){this.restatingExposure=!0;try{e(t)}finally{this.restatingExposure=!1}}cancelExposure(){this.exposureFrameId!==null&&(cancelAnimationFrame(this.exposureFrameId),this.exposureFrameId=null)}setLensOptics(e){const t=this.lensOptics;this.lensOptics=e,(t===void 0!=(e===void 0)||t&&e&&(t.focalLengthMm!==e.focalLengthMm||t.fNumber!==e.fNumber||t.focusDistance!==e.focusDistance||t.frameHeightMm!==e.frameHeightMm))&&(e&&this.depthOfFieldPass&&this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.render())}usableDepthOfFieldPass(){const e=this.lensOptics;if(!e)return;const t=this.renderer.getDrawingBufferSize(new Pe),n=Math.max(1,Math.round(t.x)),i=Math.max(1,Math.round(t.y));return this.depthOfFieldPass||(this.depthOfFieldPass=new da(n,i)),this.depthOfFieldPass.resize(n,i),this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.depthOfFieldPass}usableEquidistantPass(){if(this.projectionKind!=="equidistant")return;const e=this.renderer.getDrawingBufferSize(new Pe);if(ua.supports(this.camera.fov,e.x/Math.max(e.y,1)))return this.equidistantPass?this.equidistantPass.resize(e.x,e.y):this.equidistantPass=new ua(e.x,e.y),this.equidistantPass}aimAtScreenPoint(e,t,n){const i=this.projectionKind==="equidistant"?this.equidistantPass:void 0;if(!i){e.setFromCamera(new Pe(t,n),this.camera);return}const r=i.directionFor(t,n,this.camera.fov);this.camera.updateMatrixWorld(),e.ray.origin.setFromMatrixPosition(this.camera.matrixWorld),e.ray.direction.set(r.x,r.y,r.z).applyQuaternion(this.camera.quaternion).normalize(),e.camera=this.camera}pickCloudAt(e,t){return this.layeredClouds?.pickInstance(this.cloudDirectionAt(e,t))}cloudDirectionAt(e,t){return this.directionAtScreenPoint(e,t,new C)}directionAtScreenPoint(e,t,n){return this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),n.copy(this.ufoOcclusionRaycaster.ray.direction)}screenPointOf(e){this.camera.updateMatrixWorld();const t=this.screenPointScratch.copy(e).applyQuaternion(this.screenPointQuaternion.copy(this.camera.quaternion).invert());if(t.z>=0)return;const n=this.renderer.getDrawingBufferSize(this.screenPointSize),i=n.x/Math.max(n.y,1);if(this.projectionKind==="equidistant"&&this.equidistantPass)return ua.ndcFor(t,this.camera.fov,i);const r=Math.tan(this.camera.fov/2*Tn);return{ndcX:t.x/-t.z/(i*r),ndcY:t.y/-t.z/r}}screenPointScratch=new C;screenPointQuaternion=new us;screenPointSize=new Pe;updateLensFlarePosition(){const e=this.lensFlare;if(!e)return;if(!this.sunVisible){e.mesh.visible=!1;return}if(this.camera.updateMatrixWorld(),this.lensFlareScratch.copy(this.sunWorldPosition).applyMatrix4(this.camera.matrixWorldInverse),this.lensFlareScratch.z>0){e.mesh.visible=!1;return}const t=this.sunVisibleFraction();if(t<=0){e.mesh.visible=!1;return}e.mesh.visible=!0,this.sunUnhiddenFraction=t,this.applyDazzleStrength();const n=this.lensFlareScratch.copy(this.sunWorldPosition).project(this.camera);e.uniforms.uLensPosition.value.set(n.x,n.y);const i=this.renderer.domElement.width,r=this.renderer.domElement.height;e.uniforms.uResolution.value.set(i,r),e.uniforms.uTanHalfFov.value=Math.tan(this.camera.fov*Math.PI/360)}sunVisibleFraction(){let e=0;for(const t of Of)this.isSunOccluded(t[0],t[1])||e++;return e/Of.length}raycastableDecor(){const e=[];for(const t of this.decorObjects){if(t.kind==="crop")continue;const n=this.decorGroups.get(t.id);n&&e.push(n)}return e}isSunOccluded(e=0,t=0){this.scene.updateMatrixWorld();const n=[];this.groundMesh&&n.push(this.groundMesh),this.terrainMesh&&n.push(this.terrainMesh);for(const o of this.raycastableDecor())n.push(o);if(n.length===0)return!1;const i=this.sunOcclusionDirectionScratch.copy(this.sunWorldPosition).sub(this.camera.position),r=i.length();if(i.normalize(),e!==0||t!==0){const o=Math.PI/180,c=this.sunOcclusionRightScratch.set(i.z,0,-i.x);c.lengthSq()<1e-9&&c.set(1,0,0),c.normalize();const l=this.sunOcclusionUpScratch.crossVectors(c,i).normalize();i.addScaledVector(c,e*o).addScaledVector(l,t*o).normalize()}this.sunOcclusionRaycaster.set(this.camera.position,i);const a=this.sunOcclusionRaycaster.intersectObjects(n,!0)[0];return a!==void 0&&a.distance<r}setPhenomena(e,t){this.phenomena.set(e,t)}decorDistancesAt(e,t,n){this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=Tf;let i,r;for(const a of this.decorObjects){if(a.kind==="crop")continue;const o=this.decorGroups.get(a.id);if(!o)continue;const c=this.ufoOcclusionRaycaster.intersectObject(o,!0)[0];c&&(a.occludesSourceIds?.includes(n)?i=i===void 0?c.distance:Math.max(i,c.distance):r=r===void 0?c.distance:Math.min(r,c.distance))}return{behindM:i,inFrontM:r}}pickBodyAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const n=[...this.hitAreas.entries()],i=this.raycaster.intersectObjects(n.map(([,r])=>r))[0];if(i&&!this.groundHides(e,t))return n.find(([,r])=>r===i.object)?.[0]}pickStarAt(e,t){if(this.namedStars.length===0)return;this.aimAtScreenPoint(this.raycaster,e,t);const n=this.raycaster.ray.direction,i=Math.cos(Ub*this.camera.fov*Math.PI/180);let r,a=i;for(const o of this.namedStars){const c=o.direction.dot(n);c>a&&(a=c,r={star:o.star,altitudeDeg:o.altitudeDeg})}return r&&this.groundHides(e,t)?void 0:r}groundHides(e,t){const n=[this.terrainMesh,this.groundMesh].filter(i=>i!==void 0);return n.length===0?!1:(this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=Tf,this.ufoOcclusionRaycaster.intersectObjects(n,!0).length>0)}pickDecorAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const n=[...this.decorGroups.entries()],i=this.raycaster.intersectObjects(n.map(([,a])=>a),!0)[0];if(!i)return;let r=i.object;for(;r&&!n.some(([,a])=>a===r);)r=r.parent;return n.find(([,a])=>a===r)?.[0]}dispose(){this.stopTwinkle(),this.phenomena.clear(),this.terrainBuildToken++,this.disposeMesh(this.skyMesh),this.disposeMesh(this.groundMesh),this.disposeMesh(this.terrainMesh),this.disposeCloudSystem(),this.disposeCirrus(),this.disposePrecipitationPoints(),this.disposeRain(),this.disposeStarTiers(),this.meteorSystem?.dispose(),this.meteorSystem=void 0,this.iceHalos?.dispose(),this.iceHalos=void 0,this.rainbow?.dispose(),this.rainbow=void 0,this.skyGlow?.dispose(),this.skyGlow=void 0,this.depthOfFieldPass?.dispose(),this.depthOfFieldPass=void 0,this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0,this.cometTail?.dispose(),this.cometTail=void 0;for(const e of this.bodyMeshes.values())this.disposeMesh(e);this.bodyMeshes.clear();for(const e of[...this.hitAreas.keys()])this.disposeHitArea(e);for(const e of[...this.glareSprites.keys()])this.disposeGlare(e);this.disposeCompassLabels();for(const e of this.decorGroups.values())Jt.dispose(e);this.decorGroups.clear(),this.streetlightLights.clear(),this.lensFlare&&(this.lensFlare.mesh.removeFromParent(),this.lensFlare.mesh.geometry.dispose(),this.lensFlare.mesh.material.dispose(),this.lensFlare=void 0),this.renderer.dispose()}animationsRunning=!1;startTwinkle(){if(this.animationFrameId!==null||!this.needsAnimationLoop())return;let e;const t=n=>{const i=e===void 0?0:Math.min((n-e)/1e3,vE);e=n,this.updateTwinkle(n/1e3),this.updatePrecipitation(n/1e3,i),this.updateRain(i),this.updateLightning(n/1e3,i),this.lensFlare&&(this.lensFlare.uniforms.uTime.value=n/1e3),this.developingExposure||this.render(),this.animationFrameId=requestAnimationFrame(t)};this.animationFrameId=requestAnimationFrame(t)}setAnimationsRunning(e){e!==this.animationsRunning&&(this.animationsRunning=e,e?this.nextLightningAtS=null:this.lightningFlashRemainingS>0&&(this.lightningFlashRemainingS=0,this.restoreFogColor()),this.syncAnimationLoop(),e||this.render())}stopTwinkle(){this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}restoreFogColor(){this.scene.fog&&this.scene.fog.color.setRGB(...this.baseFogColor)}needsAnimationLoop(){return this.animationsRunning&&(this.starTiers.length>0||this.precipitationPoints!==void 0||this.rainSystem!==void 0||this.lightningArmed||this.lensFlare!==void 0&&this.sunVisible)}syncAnimationLoop(){this.needsAnimationLoop()?this.startTwinkle():this.stopTwinkle()}buildSky(e){this.disposeMesh(this.skyMesh);const t=new cn(Ro,32,16),n=t.attributes.position,i=[];for(let a=0;a<n.count;a++){const{altitudeDeg:o,azimuthDeg:c}=_3(n.getX(a),n.getY(a),n.getZ(a)),l=R3(o,c,e.azimuthDeg,e.altitudeDeg);i.push(l[0],l[1],l[2])}t.setAttribute("color",new bt(i,3));const r=new Fi({vertexColors:!0,side:Ft,fog:!1,depthWrite:!1});this.skyMesh=new Ye(t,r),this.skyMesh.renderOrder=-1,this.celestialGroup.add(this.skyMesh)}buildGround(){this.disposeMesh(this.groundMesh),this.groundRadius=Rf(this.observerElevationM);const e=new Nu(this.groundRadius,48),t=new Ta({color:new ce(Dl,Dl,Dl),fog:!0});this.groundMesh=new Ye(e,t),this.groundMesh.rotation.x=-Math.PI/2,this.groundMesh.position.y=0,this.groundMesh.receiveShadow=!0,this.scene.add(this.groundMesh),this.applyGroundDepthWrite()}applyGroundDepthWrite(){const e=this.groundMesh?.material;if(!e)return;const t=this.terrainMesh===void 0;e.depthWrite!==t&&(e.depthWrite=t,e.needsUpdate=!0)}cloudTransmission(e){const t=fn(e.altitudeDeg,e.azimuthDeg,1);if(this.layeredClouds)return this.layeredClouds.transmissionAt(t);let n=1;const i=this.lowerCloudCover();i>0&&(n*=1-Ct.alphaAt(t,Math.abs(this.cloudLayerOffset()),i,this.cloudFieldOffset)*zb);const r=this.weather.highCloudCover??0;return r>0&&(n*=1-Ct.alphaAt(t,Co,r)*kb),Math.max(0,Math.min(1,n))}setBodyMesh(e,t,n,i,r){if(this.disposeMesh(this.bodyMeshes.get(e)),this.disposeHitArea(e),this.disposeGlare(e),t.altitudeDeg<pu){this.bodyMeshes.delete(e),e==="sun"&&(this.sunVisible=!1);return}const{x:a,y:o,z:c}=fn(t.altitudeDeg,t.azimuthDeg,Do),l=vs(t.altitudeDeg),h=this.cloudTransmission(t),u=new ce(i.r*l[0]*h,i.g*l[1]*h,i.b*l[2]*h),d=new cn(n,16,16),f=new Fi({color:u,fog:!1}),p=new Ye(d,f);p.position.set(a,o,c),this.celestialGroup.add(p),this.bodyMeshes.set(e,p),this.setHitArea(e,a,o,c,n);const v=r-2.5*Math.log10(Math.max(h,.001));if(e==="sun"&&(this.sunCloudTransmission=h),e!=="sun"&&this.setGlare(e,a,o,c,v,u),e==="sun"){this.sunVisible=!0;const g=this.celestialGroup.scale.x;this.sunWorldPosition.set(a*g,o*g+this.celestialGroup.position.y,c*g),this.lensFlare||(this.lensFlare=ub(),this.lensFlare.uniforms.uOpacity.value=eE,this.lensFlare.uniforms.uFlareIntensity.value=this.lensFlareArtifactIntensity,this.lensFlare.uniforms.uStarPoints.value=this.starPoints,this.scene.add(this.lensFlare.mesh)),this.applyLensFlareTint(l)}}setMoonMesh(e,t){const n="moon";if(this.disposeMesh(this.bodyMeshes.get(n)),this.disposeHitArea(n),this.disposeGlare(n),e.magnitude>t||e.altitudeDeg<pu){this.bodyMeshes.delete(n);return}const{x:i,y:r,z:a}=fn(e.altitudeDeg,e.azimuthDeg,Do),o=vs(e.altitudeDeg),c=new ce(o[0],o[1],o[2]),l=new ia({map:DE(e.phase),color:c,fog:!1}),h=new Ja(l);h.position.set(i,r,a);const u=Cl*2;h.scale.set(u,u,1),this.celestialGroup.add(h),this.bodyMeshes.set(n,h),this.setHitArea(n,i,r,a,Cl),this.setGlare(n,i,r,a,e.magnitude,c)}setHitArea(e,t,n,i,r){const a=new ia({transparent:!0,opacity:0,depthTest:!1,depthWrite:!1,fog:!1}),o=new Ja(a);o.position.set(t,n,i);const c=r*Fb;o.scale.set(c,c,1),this.celestialGroup.add(o),this.hitAreas.set(e,o)}disposeHitArea(e){const t=this.hitAreas.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.hitAreas.delete(e))}setGlare(e,t,n,i,r,a){const o=P3(r);if(o<=0){this.disposeGlare(e);return}const c=N3(o),l=this.glareSprites.get(e),h=l??new Ja(new ia({map:RE(),transparent:!0,blending:Qn,depthWrite:!1,fog:!1}));h.material.color.copy(a),h.material.opacity=F3(o),h.position.set(t,n,i),h.scale.set(c*2,c*2,1),l||(this.celestialGroup.add(h),this.glareSprites.set(e,h))}disposeGlare(e){const t=this.glareSprites.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.glareSprites.delete(e))}buildComet(e,t){const n=e&&`comet:${e.id}`;if(!e||!n||e.magnitude>t){this.disposeComet();return}this.cometKey&&this.cometKey!==n&&this.disposeComet();const i=gl(e.magnitude,t),r=vl(i);this.cometKey=n,this.setBodyMesh(n,e.position,Cf*(.5+.5*i),new ce(r,r,r),e.magnitude),this.cometTail||(this.cometTail=new Rn(Do),this.celestialGroup.add(this.cometTail.object)),this.cometTail.set(e.position,e.tailEnd,i)}buildIceHalos(e,t){this.iceHalos||(this.iceHalos=new oi,this.iceHalos.setCloudOffset(this.cloudFieldOffset),this.iceHalos.onReady=()=>this.render(),this.celestialGroup.add(this.iceHalos.object));const n=this.highCloudCover(),i=this.layeredClouds?.cirrusMask;if(this.iceHalos.setCloudOffset(i?.offset??this.cloudFieldOffset),n===void 0){this.iceHalos.update({x:0,y:1,z:0},-1,0,[1,1,1],{cover:0,layerHeight:Co},0);return}const r=this.lowerCloudCover(),a=et.deckLitUntilDeg(et.DECK_HEIGHT_M),o=e.altitudeDeg>-a?e:t,c=et.strength(n,r,o.altitudeDeg,a)*(o===e?1:If),{x:l,y:h,z:u}=fn(o.altitudeDeg,o.azimuthDeg,1),d=vs(o.altitudeDeg);this.iceHalos.update({x:l,y:h,z:u},o.altitudeDeg,c,[d[0],d[1],d[2]],{cover:i?.cover??n,layerHeight:i?.layerHeight??Co},i?.iceCrystalAlignment??this.weather.iceCrystalAlignment??.65)}buildRainbow(e,t){this.rainbow||(this.rainbow=new fa,this.celestialGroup.add(this.rainbow.object));const n=this.weather.precipitationType==="rain"?this.weather.precipitationIntensity:0,i=e.altitudeDeg>0,r=i?e:t,a=this.lowerCloudCover(),o=If*yn.moonlightShare(t.magnitude),c=yn.strength(n,a,r.altitudeDeg)*(i?1:o);if(c<=0){this.rainbow.update({x:0,y:1,z:0},0,[1,1,1],!0);return}const{x:l,y:h,z:u}=fn(r.altitudeDeg,r.azimuthDeg,1),d=vs(r.altitudeDeg);this.rainbow.update({x:l,y:h,z:u},c,[d[0],d[1],d[2]],i)}buildSkyGlow(e,t){if(!e.frame){this.skyGlow?.hide();return}this.skyGlow||(this.skyGlow=new Xn,this.skyGlow.onReady=()=>this.render(),this.celestialGroup.add(this.skyGlow.object));const{date:n,observer:i}=e.frame,r=qn.galactic(n,i),a=ci.directionOf(r.centre),o=ci.directionOf(r.rotation),c=ci.directionOf(r.pole),l=new ke().set(a.x,a.y,a.z,o.x,o.y,o.z,c.x,c.y,c.z),h=ci.directionOf(qn.eclipticPole(n,i)),u=ci.directionOf(e.sun),d=u.clone().addScaledVector(h,-u.dot(h)).normalize();this.skyGlow.update({galactic:l,eclipticPole:h,sunLongitude:d,sunDirection:u,sunAltitudeDeg:e.sun.altitudeDeg,moon:{direction:ci.directionOf(e.moon),altitudeDeg:e.moon.altitudeDeg,phaseAngleDeg:Ze.phaseAngleOf(e.moon.phase.illuminatedFraction)},skyColor:new C(t[0],t[1],t[2])})}static directionOf(e){const{x:t,y:n,z:i}=fn(e.altitudeDeg,e.azimuthDeg,1);return new C(t,n,i).normalize()}disposeComet(){this.cometTail?.set(void 0,void 0,0),this.cometKey&&(this.disposeMesh(this.bodyMeshes.get(this.cometKey)),this.bodyMeshes.delete(this.cometKey),this.disposeHitArea(this.cometKey),this.disposeGlare(this.cometKey),this.cometKey=void 0)}buildPlanets(e,t){const n=new Set(["sun","moon",...this.cometKey?[this.cometKey]:[]]);for(const i of e){if(i.magnitude>t)continue;n.add(i.body);const r=gl(i.magnitude,t),a=vl(r),o=ME[i.body]??new ce(1,1,1),c=new ce(o.r*a,o.g*a,o.b*a),l=Cf*(.5+.5*r);this.setBodyMesh(i.body,i.position,l,c,i.magnitude)}for(const i of[...this.bodyMeshes.keys()])n.has(i)||(this.disposeMesh(this.bodyMeshes.get(i)),this.bodyMeshes.delete(i),this.disposeHitArea(i),this.disposeGlare(i))}buildStars(e,t){if(this.disposeStarTiers(),this.namedStars=[],!e||e.catalog.count===0){this.syncAnimationLoop();return}const{catalog:n,date:i,observer:r}=e,a=zl(1337),o=[];for(let c=0;c<n.count;c++){const l=n.mag[c];if(l>t)break;const{altitudeDeg:h,azimuthDeg:u}=Cr(n.ra[c],n.dec[c],i,r);if(h<Pf)continue;const{x:d,y:f,z:p}=fn(h,u,Df);o.push({x:d,y:f,z:p,brightness:gl(l,t),phase:a()*Math.PI*2,speedFactor:.7+a()*.6})}for(const c of XS){if(c.mag>t)continue;const{altitudeDeg:l,azimuthDeg:h}=Cr(c.raHours,c.decDeg,i,r);if(l<Pf)continue;const{x:u,y:d,z:f}=fn(l,h,Df);this.namedStars.push({star:c,direction:new C(u,d,f).normalize(),altitudeDeg:l})}this.starTiers=am.map((c,l)=>{const h=o.filter(b=>H3(b.brightness)===l),u=new Float32Array(h.length*3),d=new Float32Array(h.length),f=new Float32Array(h.length),p=new Float32Array(h.length);h.forEach((b,_)=>{u[_*3]=b.x,u[_*3+1]=b.y,u[_*3+2]=b.z,d[_]=b.brightness,f[_]=b.phase,p[_]=b.speedFactor});const v=new Et;v.setAttribute("position",new dt(u,3));const g=new dt(new Float32Array(h.length*3),3);v.setAttribute("color",g);const m=new kp({vertexColors:!0,size:c.size,sizeAttenuation:!1,fog:!1});ws.apply(m);const E=new Go(v,m);return this.celestialGroup.add(E),{points:E,colorAttribute:g,brightness:d,phase:f,speedFactor:p}}),this.updateTwinkle(0),this.startTwinkle()}updateTwinkle(e){for(const t of this.starTiers){const n=t.colorAttribute.array;for(let i=0;i<t.brightness.length;i++){const r=W3(t.brightness[i],{phase:t.phase[i],speedFactor:t.speedFactor[i]},e),a=vl(t.brightness[i])*r;n[i*3]=a,n[i*3+1]=a,n[i*3+2]=a}t.colorAttribute.needsUpdate=!0}}buildClouds(){if(this.cloudRendering==="volume"||this.weather.cloudLayers!==void 0){this.layeredClouds||(this.disposeCloudSystem(),this.layeredClouds=new g3(this.celestialGroup,Il,this.cloudRendering)),this.disposeCirrus(),this.layeredClouds.update(this.weather,this.observerElevationM+1.6),this.layeredClouds.setOffsets(this.cloudOffsetM,this.cloudLayerOffsetsM),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}this.disposeCloudSystem();const e=this.lowerCloudCover();if(e<=0)return;const t=this.weather.cloudDarkness,n=new ce(Ms[0]+(Ol[0]-Ms[0])*t,Ms[1]+(Ol[1]-Ms[1])*t,Ms[2]+(Ol[2]-Ms[2])*t),{material:i,uniforms:r}=Bh(n,e,Math.abs(this.cloudLayerOffset()));this.cloudMaterial=i,this.cloudUniforms=r,r.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);const a=Hh(Il);this.cloudMesh=new Ye(a,i),this.cloudLayerOffset()<0&&(this.cloudMesh.scale.y=-1),this.cloudMesh.renderOrder=Uf,this.celestialGroup.add(this.cloudMesh)}lowerCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(e=>e.type!=="cirrus").reduce((e,t)=>e*(1-t.coverage),1):this.weather.lowerCloudCover??this.weather.cloudCover}highCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(e=>e.type==="cirrus").reduce((e,t)=>e*(1-t.coverage),1):this.weather.highCloudCover}buildCirrus(){if(this.disposeCirrus(),this.layeredClouds)return;const e=this.weather.highCloudCover??0;if(e<=0)return;const{material:t,uniforms:n}=Bh(new ce(...Ms),e,Co,1);this.cirrusMaterial=t,this.cirrusUniforms=n,n.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.cirrusMesh=new Ye(Hh(Il*1.04),t),this.cirrusMesh.renderOrder=Uf-1,this.celestialGroup.add(this.cirrusMesh)}disposeCirrus(){this.cirrusMesh&&(this.cirrusMesh.removeFromParent(),this.cirrusMesh.geometry.dispose()),this.cirrusMaterial?.dispose(),this.cirrusMesh=void 0,this.cirrusMaterial=void 0,this.cirrusUniforms=void 0}syncCloudLayer(){this.layeredClouds?.update(this.weather,this.observerElevationM+1.6);const e=this.cloudLayerOffset();this.cloudUniforms&&(this.cloudUniforms.layerHeight.value=Math.abs(e)),this.cloudMesh&&(this.cloudMesh.scale.y=e<0?-1:1)}cloudLayerOffset(){const t=((this.weather.cloudBaseM??1e3)-this.observerElevationM)*Ll;return Math.sign(t||1)*Math.max(Math.abs(t),nE)}updateCloudLighting(e,t){const n=[this.cloudUniforms,this.cirrusUniforms].filter(l=>l!==void 0);if(n.length===0&&!this.layeredClouds)return;const{x:i,y:r,z:a}=fn(e.altitudeDeg,e.azimuthDeg,1),o=vs(e.altitudeDeg),c=Math.max(0,Math.sin(Math.max(e.altitudeDeg,0)*Tn));this.layeredClouds?.setLighting(new C(i,r,a),new ce(o[0]*c,.96*o[1]*c,.88*o[2]*c),new ce(...t),new ce(...t));for(const l of n)l.sunDir.value.set(i,r,a),l.sunColor.value.setRGB(o[0]*c,.96*o[1]*c,.88*o[2]*c),l.ambientColor.value.setRGB(t[0],t[1],t[2])}disposeCloudSystem(){this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.cloudMesh&&(this.cloudMesh.removeFromParent(),this.cloudMesh.geometry.dispose()),this.cloudMaterial?.dispose(),this.cloudMesh=void 0,this.cloudMaterial=void 0,this.cloudUniforms=void 0}disposePrecipitationPoints(){this.precipitationPoints&&(this.precipitationPoints.removeFromParent(),this.precipitationPoints.geometry.dispose(),this.precipitationPoints.material.dispose()),this.precipitationPoints=void 0,this.precipitationPositions=void 0,this.precipitationPhase=void 0,this.precipitationSpeedJitter=void 0,this.precipitationWobbleFreqJitter=void 0,this.precipitationWobbleAmpJitter=void 0,this.precipitationBounceRemaining=void 0,this.precipitationBounceHeight=void 0,this.precipitationBounceDuration=void 0,this.precipitationBounceVelX=void 0,this.precipitationBounceVelZ=void 0,this.precipitationUniforms=void 0}buildPrecipitation(){this.disposePrecipitationPoints(),this.disposeRain();const e=this.weather.precipitationType;if(e==="none")return;if(e==="rain"){this.buildRain();return}const t=Ff[e],n=t.poolSize,i=zl(9001),r=new Float32Array(n*3),a=new Float32Array(n),o=new Float32Array(n),c=new Float32Array(n),l=new Float32Array(n),h=new Float32Array(n),u=new Float32Array(n),d=new Float32Array(n),f=new Float32Array(n),p=new Float32Array(n);for(let b=0;b<n;b++){const _=i()*Math.PI*2,S=i()*t.radiusM;r[b*3]=Math.cos(_)*S,r[b*3+1]=hr+i()*(t.topYM-hr),r[b*3+2]=Math.sin(_)*S,a[b]=i()*Math.PI*2,o[b]=.7+i()*.6,c[b]=.6+i()*.8,l[b]=.4+i()*1.2}const v=new Et;v.setAttribute("position",new dt(r,3)),v.setDrawRange(0,Fl(n,this.weather.precipitationIntensity));const g={uSize:{value:t.size},uScale:{value:.5*this.renderer.domElement.height},uOpacity:{value:t.opacity},uColor:{value:t.color},uHazeColor:{value:new ce(...this.baseFogColor)},uTexture:{value:_E(e)},uNearFocusDistance:{value:Wf},uHazeDistance:{value:t.radiusM*Xf}},m=new wt({uniforms:g,vertexShader:AE,fragmentShader:TE,transparent:!0,depthWrite:!1});this.precipitationUniforms=g;const E=new Go(v,m);E.renderOrder=Nl,this.scene.add(E),this.precipitationPoints=E,this.precipitationPositions=r,this.precipitationPhase=a,this.precipitationSpeedJitter=o,this.precipitationWobbleFreqJitter=c,this.precipitationWobbleAmpJitter=l,this.precipitationBounceRemaining=h,this.precipitationBounceHeight=u,this.precipitationBounceDuration=d,this.precipitationBounceVelX=f,this.precipitationBounceVelZ=p}updatePrecipitation(e,t){if(!this.precipitationPoints||!this.precipitationPositions||!this.precipitationPhase||!this.precipitationSpeedJitter||(this.precipitationUniforms?.uHazeColor.value.setRGB(...this.baseFogColor),t<=0))return;const n=this.weather.precipitationType;if(n==="none"||n==="rain")return;const i=Ff[n],r=this.weather.windDirectionDeg*Tn,a=Math.sin(r)*this.weather.windSpeed*i.driftSensitivity,o=-Math.cos(r)*this.weather.windSpeed*i.driftSensitivity,c=this.precipitationPositions,l=this.precipitationPhase,h=this.precipitationSpeedJitter,u=this.precipitationWobbleFreqJitter,d=this.precipitationWobbleAmpJitter,f=this.precipitationBounceRemaining,p=this.precipitationBounceHeight,v=this.precipitationBounceDuration,g=this.precipitationBounceVelX,m=this.precipitationBounceVelZ,E=n==="snow"&&u&&d,b=n==="hail"&&f&&p&&v&&g&&m;for(let _=0,S=0;_<c.length;_+=3,S++){if(b&&f[S]>0){if(f[S]-=t,f[S]<=0){const x=Math.random()*Math.PI*2,A=Math.sqrt(Math.random())*i.radiusM;c[_]=Math.cos(x)*A,c[_+1]=i.topYM,c[_+2]=Math.sin(x)*A,f[S]=0}else{const x=1-f[S]/v[S];c[_+1]=hr+Math.sin(Math.PI*x)*p[S],c[_]=Io(c[_]+(a+g[S])*t,i.radiusM),c[_+2]=Io(c[_+2]+(o+m[S])*t,i.radiusM)}continue}let w=0,R=0;if(E){const x=fE*u[S],A=pE*d[S];w=Math.sin(e*x*Math.PI*2+l[S])*A,R=Math.sin(e*x*Math.PI*2+l[S]+Math.PI/2)*A}if(c[_]+=(a+w)*t,c[_+1]-=i.fallSpeedMPerS*h[S]*t,c[_+2]+=(o+R)*t,c[_]=Io(c[_],i.radiusM),c[_+2]=Io(c[_+2],i.radiusM),c[_+1]<hr){if(b){p[S]=Zf*(.2+Math.random()*1.6),v[S]=mE*(.5+Math.random()),f[S]=v[S];const P=Math.random()*Math.PI*2,D=gE*(p[S]/Zf);g[S]=Math.cos(P)*D,m[S]=Math.sin(P)*D,c[_+1]=hr;continue}const x=Math.random()*Math.PI*2,A=Math.sqrt(Math.random())*i.radiusM;c[_]=Math.cos(x)*A,c[_+1]=i.topYM,c[_+2]=Math.sin(x)*A}}this.precipitationPoints.geometry.attributes.position.needsUpdate=!0}buildRain(){const e=Hf(this.weather.precipitationIntensity);this.rainSystem=ob({count:zf,radiusM:ea,heightM:sE,bottomYM:kf,overallSpeed:rE,color:oE,opacity:.85,visibleCount:Fl(zf,this.weather.precipitationIntensity),speedStreak:hE(e),pixelSize:Yf,seed:9001,nearFocusDistanceM:Wf,hazeDistanceM:ea*Xf,hazeColor:new ce(...this.baseFogColor)}),this.rainLastVerticalFacing=-1,this.syncRainSlant(),this.rainSystem.points.renderOrder=Nl,this.scene.add(this.rainSystem.points),this.buildRainSplashes()}buildRainSplashes(){const e=zl(4242),t=new Float32Array(cr*3),n=new Float32Array(cr),i=new Float32Array(cr),r=new Float32Array(cr);for(let h=0;h<cr;h++){const u=e()*Math.PI*2,d=Math.sqrt(e())*ea;t[h*3]=Math.cos(u)*d,t[h*3+1]=kf,t[h*3+2]=Math.sin(u)*d,i[h]=Po(Gf,Vf),n[h]=e()*i[h],r[h]=n[h]/i[h]}const a=new Et;a.setAttribute("position",new dt(t,3));const o=new dt(r,1);a.setAttribute("aLife",o),a.setDrawRange(0,Fl(cr,this.weather.precipitationIntensity));const c=new wt({uniforms:{uMaxSize:{value:uE},uScale:{value:.5*this.renderer.domElement.height},uColor:{value:dE},uTexture:{value:bE()}},vertexShader:EE,fragmentShader:wE,transparent:!0,depthWrite:!1}),l=new Go(a,c);l.renderOrder=Nl,this.scene.add(l),this.rainSplashSystem={points:l,positions:t,life:n,duration:i,lifeAttribute:o}}disposeRain(){this.rainSystem&&(this.rainSystem.points.removeFromParent(),this.rainSystem.points.geometry.dispose(),this.rainSystem.points.material.dispose()),this.rainSystem=void 0,this.disposeRainSplashes()}disposeRainSplashes(){this.rainSplashSystem&&(this.rainSplashSystem.points.removeFromParent(),this.rainSplashSystem.points.geometry.dispose(),this.rainSplashSystem.points.material.dispose()),this.rainSplashSystem=void 0}syncRainSlant(){const e=this.rainSystem;if(!e)return;const t=this.weather.windDirectionDeg*Tn;e.uniforms.uDropVelocity.value.set(Math.sin(t)*this.weather.windSpeed,-Hf(this.weather.precipitationIntensity),-Math.cos(t)*this.weather.windSpeed);const n=this.renderer.getSize(this.rainViewportSize);e.uniforms.uAspect.value=n.x/Math.max(n.y,1)}updateRain(e){const t=this.rainSystem;if(!t)return;t.uniforms.uTime.value+=e,t.uniforms.uHazeColor.value.setRGB(...this.baseFogColor);const n=this.weather.windDirectionDeg*Tn,i=Math.sin(n)*this.weather.windSpeed,r=-Math.cos(n)*this.weather.windSpeed,a=ea,o=l=>(l%(a*2)+a*3)%(a*2)-a;t.uniforms.uWindOffset.value.set(o(t.uniforms.uWindOffset.value.x+i*e),o(t.uniforms.uWindOffset.value.y+r*e)),this.syncRainSlant(),this.camera.getWorldDirection(this.rainCameraDirection);const c=Math.abs(this.rainCameraDirection.y);if(Math.abs(c-this.rainLastVerticalFacing)>.001){this.rainLastVerticalFacing=c;const l=Kf+(1-Kf)*(1-c),h=$f+(1-$f)*(1-c);t.uniforms.uUvSquash.value=h,t.uniforms.uPixelSize.value=Yf*l*(.5+.5*h)}this.updateRainSplashes(e)}updateRainSplashes(e){const t=this.rainSplashSystem;if(!t||e<=0)return;const{positions:n,life:i,duration:r,lifeAttribute:a}=t,o=a.array;for(let c=0,l=0;c<n.length;c+=3,l++){if(i[l]+=e,i[l]>=r[l]){const h=Math.random()*Math.PI*2,u=Math.sqrt(Math.random())*ea;n[c]=Math.cos(h)*u,n[c+2]=Math.sin(h)*u,r[l]=Po(Gf,Vf),i[l]=0}o[l]=i[l]/r[l]}t.points.geometry.attributes.position.needsUpdate=!0,a.needsUpdate=!0}updateLightning(e,t){if(this.lightningArmed){if(this.lightningFlashRemainingS>0){this.lightningFlashRemainingS=Math.max(0,this.lightningFlashRemainingS-t);const n=this.lightningFlashRemainingS/jf;this.scene.fog&&this.scene.fog.color.setRGB(this.baseFogColor[0]+(1-this.baseFogColor[0])*n,this.baseFogColor[1]+(1-this.baseFogColor[1])*n,this.baseFogColor[2]+(1-this.baseFogColor[2])*n);return}if(this.nextLightningAtS===null){this.nextLightningAtS=e+Po(Jf,Qf);return}e>=this.nextLightningAtS&&(this.lightningFlashRemainingS=jf,this.nextLightningAtS=e+Po(Jf,Qf),this.onLightningFlash?.())}}buildCompassLabels(){const e=gu(navigator.languages,Yb),t=qb[e];this.compassSprites=Xb.map((n,i)=>{const r=t[i],a=new ia({map:CE(r),depthTest:!1,fog:!1}),o=new Ja(a),{x:c,y:l,z:h}=fn(0,n,Kb);return o.position.set(c,l,h),o.scale.set(Pl,Pl,1),o.renderOrder=Zb,o.visible=this.compassHovered||this.compassForced,this.celestialGroup.add(o),o}),this.updateCompassScale()}updateCompassScale(){const e=this.camera.fov*Math.PI/360,t=$b*Math.PI/360,n=Pl*Math.tan(e)/Math.tan(t);for(const i of this.compassSprites)i.scale.set(n,n,1)}disposeCompassLabels(){for(const e of this.compassSprites)e.removeFromParent(),e.material.map?.dispose(),e.material.dispose();this.compassSprites=[]}disposeStarTiers(){for(const e of this.starTiers)this.disposeMesh(e.points);this.starTiers=[]}disposeMesh(e){if(!e)return;e.removeFromParent(),"geometry"in e&&e.geometry.dispose();const t=e.material;for(const n of Array.isArray(t)?t:[t]){const i=n.map;i&&i.dispose(),n.dispose()}}}const Tn=Math.PI/180;function dc(s,e,t){return Math.max(e,Math.min(t,s))}function Po(s,e){return s+Math.random()*(e-s)}function Io(s,e){return(s%(e*2)+e*3)%(e*2)-e}let Lo,No;function _E(s){switch(s){case"snow":return yE();case"hail":return SE()}}function yE(){if(Lo)return Lo;const s=64,e=document.createElement("canvas");e.width=s,e.height=s;const t=e.getContext("2d"),n=t.createRadialGradient(s/2,s/2,0,s/2,s/2,s/2);return n.addColorStop(0,"rgba(255,255,255,0.95)"),n.addColorStop(.5,"rgba(255,255,255,0.55)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,s,s),Lo=new yi(e),Lo}function SE(){if(No)return No;const s=64,e=document.createElement("canvas");e.width=s,e.height=s;const t=e.getContext("2d"),n=t.createRadialGradient(s/2,s/2,0,s/2,s/2,s/2);return n.addColorStop(0,"rgba(255,255,255,1)"),n.addColorStop(.55,"rgba(255,255,255,0.95)"),n.addColorStop(.8,"rgba(255,255,255,0.4)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,s,s),No=new yi(e),No}let Oo;function bE(){if(Oo)return Oo;const s=64,e=document.createElement("canvas");e.width=s,e.height=s;const t=e.getContext("2d"),n=t.createRadialGradient(s/2,s/2,0,s/2,s/2,s/2);return n.addColorStop(0,"rgba(255,255,255,0)"),n.addColorStop(.4,"rgba(255,255,255,0)"),n.addColorStop(.6,"rgba(255,255,255,0.9)"),n.addColorStop(.8,"rgba(255,255,255,0.25)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,s,s),Oo=new yi(e),Oo}const EE=`
5914
5914
  uniform float uMaxSize;
5915
5915
  uniform float uScale;
5916
5916
  attribute float aLife;
@@ -6248,7 +6248,7 @@ void main()
6248
6248
  `+i.vertexShader,i.vertexShader=i.vertexShader.replace("#include <project_vertex>",`#include <project_vertex>
6249
6249
  cloudPoint = (modelMatrix * vec4(transformed, 1.0)).xyz - cameraPosition;`);let r=`varying vec3 cloudPoint;
6250
6250
  `,a="";t.forEach((o,l)=>{const c=`cloud${l}_`;for(const[h,u]of Object.entries(o.uniforms))i.uniforms[c+h]=u;r+=B3(c),a+=`diffuseColor.a *= ${c}transmissionAt(normalize(cloudPoint), length(cloudPoint));
6251
- `}),i.fragmentShader=r+i.fragmentShader,i.fragmentShader=i.fragmentShader.replace("#include <opaque_fragment>",a+"#include <opaque_fragment>")},e.needsUpdate=!0}meshes=new Map;signatures=new Map;extents=new Map;placed=[];frame;direction=new D;up=new D;lookAt=new Xe;vertex=new D;centre=new D;right=new D;above=new D;set(e,t){this.placed=e,this.frame=t;const n=new Set(e.map(i=>i.sourceId));for(const[i,r]of this.meshes)n.has(i)||(this.dispose(r),this.meshes.delete(i),this.signatures.delete(i),this.extents.delete(i));for(const i of e){let r=this.meshes.get(i.sourceId);r||(r=new Ye(new qi(1,1,Yn.SEGMENTS,Yn.SEGMENTS),new Bi({transparent:!0,depthWrite:!1,depthTest:!0,fog:!1,toneMapped:!1})),this.configureCloudMaterial(r.material),r.frustumCulled=!1,r.layers.set(tg),this.scene.add(r),this.meshes.set(i.sourceId,r)),r.renderOrder=nw+i.renderOrder,r.visible=!i.hidden&&i.shape.transparency<1,r.visible&&this.paint(r,i,t)}}place(e,t,n){const i=this.frame;if(i)for(const r of this.placed){const a=this.meshes.get(r.sourceId);if(!a||!a.visible)continue;const o=this.extents.get(r.sourceId);if(!o)continue;const{bounds:l}=r.shape;let c=l.x+l.width/2,h=l.y+l.height/2,u=!0;if(r.aim){const d=n(Yn.directionOf(r.aim,this.direction));d&&Math.abs(d.ndcX)<Yn.FURTHEST_NDC&&Math.abs(d.ndcY)<Yn.FURTHEST_NDC?(c=(d.ndcX+1)/2*i.canvasWidthPx,h=(1-d.ndcY)/2*i.canvasHeightPx):u=!1}u?this.curve(a,e,t,i,o,c,h,r.distanceM):this.flat(a,e,i,o,r.distanceM)}}static FURTHEST_NDC=4;curve(e,t,n,i,r,a,o,l){const c=a-r.width/2,h=o-r.height/2,u=e.geometry.attributes.position,d=Yn.SEGMENTS;let f=0;for(let p=0;p<=d;p++){const v=h+p/d*r.height;for(let g=0;g<=d;g++){const m=c+g/d*r.width;n(m/i.canvasWidthPx*2-1,-(v/i.canvasHeightPx*2-1),this.direction),this.vertex.copy(t.position).addScaledVector(this.direction,l),u.setXYZ(f++,this.vertex.x,this.vertex.y,this.vertex.z)}}u.needsUpdate=!0,e.matrixAutoUpdate=!1,e.matrix.identity(),e.matrixWorldNeedsUpdate=!0,e.scale.set(mt.sizeMAt(l,i.projection.pxToDeg(r.width)),mt.sizeMAt(l,i.projection.pxToDeg(r.height)),1)}flat(e,t,n,i,r){const a=e.geometry.attributes.position,o=Yn.SEGMENTS,l=mt.sizeMAt(r,n.projection.pxToDeg(i.width)),c=mt.sizeMAt(r,n.projection.pxToDeg(i.height));this.up.set(0,1,0).applyQuaternion(t.quaternion),this.centre.copy(t.position).addScaledVector(this.direction,r),this.lookAt.lookAt(t.position,this.centre,this.up),this.right.setFromMatrixColumn(this.lookAt,0),this.above.setFromMatrixColumn(this.lookAt,1);let h=0;for(let u=0;u<=o;u++){const d=.5-u/o;for(let f=0;f<=o;f++){const p=f/o-.5;this.vertex.copy(this.centre).addScaledVector(this.right,p*l).addScaledVector(this.above,d*c),a.setXYZ(h++,this.vertex.x,this.vertex.y,this.vertex.z)}}a.needsUpdate=!0,e.matrixAutoUpdate=!1,e.matrix.identity(),e.matrixWorldNeedsUpdate=!0,e.scale.set(l,c,1)}static SEGMENTS=16;static directionOf(e,t){const n=e.azimuthDeg*Math.PI/180,i=e.altitudeDeg*Math.PI/180;return t.set(Math.sin(n)*Math.cos(i),Math.sin(i),-Math.cos(n)*Math.cos(i))}get any(){for(const e of this.meshes.values())if(e.visible)return!0;return!1}get furthestM(){return this.placed.reduce((e,t)=>Math.max(e,t.distanceM),0)}paint(e,t,n){const{shape:i}=t,r=Qc.paintExtent(i);this.extents.set(t.sourceId,r);const a=Yn.signatureOf(i,n);if(this.signatures.get(t.sourceId)===a&&e.material.map)return;this.signatures.set(t.sourceId,a);const o=Math.min(n.scale,iw/Math.max(r.width,r.height,1)),l=Math.max(1,Math.ceil(r.width*o)),c=Math.max(1,Math.ceil(r.height*o)),h=e.material.map,u=h?.image??document.createElement("canvas"),d=u.width!==l||u.height!==c;d&&(u.width=l,u.height=c);const f=u.getContext("2d");if(!f)return;f.clearRect(0,0,l,c);const p=new Qc(f);if(p.setStarPoints(n.starPoints),p.setRoll(n.rollRad),p.paintInto(i,r,o),h&&!d){h.needsUpdate=!0;return}h?.dispose();const v=new Si(u);v.colorSpace=Dn,v.minFilter=_t,v.generateMipmaps=!1,e.material.map=v,e.material.needsUpdate=!0}static signatureOf(e,t){const{bounds:n}=e;return JSON.stringify([e.kind,Math.round(n.width*10),Math.round(n.height*10),e.color,e.angle,e.transparency,e.haloScale,e.blur??0,e.brightness??0,e.kind==="polygon"?e.points:void 0,t.scale,t.starPoints,t.rollRad])}dispose(e){e.removeFromParent(),e.geometry.dispose(),e.material.map?.dispose(),e.material.dispose()}clear(){for(const e of this.meshes.values())this.dispose(e);this.meshes.clear(),this.signatures.clear(),this.extents.clear(),this.placed=[]}}function sw(s,e){return JSON.stringify(s.cloudLayers)===JSON.stringify(e.cloudLayers)&&s.cloudCover===e.cloudCover&&s.cloudDarkness===e.cloudDarkness&&s.cloudBaseM===e.cloudBaseM&&s.highCloudCover===e.highCloudCover&&s.iceCrystalAlignment===e.iceCrystalAlignment&&s.lowerCloudCover===e.lowerCloudCover&&s.precipitationType===e.precipitationType&&s.precipitationIntensity===e.precipitationIntensity&&s.windDirectionDeg===e.windDirectionDeg&&s.windSpeed===e.windSpeed&&s.storm===e.storm}const Lo=900,Uc=1,zf=.5,da=900,rw=6371e3,aw=3e4;function Bf(s){const e=Math.sqrt(2*rw*Math.max(s,0));return Math.max(da,Math.min(e,aw))}const Fc=.5,Hf=850,ow=.03,No=850,kc=4,Gf=1.5,Vf=-1,lw=6,Su=-4,Wf=.2,Oo=2600,cw=.97,hw=.38,Xf=Su,uw=3,dw=.15,fw=.6,pw=40,mw=30,gw=[0,45,90,135,180,225,270,315],vw={en:["N","NE","E","SE","S","SW","W","NW"],fr:["N","NE","E","SE","S","SO","O","NO"]},xw=["en","fr"],Mw=880,zc=40,_w=60,yw=10,Sw=1,bw=150,ww=55,Ew=.5,Aw=2.05,qf=.265,Yf=[[0,0],...Array.from({length:8},(s,e)=>{const t=e*Math.PI/4;return[Math.cos(t)*qf,Math.sin(t)*qf]})],Bc=700,Hc=250/Eu,Tw=12,Kf=5,Gc=6,bs=[.92,.92,.95],Vc=[.15,.15,.19],$f={snow:{fallSpeedMPerS:2,size:.3,color:new le(1,1,1),driftSensitivity:1,radiusM:25,topYM:20,opacity:.75,poolSize:2400},hail:{fallSpeedMPerS:14,size:.5,color:new le(.95,.98,1),driftSensitivity:.25,radiusM:25,topYM:10,opacity:.95,poolSize:1200}},mr=0,Wc=0,Rw=150,Zf=3e3,sa=20,Cw=15,Jf=mr,Dw=40,jf=1,Pw=9;function Qf(s){return jf+(Pw-jf)*s}const Iw=new le(.75,.82,.92),Lw=10,Nw=.5;function Ow(s){return xl(s/Lw,Nw,1)}const fr=200,ep=.18,tp=.32,Uw=.35,Fw=new le(.85,.9,.98),np=5,ip=.85,sp=.01;function Xc(s,e){return Math.round(s*(sp+(1-sp)*e))}const rp=230,ap=.7,op=.05,kw=.6,zw=.7,Bw=.15,lp=.35,Hw=3,Gw=1/12,Vw=.5,cp=8,hp=25,up=.12,Ww={Venus:new le(1,.96,.85),Mars:new le(1,.55,.4),Jupiter:new le(.95,.87,.72),Saturn:new le(.92,.86,.68)};class li{renderer;scene=new Al;phenomena=new Yn(this.scene);camera;celestialGroup=new an;skyMesh;groundMesh;terrainMesh;terrainProviders;terrainOrigin;terrainBuildToken=0;terrainAttribution;decorModelProvider=ew[0].create();decorModelToken=0;decorModelCredits=new Map;starTiers=[];bodyMeshes=new Map;hitAreas=new Map;glareSprites=new Map;decorObjects=[];decorGroups=new Map;decorReferencePose;decorCurrentPose;decorTime=0;celestialLight=new w2(16777215,0);celestialLightTarget=new yt;skyLight=new M2(16777215,0,0);streetlightLights=new Map;compassSprites=[];showCompass=!1;compassHovered=!1;compassForced=!1;animationFrameId=null;raycaster=new mc;weather=vp;observerElevationM=0;groundRadius=da;terrainRadius=da;cloudRendering="surface";layeredClouds;cloudLayerOffsetsM={};cloudOffsetM=new D;cloudFieldOffset=new D;cloudMesh;cirrusMesh;cirrusMaterial;cirrusUniforms;cloudMaterial;cloudUniforms;precipitationPoints;precipitationPositions;precipitationPhase;precipitationSpeedJitter;precipitationWobbleFreqJitter;precipitationWobbleAmpJitter;precipitationBounceRemaining;precipitationBounceHeight;precipitationBounceDuration;precipitationBounceVelX;precipitationBounceVelZ;precipitationUniforms;rainSystem;rainSplashSystem;rainCameraDirection=new D;rainLastVerticalFacing=-1;rainViewportSize=new Pe;lightningArmed=!1;nextLightningAtS=null;lightningFlashRemainingS=0;baseFogColor=[0,0,0];lastSunPosition;lensFlare;sunCloudTransmission=1;sunUnhiddenFraction=1;lensFlareArtifactIntensity=0;sunWorldPosition=new D;sunVisible=!1;lensFlareScratch=new D;sunOcclusionRaycaster=new mc;sunOcclusionDirectionScratch=new D;sunOcclusionRightScratch=new D;sunOcclusionUpScratch=new D;ufoOcclusionRaycaster=new mc;projectionKind="rectilinear";starPoints=0;namedStars=[];equidistantPass;depthOfFieldPass;exposureAccumulation;exposureInstants=1;get developingExposure(){return this.exposureInstants>1&&this.exposureInstantAt!==void 0}static EXPOSURE_BUDGET_MS=12;exposureFrameId=null;exposureInstantsDone=0;exposureInstantAt;restatingExposure=!1;lensOptics;instrumentMagnitudeGain=0;meteorSystem;cometTail;iceHalos;rainbow;skyGlow;cometKey;onLightningFlash;constructor(e,t=M1(),n){this.renderer=new P3({canvas:e,antialias:!0}),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio||1,2)),this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=fa,this.camera=new Sn(60,e.width/Math.max(e.height,1),.1,Lo*1.2),this.camera.position.set(0,1.6,0),this.terrainProviders=t,this.onLightningFlash=n,this.celestialLight.shadow.mapSize.set(1024,1024),this.celestialLight.shadow.camera.left=-120,this.celestialLight.shadow.camera.right=120,this.celestialLight.shadow.camera.top=120,this.celestialLight.shadow.camera.bottom=-120,this.celestialLight.shadow.camera.near=1,this.celestialLight.shadow.camera.far=1e3,this.celestialLight.shadow.bias=-.0015,this.celestialLight.target=this.celestialLightTarget,this.scene.add(this.celestialLight,this.celestialLightTarget,this.skyLight),this.scene.add(this.celestialGroup)}get currentTerrainAttribution(){return this.terrainAttribution}resize(e,t){this.renderer.setSize(e,t,!1),this.camera.aspect=e/Math.max(t,1),this.camera.updateProjectionMatrix(),this.render()}setCloudRendering(e){e!==this.cloudRendering&&(this.cloudRendering=e,this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.buildClouds(),this.buildCirrus(),this.render())}setCloudOffset(e,t={}){this.cloudOffsetM.set(e.x,0,e.z),this.cloudLayerOffsetsM=t,this.layeredClouds?.setOffsets(e,t),this.cloudFieldOffset.set(e.x*Hc,0,e.z*Hc);for(const n of[this.cloudUniforms,this.cirrusUniforms])n?.fieldOffset.value.copy(this.cloudFieldOffset);this.iceHalos?.setCloudOffset(this.layeredClouds?.cirrusMask?.offset??this.cloudFieldOffset)}setObserverPose(e){const t=((e.rollDeg??0)+this.gaitOffset.rollDeg)*Tn,n=(e.pitchDeg+this.lookPitchDeg+this.gaitOffset.pitchDeg)*Tn;if(e.headingDeg!==void 0?this.camera.rotation.set(n,-(e.headingDeg+this.lookYawDeg+this.gaitOffset.yawDeg)*Tn,t,"YXZ"):this.camera.rotation.set(n,this.camera.rotation.y,t,"YXZ"),e.elevationM!==this.observerElevationM&&(this.observerElevationM=e.elevationM,this.syncCloudLayer(),Math.abs(Bf(e.elevationM)-this.groundRadius)>1&&(this.buildGround(),this.celestialGroup.scale.setScalar(this.groundRadius/da),this.camera.far=Math.max(Lo*1.2,this.groundRadius*2.5),this.camera.updateProjectionMatrix())),this.terrainMesh&&this.terrainOrigin&&e.lat!==void 0&&e.lng!==void 0){const i=rn(this.terrainOrigin.lat,this.terrainOrigin.lng,e.lat,e.lng);this.terrainMesh.position.x=i.x,this.terrainMesh.position.z=i.z}this.poseCameraY=this.groundYUnder(0,0)+1.6+e.elevationM,this.camera.position.y=this.poseCameraY,this.celestialGroup.position.y=this.camera.position.y,this.camera.fov!==e.fovDeg&&(this.camera.fov=e.fovDeg,this.camera.updateProjectionMatrix(),this.updateCompassScale())}setTerrainProviders(e){this.terrainProviders=e,this.disposeMesh(this.terrainMesh),this.terrainMesh=void 0,this.terrainOrigin=void 0,this.terrainAttribution=void 0,this.applyGroundDepthWrite(),this.terrainBuildToken++}setTerrainOrigin(e,t,n){if(e===void 0||t===void 0)return;const i=this.groundRadius;if(this.terrainOrigin&&Math.abs(this.terrainRadius-i)<i*.1){const{x:l,z:c}=rn(e,t,this.terrainOrigin.lat,this.terrainOrigin.lng);if(Math.sqrt(l*l+c*c)<bw*(i/da))return}const r=this.terrainOrigin,a=this.terrainRadius;this.terrainOrigin={lat:e,lng:t},this.terrainRadius=i;const o=++this.terrainBuildToken;Sb(e,t,this.terrainProviders,i).then(({mesh:l,attribution:c})=>{if(o!==this.terrainBuildToken)return;const h=this.terrainMesh,u=r?rn(e,t,r.lat,r.lng):void 0;h&&u&&Math.hypot(u.x,u.z)<=a&&(l.position.y=h.position.y+this.groundYOfPatch(h,u.x,u.z)),this.disposeMesh(this.terrainMesh),l.renderOrder=Sw,this.terrainMesh=l,this.terrainAttribution=c,this.scene.add(l),this.applyGroundDepthWrite(),this.decorCurrentPose&&(this.setObserverPose(this.decorCurrentPose),this.updateDecorAnchoring(this.decorReferencePose,this.decorCurrentPose,this.decorTime)),this.render(),n?.()}).catch(l=>{console.warn("Terrain build failed, keeping the flat ground fallback:",l),n?.()})}setShowCompass(e){this.showCompass!==e&&(this.showCompass=e,this.disposeCompassLabels(),e&&this.buildCompassLabels(),this.render())}applyLensFlareTint(e){if(!this.lensFlare)return;const t=ww*this.sunCloudTransmission;this.lensFlare.uniforms.uColorGain.value.setRGB(t*e[0],t*e[1],t*e[2]),this.applyDazzleStrength()}applyDazzleStrength(){if(!this.lensFlare)return;const e=this.lastSunPosition?.altitudeDeg??-90,t=hS(e)*this.sunCloudTransmission*this.sunUnhiddenFraction,n=ys(e);this.lensFlare.uniforms.uDazzleColour.value.setRGB(n[0],n[1],n[2]),this.lensFlare.uniforms.uVeilStrength.value=Aw**2*Math.max(0,t)}setCompassHovered(e){this.compassHovered!==e&&(this.compassHovered=e,this.updateCompassVisibility())}setCompassForced(e){this.compassForced!==e&&(this.compassForced=e,this.updateCompassVisibility())}updateCompassVisibility(){const e=this.compassHovered||this.compassForced;for(const t of this.compassSprites)t.visible=e;this.render()}setWeather(e){sw(this.weather,e)||(this.weather=e,this.buildClouds(),this.buildCirrus(),this.buildPrecipitation(),this.lightningArmed=e.storm&&e.cloudDarkness>=Vw,this.lightningArmed||(this.nextLightningAtS=null,this.lightningFlashRemainingS=0,this.restoreFogColor()),this.syncAnimationLoop(),this.render())}setDecor(e){if(this.decorObjects!==e){this.decorObjects=e,this.decorModelToken++,this.decorModelCredits.clear();for(const t of this.decorGroups.values())t.removeFromParent(),jt.dispose(t);this.decorGroups.clear(),this.streetlightLights.clear();for(const t of e){const n=jt.build(t,t.lit??!1);this.scene.add(n),this.decorGroups.set(t.id,n),t.kind==="streetlight"&&this.addStreetlightLight(t.id,n),this.loadDecorModel(t,this.decorModelToken)}this.celestialLight.castShadow=this.decorGroups.size>0}}setDecorModelProvider(e){this.decorModelProvider=e;const t=this.decorObjects;this.decorObjects=[],this.setDecor(t)}get currentDecorModelCredits(){return[...this.decorModelCredits.values()]}async loadDecorModel(e,t){const n=e.model;if(!(!n||!jt.usesModel(e)))try{const i=n.url?void 0:n.id?await this.decorModelProvider.entry(n.id):void 0,r=n.url??i?.url,a=n.credit??i?.credit;if(!r||!a)return;const o=await tw(r);if(t!==this.decorModelToken)return;const l=this.decorGroups.get(e.id);if(!l)return;jt.applyModel(l,e,o,{headingOffsetDeg:n.headingOffsetDeg??i?.headingOffsetDeg,depictedSizeM:i?.sizeM}),this.decorModelCredits.set(e.id,a),this.render()}catch(i){console.warn(`Keeping the built-in shape for decor "${e.id}":`,i)}}updateDecorAnchoring(e,t,n=0){this.decorReferencePose=e,this.decorCurrentPose=t,this.decorTime=n;const i=e?.lat!==void 0&&e.lng!==void 0&&t?.lat!==void 0&&t?.lng!==void 0?rn(e.lat,e.lng,t.lat,t.lng):{x:0,z:0},r=this.decorObjects.find(c=>c.witnessSide!==void 0&&_p(c.kind));r||(i.x-=this.gaitOffset.eastM,i.z+=this.gaitOffset.northM,this.camera.position.y=this.poseCameraY+this.gaitOffset.upM,this.celestialGroup.position.y=this.camera.position.y);const a={x:0,z:0};let o=0;if(r){const c=jt.occupantView(r),h=-(r.headingDeg??0)*Tn,u=c.x*Math.cos(h)+c.z*Math.sin(h),d=-c.x*Math.sin(h)+c.z*Math.cos(h),f=r.eastM+i.x,p=-r.northM+i.z;a.x=-(f+u),a.z=-(p+d),this.camera.position.y=this.groundYUnder(f,p)+c.eyeY,this.camera.rotation.set(this.indoorLookPitchDeg*Tn,-(c.headingDeg+this.indoorLookYawDeg)*Tn,0,"YXZ")}for(const c of this.decorObjects){const h=this.decorGroups.get(c.id);if(!h)continue;const u=Sl(c,n),d=u.eastM+i.x+a.x,f=-u.northM+i.z+a.z;if(h.position.set(d,this.groundUnderFootprint(c,d,f,u.headingDeg)+u.altitudeM,f),c.kind==="crop"){const p=Math.hypot(d,f);h.visible=p<=Rw}if(u.headingDeg!==void 0&&(h.rotation.y=-u.headingDeg*Tn),c.kind==="crop"&&h.visible){const p=this.terrainMesh,v=[p?.geometry.uuid,d-(p?.position.x??0),f-(p?.position.z??0),h.position.y-(p?.position.y??0),u.headingDeg,u.altitudeM].map(g=>typeof g=="number"?g.toFixed(4):g).join(":");h.userData.cropGroundKey!==v&&(jt.fitCropToGround(h,(g,m)=>this.groundYUnder(g,m)+u.altitudeM),h.userData.cropGroundKey=v)}o=Math.max(o,h.position.distanceTo(this.camera.position))}const l=Math.max(Lo*1.2,this.groundRadius*2.5,o*1.2);Math.abs(this.camera.far-l)>1&&(this.camera.far=l,this.camera.updateProjectionMatrix())}groundYUnder(e,t){const n=this.terrainMesh;return n?n.position.y+this.groundYOfPatch(n,e-n.position.x,t-n.position.z):Wc}groundYOfPatch(e,t,n){const i=e.geometry.getAttribute("position"),r=Math.round(Math.sqrt(i.count));if(r<2||r*r!==i.count)return Wc;const a=i.getX(0),o=i.getX(r-1),l=i.getZ(0),c=i.getZ((r-1)*r),h=xl((t-a)/(o-a)*(r-1),0,r-1),u=xl((n-l)/(c-l)*(r-1),0,r-1);if(!Number.isFinite(h)||!Number.isFinite(u))return Wc;const d=Math.min(Math.floor(h),r-2),f=Math.min(Math.floor(u),r-2),p=h-d,v=u-f,g=(S,E)=>i.getY(S*r+E),m=g(f,d),w=g(f,d+1),b=g(f+1,d),_=g(f+1,d+1);return p+v<=1?m+(w-m)*p+(b-m)*v:_+(b-_)*(1-p)+(w-_)*(1-v)}groundUnderFootprint(e,t,n,i){return jt.groundUnderFootprint(e,t,n,i,(r,a)=>this.groundYUnder(r,a))}lookYawDeg=0;lookPitchDeg=0;poseCameraY=1.6;setGait(e){this.gaitOffset=e}gaitOffset={eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0};setLookOffset(e,t){this.lookYawDeg=e,this.lookPitchDeg=t}indoorLookYawDeg=0;indoorLookPitchDeg=0;setIndoorLook(e,t){this.indoorLookYawDeg=e,this.indoorLookPitchDeg=t}updateDecorLitState(e,t=0){for(const n of this.decorObjects){const i=this.decorGroups.get(n.id);if(i&&n.lights?.length&&jt.setLights(i,n.lights,e,i.position.distanceTo(this.camera.position),t),n.kind!=="streetlight"&&n.kind!=="vehicle")continue;const r=this.decorGroups.get(n.id);if(!r)continue;const a=yp(n,e);jt.setLit(r,n.kind,a);const o=this.streetlightLights.get(n.id);o&&(o.visible=a)}}addStreetlightLight(e,t){const n=jt.bodyOf(t),i=n.children.find(a=>a.userData.emissive);if(!i)return;const r=new S2(16764006,pw,mw);r.position.copy(i.position).multiply(n.scale),r.castShadow=!0,r.shadow.mapSize.set(512,512),r.shadow.bias=-.002,t.add(r),this.streetlightLights.set(e,r)}setAstronomy(e){const t=jh(e.sun.altitudeDeg),n=t.horizon;this.baseFogColor=n,this.lastSunPosition=e.sun,this.buildSky(e.sun),this.buildGround(),this.updateCloudLighting(e.sun,n),this.updateCelestialLight(e,t.zenith,n);const i=ym(e.sun.altitudeDeg,this.instrumentMagnitudeGain);this.buildStars(e.stars,i),this.setBodyMesh("sun",e.sun,kc,new le(1,.96,.88),e.sun.magnitude),this.setMoonMesh(e.moon,i),this.buildPlanets(e.planets,i),this.buildComet(e.comet,i),this.buildIceHalos(e.sun,e.moon),this.buildRainbow(e.sun,e.moon),this.buildSkyGlow(e,t.zenith),this.scene.fog=new Bu(new le(...n),this.groundRadius*.2,this.groundRadius),this.syncAnimationLoop(),this.render()}updateCelestialLight(e,t,n){this.skyLight.color.setRGB(t[0],t[1],t[2]),this.skyLight.groundColor.setRGB(n[0],n[1],n[2]),this.skyLight.intensity=fw;const i=e.sun.altitudeDeg>=Xf,r=!i&&e.moon.altitudeDeg>=Xf;if(!i&&!r){this.celestialLight.intensity=0;return}const a=i?e.sun:e.moon,{x:o,y:l,z:c}=fn(a.altitudeDeg,a.azimuthDeg,No);this.celestialLight.position.set(o,l,c);const h=ys(a.altitudeDeg);this.celestialLight.color.setRGB(h[0],h[1],h[2]);const u=Math.max(0,Math.sin(Math.max(a.altitudeDeg,0)*Tn));this.celestialLight.intensity=(i?uw:dw)*u,this.celestialLight.castShadow=this.decorGroups.size>0}setMeteorShower(e,t,n){this.meteorSystem||(this.meteorSystem=new $t,this.celestialGroup.add(this.meteorSystem.object)),this.meteorSystem.setShower(e,t,n)}get meteorSchedule(){return this.meteorSystem?.schedule??[]}meteorMidpoint(e){return this.meteorSystem?.midpointOf(e)}updateMeteors(e){this.meteorSystem?.update(e)}setInstrument(e){this.projectionKind=e.projection;const t=Ut.starPointsOf(e),n=Ut.flareArtifactsOf(e);t===this.starPoints&&n===this.lensFlareArtifactIntensity||(this.starPoints=t,this.lensFlareArtifactIntensity=n,this.lensFlare&&(this.lensFlare.uniforms.uStarPoints.value=t,this.lensFlare.uniforms.uFlareIntensity.value=n),this.render())}setInstrumentGain(e){this.instrumentMagnitudeGain=Number.isFinite(e)?e:0}render(){this.restatingExposure||(this.renderOnce(),this.developingExposure&&this.startExposure())}setExposure(e,t){const n=t?Math.max(1,Math.round(e)):1;if(n===this.exposureInstants&&(n===1||t===this.exposureInstantAt)){this.exposureInstantAt=t;return}this.exposureInstants=n,this.exposureInstantAt=t,n===1&&(this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0),this.render()}renderOnce(e){const t=this.usableEquidistantPass();this.phenomena.setCloudLayers(this.layeredClouds?.volumes??[]),this.phenomena.place(this.camera,(r,a,o)=>this.directionAtScreenPoint(r,a,o),r=>this.screenPointOf(r));const n=this.phenomena.furthestM*1.2;n>this.camera.far&&(this.camera.far=n,this.camera.updateProjectionMatrix());const i=this.renderer.getRenderTarget();if(!t){this.updateLensFlarePosition();const r=this.usableDepthOfFieldPass();r?.setEncodesOutput(e===void 0),this.skyGlow?.setDestinationEncoded(e===void 0&&!r),e&&this.renderer.setRenderTarget(e),r?r.render(this.renderer,this.scene,this.camera,()=>this.renderPhenomenaPass()):(this.renderer.render(this.scene,this.camera),this.renderPhenomenaPass()),e&&this.renderer.setRenderTarget(i);return}t.setEncodesOutput(e===void 0),this.skyGlow?.setDestinationEncoded(!1),e&&this.renderer.setRenderTarget(e),t.render(this.renderer,this.scene,this.camera,this.camera.fov,()=>this.updateLensFlarePosition(),()=>this.renderPhenomenaPass()),e&&this.renderer.setRenderTarget(i)}renderPhenomenaPass(){if(!this.phenomena.any)return;const e=this.renderer.autoClear,t=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,this.renderer.clearDepth();for(const n of this.decorObjects){const i=this.decorGroups.get(n.id);i&&li.markDecorDepth(i,n.kind!=="crop")}this.camera.layers.set(Uc),this.scene.overrideMaterial=this.decorDepthMaterial,this.renderer.render(this.scene,this.camera),this.scene.overrideMaterial=null,this.camera.layers.set(tg),this.renderer.render(this.scene,this.camera),this.camera.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=t}decorDepthMaterial=new Bi({colorWrite:!1});static markDecorDepth(e,t){e.traverse(n=>{if(!(n instanceof Ye))return;const i=Array.isArray(n.material)?n.material[0]:n.material;t&&i.depthWrite!==!1&&i.blending!==jn?n.layers.enable(Uc):n.layers.disable(Uc)})}startExposure(){this.cancelExposure();const e=this.renderer.getDrawingBufferSize(new Pe),t=Math.max(1,Math.round(e.x)),n=Math.max(1,Math.round(e.y));this.exposureAccumulation||(this.exposureAccumulation=new G3(t,n)),this.exposureAccumulation.resize(t,n),this.exposureAccumulation.open(this.renderer),this.exposureInstantsDone=0,this.exposureFrameId=requestAnimationFrame(()=>this.developExposure())}developExposure(){this.exposureFrameId=null;const e=this.exposureInstantAt,t=this.exposureAccumulation;if(!e||!t)return;const n=1/this.exposureInstants,i=performance.now()+li.EXPOSURE_BUDGET_MS;do this.restateAt(e,this.exposureInstantsDone),this.renderOnce(t.instantTarget),t.add(this.renderer,n),this.exposureInstantsDone++;while(this.exposureInstantsDone<this.exposureInstants&&performance.now()<i);this.restateAt(e,0),t.develop(this.renderer,this.exposureInstants/this.exposureInstantsDone),this.exposureInstantsDone<this.exposureInstants&&(this.exposureFrameId=requestAnimationFrame(()=>this.developExposure()))}restateAt(e,t){this.restatingExposure=!0;try{e(t)}finally{this.restatingExposure=!1}}cancelExposure(){this.exposureFrameId!==null&&(cancelAnimationFrame(this.exposureFrameId),this.exposureFrameId=null)}setLensOptics(e){const t=this.lensOptics;this.lensOptics=e,(t===void 0!=(e===void 0)||t&&e&&(t.focalLengthMm!==e.focalLengthMm||t.fNumber!==e.fNumber||t.focusDistance!==e.focusDistance||t.frameHeightMm!==e.frameHeightMm))&&(e&&this.depthOfFieldPass&&this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.render())}usableDepthOfFieldPass(){const e=this.lensOptics;if(!e)return;const t=this.renderer.getDrawingBufferSize(new Pe),n=Math.max(1,Math.round(t.x)),i=Math.max(1,Math.round(t.y));return this.depthOfFieldPass||(this.depthOfFieldPass=new va(n,i)),this.depthOfFieldPass.resize(n,i),this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.depthOfFieldPass}usableEquidistantPass(){if(this.projectionKind!=="equidistant")return;const e=this.renderer.getDrawingBufferSize(new Pe);if(ga.supports(this.camera.fov,e.x/Math.max(e.y,1)))return this.equidistantPass?this.equidistantPass.resize(e.x,e.y):this.equidistantPass=new ga(e.x,e.y),this.equidistantPass}aimAtScreenPoint(e,t,n){const i=this.projectionKind==="equidistant"?this.equidistantPass:void 0;if(!i){e.setFromCamera(new Pe(t,n),this.camera);return}const r=i.directionFor(t,n,this.camera.fov);this.camera.updateMatrixWorld(),e.ray.origin.setFromMatrixPosition(this.camera.matrixWorld),e.ray.direction.set(r.x,r.y,r.z).applyQuaternion(this.camera.quaternion).normalize(),e.camera=this.camera}pickCloudAt(e,t){return this.layeredClouds?.pickInstance(this.cloudDirectionAt(e,t))}cloudDirectionAt(e,t){return this.directionAtScreenPoint(e,t,new D)}directionAtScreenPoint(e,t,n){return this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),n.copy(this.ufoOcclusionRaycaster.ray.direction)}screenPointOf(e){this.camera.updateMatrixWorld();const t=this.screenPointScratch.copy(e).applyQuaternion(this.screenPointQuaternion.copy(this.camera.quaternion).invert());if(t.z>=0)return;const n=this.renderer.getDrawingBufferSize(this.screenPointSize),i=n.x/Math.max(n.y,1);if(this.projectionKind==="equidistant"&&this.equidistantPass)return ga.ndcFor(t,this.camera.fov,i);const r=Math.tan(this.camera.fov/2*Tn);return{ndcX:t.x/-t.z/(i*r),ndcY:t.y/-t.z/r}}screenPointScratch=new D;screenPointQuaternion=new ps;screenPointSize=new Pe;updateLensFlarePosition(){const e=this.lensFlare;if(!e)return;if(!this.sunVisible){e.mesh.visible=!1;return}if(this.camera.updateMatrixWorld(),this.lensFlareScratch.copy(this.sunWorldPosition).applyMatrix4(this.camera.matrixWorldInverse),this.lensFlareScratch.z>0){e.mesh.visible=!1;return}const t=this.sunVisibleFraction();if(t<=0){e.mesh.visible=!1;return}e.mesh.visible=!0,this.sunUnhiddenFraction=t,this.applyDazzleStrength();const n=this.lensFlareScratch.copy(this.sunWorldPosition).project(this.camera);e.uniforms.uLensPosition.value.set(n.x,n.y);const i=this.renderer.domElement.width,r=this.renderer.domElement.height;e.uniforms.uResolution.value.set(i,r),e.uniforms.uTanHalfFov.value=Math.tan(this.camera.fov*Math.PI/360)}sunVisibleFraction(){let e=0;for(const t of Yf)this.isSunOccluded(t[0],t[1])||e++;return e/Yf.length}raycastableDecor(){const e=[];for(const t of this.decorObjects){if(t.kind==="crop")continue;const n=this.decorGroups.get(t.id);n&&e.push(n)}return e}isSunOccluded(e=0,t=0){this.scene.updateMatrixWorld();const n=[];this.groundMesh&&n.push(this.groundMesh),this.terrainMesh&&n.push(this.terrainMesh);for(const o of this.raycastableDecor())n.push(o);if(n.length===0)return!1;const i=this.sunOcclusionDirectionScratch.copy(this.sunWorldPosition).sub(this.camera.position),r=i.length();if(i.normalize(),e!==0||t!==0){const o=Math.PI/180,l=this.sunOcclusionRightScratch.set(i.z,0,-i.x);l.lengthSq()<1e-9&&l.set(1,0,0),l.normalize();const c=this.sunOcclusionUpScratch.crossVectors(l,i).normalize();i.addScaledVector(l,e*o).addScaledVector(c,t*o).normalize()}this.sunOcclusionRaycaster.set(this.camera.position,i);const a=this.sunOcclusionRaycaster.intersectObjects(n,!0)[0];return a!==void 0&&a.distance<r}setPhenomena(e,t){this.phenomena.set(e,t)}decorDistancesAt(e,t,n){this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=zf;let i,r;for(const a of this.decorObjects){if(a.kind==="crop")continue;const o=this.decorGroups.get(a.id);if(!o)continue;const l=this.ufoOcclusionRaycaster.intersectObject(o,!0)[0];l&&(a.occludesSourceIds?.includes(n)?i=i===void 0?l.distance:Math.max(i,l.distance):r=r===void 0?l.distance:Math.min(r,l.distance))}return{behindM:i,inFrontM:r}}pickBodyAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const n=[...this.hitAreas.entries()],i=this.raycaster.intersectObjects(n.map(([,r])=>r))[0];if(i&&!this.groundHides(e,t))return n.find(([,r])=>r===i.object)?.[0]}pickStarAt(e,t){if(this.namedStars.length===0)return;this.aimAtScreenPoint(this.raycaster,e,t);const n=this.raycaster.ray.direction,i=Math.cos(ow*this.camera.fov*Math.PI/180);let r,a=i;for(const o of this.namedStars){const l=o.direction.dot(n);l>a&&(a=l,r={star:o.star,altitudeDeg:o.altitudeDeg})}return r&&this.groundHides(e,t)?void 0:r}groundHides(e,t){const n=[this.terrainMesh,this.groundMesh].filter(i=>i!==void 0);return n.length===0?!1:(this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=zf,this.ufoOcclusionRaycaster.intersectObjects(n,!0).length>0)}pickDecorAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const n=[...this.decorGroups.entries()],i=this.raycaster.intersectObjects(n.map(([,a])=>a),!0)[0];if(!i)return;let r=i.object;for(;r&&!n.some(([,a])=>a===r);)r=r.parent;return n.find(([,a])=>a===r)?.[0]}dispose(){this.stopTwinkle(),this.phenomena.clear(),this.terrainBuildToken++,this.disposeMesh(this.skyMesh),this.disposeMesh(this.groundMesh),this.disposeMesh(this.terrainMesh),this.disposeCloudSystem(),this.disposeCirrus(),this.disposePrecipitationPoints(),this.disposeRain(),this.disposeStarTiers(),this.meteorSystem?.dispose(),this.meteorSystem=void 0,this.iceHalos?.dispose(),this.iceHalos=void 0,this.rainbow?.dispose(),this.rainbow=void 0,this.skyGlow?.dispose(),this.skyGlow=void 0,this.depthOfFieldPass?.dispose(),this.depthOfFieldPass=void 0,this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0,this.cometTail?.dispose(),this.cometTail=void 0;for(const e of this.bodyMeshes.values())this.disposeMesh(e);this.bodyMeshes.clear();for(const e of[...this.hitAreas.keys()])this.disposeHitArea(e);for(const e of[...this.glareSprites.keys()])this.disposeGlare(e);this.disposeCompassLabels();for(const e of this.decorGroups.values())jt.dispose(e);this.decorGroups.clear(),this.streetlightLights.clear(),this.lensFlare&&(this.lensFlare.mesh.removeFromParent(),this.lensFlare.mesh.geometry.dispose(),this.lensFlare.mesh.material.dispose(),this.lensFlare=void 0),this.renderer.dispose()}animationsRunning=!1;startTwinkle(){if(this.animationFrameId!==null||!this.needsAnimationLoop())return;let e;const t=n=>{const i=e===void 0?0:Math.min((n-e)/1e3,Gw);e=n,this.updateTwinkle(n/1e3),this.updatePrecipitation(n/1e3,i),this.updateRain(i),this.updateLightning(n/1e3,i),this.lensFlare&&(this.lensFlare.uniforms.uTime.value=n/1e3),this.developingExposure||this.render(),this.animationFrameId=requestAnimationFrame(t)};this.animationFrameId=requestAnimationFrame(t)}setAnimationsRunning(e){e!==this.animationsRunning&&(this.animationsRunning=e,e?this.nextLightningAtS=null:this.lightningFlashRemainingS>0&&(this.lightningFlashRemainingS=0,this.restoreFogColor()),this.syncAnimationLoop(),e||this.render())}stopTwinkle(){this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}restoreFogColor(){this.scene.fog&&this.scene.fog.color.setRGB(...this.baseFogColor)}needsAnimationLoop(){return this.animationsRunning&&(this.starTiers.length>0||this.precipitationPoints!==void 0||this.rainSystem!==void 0||this.lightningArmed||this.lensFlare!==void 0&&this.sunVisible)}syncAnimationLoop(){this.needsAnimationLoop()?this.startTwinkle():this.stopTwinkle()}buildSky(e){this.disposeMesh(this.skyMesh);const t=new ln(Lo,32,16),n=t.attributes.position,i=[];for(let a=0;a<n.count;a++){const{altitudeDeg:o,azimuthDeg:l}=X3(n.getX(a),n.getY(a),n.getZ(a)),c=Q3(o,l,e.azimuthDeg,e.altitudeDeg);i.push(c[0],c[1],c[2])}t.setAttribute("color",new bt(i,3));const r=new Bi({vertexColors:!0,side:kt,fog:!1,depthWrite:!1});this.skyMesh=new Ye(t,r),this.skyMesh.renderOrder=-1,this.celestialGroup.add(this.skyMesh)}buildGround(){this.disposeMesh(this.groundMesh),this.groundRadius=Bf(this.observerElevationM);const e=new Vu(this.groundRadius,48),t=new Ia({color:new le(Fc,Fc,Fc),fog:!0});this.groundMesh=new Ye(e,t),this.groundMesh.rotation.x=-Math.PI/2,this.groundMesh.position.y=0,this.groundMesh.receiveShadow=!0,this.scene.add(this.groundMesh),this.applyGroundDepthWrite()}applyGroundDepthWrite(){const e=this.groundMesh?.material;if(!e)return;const t=this.terrainMesh===void 0;e.depthWrite!==t&&(e.depthWrite=t,e.needsUpdate=!0)}cloudTransmission(e){const t=fn(e.altitudeDeg,e.azimuthDeg,1);if(this.layeredClouds)return this.layeredClouds.transmissionAt(t);let n=1;const i=this.lowerCloudCover();i>0&&(n*=1-Dt.alphaAt(t,Math.abs(this.cloudLayerOffset()),i,this.cloudFieldOffset)*cw);const r=this.weather.highCloudCover??0;return r>0&&(n*=1-Dt.alphaAt(t,Oo,r)*hw),Math.max(0,Math.min(1,n))}setBodyMesh(e,t,n,i,r){if(this.disposeMesh(this.bodyMeshes.get(e)),this.disposeHitArea(e),this.disposeGlare(e),t.altitudeDeg<Su){this.bodyMeshes.delete(e),e==="sun"&&(this.sunVisible=!1);return}const{x:a,y:o,z:l}=fn(t.altitudeDeg,t.azimuthDeg,No),c=ys(t.altitudeDeg),h=this.cloudTransmission(t),u=new le(i.r*c[0]*h,i.g*c[1]*h,i.b*c[2]*h),d=new ln(n,16,16),f=new Bi({color:u,fog:!1}),p=new Ye(d,f);p.position.set(a,o,l),this.celestialGroup.add(p),this.bodyMeshes.set(e,p),this.setHitArea(e,a,o,l,n);const v=r-2.5*Math.log10(Math.max(h,.001));if(e==="sun"&&(this.sunCloudTransmission=h),e!=="sun"&&this.setGlare(e,a,o,l,v,u),e==="sun"){this.sunVisible=!0;const g=this.celestialGroup.scale.x;this.sunWorldPosition.set(a*g,o*g+this.celestialGroup.position.y,l*g),this.lensFlare||(this.lensFlare=Ub(),this.lensFlare.uniforms.uOpacity.value=Ew,this.lensFlare.uniforms.uFlareIntensity.value=this.lensFlareArtifactIntensity,this.lensFlare.uniforms.uStarPoints.value=this.starPoints,this.scene.add(this.lensFlare.mesh)),this.applyLensFlareTint(c)}}setMoonMesh(e,t){const n="moon";if(this.disposeMesh(this.bodyMeshes.get(n)),this.disposeHitArea(n),this.disposeGlare(n),e.magnitude>t||e.altitudeDeg<Su){this.bodyMeshes.delete(n);return}const{x:i,y:r,z:a}=fn(e.altitudeDeg,e.azimuthDeg,No),o=ys(e.altitudeDeg),l=new le(o[0],o[1],o[2]),c=new la({map:eE(e.phase),color:l,fog:!1}),h=new no(c);h.position.set(i,r,a);const u=kc*2;h.scale.set(u,u,1),this.celestialGroup.add(h),this.bodyMeshes.set(n,h),this.setHitArea(n,i,r,a,kc),this.setGlare(n,i,r,a,e.magnitude,l)}setHitArea(e,t,n,i,r){const a=new la({transparent:!0,opacity:0,depthTest:!1,depthWrite:!1,fog:!1}),o=new no(a);o.position.set(t,n,i);const l=r*lw;o.scale.set(l,l,1),this.celestialGroup.add(o),this.hitAreas.set(e,o)}disposeHitArea(e){const t=this.hitAreas.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.hitAreas.delete(e))}setGlare(e,t,n,i,r,a){const o=nS(r);if(o<=0){this.disposeGlare(e);return}const l=rS(o),c=this.glareSprites.get(e),h=c??new no(new la({map:Qw(),transparent:!0,blending:jn,depthWrite:!1,fog:!1}));h.material.color.copy(a),h.material.opacity=lS(o),h.position.set(t,n,i),h.scale.set(l*2,l*2,1),c||(this.celestialGroup.add(h),this.glareSprites.set(e,h))}disposeGlare(e){const t=this.glareSprites.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.glareSprites.delete(e))}buildComet(e,t){const n=e&&`comet:${e.id}`;if(!e||!n||e.magnitude>t){this.disposeComet();return}this.cometKey&&this.cometKey!==n&&this.disposeComet();const i=wc(e.magnitude,t),r=Ec(i);this.cometKey=n,this.setBodyMesh(n,e.position,Gf*(.5+.5*i),new le(r,r,r),e.magnitude),this.cometTail||(this.cometTail=new Rn(No),this.celestialGroup.add(this.cometTail.object)),this.cometTail.set(e.position,e.tailEnd,i)}buildIceHalos(e,t){this.iceHalos||(this.iceHalos=new oi,this.iceHalos.setCloudOffset(this.cloudFieldOffset),this.iceHalos.onReady=()=>this.render(),this.celestialGroup.add(this.iceHalos.object));const n=this.highCloudCover(),i=this.layeredClouds?.cirrusMask;if(this.iceHalos.setCloudOffset(i?.offset??this.cloudFieldOffset),n===void 0){this.iceHalos.update({x:0,y:1,z:0},-1,0,[1,1,1],{cover:0,layerHeight:Oo},0);return}const r=this.lowerCloudCover(),a=et.deckLitUntilDeg(et.DECK_HEIGHT_M),o=e.altitudeDeg>-a?e:t,l=et.strength(n,r,o.altitudeDeg,a)*(o===e?1:Wf),{x:c,y:h,z:u}=fn(o.altitudeDeg,o.azimuthDeg,1),d=ys(o.altitudeDeg);this.iceHalos.update({x:c,y:h,z:u},o.altitudeDeg,l,[d[0],d[1],d[2]],{cover:i?.cover??n,layerHeight:i?.layerHeight??Oo},i?.iceCrystalAlignment??this.weather.iceCrystalAlignment??Sg)}buildRainbow(e,t){this.rainbow||(this.rainbow=new xa,this.celestialGroup.add(this.rainbow.object));const n=this.weather.precipitationType==="rain"?this.weather.precipitationIntensity:0,i=e.altitudeDeg>0,r=i?e:t,a=this.lowerCloudCover(),o=Wf*yn.moonlightShare(t.magnitude),l=yn.strength(n,a,r.altitudeDeg)*(i?1:o);if(l<=0){this.rainbow.update({x:0,y:1,z:0},0,[1,1,1],!0);return}const{x:c,y:h,z:u}=fn(r.altitudeDeg,r.azimuthDeg,1),d=ys(r.altitudeDeg);this.rainbow.update({x:c,y:h,z:u},l,[d[0],d[1],d[2]],i)}buildSkyGlow(e,t){if(!e.frame){this.skyGlow?.hide();return}this.skyGlow||(this.skyGlow=new Xn,this.skyGlow.onReady=()=>this.render(),this.celestialGroup.add(this.skyGlow.object));const{date:n,observer:i}=e.frame,r=qn.galactic(n,i),a=li.directionOf(r.centre),o=li.directionOf(r.rotation),l=li.directionOf(r.pole),c=new ze().set(a.x,a.y,a.z,o.x,o.y,o.z,l.x,l.y,l.z),h=li.directionOf(qn.eclipticPole(n,i)),u=li.directionOf(e.sun),d=u.clone().addScaledVector(h,-u.dot(h)).normalize();this.skyGlow.update({galactic:c,eclipticPole:h,sunLongitude:d,sunDirection:u,sunAltitudeDeg:e.sun.altitudeDeg,moon:{direction:li.directionOf(e.moon),altitudeDeg:e.moon.altitudeDeg,phaseAngleDeg:Ze.phaseAngleOf(e.moon.phase.illuminatedFraction)},skyColor:new D(t[0],t[1],t[2])})}static directionOf(e){const{x:t,y:n,z:i}=fn(e.altitudeDeg,e.azimuthDeg,1);return new D(t,n,i).normalize()}disposeComet(){this.cometTail?.set(void 0,void 0,0),this.cometKey&&(this.disposeMesh(this.bodyMeshes.get(this.cometKey)),this.bodyMeshes.delete(this.cometKey),this.disposeHitArea(this.cometKey),this.disposeGlare(this.cometKey),this.cometKey=void 0)}buildPlanets(e,t){const n=new Set(["sun","moon",...this.cometKey?[this.cometKey]:[]]);for(const i of e){if(i.magnitude>t)continue;n.add(i.body);const r=wc(i.magnitude,t),a=Ec(r),o=Ww[i.body]??new le(1,1,1),l=new le(o.r*a,o.g*a,o.b*a),c=Gf*(.5+.5*r);this.setBodyMesh(i.body,i.position,c,l,i.magnitude)}for(const i of[...this.bodyMeshes.keys()])n.has(i)||(this.disposeMesh(this.bodyMeshes.get(i)),this.bodyMeshes.delete(i),this.disposeHitArea(i),this.disposeGlare(i))}buildStars(e,t){if(this.disposeStarTiers(),this.namedStars=[],!e||e.catalog.count===0){this.syncAnimationLoop();return}const{catalog:n,date:i,observer:r}=e,a=qc(1337),o=[];for(let l=0;l<n.count;l++){const c=n.mag[l];if(c>t)break;const{altitudeDeg:h,azimuthDeg:u}=Nr(n.ra[l],n.dec[l],i,r);if(h<Vf)continue;const{x:d,y:f,z:p}=fn(h,u,Hf);o.push({x:d,y:f,z:p,brightness:wc(c,t),phase:a()*Math.PI*2,speedFactor:.7+a()*.6})}for(const l of gb){if(l.mag>t)continue;const{altitudeDeg:c,azimuthDeg:h}=Nr(l.raHours,l.decDeg,i,r);if(c<Vf)continue;const{x:u,y:d,z:f}=fn(c,h,Hf);this.namedStars.push({star:l,direction:new D(u,d,f).normalize(),altitudeDeg:c})}this.starTiers=bm.map((l,c)=>{const h=o.filter(b=>dS(b.brightness)===c),u=new Float32Array(h.length*3),d=new Float32Array(h.length),f=new Float32Array(h.length),p=new Float32Array(h.length);h.forEach((b,_)=>{u[_*3]=b.x,u[_*3+1]=b.y,u[_*3+2]=b.z,d[_]=b.brightness,f[_]=b.phase,p[_]=b.speedFactor});const v=new wt;v.setAttribute("position",new dt(u,3));const g=new dt(new Float32Array(h.length*3),3);v.setAttribute("color",g);const m=new nm({vertexColors:!0,size:l.size,sizeAttenuation:!1,fog:!1});Cs.apply(m);const w=new Ko(v,m);return this.celestialGroup.add(w),{points:w,colorAttribute:g,brightness:d,phase:f,speedFactor:p}}),this.updateTwinkle(0),this.startTwinkle()}updateTwinkle(e){for(const t of this.starTiers){const n=t.colorAttribute.array;for(let i=0;i<t.brightness.length;i++){const r=mS(t.brightness[i],{phase:t.phase[i],speedFactor:t.speedFactor[i]},e),a=Ec(t.brightness[i])*r;n[i*3]=a,n[i*3+1]=a,n[i*3+2]=a}t.colorAttribute.needsUpdate=!0}}buildClouds(){if(this.cloudRendering==="volume"||this.weather.cloudLayers!==void 0){this.layeredClouds||(this.disposeCloudSystem(),this.layeredClouds=new H3(this.celestialGroup,Bc,this.cloudRendering)),this.disposeCirrus(),this.layeredClouds.update(this.weather,this.observerElevationM+1.6),this.layeredClouds.setOffsets(this.cloudOffsetM,this.cloudLayerOffsetsM),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}this.disposeCloudSystem();const e=this.lowerCloudCover();if(e<=0)return;const t=this.weather.cloudDarkness,n=new le(bs[0]+(Vc[0]-bs[0])*t,bs[1]+(Vc[1]-bs[1])*t,bs[2]+(Vc[2]-bs[2])*t),{material:i,uniforms:r}=Yh(n,e,Math.abs(this.cloudLayerOffset()));this.cloudMaterial=i,this.cloudUniforms=r,r.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);const a=Kh(Bc);this.cloudMesh=new Ye(a,i),this.cloudLayerOffset()<0&&(this.cloudMesh.scale.y=-1),this.cloudMesh.renderOrder=Kf,this.celestialGroup.add(this.cloudMesh)}lowerCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(e=>e.type!=="cirrus").reduce((e,t)=>e*(1-t.coverage),1):this.weather.lowerCloudCover??this.weather.cloudCover}highCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(e=>e.type==="cirrus").reduce((e,t)=>e*(1-t.coverage),1):this.weather.highCloudCover}buildCirrus(){if(this.disposeCirrus(),this.layeredClouds)return;const e=this.weather.highCloudCover??0;if(e<=0)return;const{material:t,uniforms:n}=Yh(new le(...bs),e,Oo,1);this.cirrusMaterial=t,this.cirrusUniforms=n,n.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.cirrusMesh=new Ye(Kh(Bc*1.04),t),this.cirrusMesh.renderOrder=Kf-1,this.celestialGroup.add(this.cirrusMesh)}disposeCirrus(){this.cirrusMesh&&(this.cirrusMesh.removeFromParent(),this.cirrusMesh.geometry.dispose()),this.cirrusMaterial?.dispose(),this.cirrusMesh=void 0,this.cirrusMaterial=void 0,this.cirrusUniforms=void 0}syncCloudLayer(){this.layeredClouds?.update(this.weather,this.observerElevationM+1.6);const e=this.cloudLayerOffset();this.cloudUniforms&&(this.cloudUniforms.layerHeight.value=Math.abs(e)),this.cloudMesh&&(this.cloudMesh.scale.y=e<0?-1:1)}cloudLayerOffset(){const t=((this.weather.cloudBaseM??Eu)-this.observerElevationM)*Hc;return Math.sign(t||1)*Math.max(Math.abs(t),Tw)}updateCloudLighting(e,t){const n=[this.cloudUniforms,this.cirrusUniforms].filter(c=>c!==void 0);if(n.length===0&&!this.layeredClouds)return;const{x:i,y:r,z:a}=fn(e.altitudeDeg,e.azimuthDeg,1),o=ys(e.altitudeDeg),l=Math.max(0,Math.sin(Math.max(e.altitudeDeg,0)*Tn));this.layeredClouds?.setLighting(new D(i,r,a),new le(o[0]*l,.96*o[1]*l,.88*o[2]*l),new le(...t),new le(...t));for(const c of n)c.sunDir.value.set(i,r,a),c.sunColor.value.setRGB(o[0]*l,.96*o[1]*l,.88*o[2]*l),c.ambientColor.value.setRGB(t[0],t[1],t[2])}disposeCloudSystem(){this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.cloudMesh&&(this.cloudMesh.removeFromParent(),this.cloudMesh.geometry.dispose()),this.cloudMaterial?.dispose(),this.cloudMesh=void 0,this.cloudMaterial=void 0,this.cloudUniforms=void 0}disposePrecipitationPoints(){this.precipitationPoints&&(this.precipitationPoints.removeFromParent(),this.precipitationPoints.geometry.dispose(),this.precipitationPoints.material.dispose()),this.precipitationPoints=void 0,this.precipitationPositions=void 0,this.precipitationPhase=void 0,this.precipitationSpeedJitter=void 0,this.precipitationWobbleFreqJitter=void 0,this.precipitationWobbleAmpJitter=void 0,this.precipitationBounceRemaining=void 0,this.precipitationBounceHeight=void 0,this.precipitationBounceDuration=void 0,this.precipitationBounceVelX=void 0,this.precipitationBounceVelZ=void 0,this.precipitationUniforms=void 0}buildPrecipitation(){this.disposePrecipitationPoints(),this.disposeRain();const e=this.weather.precipitationType;if(e==="none")return;if(e==="rain"){this.buildRain();return}const t=$f[e],n=t.poolSize,i=qc(9001),r=new Float32Array(n*3),a=new Float32Array(n),o=new Float32Array(n),l=new Float32Array(n),c=new Float32Array(n),h=new Float32Array(n),u=new Float32Array(n),d=new Float32Array(n),f=new Float32Array(n),p=new Float32Array(n);for(let b=0;b<n;b++){const _=i()*Math.PI*2,S=i()*t.radiusM;r[b*3]=Math.cos(_)*S,r[b*3+1]=mr+i()*(t.topYM-mr),r[b*3+2]=Math.sin(_)*S,a[b]=i()*Math.PI*2,o[b]=.7+i()*.6,l[b]=.6+i()*.8,c[b]=.4+i()*1.2}const v=new wt;v.setAttribute("position",new dt(r,3)),v.setDrawRange(0,Xc(n,this.weather.precipitationIntensity));const g={uSize:{value:t.size},uScale:{value:.5*this.renderer.domElement.height},uOpacity:{value:t.opacity},uColor:{value:t.color},uHazeColor:{value:new le(...this.baseFogColor)},uTexture:{value:Xw(e)},uNearFocusDistance:{value:np},uHazeDistance:{value:t.radiusM*ip}},m=new Et({uniforms:g,vertexShader:Jw,fragmentShader:jw,transparent:!0,depthWrite:!1});this.precipitationUniforms=g;const w=new Ko(v,m);w.renderOrder=Gc,this.scene.add(w),this.precipitationPoints=w,this.precipitationPositions=r,this.precipitationPhase=a,this.precipitationSpeedJitter=o,this.precipitationWobbleFreqJitter=l,this.precipitationWobbleAmpJitter=c,this.precipitationBounceRemaining=h,this.precipitationBounceHeight=u,this.precipitationBounceDuration=d,this.precipitationBounceVelX=f,this.precipitationBounceVelZ=p}updatePrecipitation(e,t){if(!this.precipitationPoints||!this.precipitationPositions||!this.precipitationPhase||!this.precipitationSpeedJitter||(this.precipitationUniforms?.uHazeColor.value.setRGB(...this.baseFogColor),t<=0))return;const n=this.weather.precipitationType;if(n==="none"||n==="rain")return;const i=$f[n],r=this.weather.windDirectionDeg*Tn,a=Math.sin(r)*this.weather.windSpeed*i.driftSensitivity,o=-Math.cos(r)*this.weather.windSpeed*i.driftSensitivity,l=this.precipitationPositions,c=this.precipitationPhase,h=this.precipitationSpeedJitter,u=this.precipitationWobbleFreqJitter,d=this.precipitationWobbleAmpJitter,f=this.precipitationBounceRemaining,p=this.precipitationBounceHeight,v=this.precipitationBounceDuration,g=this.precipitationBounceVelX,m=this.precipitationBounceVelZ,w=n==="snow"&&u&&d,b=n==="hail"&&f&&p&&v&&g&&m;for(let _=0,S=0;_<l.length;_+=3,S++){if(b&&f[S]>0){if(f[S]-=t,f[S]<=0){const x=Math.random()*Math.PI*2,A=Math.sqrt(Math.random())*i.radiusM;l[_]=Math.cos(x)*A,l[_+1]=i.topYM,l[_+2]=Math.sin(x)*A,f[S]=0}else{const x=1-f[S]/v[S];l[_+1]=mr+Math.sin(Math.PI*x)*p[S],l[_]=Fo(l[_]+(a+g[S])*t,i.radiusM),l[_+2]=Fo(l[_+2]+(o+m[S])*t,i.radiusM)}continue}let E=0,R=0;if(w){const x=kw*u[S],A=zw*d[S];E=Math.sin(e*x*Math.PI*2+c[S])*A,R=Math.sin(e*x*Math.PI*2+c[S]+Math.PI/2)*A}if(l[_]+=(a+E)*t,l[_+1]-=i.fallSpeedMPerS*h[S]*t,l[_+2]+=(o+R)*t,l[_]=Fo(l[_],i.radiusM),l[_+2]=Fo(l[_+2],i.radiusM),l[_+1]<mr){if(b){p[S]=lp*(.2+Math.random()*1.6),v[S]=Bw*(.5+Math.random()),f[S]=v[S];const P=Math.random()*Math.PI*2,C=Hw*(p[S]/lp);g[S]=Math.cos(P)*C,m[S]=Math.sin(P)*C,l[_+1]=mr;continue}const x=Math.random()*Math.PI*2,A=Math.sqrt(Math.random())*i.radiusM;l[_]=Math.cos(x)*A,l[_+1]=i.topYM,l[_+2]=Math.sin(x)*A}}this.precipitationPoints.geometry.attributes.position.needsUpdate=!0}buildRain(){const e=Qf(this.weather.precipitationIntensity);this.rainSystem=Ib({count:Zf,radiusM:sa,heightM:Cw,bottomYM:Jf,overallSpeed:Dw,color:Iw,opacity:.85,visibleCount:Xc(Zf,this.weather.precipitationIntensity),speedStreak:Ow(e),pixelSize:rp,seed:9001,nearFocusDistanceM:np,hazeDistanceM:sa*ip,hazeColor:new le(...this.baseFogColor)}),this.rainLastVerticalFacing=-1,this.syncRainSlant(),this.rainSystem.points.renderOrder=Gc,this.scene.add(this.rainSystem.points),this.buildRainSplashes()}buildRainSplashes(){const e=qc(4242),t=new Float32Array(fr*3),n=new Float32Array(fr),i=new Float32Array(fr),r=new Float32Array(fr);for(let h=0;h<fr;h++){const u=e()*Math.PI*2,d=Math.sqrt(e())*sa;t[h*3]=Math.cos(u)*d,t[h*3+1]=Jf,t[h*3+2]=Math.sin(u)*d,i[h]=Uo(ep,tp),n[h]=e()*i[h],r[h]=n[h]/i[h]}const a=new wt;a.setAttribute("position",new dt(t,3));const o=new dt(r,1);a.setAttribute("aLife",o),a.setDrawRange(0,Xc(fr,this.weather.precipitationIntensity));const l=new Et({uniforms:{uMaxSize:{value:Uw},uScale:{value:.5*this.renderer.domElement.height},uColor:{value:Fw},uTexture:{value:Kw()}},vertexShader:$w,fragmentShader:Zw,transparent:!0,depthWrite:!1}),c=new Ko(a,l);c.renderOrder=Gc,this.scene.add(c),this.rainSplashSystem={points:c,positions:t,life:n,duration:i,lifeAttribute:o}}disposeRain(){this.rainSystem&&(this.rainSystem.points.removeFromParent(),this.rainSystem.points.geometry.dispose(),this.rainSystem.points.material.dispose()),this.rainSystem=void 0,this.disposeRainSplashes()}disposeRainSplashes(){this.rainSplashSystem&&(this.rainSplashSystem.points.removeFromParent(),this.rainSplashSystem.points.geometry.dispose(),this.rainSplashSystem.points.material.dispose()),this.rainSplashSystem=void 0}syncRainSlant(){const e=this.rainSystem;if(!e)return;const t=this.weather.windDirectionDeg*Tn;e.uniforms.uDropVelocity.value.set(Math.sin(t)*this.weather.windSpeed,-Qf(this.weather.precipitationIntensity),-Math.cos(t)*this.weather.windSpeed);const n=this.renderer.getSize(this.rainViewportSize);e.uniforms.uAspect.value=n.x/Math.max(n.y,1)}updateRain(e){const t=this.rainSystem;if(!t)return;t.uniforms.uTime.value+=e,t.uniforms.uHazeColor.value.setRGB(...this.baseFogColor);const n=this.weather.windDirectionDeg*Tn,i=Math.sin(n)*this.weather.windSpeed,r=-Math.cos(n)*this.weather.windSpeed,a=sa,o=c=>(c%(a*2)+a*3)%(a*2)-a;t.uniforms.uWindOffset.value.set(o(t.uniforms.uWindOffset.value.x+i*e),o(t.uniforms.uWindOffset.value.y+r*e)),this.syncRainSlant(),this.camera.getWorldDirection(this.rainCameraDirection);const l=Math.abs(this.rainCameraDirection.y);if(Math.abs(l-this.rainLastVerticalFacing)>.001){this.rainLastVerticalFacing=l;const c=ap+(1-ap)*(1-l),h=op+(1-op)*(1-l);t.uniforms.uUvSquash.value=h,t.uniforms.uPixelSize.value=rp*c*(.5+.5*h)}this.updateRainSplashes(e)}updateRainSplashes(e){const t=this.rainSplashSystem;if(!t||e<=0)return;const{positions:n,life:i,duration:r,lifeAttribute:a}=t,o=a.array;for(let l=0,c=0;l<n.length;l+=3,c++){if(i[c]+=e,i[c]>=r[c]){const h=Math.random()*Math.PI*2,u=Math.sqrt(Math.random())*sa;n[l]=Math.cos(h)*u,n[l+2]=Math.sin(h)*u,r[c]=Uo(ep,tp),i[c]=0}o[c]=i[c]/r[c]}t.points.geometry.attributes.position.needsUpdate=!0,a.needsUpdate=!0}updateLightning(e,t){if(this.lightningArmed){if(this.lightningFlashRemainingS>0){this.lightningFlashRemainingS=Math.max(0,this.lightningFlashRemainingS-t);const n=this.lightningFlashRemainingS/up;this.scene.fog&&this.scene.fog.color.setRGB(this.baseFogColor[0]+(1-this.baseFogColor[0])*n,this.baseFogColor[1]+(1-this.baseFogColor[1])*n,this.baseFogColor[2]+(1-this.baseFogColor[2])*n);return}if(this.nextLightningAtS===null){this.nextLightningAtS=e+Uo(cp,hp);return}e>=this.nextLightningAtS&&(this.lightningFlashRemainingS=up,this.nextLightningAtS=e+Uo(cp,hp),this.onLightningFlash?.())}}buildCompassLabels(){const e=bl(navigator.languages,xw),t=vw[e];this.compassSprites=gw.map((n,i)=>{const r=t[i],a=new la({map:tE(r),depthTest:!1,fog:!1}),o=new no(a),{x:l,y:c,z:h}=fn(0,n,Mw);return o.position.set(l,c,h),o.scale.set(zc,zc,1),o.renderOrder=yw,o.visible=this.compassHovered||this.compassForced,this.celestialGroup.add(o),o}),this.updateCompassScale()}updateCompassScale(){const e=this.camera.fov*Math.PI/360,t=_w*Math.PI/360,n=zc*Math.tan(e)/Math.tan(t);for(const i of this.compassSprites)i.scale.set(n,n,1)}disposeCompassLabels(){for(const e of this.compassSprites)e.removeFromParent(),e.material.map?.dispose(),e.material.dispose();this.compassSprites=[]}disposeStarTiers(){for(const e of this.starTiers)this.disposeMesh(e.points);this.starTiers=[]}disposeMesh(e){if(!e)return;e.removeFromParent(),"geometry"in e&&e.geometry.dispose();const t=e.material;for(const n of Array.isArray(t)?t:[t]){const i=n.map;i&&i.dispose(),n.dispose()}}}const Tn=Math.PI/180;function xl(s,e,t){return Math.max(e,Math.min(t,s))}function Uo(s,e){return s+Math.random()*(e-s)}function Fo(s,e){return(s%(e*2)+e*3)%(e*2)-e}let ko,zo;function Xw(s){switch(s){case"snow":return qw();case"hail":return Yw()}}function qw(){if(ko)return ko;const s=64,e=document.createElement("canvas");e.width=s,e.height=s;const t=e.getContext("2d"),n=t.createRadialGradient(s/2,s/2,0,s/2,s/2,s/2);return n.addColorStop(0,"rgba(255,255,255,0.95)"),n.addColorStop(.5,"rgba(255,255,255,0.55)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,s,s),ko=new Si(e),ko}function Yw(){if(zo)return zo;const s=64,e=document.createElement("canvas");e.width=s,e.height=s;const t=e.getContext("2d"),n=t.createRadialGradient(s/2,s/2,0,s/2,s/2,s/2);return n.addColorStop(0,"rgba(255,255,255,1)"),n.addColorStop(.55,"rgba(255,255,255,0.95)"),n.addColorStop(.8,"rgba(255,255,255,0.4)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,s,s),zo=new Si(e),zo}let Bo;function Kw(){if(Bo)return Bo;const s=64,e=document.createElement("canvas");e.width=s,e.height=s;const t=e.getContext("2d"),n=t.createRadialGradient(s/2,s/2,0,s/2,s/2,s/2);return n.addColorStop(0,"rgba(255,255,255,0)"),n.addColorStop(.4,"rgba(255,255,255,0)"),n.addColorStop(.6,"rgba(255,255,255,0.9)"),n.addColorStop(.8,"rgba(255,255,255,0.25)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,s,s),Bo=new Si(e),Bo}const $w=`
6251
+ `}),i.fragmentShader=r+i.fragmentShader,i.fragmentShader=i.fragmentShader.replace("#include <opaque_fragment>",a+"#include <opaque_fragment>")},e.needsUpdate=!0}meshes=new Map;signatures=new Map;extents=new Map;placed=[];frame;direction=new D;up=new D;lookAt=new Xe;vertex=new D;centre=new D;right=new D;above=new D;set(e,t){this.placed=e,this.frame=t;const n=new Set(e.map(i=>i.sourceId));for(const[i,r]of this.meshes)n.has(i)||(this.dispose(r),this.meshes.delete(i),this.signatures.delete(i),this.extents.delete(i));for(const i of e){let r=this.meshes.get(i.sourceId);r||(r=new Ye(new qi(1,1,Yn.SEGMENTS,Yn.SEGMENTS),new Bi({transparent:!0,depthWrite:!1,depthTest:!0,fog:!1,toneMapped:!1})),this.configureCloudMaterial(r.material),r.frustumCulled=!1,r.layers.set(tg),this.scene.add(r),this.meshes.set(i.sourceId,r)),r.renderOrder=nw+i.renderOrder,r.visible=!i.hidden&&i.shape.transparency<1,r.visible&&this.paint(r,i,t)}}place(e,t,n){const i=this.frame;if(i)for(const r of this.placed){const a=this.meshes.get(r.sourceId);if(!a||!a.visible)continue;const o=this.extents.get(r.sourceId);if(!o)continue;const{bounds:l}=r.shape;let c=l.x+l.width/2,h=l.y+l.height/2,u=!0;if(r.aim){const d=n(Yn.directionOf(r.aim,this.direction));d&&Math.abs(d.ndcX)<Yn.FURTHEST_NDC&&Math.abs(d.ndcY)<Yn.FURTHEST_NDC?(c=(d.ndcX+1)/2*i.canvasWidthPx,h=(1-d.ndcY)/2*i.canvasHeightPx):u=!1}u?this.curve(a,e,t,i,o,c,h,r.distanceM):this.flat(a,e,i,o,r.distanceM)}}static FURTHEST_NDC=4;curve(e,t,n,i,r,a,o,l){const c=a-r.width/2,h=o-r.height/2,u=e.geometry.attributes.position,d=Yn.SEGMENTS;let f=0;for(let p=0;p<=d;p++){const v=h+p/d*r.height;for(let g=0;g<=d;g++){const m=c+g/d*r.width;n(m/i.canvasWidthPx*2-1,-(v/i.canvasHeightPx*2-1),this.direction),this.vertex.copy(t.position).addScaledVector(this.direction,l),u.setXYZ(f++,this.vertex.x,this.vertex.y,this.vertex.z)}}u.needsUpdate=!0,e.matrixAutoUpdate=!1,e.matrix.identity(),e.matrixWorldNeedsUpdate=!0,e.scale.set(mt.sizeMAt(l,i.projection.pxToDeg(r.width)),mt.sizeMAt(l,i.projection.pxToDeg(r.height)),1)}flat(e,t,n,i,r){const a=e.geometry.attributes.position,o=Yn.SEGMENTS,l=mt.sizeMAt(r,n.projection.pxToDeg(i.width)),c=mt.sizeMAt(r,n.projection.pxToDeg(i.height));this.up.set(0,1,0).applyQuaternion(t.quaternion),this.centre.copy(t.position).addScaledVector(this.direction,r),this.lookAt.lookAt(t.position,this.centre,this.up),this.right.setFromMatrixColumn(this.lookAt,0),this.above.setFromMatrixColumn(this.lookAt,1);let h=0;for(let u=0;u<=o;u++){const d=.5-u/o;for(let f=0;f<=o;f++){const p=f/o-.5;this.vertex.copy(this.centre).addScaledVector(this.right,p*l).addScaledVector(this.above,d*c),a.setXYZ(h++,this.vertex.x,this.vertex.y,this.vertex.z)}}a.needsUpdate=!0,e.matrixAutoUpdate=!1,e.matrix.identity(),e.matrixWorldNeedsUpdate=!0,e.scale.set(l,c,1)}static SEGMENTS=16;static directionOf(e,t){const n=e.azimuthDeg*Math.PI/180,i=e.altitudeDeg*Math.PI/180;return t.set(Math.sin(n)*Math.cos(i),Math.sin(i),-Math.cos(n)*Math.cos(i))}get any(){for(const e of this.meshes.values())if(e.visible)return!0;return!1}get furthestM(){return this.placed.reduce((e,t)=>Math.max(e,t.distanceM),0)}paint(e,t,n){const{shape:i}=t,r=Qc.paintExtent(i);this.extents.set(t.sourceId,r);const a=Yn.signatureOf(i,n);if(this.signatures.get(t.sourceId)===a&&e.material.map)return;this.signatures.set(t.sourceId,a);const o=Math.min(n.scale,iw/Math.max(r.width,r.height,1)),l=Math.max(1,Math.ceil(r.width*o)),c=Math.max(1,Math.ceil(r.height*o)),h=e.material.map,u=h?.image??document.createElement("canvas"),d=u.width!==l||u.height!==c;d&&(u.width=l,u.height=c);const f=u.getContext("2d");if(!f)return;f.clearRect(0,0,l,c);const p=new Qc(f);if(p.setStarPoints(n.starPoints),p.setRoll(n.rollRad),p.paintInto(i,r,o),h&&!d){h.needsUpdate=!0;return}h?.dispose();const v=new Si(u);v.colorSpace=Dn,v.minFilter=_t,v.generateMipmaps=!1,e.material.map=v,e.material.needsUpdate=!0}static signatureOf(e,t){const{bounds:n}=e;return JSON.stringify([e.kind,Math.round(n.width*10),Math.round(n.height*10),e.color,e.angle,e.transparency,e.haloScale,e.blur??0,e.brightness??0,e.kind==="polygon"?e.points:void 0,t.scale,t.starPoints,t.rollRad])}dispose(e){e.removeFromParent(),e.geometry.dispose(),e.material.map?.dispose(),e.material.dispose()}clear(){for(const e of this.meshes.values())this.dispose(e);this.meshes.clear(),this.signatures.clear(),this.extents.clear(),this.placed=[]}}function sw(s,e){return JSON.stringify(s.cloudLayers)===JSON.stringify(e.cloudLayers)&&s.cloudCover===e.cloudCover&&s.cloudDarkness===e.cloudDarkness&&s.cloudBaseM===e.cloudBaseM&&s.highCloudCover===e.highCloudCover&&s.iceCrystalAlignment===e.iceCrystalAlignment&&s.lowerCloudCover===e.lowerCloudCover&&s.precipitationType===e.precipitationType&&s.precipitationIntensity===e.precipitationIntensity&&s.windDirectionDeg===e.windDirectionDeg&&s.windSpeed===e.windSpeed&&s.storm===e.storm}const Lo=900,Uc=1,zf=.5,da=900,rw=6371e3,aw=3e4;function Bf(s){const e=Math.sqrt(2*rw*Math.max(s,0));return Math.max(da,Math.min(e,aw))}const Fc=.5,Hf=850,ow=.03,No=850,kc=4,Gf=1.5,Vf=-1,lw=6,Su=-4,Wf=.2,Oo=2600,cw=.97,hw=.38,Xf=Su,uw=3,dw=.15,fw=.6,pw=40,mw=30,gw=[0,45,90,135,180,225,270,315],vw={en:["N","NE","E","SE","S","SW","W","NW"],fr:["N","NE","E","SE","S","SO","O","NO"]},xw=["en","fr"],Mw=880,zc=40,_w=60,yw=10,Sw=1,bw=150,ww=55,Ew=.5,Aw=2.05,qf=.265,Yf=[[0,0],...Array.from({length:8},(s,e)=>{const t=e*Math.PI/4;return[Math.cos(t)*qf,Math.sin(t)*qf]})],Bc=700,Hc=250/Eu,Tw=12,Kf=5,Gc=6,bs=[.92,.92,.95],Vc=[.15,.15,.19],$f={snow:{fallSpeedMPerS:2,size:.3,color:new le(1,1,1),driftSensitivity:1,radiusM:25,topYM:20,opacity:.75,poolSize:2400},hail:{fallSpeedMPerS:14,size:.5,color:new le(.95,.98,1),driftSensitivity:.25,radiusM:25,topYM:10,opacity:.95,poolSize:1200}},mr=0,Wc=0,Rw=150,Zf=3e3,sa=20,Cw=15,Jf=mr,Dw=40,jf=1,Pw=9;function Qf(s){return jf+(Pw-jf)*s}const Iw=new le(.75,.82,.92),Lw=10,Nw=.5;function Ow(s){return xl(s/Lw,Nw,1)}const fr=200,ep=.18,tp=.32,Uw=.35,Fw=new le(.85,.9,.98),np=5,ip=.85,sp=.01;function Xc(s,e){return Math.round(s*(sp+(1-sp)*e))}const rp=230,ap=.7,op=.05,kw=.6,zw=.7,Bw=.15,lp=.35,Hw=3,Gw=1/12,Vw=.5,cp=8,hp=25,up=.12,Ww={Venus:new le(1,.96,.85),Mars:new le(1,.55,.4),Jupiter:new le(.95,.87,.72),Saturn:new le(.92,.86,.68)};class li{renderer;scene=new Al;phenomena=new Yn(this.scene);camera;celestialGroup=new an;skyMesh;groundMesh;terrainMesh;terrainProviders;terrainOrigin;terrainBuildToken=0;terrainAttribution;decorModelProvider=ew[0].create();decorModelToken=0;decorModelCredits=new Map;starTiers=[];bodyMeshes=new Map;hitAreas=new Map;glareSprites=new Map;decorObjects=[];decorGroups=new Map;decorReferencePose;decorCurrentPose;decorTime=0;celestialLight=new w2(16777215,0);celestialLightTarget=new yt;skyLight=new M2(16777215,0,0);streetlightLights=new Map;compassSprites=[];showCompass=!1;compassHovered=!1;compassForced=!1;animationFrameId=null;raycaster=new mc;weather=vp;observerElevationM=0;groundRadius=da;terrainRadius=da;cloudRendering="volume";layeredClouds;cloudLayerOffsetsM={};cloudOffsetM=new D;cloudFieldOffset=new D;cloudMesh;cirrusMesh;cirrusMaterial;cirrusUniforms;cloudMaterial;cloudUniforms;precipitationPoints;precipitationPositions;precipitationPhase;precipitationSpeedJitter;precipitationWobbleFreqJitter;precipitationWobbleAmpJitter;precipitationBounceRemaining;precipitationBounceHeight;precipitationBounceDuration;precipitationBounceVelX;precipitationBounceVelZ;precipitationUniforms;rainSystem;rainSplashSystem;rainCameraDirection=new D;rainLastVerticalFacing=-1;rainViewportSize=new Pe;lightningArmed=!1;nextLightningAtS=null;lightningFlashRemainingS=0;baseFogColor=[0,0,0];lastSunPosition;lensFlare;sunCloudTransmission=1;sunUnhiddenFraction=1;lensFlareArtifactIntensity=0;sunWorldPosition=new D;sunVisible=!1;lensFlareScratch=new D;sunOcclusionRaycaster=new mc;sunOcclusionDirectionScratch=new D;sunOcclusionRightScratch=new D;sunOcclusionUpScratch=new D;ufoOcclusionRaycaster=new mc;projectionKind="rectilinear";starPoints=0;namedStars=[];equidistantPass;depthOfFieldPass;exposureAccumulation;exposureInstants=1;get developingExposure(){return this.exposureInstants>1&&this.exposureInstantAt!==void 0}static EXPOSURE_BUDGET_MS=12;exposureFrameId=null;exposureInstantsDone=0;exposureInstantAt;restatingExposure=!1;lensOptics;instrumentMagnitudeGain=0;meteorSystem;cometTail;iceHalos;rainbow;skyGlow;cometKey;onLightningFlash;constructor(e,t=M1(),n){this.renderer=new P3({canvas:e,antialias:!0}),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio||1,2)),this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=fa,this.camera=new Sn(60,e.width/Math.max(e.height,1),.1,Lo*1.2),this.camera.position.set(0,1.6,0),this.terrainProviders=t,this.onLightningFlash=n,this.celestialLight.shadow.mapSize.set(1024,1024),this.celestialLight.shadow.camera.left=-120,this.celestialLight.shadow.camera.right=120,this.celestialLight.shadow.camera.top=120,this.celestialLight.shadow.camera.bottom=-120,this.celestialLight.shadow.camera.near=1,this.celestialLight.shadow.camera.far=1e3,this.celestialLight.shadow.bias=-.0015,this.celestialLight.target=this.celestialLightTarget,this.scene.add(this.celestialLight,this.celestialLightTarget,this.skyLight),this.scene.add(this.celestialGroup)}get currentTerrainAttribution(){return this.terrainAttribution}resize(e,t){this.renderer.setSize(e,t,!1),this.camera.aspect=e/Math.max(t,1),this.camera.updateProjectionMatrix(),this.render()}setCloudRendering(e){e!==this.cloudRendering&&(this.cloudRendering=e,this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.buildClouds(),this.buildCirrus(),this.render())}setCloudOffset(e,t={}){this.cloudOffsetM.set(e.x,0,e.z),this.cloudLayerOffsetsM=t,this.layeredClouds?.setOffsets(e,t),this.cloudFieldOffset.set(e.x*Hc,0,e.z*Hc);for(const n of[this.cloudUniforms,this.cirrusUniforms])n?.fieldOffset.value.copy(this.cloudFieldOffset);this.iceHalos?.setCloudOffset(this.layeredClouds?.cirrusMask?.offset??this.cloudFieldOffset)}setObserverPose(e){const t=((e.rollDeg??0)+this.gaitOffset.rollDeg)*Tn,n=(e.pitchDeg+this.lookPitchDeg+this.gaitOffset.pitchDeg)*Tn;if(e.headingDeg!==void 0?this.camera.rotation.set(n,-(e.headingDeg+this.lookYawDeg+this.gaitOffset.yawDeg)*Tn,t,"YXZ"):this.camera.rotation.set(n,this.camera.rotation.y,t,"YXZ"),e.elevationM!==this.observerElevationM&&(this.observerElevationM=e.elevationM,this.syncCloudLayer(),Math.abs(Bf(e.elevationM)-this.groundRadius)>1&&(this.buildGround(),this.celestialGroup.scale.setScalar(this.groundRadius/da),this.camera.far=Math.max(Lo*1.2,this.groundRadius*2.5),this.camera.updateProjectionMatrix())),this.terrainMesh&&this.terrainOrigin&&e.lat!==void 0&&e.lng!==void 0){const i=rn(this.terrainOrigin.lat,this.terrainOrigin.lng,e.lat,e.lng);this.terrainMesh.position.x=i.x,this.terrainMesh.position.z=i.z}this.poseCameraY=this.groundYUnder(0,0)+1.6+e.elevationM,this.camera.position.y=this.poseCameraY,this.celestialGroup.position.y=this.camera.position.y,this.camera.fov!==e.fovDeg&&(this.camera.fov=e.fovDeg,this.camera.updateProjectionMatrix(),this.updateCompassScale())}setTerrainProviders(e){this.terrainProviders=e,this.disposeMesh(this.terrainMesh),this.terrainMesh=void 0,this.terrainOrigin=void 0,this.terrainAttribution=void 0,this.applyGroundDepthWrite(),this.terrainBuildToken++}setTerrainOrigin(e,t,n){if(e===void 0||t===void 0)return;const i=this.groundRadius;if(this.terrainOrigin&&Math.abs(this.terrainRadius-i)<i*.1){const{x:l,z:c}=rn(e,t,this.terrainOrigin.lat,this.terrainOrigin.lng);if(Math.sqrt(l*l+c*c)<bw*(i/da))return}const r=this.terrainOrigin,a=this.terrainRadius;this.terrainOrigin={lat:e,lng:t},this.terrainRadius=i;const o=++this.terrainBuildToken;Sb(e,t,this.terrainProviders,i).then(({mesh:l,attribution:c})=>{if(o!==this.terrainBuildToken)return;const h=this.terrainMesh,u=r?rn(e,t,r.lat,r.lng):void 0;h&&u&&Math.hypot(u.x,u.z)<=a&&(l.position.y=h.position.y+this.groundYOfPatch(h,u.x,u.z)),this.disposeMesh(this.terrainMesh),l.renderOrder=Sw,this.terrainMesh=l,this.terrainAttribution=c,this.scene.add(l),this.applyGroundDepthWrite(),this.decorCurrentPose&&(this.setObserverPose(this.decorCurrentPose),this.updateDecorAnchoring(this.decorReferencePose,this.decorCurrentPose,this.decorTime)),this.render(),n?.()}).catch(l=>{console.warn("Terrain build failed, keeping the flat ground fallback:",l),n?.()})}setShowCompass(e){this.showCompass!==e&&(this.showCompass=e,this.disposeCompassLabels(),e&&this.buildCompassLabels(),this.render())}applyLensFlareTint(e){if(!this.lensFlare)return;const t=ww*this.sunCloudTransmission;this.lensFlare.uniforms.uColorGain.value.setRGB(t*e[0],t*e[1],t*e[2]),this.applyDazzleStrength()}applyDazzleStrength(){if(!this.lensFlare)return;const e=this.lastSunPosition?.altitudeDeg??-90,t=hS(e)*this.sunCloudTransmission*this.sunUnhiddenFraction,n=ys(e);this.lensFlare.uniforms.uDazzleColour.value.setRGB(n[0],n[1],n[2]),this.lensFlare.uniforms.uVeilStrength.value=Aw**2*Math.max(0,t)}setCompassHovered(e){this.compassHovered!==e&&(this.compassHovered=e,this.updateCompassVisibility())}setCompassForced(e){this.compassForced!==e&&(this.compassForced=e,this.updateCompassVisibility())}updateCompassVisibility(){const e=this.compassHovered||this.compassForced;for(const t of this.compassSprites)t.visible=e;this.render()}setWeather(e){sw(this.weather,e)||(this.weather=e,this.buildClouds(),this.buildCirrus(),this.buildPrecipitation(),this.lightningArmed=e.storm&&e.cloudDarkness>=Vw,this.lightningArmed||(this.nextLightningAtS=null,this.lightningFlashRemainingS=0,this.restoreFogColor()),this.syncAnimationLoop(),this.render())}setDecor(e){if(this.decorObjects!==e){this.decorObjects=e,this.decorModelToken++,this.decorModelCredits.clear();for(const t of this.decorGroups.values())t.removeFromParent(),jt.dispose(t);this.decorGroups.clear(),this.streetlightLights.clear();for(const t of e){const n=jt.build(t,t.lit??!1);this.scene.add(n),this.decorGroups.set(t.id,n),t.kind==="streetlight"&&this.addStreetlightLight(t.id,n),this.loadDecorModel(t,this.decorModelToken)}this.celestialLight.castShadow=this.decorGroups.size>0}}setDecorModelProvider(e){this.decorModelProvider=e;const t=this.decorObjects;this.decorObjects=[],this.setDecor(t)}get currentDecorModelCredits(){return[...this.decorModelCredits.values()]}async loadDecorModel(e,t){const n=e.model;if(!(!n||!jt.usesModel(e)))try{const i=n.url?void 0:n.id?await this.decorModelProvider.entry(n.id):void 0,r=n.url??i?.url,a=n.credit??i?.credit;if(!r||!a)return;const o=await tw(r);if(t!==this.decorModelToken)return;const l=this.decorGroups.get(e.id);if(!l)return;jt.applyModel(l,e,o,{headingOffsetDeg:n.headingOffsetDeg??i?.headingOffsetDeg,depictedSizeM:i?.sizeM}),this.decorModelCredits.set(e.id,a),this.render()}catch(i){console.warn(`Keeping the built-in shape for decor "${e.id}":`,i)}}updateDecorAnchoring(e,t,n=0){this.decorReferencePose=e,this.decorCurrentPose=t,this.decorTime=n;const i=e?.lat!==void 0&&e.lng!==void 0&&t?.lat!==void 0&&t?.lng!==void 0?rn(e.lat,e.lng,t.lat,t.lng):{x:0,z:0},r=this.decorObjects.find(c=>c.witnessSide!==void 0&&_p(c.kind));r||(i.x-=this.gaitOffset.eastM,i.z+=this.gaitOffset.northM,this.camera.position.y=this.poseCameraY+this.gaitOffset.upM,this.celestialGroup.position.y=this.camera.position.y);const a={x:0,z:0};let o=0;if(r){const c=jt.occupantView(r),h=-(r.headingDeg??0)*Tn,u=c.x*Math.cos(h)+c.z*Math.sin(h),d=-c.x*Math.sin(h)+c.z*Math.cos(h),f=r.eastM+i.x,p=-r.northM+i.z;a.x=-(f+u),a.z=-(p+d),this.camera.position.y=this.groundYUnder(f,p)+c.eyeY,this.camera.rotation.set(this.indoorLookPitchDeg*Tn,-(c.headingDeg+this.indoorLookYawDeg)*Tn,0,"YXZ")}for(const c of this.decorObjects){const h=this.decorGroups.get(c.id);if(!h)continue;const u=Sl(c,n),d=u.eastM+i.x+a.x,f=-u.northM+i.z+a.z;if(h.position.set(d,this.groundUnderFootprint(c,d,f,u.headingDeg)+u.altitudeM,f),c.kind==="crop"){const p=Math.hypot(d,f);h.visible=p<=Rw}if(u.headingDeg!==void 0&&(h.rotation.y=-u.headingDeg*Tn),c.kind==="crop"&&h.visible){const p=this.terrainMesh,v=[p?.geometry.uuid,d-(p?.position.x??0),f-(p?.position.z??0),h.position.y-(p?.position.y??0),u.headingDeg,u.altitudeM].map(g=>typeof g=="number"?g.toFixed(4):g).join(":");h.userData.cropGroundKey!==v&&(jt.fitCropToGround(h,(g,m)=>this.groundYUnder(g,m)+u.altitudeM),h.userData.cropGroundKey=v)}o=Math.max(o,h.position.distanceTo(this.camera.position))}const l=Math.max(Lo*1.2,this.groundRadius*2.5,o*1.2);Math.abs(this.camera.far-l)>1&&(this.camera.far=l,this.camera.updateProjectionMatrix())}groundYUnder(e,t){const n=this.terrainMesh;return n?n.position.y+this.groundYOfPatch(n,e-n.position.x,t-n.position.z):Wc}groundYOfPatch(e,t,n){const i=e.geometry.getAttribute("position"),r=Math.round(Math.sqrt(i.count));if(r<2||r*r!==i.count)return Wc;const a=i.getX(0),o=i.getX(r-1),l=i.getZ(0),c=i.getZ((r-1)*r),h=xl((t-a)/(o-a)*(r-1),0,r-1),u=xl((n-l)/(c-l)*(r-1),0,r-1);if(!Number.isFinite(h)||!Number.isFinite(u))return Wc;const d=Math.min(Math.floor(h),r-2),f=Math.min(Math.floor(u),r-2),p=h-d,v=u-f,g=(S,E)=>i.getY(S*r+E),m=g(f,d),w=g(f,d+1),b=g(f+1,d),_=g(f+1,d+1);return p+v<=1?m+(w-m)*p+(b-m)*v:_+(b-_)*(1-p)+(w-_)*(1-v)}groundUnderFootprint(e,t,n,i){return jt.groundUnderFootprint(e,t,n,i,(r,a)=>this.groundYUnder(r,a))}lookYawDeg=0;lookPitchDeg=0;poseCameraY=1.6;setGait(e){this.gaitOffset=e}gaitOffset={eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0};setLookOffset(e,t){this.lookYawDeg=e,this.lookPitchDeg=t}indoorLookYawDeg=0;indoorLookPitchDeg=0;setIndoorLook(e,t){this.indoorLookYawDeg=e,this.indoorLookPitchDeg=t}updateDecorLitState(e,t=0){for(const n of this.decorObjects){const i=this.decorGroups.get(n.id);if(i&&n.lights?.length&&jt.setLights(i,n.lights,e,i.position.distanceTo(this.camera.position),t),n.kind!=="streetlight"&&n.kind!=="vehicle")continue;const r=this.decorGroups.get(n.id);if(!r)continue;const a=yp(n,e);jt.setLit(r,n.kind,a);const o=this.streetlightLights.get(n.id);o&&(o.visible=a)}}addStreetlightLight(e,t){const n=jt.bodyOf(t),i=n.children.find(a=>a.userData.emissive);if(!i)return;const r=new S2(16764006,pw,mw);r.position.copy(i.position).multiply(n.scale),r.castShadow=!0,r.shadow.mapSize.set(512,512),r.shadow.bias=-.002,t.add(r),this.streetlightLights.set(e,r)}setAstronomy(e){const t=jh(e.sun.altitudeDeg),n=t.horizon;this.baseFogColor=n,this.lastSunPosition=e.sun,this.buildSky(e.sun),this.buildGround(),this.updateCloudLighting(e.sun,n),this.updateCelestialLight(e,t.zenith,n);const i=ym(e.sun.altitudeDeg,this.instrumentMagnitudeGain);this.buildStars(e.stars,i),this.setBodyMesh("sun",e.sun,kc,new le(1,.96,.88),e.sun.magnitude),this.setMoonMesh(e.moon,i),this.buildPlanets(e.planets,i),this.buildComet(e.comet,i),this.buildIceHalos(e.sun,e.moon),this.buildRainbow(e.sun,e.moon),this.buildSkyGlow(e,t.zenith),this.scene.fog=new Bu(new le(...n),this.groundRadius*.2,this.groundRadius),this.syncAnimationLoop(),this.render()}updateCelestialLight(e,t,n){this.skyLight.color.setRGB(t[0],t[1],t[2]),this.skyLight.groundColor.setRGB(n[0],n[1],n[2]),this.skyLight.intensity=fw;const i=e.sun.altitudeDeg>=Xf,r=!i&&e.moon.altitudeDeg>=Xf;if(!i&&!r){this.celestialLight.intensity=0;return}const a=i?e.sun:e.moon,{x:o,y:l,z:c}=fn(a.altitudeDeg,a.azimuthDeg,No);this.celestialLight.position.set(o,l,c);const h=ys(a.altitudeDeg);this.celestialLight.color.setRGB(h[0],h[1],h[2]);const u=Math.max(0,Math.sin(Math.max(a.altitudeDeg,0)*Tn));this.celestialLight.intensity=(i?uw:dw)*u,this.celestialLight.castShadow=this.decorGroups.size>0}setMeteorShower(e,t,n){this.meteorSystem||(this.meteorSystem=new $t,this.celestialGroup.add(this.meteorSystem.object)),this.meteorSystem.setShower(e,t,n)}get meteorSchedule(){return this.meteorSystem?.schedule??[]}meteorMidpoint(e){return this.meteorSystem?.midpointOf(e)}updateMeteors(e){this.meteorSystem?.update(e)}setInstrument(e){this.projectionKind=e.projection;const t=Ut.starPointsOf(e),n=Ut.flareArtifactsOf(e);t===this.starPoints&&n===this.lensFlareArtifactIntensity||(this.starPoints=t,this.lensFlareArtifactIntensity=n,this.lensFlare&&(this.lensFlare.uniforms.uStarPoints.value=t,this.lensFlare.uniforms.uFlareIntensity.value=n),this.render())}setInstrumentGain(e){this.instrumentMagnitudeGain=Number.isFinite(e)?e:0}render(){this.restatingExposure||(this.renderOnce(),this.developingExposure&&this.startExposure())}setExposure(e,t){const n=t?Math.max(1,Math.round(e)):1;if(n===this.exposureInstants&&(n===1||t===this.exposureInstantAt)){this.exposureInstantAt=t;return}this.exposureInstants=n,this.exposureInstantAt=t,n===1&&(this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0),this.render()}renderOnce(e){const t=this.usableEquidistantPass();this.phenomena.setCloudLayers(this.layeredClouds?.volumes??[]),this.phenomena.place(this.camera,(r,a,o)=>this.directionAtScreenPoint(r,a,o),r=>this.screenPointOf(r));const n=this.phenomena.furthestM*1.2;n>this.camera.far&&(this.camera.far=n,this.camera.updateProjectionMatrix());const i=this.renderer.getRenderTarget();if(!t){this.updateLensFlarePosition();const r=this.usableDepthOfFieldPass();r?.setEncodesOutput(e===void 0),this.skyGlow?.setDestinationEncoded(e===void 0&&!r),e&&this.renderer.setRenderTarget(e),r?r.render(this.renderer,this.scene,this.camera,()=>this.renderPhenomenaPass()):(this.renderer.render(this.scene,this.camera),this.renderPhenomenaPass()),e&&this.renderer.setRenderTarget(i);return}t.setEncodesOutput(e===void 0),this.skyGlow?.setDestinationEncoded(!1),e&&this.renderer.setRenderTarget(e),t.render(this.renderer,this.scene,this.camera,this.camera.fov,()=>this.updateLensFlarePosition(),()=>this.renderPhenomenaPass()),e&&this.renderer.setRenderTarget(i)}renderPhenomenaPass(){if(!this.phenomena.any)return;const e=this.renderer.autoClear,t=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,this.renderer.clearDepth();for(const n of this.decorObjects){const i=this.decorGroups.get(n.id);i&&li.markDecorDepth(i,n.kind!=="crop")}this.camera.layers.set(Uc),this.scene.overrideMaterial=this.decorDepthMaterial,this.renderer.render(this.scene,this.camera),this.scene.overrideMaterial=null,this.camera.layers.set(tg),this.renderer.render(this.scene,this.camera),this.camera.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=t}decorDepthMaterial=new Bi({colorWrite:!1});static markDecorDepth(e,t){e.traverse(n=>{if(!(n instanceof Ye))return;const i=Array.isArray(n.material)?n.material[0]:n.material;t&&i.depthWrite!==!1&&i.blending!==jn?n.layers.enable(Uc):n.layers.disable(Uc)})}startExposure(){this.cancelExposure();const e=this.renderer.getDrawingBufferSize(new Pe),t=Math.max(1,Math.round(e.x)),n=Math.max(1,Math.round(e.y));this.exposureAccumulation||(this.exposureAccumulation=new G3(t,n)),this.exposureAccumulation.resize(t,n),this.exposureAccumulation.open(this.renderer),this.exposureInstantsDone=0,this.exposureFrameId=requestAnimationFrame(()=>this.developExposure())}developExposure(){this.exposureFrameId=null;const e=this.exposureInstantAt,t=this.exposureAccumulation;if(!e||!t)return;const n=1/this.exposureInstants,i=performance.now()+li.EXPOSURE_BUDGET_MS;do this.restateAt(e,this.exposureInstantsDone),this.renderOnce(t.instantTarget),t.add(this.renderer,n),this.exposureInstantsDone++;while(this.exposureInstantsDone<this.exposureInstants&&performance.now()<i);this.restateAt(e,0),t.develop(this.renderer,this.exposureInstants/this.exposureInstantsDone),this.exposureInstantsDone<this.exposureInstants&&(this.exposureFrameId=requestAnimationFrame(()=>this.developExposure()))}restateAt(e,t){this.restatingExposure=!0;try{e(t)}finally{this.restatingExposure=!1}}cancelExposure(){this.exposureFrameId!==null&&(cancelAnimationFrame(this.exposureFrameId),this.exposureFrameId=null)}setLensOptics(e){const t=this.lensOptics;this.lensOptics=e,(t===void 0!=(e===void 0)||t&&e&&(t.focalLengthMm!==e.focalLengthMm||t.fNumber!==e.fNumber||t.focusDistance!==e.focusDistance||t.frameHeightMm!==e.frameHeightMm))&&(e&&this.depthOfFieldPass&&this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.render())}usableDepthOfFieldPass(){const e=this.lensOptics;if(!e)return;const t=this.renderer.getDrawingBufferSize(new Pe),n=Math.max(1,Math.round(t.x)),i=Math.max(1,Math.round(t.y));return this.depthOfFieldPass||(this.depthOfFieldPass=new va(n,i)),this.depthOfFieldPass.resize(n,i),this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.depthOfFieldPass}usableEquidistantPass(){if(this.projectionKind!=="equidistant")return;const e=this.renderer.getDrawingBufferSize(new Pe);if(ga.supports(this.camera.fov,e.x/Math.max(e.y,1)))return this.equidistantPass?this.equidistantPass.resize(e.x,e.y):this.equidistantPass=new ga(e.x,e.y),this.equidistantPass}aimAtScreenPoint(e,t,n){const i=this.projectionKind==="equidistant"?this.equidistantPass:void 0;if(!i){e.setFromCamera(new Pe(t,n),this.camera);return}const r=i.directionFor(t,n,this.camera.fov);this.camera.updateMatrixWorld(),e.ray.origin.setFromMatrixPosition(this.camera.matrixWorld),e.ray.direction.set(r.x,r.y,r.z).applyQuaternion(this.camera.quaternion).normalize(),e.camera=this.camera}pickCloudAt(e,t){return this.layeredClouds?.pickInstance(this.cloudDirectionAt(e,t))}cloudDirectionAt(e,t){return this.directionAtScreenPoint(e,t,new D)}directionAtScreenPoint(e,t,n){return this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),n.copy(this.ufoOcclusionRaycaster.ray.direction)}screenPointOf(e){this.camera.updateMatrixWorld();const t=this.screenPointScratch.copy(e).applyQuaternion(this.screenPointQuaternion.copy(this.camera.quaternion).invert());if(t.z>=0)return;const n=this.renderer.getDrawingBufferSize(this.screenPointSize),i=n.x/Math.max(n.y,1);if(this.projectionKind==="equidistant"&&this.equidistantPass)return ga.ndcFor(t,this.camera.fov,i);const r=Math.tan(this.camera.fov/2*Tn);return{ndcX:t.x/-t.z/(i*r),ndcY:t.y/-t.z/r}}screenPointScratch=new D;screenPointQuaternion=new ps;screenPointSize=new Pe;updateLensFlarePosition(){const e=this.lensFlare;if(!e)return;if(!this.sunVisible){e.mesh.visible=!1;return}if(this.camera.updateMatrixWorld(),this.lensFlareScratch.copy(this.sunWorldPosition).applyMatrix4(this.camera.matrixWorldInverse),this.lensFlareScratch.z>0){e.mesh.visible=!1;return}const t=this.sunVisibleFraction();if(t<=0){e.mesh.visible=!1;return}e.mesh.visible=!0,this.sunUnhiddenFraction=t,this.applyDazzleStrength();const n=this.lensFlareScratch.copy(this.sunWorldPosition).project(this.camera);e.uniforms.uLensPosition.value.set(n.x,n.y);const i=this.renderer.domElement.width,r=this.renderer.domElement.height;e.uniforms.uResolution.value.set(i,r),e.uniforms.uTanHalfFov.value=Math.tan(this.camera.fov*Math.PI/360)}sunVisibleFraction(){let e=0;for(const t of Yf)this.isSunOccluded(t[0],t[1])||e++;return e/Yf.length}raycastableDecor(){const e=[];for(const t of this.decorObjects){if(t.kind==="crop")continue;const n=this.decorGroups.get(t.id);n&&e.push(n)}return e}isSunOccluded(e=0,t=0){this.scene.updateMatrixWorld();const n=[];this.groundMesh&&n.push(this.groundMesh),this.terrainMesh&&n.push(this.terrainMesh);for(const o of this.raycastableDecor())n.push(o);if(n.length===0)return!1;const i=this.sunOcclusionDirectionScratch.copy(this.sunWorldPosition).sub(this.camera.position),r=i.length();if(i.normalize(),e!==0||t!==0){const o=Math.PI/180,l=this.sunOcclusionRightScratch.set(i.z,0,-i.x);l.lengthSq()<1e-9&&l.set(1,0,0),l.normalize();const c=this.sunOcclusionUpScratch.crossVectors(l,i).normalize();i.addScaledVector(l,e*o).addScaledVector(c,t*o).normalize()}this.sunOcclusionRaycaster.set(this.camera.position,i);const a=this.sunOcclusionRaycaster.intersectObjects(n,!0)[0];return a!==void 0&&a.distance<r}setPhenomena(e,t){this.phenomena.set(e,t)}decorDistancesAt(e,t,n){this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=zf;let i,r;for(const a of this.decorObjects){if(a.kind==="crop")continue;const o=this.decorGroups.get(a.id);if(!o)continue;const l=this.ufoOcclusionRaycaster.intersectObject(o,!0)[0];l&&(a.occludesSourceIds?.includes(n)?i=i===void 0?l.distance:Math.max(i,l.distance):r=r===void 0?l.distance:Math.min(r,l.distance))}return{behindM:i,inFrontM:r}}pickBodyAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const n=[...this.hitAreas.entries()],i=this.raycaster.intersectObjects(n.map(([,r])=>r))[0];if(i&&!this.groundHides(e,t))return n.find(([,r])=>r===i.object)?.[0]}pickStarAt(e,t){if(this.namedStars.length===0)return;this.aimAtScreenPoint(this.raycaster,e,t);const n=this.raycaster.ray.direction,i=Math.cos(ow*this.camera.fov*Math.PI/180);let r,a=i;for(const o of this.namedStars){const l=o.direction.dot(n);l>a&&(a=l,r={star:o.star,altitudeDeg:o.altitudeDeg})}return r&&this.groundHides(e,t)?void 0:r}groundHides(e,t){const n=[this.terrainMesh,this.groundMesh].filter(i=>i!==void 0);return n.length===0?!1:(this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=zf,this.ufoOcclusionRaycaster.intersectObjects(n,!0).length>0)}pickDecorAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const n=[...this.decorGroups.entries()],i=this.raycaster.intersectObjects(n.map(([,a])=>a),!0)[0];if(!i)return;let r=i.object;for(;r&&!n.some(([,a])=>a===r);)r=r.parent;return n.find(([,a])=>a===r)?.[0]}dispose(){this.stopTwinkle(),this.phenomena.clear(),this.terrainBuildToken++,this.disposeMesh(this.skyMesh),this.disposeMesh(this.groundMesh),this.disposeMesh(this.terrainMesh),this.disposeCloudSystem(),this.disposeCirrus(),this.disposePrecipitationPoints(),this.disposeRain(),this.disposeStarTiers(),this.meteorSystem?.dispose(),this.meteorSystem=void 0,this.iceHalos?.dispose(),this.iceHalos=void 0,this.rainbow?.dispose(),this.rainbow=void 0,this.skyGlow?.dispose(),this.skyGlow=void 0,this.depthOfFieldPass?.dispose(),this.depthOfFieldPass=void 0,this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0,this.cometTail?.dispose(),this.cometTail=void 0;for(const e of this.bodyMeshes.values())this.disposeMesh(e);this.bodyMeshes.clear();for(const e of[...this.hitAreas.keys()])this.disposeHitArea(e);for(const e of[...this.glareSprites.keys()])this.disposeGlare(e);this.disposeCompassLabels();for(const e of this.decorGroups.values())jt.dispose(e);this.decorGroups.clear(),this.streetlightLights.clear(),this.lensFlare&&(this.lensFlare.mesh.removeFromParent(),this.lensFlare.mesh.geometry.dispose(),this.lensFlare.mesh.material.dispose(),this.lensFlare=void 0),this.renderer.dispose()}animationsRunning=!1;startTwinkle(){if(this.animationFrameId!==null||!this.needsAnimationLoop())return;let e;const t=n=>{const i=e===void 0?0:Math.min((n-e)/1e3,Gw);e=n,this.updateTwinkle(n/1e3),this.updatePrecipitation(n/1e3,i),this.updateRain(i),this.updateLightning(n/1e3,i),this.lensFlare&&(this.lensFlare.uniforms.uTime.value=n/1e3),this.developingExposure||this.render(),this.animationFrameId=requestAnimationFrame(t)};this.animationFrameId=requestAnimationFrame(t)}setAnimationsRunning(e){e!==this.animationsRunning&&(this.animationsRunning=e,e?this.nextLightningAtS=null:this.lightningFlashRemainingS>0&&(this.lightningFlashRemainingS=0,this.restoreFogColor()),this.syncAnimationLoop(),e||this.render())}stopTwinkle(){this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}restoreFogColor(){this.scene.fog&&this.scene.fog.color.setRGB(...this.baseFogColor)}needsAnimationLoop(){return this.animationsRunning&&(this.starTiers.length>0||this.precipitationPoints!==void 0||this.rainSystem!==void 0||this.lightningArmed||this.lensFlare!==void 0&&this.sunVisible)}syncAnimationLoop(){this.needsAnimationLoop()?this.startTwinkle():this.stopTwinkle()}buildSky(e){this.disposeMesh(this.skyMesh);const t=new ln(Lo,32,16),n=t.attributes.position,i=[];for(let a=0;a<n.count;a++){const{altitudeDeg:o,azimuthDeg:l}=X3(n.getX(a),n.getY(a),n.getZ(a)),c=Q3(o,l,e.azimuthDeg,e.altitudeDeg);i.push(c[0],c[1],c[2])}t.setAttribute("color",new bt(i,3));const r=new Bi({vertexColors:!0,side:kt,fog:!1,depthWrite:!1});this.skyMesh=new Ye(t,r),this.skyMesh.renderOrder=-1,this.celestialGroup.add(this.skyMesh)}buildGround(){this.disposeMesh(this.groundMesh),this.groundRadius=Bf(this.observerElevationM);const e=new Vu(this.groundRadius,48),t=new Ia({color:new le(Fc,Fc,Fc),fog:!0});this.groundMesh=new Ye(e,t),this.groundMesh.rotation.x=-Math.PI/2,this.groundMesh.position.y=0,this.groundMesh.receiveShadow=!0,this.scene.add(this.groundMesh),this.applyGroundDepthWrite()}applyGroundDepthWrite(){const e=this.groundMesh?.material;if(!e)return;const t=this.terrainMesh===void 0;e.depthWrite!==t&&(e.depthWrite=t,e.needsUpdate=!0)}cloudTransmission(e){const t=fn(e.altitudeDeg,e.azimuthDeg,1);if(this.layeredClouds)return this.layeredClouds.transmissionAt(t);let n=1;const i=this.lowerCloudCover();i>0&&(n*=1-Dt.alphaAt(t,Math.abs(this.cloudLayerOffset()),i,this.cloudFieldOffset)*cw);const r=this.weather.highCloudCover??0;return r>0&&(n*=1-Dt.alphaAt(t,Oo,r)*hw),Math.max(0,Math.min(1,n))}setBodyMesh(e,t,n,i,r){if(this.disposeMesh(this.bodyMeshes.get(e)),this.disposeHitArea(e),this.disposeGlare(e),t.altitudeDeg<Su){this.bodyMeshes.delete(e),e==="sun"&&(this.sunVisible=!1);return}const{x:a,y:o,z:l}=fn(t.altitudeDeg,t.azimuthDeg,No),c=ys(t.altitudeDeg),h=this.cloudTransmission(t),u=new le(i.r*c[0]*h,i.g*c[1]*h,i.b*c[2]*h),d=new ln(n,16,16),f=new Bi({color:u,fog:!1}),p=new Ye(d,f);p.position.set(a,o,l),this.celestialGroup.add(p),this.bodyMeshes.set(e,p),this.setHitArea(e,a,o,l,n);const v=r-2.5*Math.log10(Math.max(h,.001));if(e==="sun"&&(this.sunCloudTransmission=h),e!=="sun"&&this.setGlare(e,a,o,l,v,u),e==="sun"){this.sunVisible=!0;const g=this.celestialGroup.scale.x;this.sunWorldPosition.set(a*g,o*g+this.celestialGroup.position.y,l*g),this.lensFlare||(this.lensFlare=Ub(),this.lensFlare.uniforms.uOpacity.value=Ew,this.lensFlare.uniforms.uFlareIntensity.value=this.lensFlareArtifactIntensity,this.lensFlare.uniforms.uStarPoints.value=this.starPoints,this.scene.add(this.lensFlare.mesh)),this.applyLensFlareTint(c)}}setMoonMesh(e,t){const n="moon";if(this.disposeMesh(this.bodyMeshes.get(n)),this.disposeHitArea(n),this.disposeGlare(n),e.magnitude>t||e.altitudeDeg<Su){this.bodyMeshes.delete(n);return}const{x:i,y:r,z:a}=fn(e.altitudeDeg,e.azimuthDeg,No),o=ys(e.altitudeDeg),l=new le(o[0],o[1],o[2]),c=new la({map:eE(e.phase),color:l,fog:!1}),h=new no(c);h.position.set(i,r,a);const u=kc*2;h.scale.set(u,u,1),this.celestialGroup.add(h),this.bodyMeshes.set(n,h),this.setHitArea(n,i,r,a,kc),this.setGlare(n,i,r,a,e.magnitude,l)}setHitArea(e,t,n,i,r){const a=new la({transparent:!0,opacity:0,depthTest:!1,depthWrite:!1,fog:!1}),o=new no(a);o.position.set(t,n,i);const l=r*lw;o.scale.set(l,l,1),this.celestialGroup.add(o),this.hitAreas.set(e,o)}disposeHitArea(e){const t=this.hitAreas.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.hitAreas.delete(e))}setGlare(e,t,n,i,r,a){const o=nS(r);if(o<=0){this.disposeGlare(e);return}const l=rS(o),c=this.glareSprites.get(e),h=c??new no(new la({map:Qw(),transparent:!0,blending:jn,depthWrite:!1,fog:!1}));h.material.color.copy(a),h.material.opacity=lS(o),h.position.set(t,n,i),h.scale.set(l*2,l*2,1),c||(this.celestialGroup.add(h),this.glareSprites.set(e,h))}disposeGlare(e){const t=this.glareSprites.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.glareSprites.delete(e))}buildComet(e,t){const n=e&&`comet:${e.id}`;if(!e||!n||e.magnitude>t){this.disposeComet();return}this.cometKey&&this.cometKey!==n&&this.disposeComet();const i=wc(e.magnitude,t),r=Ec(i);this.cometKey=n,this.setBodyMesh(n,e.position,Gf*(.5+.5*i),new le(r,r,r),e.magnitude),this.cometTail||(this.cometTail=new Rn(No),this.celestialGroup.add(this.cometTail.object)),this.cometTail.set(e.position,e.tailEnd,i)}buildIceHalos(e,t){this.iceHalos||(this.iceHalos=new oi,this.iceHalos.setCloudOffset(this.cloudFieldOffset),this.iceHalos.onReady=()=>this.render(),this.celestialGroup.add(this.iceHalos.object));const n=this.highCloudCover(),i=this.layeredClouds?.cirrusMask;if(this.iceHalos.setCloudOffset(i?.offset??this.cloudFieldOffset),n===void 0){this.iceHalos.update({x:0,y:1,z:0},-1,0,[1,1,1],{cover:0,layerHeight:Oo},0);return}const r=this.lowerCloudCover(),a=et.deckLitUntilDeg(et.DECK_HEIGHT_M),o=e.altitudeDeg>-a?e:t,l=et.strength(n,r,o.altitudeDeg,a)*(o===e?1:Wf),{x:c,y:h,z:u}=fn(o.altitudeDeg,o.azimuthDeg,1),d=ys(o.altitudeDeg);this.iceHalos.update({x:c,y:h,z:u},o.altitudeDeg,l,[d[0],d[1],d[2]],{cover:i?.cover??n,layerHeight:i?.layerHeight??Oo},i?.iceCrystalAlignment??this.weather.iceCrystalAlignment??Sg)}buildRainbow(e,t){this.rainbow||(this.rainbow=new xa,this.celestialGroup.add(this.rainbow.object));const n=this.weather.precipitationType==="rain"?this.weather.precipitationIntensity:0,i=e.altitudeDeg>0,r=i?e:t,a=this.lowerCloudCover(),o=Wf*yn.moonlightShare(t.magnitude),l=yn.strength(n,a,r.altitudeDeg)*(i?1:o);if(l<=0){this.rainbow.update({x:0,y:1,z:0},0,[1,1,1],!0);return}const{x:c,y:h,z:u}=fn(r.altitudeDeg,r.azimuthDeg,1),d=ys(r.altitudeDeg);this.rainbow.update({x:c,y:h,z:u},l,[d[0],d[1],d[2]],i)}buildSkyGlow(e,t){if(!e.frame){this.skyGlow?.hide();return}this.skyGlow||(this.skyGlow=new Xn,this.skyGlow.onReady=()=>this.render(),this.celestialGroup.add(this.skyGlow.object));const{date:n,observer:i}=e.frame,r=qn.galactic(n,i),a=li.directionOf(r.centre),o=li.directionOf(r.rotation),l=li.directionOf(r.pole),c=new ze().set(a.x,a.y,a.z,o.x,o.y,o.z,l.x,l.y,l.z),h=li.directionOf(qn.eclipticPole(n,i)),u=li.directionOf(e.sun),d=u.clone().addScaledVector(h,-u.dot(h)).normalize();this.skyGlow.update({galactic:c,eclipticPole:h,sunLongitude:d,sunDirection:u,sunAltitudeDeg:e.sun.altitudeDeg,moon:{direction:li.directionOf(e.moon),altitudeDeg:e.moon.altitudeDeg,phaseAngleDeg:Ze.phaseAngleOf(e.moon.phase.illuminatedFraction)},skyColor:new D(t[0],t[1],t[2])})}static directionOf(e){const{x:t,y:n,z:i}=fn(e.altitudeDeg,e.azimuthDeg,1);return new D(t,n,i).normalize()}disposeComet(){this.cometTail?.set(void 0,void 0,0),this.cometKey&&(this.disposeMesh(this.bodyMeshes.get(this.cometKey)),this.bodyMeshes.delete(this.cometKey),this.disposeHitArea(this.cometKey),this.disposeGlare(this.cometKey),this.cometKey=void 0)}buildPlanets(e,t){const n=new Set(["sun","moon",...this.cometKey?[this.cometKey]:[]]);for(const i of e){if(i.magnitude>t)continue;n.add(i.body);const r=wc(i.magnitude,t),a=Ec(r),o=Ww[i.body]??new le(1,1,1),l=new le(o.r*a,o.g*a,o.b*a),c=Gf*(.5+.5*r);this.setBodyMesh(i.body,i.position,c,l,i.magnitude)}for(const i of[...this.bodyMeshes.keys()])n.has(i)||(this.disposeMesh(this.bodyMeshes.get(i)),this.bodyMeshes.delete(i),this.disposeHitArea(i),this.disposeGlare(i))}buildStars(e,t){if(this.disposeStarTiers(),this.namedStars=[],!e||e.catalog.count===0){this.syncAnimationLoop();return}const{catalog:n,date:i,observer:r}=e,a=qc(1337),o=[];for(let l=0;l<n.count;l++){const c=n.mag[l];if(c>t)break;const{altitudeDeg:h,azimuthDeg:u}=Nr(n.ra[l],n.dec[l],i,r);if(h<Vf)continue;const{x:d,y:f,z:p}=fn(h,u,Hf);o.push({x:d,y:f,z:p,brightness:wc(c,t),phase:a()*Math.PI*2,speedFactor:.7+a()*.6})}for(const l of gb){if(l.mag>t)continue;const{altitudeDeg:c,azimuthDeg:h}=Nr(l.raHours,l.decDeg,i,r);if(c<Vf)continue;const{x:u,y:d,z:f}=fn(c,h,Hf);this.namedStars.push({star:l,direction:new D(u,d,f).normalize(),altitudeDeg:c})}this.starTiers=bm.map((l,c)=>{const h=o.filter(b=>dS(b.brightness)===c),u=new Float32Array(h.length*3),d=new Float32Array(h.length),f=new Float32Array(h.length),p=new Float32Array(h.length);h.forEach((b,_)=>{u[_*3]=b.x,u[_*3+1]=b.y,u[_*3+2]=b.z,d[_]=b.brightness,f[_]=b.phase,p[_]=b.speedFactor});const v=new wt;v.setAttribute("position",new dt(u,3));const g=new dt(new Float32Array(h.length*3),3);v.setAttribute("color",g);const m=new nm({vertexColors:!0,size:l.size,sizeAttenuation:!1,fog:!1});Cs.apply(m);const w=new Ko(v,m);return this.celestialGroup.add(w),{points:w,colorAttribute:g,brightness:d,phase:f,speedFactor:p}}),this.updateTwinkle(0),this.startTwinkle()}updateTwinkle(e){for(const t of this.starTiers){const n=t.colorAttribute.array;for(let i=0;i<t.brightness.length;i++){const r=mS(t.brightness[i],{phase:t.phase[i],speedFactor:t.speedFactor[i]},e),a=Ec(t.brightness[i])*r;n[i*3]=a,n[i*3+1]=a,n[i*3+2]=a}t.colorAttribute.needsUpdate=!0}}buildClouds(){if(this.cloudRendering==="volume"||this.weather.cloudLayers!==void 0){this.layeredClouds||(this.disposeCloudSystem(),this.layeredClouds=new H3(this.celestialGroup,Bc,this.cloudRendering)),this.disposeCirrus(),this.layeredClouds.update(this.weather,this.observerElevationM+1.6),this.layeredClouds.setOffsets(this.cloudOffsetM,this.cloudLayerOffsetsM),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}this.disposeCloudSystem();const e=this.lowerCloudCover();if(e<=0)return;const t=this.weather.cloudDarkness,n=new le(bs[0]+(Vc[0]-bs[0])*t,bs[1]+(Vc[1]-bs[1])*t,bs[2]+(Vc[2]-bs[2])*t),{material:i,uniforms:r}=Yh(n,e,Math.abs(this.cloudLayerOffset()));this.cloudMaterial=i,this.cloudUniforms=r,r.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);const a=Kh(Bc);this.cloudMesh=new Ye(a,i),this.cloudLayerOffset()<0&&(this.cloudMesh.scale.y=-1),this.cloudMesh.renderOrder=Kf,this.celestialGroup.add(this.cloudMesh)}lowerCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(e=>e.type!=="cirrus").reduce((e,t)=>e*(1-t.coverage),1):this.weather.lowerCloudCover??this.weather.cloudCover}highCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(e=>e.type==="cirrus").reduce((e,t)=>e*(1-t.coverage),1):this.weather.highCloudCover}buildCirrus(){if(this.disposeCirrus(),this.layeredClouds)return;const e=this.weather.highCloudCover??0;if(e<=0)return;const{material:t,uniforms:n}=Yh(new le(...bs),e,Oo,1);this.cirrusMaterial=t,this.cirrusUniforms=n,n.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.cirrusMesh=new Ye(Kh(Bc*1.04),t),this.cirrusMesh.renderOrder=Kf-1,this.celestialGroup.add(this.cirrusMesh)}disposeCirrus(){this.cirrusMesh&&(this.cirrusMesh.removeFromParent(),this.cirrusMesh.geometry.dispose()),this.cirrusMaterial?.dispose(),this.cirrusMesh=void 0,this.cirrusMaterial=void 0,this.cirrusUniforms=void 0}syncCloudLayer(){this.layeredClouds?.update(this.weather,this.observerElevationM+1.6);const e=this.cloudLayerOffset();this.cloudUniforms&&(this.cloudUniforms.layerHeight.value=Math.abs(e)),this.cloudMesh&&(this.cloudMesh.scale.y=e<0?-1:1)}cloudLayerOffset(){const t=((this.weather.cloudBaseM??Eu)-this.observerElevationM)*Hc;return Math.sign(t||1)*Math.max(Math.abs(t),Tw)}updateCloudLighting(e,t){const n=[this.cloudUniforms,this.cirrusUniforms].filter(c=>c!==void 0);if(n.length===0&&!this.layeredClouds)return;const{x:i,y:r,z:a}=fn(e.altitudeDeg,e.azimuthDeg,1),o=ys(e.altitudeDeg),l=Math.max(0,Math.sin(Math.max(e.altitudeDeg,0)*Tn));this.layeredClouds?.setLighting(new D(i,r,a),new le(o[0]*l,.96*o[1]*l,.88*o[2]*l),new le(...t),new le(...t));for(const c of n)c.sunDir.value.set(i,r,a),c.sunColor.value.setRGB(o[0]*l,.96*o[1]*l,.88*o[2]*l),c.ambientColor.value.setRGB(t[0],t[1],t[2])}disposeCloudSystem(){this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.cloudMesh&&(this.cloudMesh.removeFromParent(),this.cloudMesh.geometry.dispose()),this.cloudMaterial?.dispose(),this.cloudMesh=void 0,this.cloudMaterial=void 0,this.cloudUniforms=void 0}disposePrecipitationPoints(){this.precipitationPoints&&(this.precipitationPoints.removeFromParent(),this.precipitationPoints.geometry.dispose(),this.precipitationPoints.material.dispose()),this.precipitationPoints=void 0,this.precipitationPositions=void 0,this.precipitationPhase=void 0,this.precipitationSpeedJitter=void 0,this.precipitationWobbleFreqJitter=void 0,this.precipitationWobbleAmpJitter=void 0,this.precipitationBounceRemaining=void 0,this.precipitationBounceHeight=void 0,this.precipitationBounceDuration=void 0,this.precipitationBounceVelX=void 0,this.precipitationBounceVelZ=void 0,this.precipitationUniforms=void 0}buildPrecipitation(){this.disposePrecipitationPoints(),this.disposeRain();const e=this.weather.precipitationType;if(e==="none")return;if(e==="rain"){this.buildRain();return}const t=$f[e],n=t.poolSize,i=qc(9001),r=new Float32Array(n*3),a=new Float32Array(n),o=new Float32Array(n),l=new Float32Array(n),c=new Float32Array(n),h=new Float32Array(n),u=new Float32Array(n),d=new Float32Array(n),f=new Float32Array(n),p=new Float32Array(n);for(let b=0;b<n;b++){const _=i()*Math.PI*2,S=i()*t.radiusM;r[b*3]=Math.cos(_)*S,r[b*3+1]=mr+i()*(t.topYM-mr),r[b*3+2]=Math.sin(_)*S,a[b]=i()*Math.PI*2,o[b]=.7+i()*.6,l[b]=.6+i()*.8,c[b]=.4+i()*1.2}const v=new wt;v.setAttribute("position",new dt(r,3)),v.setDrawRange(0,Xc(n,this.weather.precipitationIntensity));const g={uSize:{value:t.size},uScale:{value:.5*this.renderer.domElement.height},uOpacity:{value:t.opacity},uColor:{value:t.color},uHazeColor:{value:new le(...this.baseFogColor)},uTexture:{value:Xw(e)},uNearFocusDistance:{value:np},uHazeDistance:{value:t.radiusM*ip}},m=new Et({uniforms:g,vertexShader:Jw,fragmentShader:jw,transparent:!0,depthWrite:!1});this.precipitationUniforms=g;const w=new Ko(v,m);w.renderOrder=Gc,this.scene.add(w),this.precipitationPoints=w,this.precipitationPositions=r,this.precipitationPhase=a,this.precipitationSpeedJitter=o,this.precipitationWobbleFreqJitter=l,this.precipitationWobbleAmpJitter=c,this.precipitationBounceRemaining=h,this.precipitationBounceHeight=u,this.precipitationBounceDuration=d,this.precipitationBounceVelX=f,this.precipitationBounceVelZ=p}updatePrecipitation(e,t){if(!this.precipitationPoints||!this.precipitationPositions||!this.precipitationPhase||!this.precipitationSpeedJitter||(this.precipitationUniforms?.uHazeColor.value.setRGB(...this.baseFogColor),t<=0))return;const n=this.weather.precipitationType;if(n==="none"||n==="rain")return;const i=$f[n],r=this.weather.windDirectionDeg*Tn,a=Math.sin(r)*this.weather.windSpeed*i.driftSensitivity,o=-Math.cos(r)*this.weather.windSpeed*i.driftSensitivity,l=this.precipitationPositions,c=this.precipitationPhase,h=this.precipitationSpeedJitter,u=this.precipitationWobbleFreqJitter,d=this.precipitationWobbleAmpJitter,f=this.precipitationBounceRemaining,p=this.precipitationBounceHeight,v=this.precipitationBounceDuration,g=this.precipitationBounceVelX,m=this.precipitationBounceVelZ,w=n==="snow"&&u&&d,b=n==="hail"&&f&&p&&v&&g&&m;for(let _=0,S=0;_<l.length;_+=3,S++){if(b&&f[S]>0){if(f[S]-=t,f[S]<=0){const x=Math.random()*Math.PI*2,A=Math.sqrt(Math.random())*i.radiusM;l[_]=Math.cos(x)*A,l[_+1]=i.topYM,l[_+2]=Math.sin(x)*A,f[S]=0}else{const x=1-f[S]/v[S];l[_+1]=mr+Math.sin(Math.PI*x)*p[S],l[_]=Fo(l[_]+(a+g[S])*t,i.radiusM),l[_+2]=Fo(l[_+2]+(o+m[S])*t,i.radiusM)}continue}let E=0,R=0;if(w){const x=kw*u[S],A=zw*d[S];E=Math.sin(e*x*Math.PI*2+c[S])*A,R=Math.sin(e*x*Math.PI*2+c[S]+Math.PI/2)*A}if(l[_]+=(a+E)*t,l[_+1]-=i.fallSpeedMPerS*h[S]*t,l[_+2]+=(o+R)*t,l[_]=Fo(l[_],i.radiusM),l[_+2]=Fo(l[_+2],i.radiusM),l[_+1]<mr){if(b){p[S]=lp*(.2+Math.random()*1.6),v[S]=Bw*(.5+Math.random()),f[S]=v[S];const P=Math.random()*Math.PI*2,C=Hw*(p[S]/lp);g[S]=Math.cos(P)*C,m[S]=Math.sin(P)*C,l[_+1]=mr;continue}const x=Math.random()*Math.PI*2,A=Math.sqrt(Math.random())*i.radiusM;l[_]=Math.cos(x)*A,l[_+1]=i.topYM,l[_+2]=Math.sin(x)*A}}this.precipitationPoints.geometry.attributes.position.needsUpdate=!0}buildRain(){const e=Qf(this.weather.precipitationIntensity);this.rainSystem=Ib({count:Zf,radiusM:sa,heightM:Cw,bottomYM:Jf,overallSpeed:Dw,color:Iw,opacity:.85,visibleCount:Xc(Zf,this.weather.precipitationIntensity),speedStreak:Ow(e),pixelSize:rp,seed:9001,nearFocusDistanceM:np,hazeDistanceM:sa*ip,hazeColor:new le(...this.baseFogColor)}),this.rainLastVerticalFacing=-1,this.syncRainSlant(),this.rainSystem.points.renderOrder=Gc,this.scene.add(this.rainSystem.points),this.buildRainSplashes()}buildRainSplashes(){const e=qc(4242),t=new Float32Array(fr*3),n=new Float32Array(fr),i=new Float32Array(fr),r=new Float32Array(fr);for(let h=0;h<fr;h++){const u=e()*Math.PI*2,d=Math.sqrt(e())*sa;t[h*3]=Math.cos(u)*d,t[h*3+1]=Jf,t[h*3+2]=Math.sin(u)*d,i[h]=Uo(ep,tp),n[h]=e()*i[h],r[h]=n[h]/i[h]}const a=new wt;a.setAttribute("position",new dt(t,3));const o=new dt(r,1);a.setAttribute("aLife",o),a.setDrawRange(0,Xc(fr,this.weather.precipitationIntensity));const l=new Et({uniforms:{uMaxSize:{value:Uw},uScale:{value:.5*this.renderer.domElement.height},uColor:{value:Fw},uTexture:{value:Kw()}},vertexShader:$w,fragmentShader:Zw,transparent:!0,depthWrite:!1}),c=new Ko(a,l);c.renderOrder=Gc,this.scene.add(c),this.rainSplashSystem={points:c,positions:t,life:n,duration:i,lifeAttribute:o}}disposeRain(){this.rainSystem&&(this.rainSystem.points.removeFromParent(),this.rainSystem.points.geometry.dispose(),this.rainSystem.points.material.dispose()),this.rainSystem=void 0,this.disposeRainSplashes()}disposeRainSplashes(){this.rainSplashSystem&&(this.rainSplashSystem.points.removeFromParent(),this.rainSplashSystem.points.geometry.dispose(),this.rainSplashSystem.points.material.dispose()),this.rainSplashSystem=void 0}syncRainSlant(){const e=this.rainSystem;if(!e)return;const t=this.weather.windDirectionDeg*Tn;e.uniforms.uDropVelocity.value.set(Math.sin(t)*this.weather.windSpeed,-Qf(this.weather.precipitationIntensity),-Math.cos(t)*this.weather.windSpeed);const n=this.renderer.getSize(this.rainViewportSize);e.uniforms.uAspect.value=n.x/Math.max(n.y,1)}updateRain(e){const t=this.rainSystem;if(!t)return;t.uniforms.uTime.value+=e,t.uniforms.uHazeColor.value.setRGB(...this.baseFogColor);const n=this.weather.windDirectionDeg*Tn,i=Math.sin(n)*this.weather.windSpeed,r=-Math.cos(n)*this.weather.windSpeed,a=sa,o=c=>(c%(a*2)+a*3)%(a*2)-a;t.uniforms.uWindOffset.value.set(o(t.uniforms.uWindOffset.value.x+i*e),o(t.uniforms.uWindOffset.value.y+r*e)),this.syncRainSlant(),this.camera.getWorldDirection(this.rainCameraDirection);const l=Math.abs(this.rainCameraDirection.y);if(Math.abs(l-this.rainLastVerticalFacing)>.001){this.rainLastVerticalFacing=l;const c=ap+(1-ap)*(1-l),h=op+(1-op)*(1-l);t.uniforms.uUvSquash.value=h,t.uniforms.uPixelSize.value=rp*c*(.5+.5*h)}this.updateRainSplashes(e)}updateRainSplashes(e){const t=this.rainSplashSystem;if(!t||e<=0)return;const{positions:n,life:i,duration:r,lifeAttribute:a}=t,o=a.array;for(let l=0,c=0;l<n.length;l+=3,c++){if(i[c]+=e,i[c]>=r[c]){const h=Math.random()*Math.PI*2,u=Math.sqrt(Math.random())*sa;n[l]=Math.cos(h)*u,n[l+2]=Math.sin(h)*u,r[c]=Uo(ep,tp),i[c]=0}o[c]=i[c]/r[c]}t.points.geometry.attributes.position.needsUpdate=!0,a.needsUpdate=!0}updateLightning(e,t){if(this.lightningArmed){if(this.lightningFlashRemainingS>0){this.lightningFlashRemainingS=Math.max(0,this.lightningFlashRemainingS-t);const n=this.lightningFlashRemainingS/up;this.scene.fog&&this.scene.fog.color.setRGB(this.baseFogColor[0]+(1-this.baseFogColor[0])*n,this.baseFogColor[1]+(1-this.baseFogColor[1])*n,this.baseFogColor[2]+(1-this.baseFogColor[2])*n);return}if(this.nextLightningAtS===null){this.nextLightningAtS=e+Uo(cp,hp);return}e>=this.nextLightningAtS&&(this.lightningFlashRemainingS=up,this.nextLightningAtS=e+Uo(cp,hp),this.onLightningFlash?.())}}buildCompassLabels(){const e=bl(navigator.languages,xw),t=vw[e];this.compassSprites=gw.map((n,i)=>{const r=t[i],a=new la({map:tE(r),depthTest:!1,fog:!1}),o=new no(a),{x:l,y:c,z:h}=fn(0,n,Mw);return o.position.set(l,c,h),o.scale.set(zc,zc,1),o.renderOrder=yw,o.visible=this.compassHovered||this.compassForced,this.celestialGroup.add(o),o}),this.updateCompassScale()}updateCompassScale(){const e=this.camera.fov*Math.PI/360,t=_w*Math.PI/360,n=zc*Math.tan(e)/Math.tan(t);for(const i of this.compassSprites)i.scale.set(n,n,1)}disposeCompassLabels(){for(const e of this.compassSprites)e.removeFromParent(),e.material.map?.dispose(),e.material.dispose();this.compassSprites=[]}disposeStarTiers(){for(const e of this.starTiers)this.disposeMesh(e.points);this.starTiers=[]}disposeMesh(e){if(!e)return;e.removeFromParent(),"geometry"in e&&e.geometry.dispose();const t=e.material;for(const n of Array.isArray(t)?t:[t]){const i=n.map;i&&i.dispose(),n.dispose()}}}const Tn=Math.PI/180;function xl(s,e,t){return Math.max(e,Math.min(t,s))}function Uo(s,e){return s+Math.random()*(e-s)}function Fo(s,e){return(s%(e*2)+e*3)%(e*2)-e}let ko,zo;function Xw(s){switch(s){case"snow":return qw();case"hail":return Yw()}}function qw(){if(ko)return ko;const s=64,e=document.createElement("canvas");e.width=s,e.height=s;const t=e.getContext("2d"),n=t.createRadialGradient(s/2,s/2,0,s/2,s/2,s/2);return n.addColorStop(0,"rgba(255,255,255,0.95)"),n.addColorStop(.5,"rgba(255,255,255,0.55)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,s,s),ko=new Si(e),ko}function Yw(){if(zo)return zo;const s=64,e=document.createElement("canvas");e.width=s,e.height=s;const t=e.getContext("2d"),n=t.createRadialGradient(s/2,s/2,0,s/2,s/2,s/2);return n.addColorStop(0,"rgba(255,255,255,1)"),n.addColorStop(.55,"rgba(255,255,255,0.95)"),n.addColorStop(.8,"rgba(255,255,255,0.4)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,s,s),zo=new Si(e),zo}let Bo;function Kw(){if(Bo)return Bo;const s=64,e=document.createElement("canvas");e.width=s,e.height=s;const t=e.getContext("2d"),n=t.createRadialGradient(s/2,s/2,0,s/2,s/2,s/2);return n.addColorStop(0,"rgba(255,255,255,0)"),n.addColorStop(.4,"rgba(255,255,255,0)"),n.addColorStop(.6,"rgba(255,255,255,0.9)"),n.addColorStop(.8,"rgba(255,255,255,0.25)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,s,s),Bo=new Si(e),Bo}const $w=`
6252
6252
  uniform float uMaxSize;
6253
6253
  uniform float uScale;
6254
6254
  attribute float aLife;
@@ -6315,4 +6315,4 @@ void main() {
6315
6315
  }
6316
6316
  `;let Ho;function Qw(){if(Ho)return Ho;const s=128,e=document.createElement("canvas");e.width=s,e.height=s;const t=e.getContext("2d"),n=t.createRadialGradient(s/2,s/2,0,s/2,s/2,s/2);return n.addColorStop(0,"rgba(255,255,255,1)"),n.addColorStop(.4,"rgba(255,255,255,0.35)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,s,s),Ho=new Si(e),Ho}function eE(s){const t=document.createElement("canvas");t.width=128,t.height=128;const n=t.getContext("2d"),i=128/2-2,r=128/2,a=128/2,o="#2e2b26",l="#f4f1e2";n.fillStyle=o,n.beginPath(),n.arc(r,a,i,0,Math.PI*2),n.fill();const c=xl(s.illuminatedFraction,0,1),h=s.phaseFraction<.5,u=i*Math.abs(1-2*c),d=c<.5;return n.save(),n.beginPath(),n.arc(r,a,i,0,Math.PI*2),n.clip(),n.fillStyle=l,n.beginPath(),h?(n.arc(r,a,i,-Math.PI/2,Math.PI/2,!1),n.ellipse(r,a,u,i,0,Math.PI/2,-Math.PI/2,d)):(n.arc(r,a,i,Math.PI/2,-Math.PI/2,!1),n.ellipse(r,a,u,i,0,-Math.PI/2,Math.PI/2,d)),n.fill(),n.restore(),new Si(t)}function tE(s){const e=document.createElement("canvas");e.width=128,e.height=128;const t=e.getContext("2d");return t.fillStyle="rgba(0, 0, 0, 0.55)",t.beginPath(),t.arc(64,64,60,0,Math.PI*2),t.fill(),t.fillStyle="#ffffff",t.font="bold 52px sans-serif",t.textAlign="center",t.textBaseline="middle",t.fillText(s,64,68),new Si(e)}function qc(s){let e=s;return function(){e|=0,e=e+1831565813|0;let n=Math.imul(e^e>>>15,1|e);return n=n+Math.imul(n^n>>>7,61|n)^n,((n^n>>>14)>>>0)/4294967296}}const Yc=7.5,Kc=9;class ci{static cache=new Map;static load(e){let t=ci.cache.get(e);return t||(t=fetch(e).then(n=>n.arrayBuffer()).then(n=>ci.parse(n)),ci.cache.set(e,t)),t}static upTo(e,t){const n=e.filter((a,o)=>o===0||e[o-1].magnitudeLimit<t);if(n.length<=1)return ci.load(e[0].url);const i=n.map(a=>a.url).join(`
6317
6317
  `);let r=ci.cache.get(i);return r||(r=Promise.all(n.map(a=>ci.load(a.url))).then(a=>a.reduce((o,l)=>ci.concat(o,l))),ci.cache.set(i,r)),r}static parse(e){const t=e.byteLength/(4*Float32Array.BYTES_PER_ELEMENT),n=t*Float32Array.BYTES_PER_ELEMENT;return{count:t,ra:new Float32Array(e,0*n,t),dec:new Float32Array(e,1*n,t),mag:new Float32Array(e,2*n,t),ci:new Float32Array(e,3*n,t)}}static concat(e,t){const n=(i,r)=>{const a=new Float32Array(i.length+r.length);return a.set(i,0),a.set(r,i.length),a};return{count:e.count+t.count,ra:n(e.ra,t.ra),dec:n(e.dec,t.dec),mag:n(e.mag,t.mag),ci:n(e.ci,t.ci)}}}const nE=new URL(""+new URL("rain-BvWZrB9h.ogg",import.meta.url).href,import.meta.url).href,iE=new URL(""+new URL("wind-BjklexY7.ogg",import.meta.url).href,import.meta.url).href,sE=new URL(""+new URL("thunder-DA48qs_v.wav",import.meta.url).href,import.meta.url).href,rE=20,aE=1;class oE{context;buffers=new Map;ambientSource;ambientGain;ambientKey="none";ambientToken=0;ambientVolume=0;windSource;windGain;windActive=!1;windToken=0;windVolume=0;paused=!0;requested={type:"none",intensity:0,windSpeed:0};resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(e){console.warn("WeatherAudio: Web Audio unavailable, weather sounds disabled:",e);return}}this.context.state==="suspended"&&this.context.resume()}setAmbient(e,t,n){if(this.requested={type:e,intensity:t,windSpeed:n},!this.context)return;this.paused&&(e="none",t=0,n=0);const i=e==="rain"||e==="hail"?e:"none";if(this.ambientVolume=i==="hail"?Math.min(1,t*1.3+.2):i==="rain"?t:0,i!==this.ambientKey){this.ambientKey=i;const a=++this.ambientToken;this.stopSource(this.ambientSource,this.ambientGain),this.ambientSource=void 0,this.ambientGain=void 0,i!=="none"&&this.startLoop(nE,this.ambientVolume).then(o=>this.applyIfCurrent(o,a,()=>this.ambientToken,l=>{this.ambientSource=l?.source,this.ambientGain=l?.gain,l&&(l.gain.gain.value=this.ambientVolume)}))}else this.ambientGain&&(this.ambientGain.gain.value=this.ambientVolume);this.windVolume=Math.min(n/rE,1);const r=n>aE;if(r!==this.windActive){this.windActive=r;const a=++this.windToken;this.stopSource(this.windSource,this.windGain),this.windSource=void 0,this.windGain=void 0,r&&this.startLoop(iE,this.windVolume).then(o=>this.applyIfCurrent(o,a,()=>this.windToken,l=>{this.windSource=l?.source,this.windGain=l?.gain,l&&(l.gain.gain.value=this.windVolume)}))}else this.windGain&&(this.windGain.gain.value=this.windVolume)}setPaused(e){if(e===this.paused)return;this.paused=e;const{type:t,intensity:n,windSpeed:i}=this.requested;this.setAmbient(t,n,i)}playThunder(){!this.context||this.paused||this.playOneShot(sE,.9)}dispose(){this.ambientToken++,this.windToken++,this.stopSource(this.ambientSource,this.ambientGain),this.stopSource(this.windSource,this.windGain),this.ambientSource=void 0,this.ambientGain=void 0,this.windSource=void 0,this.windGain=void 0,this.context?.close(),this.context=void 0,this.buffers.clear()}applyIfCurrent(e,t,n,i){if(t!==n()){e?.source.stop();return}i(e)}async startLoop(e,t){const n=this.context;if(n)try{const i=await this.getBuffer(e),r=n.createBufferSource();r.buffer=i,r.loop=!0;const a=n.createGain();return a.gain.value=t,r.connect(a).connect(n.destination),r.start(),{source:r,gain:a}}catch(i){console.warn("Weather ambient sound failed to load, staying silent:",i);return}}async playOneShot(e,t){const n=this.context;if(n)try{const i=await this.getBuffer(e),r=n.createBufferSource();r.buffer=i;const a=n.createGain();a.gain.value=t,r.connect(a).connect(n.destination),r.start()}catch(i){console.warn("Thunder sound failed to load:",i)}}async getBuffer(e){const t=this.context;if(!t)throw new Error("WeatherAudio: AudioContext not ready — resume() must be called first");let n=this.buffers.get(e);return n||(n=fetch(e).then(i=>{if(!i.ok)throw new Error(`Audio fetch failed (${i.status}): ${e}`);return i.arrayBuffer()}).then(i=>t.decodeAudioData(i)),this.buffers.set(e,n)),n}stopSource(e,t){try{e?.stop()}catch{}e?.disconnect(),t?.disconnect()}}class Pi{constructor(e){this.elements=e;const{eccentricity:t,perihelionAu:n}=e,[i,r]=this.perifocalAxes(),a=Math.sqrt(Pi.SUN_GM_AU3_PER_DAY2*(1+t)/n);this.perihelionPosition=this.scale(i,n),this.perihelionVelocity=this.scale(r,a),this.inverseSemiMajorAxis=(1-t)/n}static SUN_GM_AU3_PER_DAY2=.0002959122082855911;static MAX_ITERATIONS=200;perihelionPosition;perihelionVelocity;inverseSemiMajorAxis;positionAt(e){const t=e-this.elements.perihelionJd,n=this.universalAnomaly(t),i=this.inverseSemiMajorAxis*n*n,r=this.elements.perihelionAu,a=1-n*n/r*Pi.stumpffC(i),o=t-n*n*n/Math.sqrt(Pi.SUN_GM_AU3_PER_DAY2)*Pi.stumpffS(i);return{x:a*this.perihelionPosition.x+o*this.perihelionVelocity.x,y:a*this.perihelionPosition.y+o*this.perihelionVelocity.y,z:a*this.perihelionPosition.z+o*this.perihelionVelocity.z}}heliocentricDistanceAt(e){const t=this.positionAt(e);return Math.hypot(t.x,t.y,t.z)}universalAnomaly(e){if(e===0)return 0;const t=Math.sign(e),n=Math.sqrt(Pi.SUN_GM_AU3_PER_DAY2)*Math.abs(e),i=o=>{const l=this.inverseSemiMajorAxis*o*o,c=this.elements.perihelionAu;return(1-this.inverseSemiMajorAxis*c)*o*o*o*Pi.stumpffS(l)+c*o};let r=Math.max(1,n/this.elements.perihelionAu);for(;i(r)<n;)r*=2;let a=0;for(let o=0;o<Pi.MAX_ITERATIONS&&r-a>1e-13*Math.max(1,r);o++){const l=(a+r)/2;i(l)<n?a=l:r=l}return t*(a+r)/2}perifocalAxes(){const e=this.elements.ascendingNodeDeg*Math.PI/180,t=this.elements.argumentOfPerihelionDeg*Math.PI/180,n=this.elements.inclinationDeg*Math.PI/180,i=Math.cos(e),r=Math.sin(e),a=Math.cos(t),o=Math.sin(t),l=Math.cos(n),c=Math.sin(n);return[{x:i*a-r*o*l,y:r*a+i*o*l,z:o*c},{x:-i*o-r*a*l,y:-r*o+i*a*l,z:a*c}]}scale(e,t){return{x:e.x*t,y:e.y*t,z:e.z*t}}static stumpffC(e){if(Math.abs(e)<1e-6)return 1/2-e/24+e*e/720;if(e>0)return(1-Math.cos(Math.sqrt(e)))/e;const t=Math.sqrt(-e);return(Math.cosh(t)-1)/-e}static stumpffS(e){if(Math.abs(e)<1e-6)return 1/6-e/120+e*e/5040;if(e>0){const n=Math.sqrt(e);return(n-Math.sin(n))/(n*n*n)}const t=Math.sqrt(-e);return(Math.sinh(t)-t)/(t*t*t)}}const ng=[{id:"halley-1910",designation:"1P/Halley",name:{en:"Halley's Comet",fr:"comète de Halley"},orbit:{eccentricity:.9672960498922706,perihelionAu:.5872100477652511,inclinationDeg:162.218798367122,ascendingNodeDeg:58.56208298700436,argumentOfPerihelionDeg:111.7366940639061,perihelionJd:2.4187816784171113e6},peakMagnitude:0,peakOn:"1910-05-20",absoluteMagnitude:4.72,activityExponent:4,tailLengthDeg:100,tailLengthAu:.1638,note:"Passed 0.15 au from Earth on 20 May 1910, and the Earth crossed the outer tail the day before — the apparition that produced a genuine public panic."},{id:"brooks-1911",designation:"C/1911 O1",name:{en:"Comet Brooks",fr:"comète Brooks"},orbit:{eccentricity:.9876404970138669,perihelionAu:.4898172916113738,inclinationDeg:33.34043866978714,ascendingNodeDeg:293.7022074981857,argumentOfPerihelionDeg:153.5578007321686,perihelionJd:2.4193378856140426e6},peakMagnitude:2,peakOn:"1911-10-25",absoluteMagnitude:5.59,activityExponent:4},{id:"skjellerup-maristany-1927",designation:"C/1927 X1",name:{en:"Comet Skjellerup-Maristany",fr:"comète Skjellerup-Maristany"},orbit:{eccentricity:.999839726885059,perihelionAu:.1761569619628186,inclinationDeg:85.1125991950808,ascendingNodeDeg:78.24360172472711,argumentOfPerihelionDeg:47.15877857390136,perihelionJd:2.4252326808989984e6},peakMagnitude:-6,peakOn:"1927-12-15",absoluteMagnitude:1.19,activityExponent:4,note:"One of the few comets of the century seen in full daylight."},{id:"de-kock-paraskevopoulos-1941",designation:"C/1941 B2",name:{en:"Comet de Kock-Paraskevopoulos",fr:"comète de Kock-Paraskevopoulos"},orbit:{eccentricity:.9991026715181549,perihelionAu:.7900329662827822,inclinationDeg:168.2039226531089,ascendingNodeDeg:43.10609347214336,argumentOfPerihelionDeg:268.6990344196369,perihelionJd:2430022157765061e-9},peakMagnitude:2,peakOn:"1941-02-05",absoluteMagnitude:5.01,activityExponent:4},{id:"southern-1947",designation:"C/1947 X1",name:{en:"the Southern Comet",fr:"comète australe"},orbit:{eccentricity:.9998424430916737,perihelionAu:.1100045955093761,inclinationDeg:138.5113919632757,ascendingNodeDeg:337.3114969669252,argumentOfPerihelionDeg:196.1820121395961,perihelionJd:2.4325220864727003e6},peakMagnitude:-3,peakOn:"1947-12-08",absoluteMagnitude:3.01,activityExponent:4,note:"A bright southern-hemisphere comet of December 1947, the month the American sighting wave of that year was still being argued over."},{id:"eclipse-1948",designation:"C/1948 V1",name:{en:"the Eclipse Comet",fr:"comète de l'éclipse"},orbit:{eccentricity:.9999130678247334,perihelionAu:.1354437057263306,inclinationDeg:23.11668597152911,ascendingNodeDeg:211.0454985994762,argumentOfPerihelionDeg:107.2474157073104,perihelionJd:2.4328519265329437e6},peakMagnitude:-2,peakOn:"1948-11-01",absoluteMagnitude:4.79,activityExponent:4,note:"Found during the total solar eclipse of 1 November 1948, which is how a comet that bright had gone unnoticed: it had been hidden in the Sun's glare."},{id:"arend-roland-1957",designation:"C/1956 R1",name:{en:"Comet Arend-Roland",fr:"comète Arend-Roland"},orbit:{eccentricity:1.0002570255357,perihelionAu:.3160532361485914,inclinationDeg:119.9440863251822,ascendingNodeDeg:215.8548157717755,argumentOfPerihelionDeg:308.775920364167,perihelionJd:2.4359365327396123e6},peakMagnitude:.5,peakOn:"1957-04-25",absoluteMagnitude:3.96,activityExponent:4,note:"Showed a spike pointing back TOWARD the Sun in late April 1957 — a real anti-tail, and much reported at the time."},{id:"mrkos-1957",designation:"C/1957 P1",name:{en:"Comet Mrkos",fr:"comète Mrkos"},orbit:{eccentricity:.9993521583504134,perihelionAu:.3549238508212375,inclinationDeg:93.9433042053929,ascendingNodeDeg:68.32441518619923,argumentOfPerihelionDeg:40.31823675802871,perihelionJd:243605193752228e-8},peakMagnitude:1,peakOn:"1957-08-05",absoluteMagnitude:5.07,activityExponent:4,note:"The second bright naked-eye comet of 1957, four months after Arend-Roland."},{id:"seki-lines-1962",designation:"C/1962 C1",name:{en:"Comet Seki-Lines",fr:"comète Seki-Lines"},orbit:{eccentricity:1.000003791331562,perihelionAu:.03139689112215131,inclinationDeg:65.01487186102287,ascendingNodeDeg:304.6776602796538,argumentOfPerihelionDeg:11.47295326312573,perihelionJd:2437756163010178e-9},peakMagnitude:-2.5,peakOn:"1962-04-01",absoluteMagnitude:9.3,activityExponent:4},{id:"ikeya-seki-1965",designation:"C/1965 S1",name:{en:"Comet Ikeya-Seki",fr:"comète Ikeya-Seki"},orbit:{eccentricity:.9999141178248997,perihelionAu:.007785966366889336,inclinationDeg:141.8642315267051,ascendingNodeDeg:346.9951764632611,argumentOfPerihelionDeg:69.04909813996062,perihelionJd:2.4390546837018197e6},peakMagnitude:-10,peakOn:"1965-10-21",alsoRecordedMagnitude:2,alsoRecordedOn:"1965-10-30",absoluteMagnitude:5.26,activityExponent:4.002,tailLengthDeg:25,tailLengthAu:.5048,note:"A sungrazer that passed 450 000 km above the Sun's surface and was seen beside it in broad daylight — the brightest comet of the twentieth century. It then stood in the dawn sky for a fortnight with a tail some 25 degrees long, which is the second magnitude recorded here."},{id:"bennett-1970",designation:"C/1969 Y1",name:{en:"Comet Bennett",fr:"comète Bennett"},orbit:{eccentricity:.9962979048768408,perihelionAu:.5376209981502136,inclinationDeg:90.03975717147327,ascendingNodeDeg:224.6576652531314,argumentOfPerihelionDeg:354.1494209173161,perihelionJd:2.4406655455270996e6},peakMagnitude:0,peakOn:"1970-03-26",absoluteMagnitude:3.36,activityExponent:4},{id:"white-ortiz-bolelli-1970",designation:"C/1970 K1",name:{en:"Comet White-Ortiz-Bolelli",fr:"comète White-Ortiz-Bolelli"},orbit:{eccentricity:.9999488875801225,perihelionAu:.00884411465256722,inclinationDeg:138.9520738221631,ascendingNodeDeg:336.8194095816687,argumentOfPerihelionDeg:61.10224765396615,perihelionJd:2.4407209807728203e6},peakMagnitude:1,peakOn:"1970-05-22",absoluteMagnitude:4.35,activityExponent:4},{id:"kohoutek-1973",designation:"C/1973 E1",name:{en:"Comet Kohoutek",fr:"comète Kohoutek"},orbit:{eccentricity:1.000007152175185,perihelionAu:.1424250377812859,inclinationDeg:14.30414984159355,ascendingNodeDeg:258.4893339663974,argumentOfPerihelionDeg:37.79772760699667,perihelionJd:2442044930687027e-9},peakMagnitude:0,peakOn:"1974-01-05",absoluteMagnitude:4.89,activityExponent:4,note:"Announced in advance as the comet of the century and remembered for disappointing: it was an ordinary naked-eye object, not the spectacle the press had promised."},{id:"west-1976",designation:"C/1975 V1",name:{en:"Comet West",fr:"comète West"},orbit:{eccentricity:1.000017859625611,perihelionAu:.1966006188461085,inclinationDeg:43.07319920579427,ascendingNodeDeg:118.9189245655447,argumentOfPerihelionDeg:358.4315101259072,perihelionJd:2442833721841768e-9},peakMagnitude:-3,peakOn:"1976-02-25",absoluteMagnitude:4.41,activityExponent:4,tailLengthDeg:30,tailLengthAu:.4325,note:"Broke into four pieces at perihelion. Barely reported at the time — the press had been burned by Kohoutek two years earlier."},{id:"iras-araki-alcock-1983",designation:"C/1983 H1",name:{en:"Comet IRAS-Araki-Alcock",fr:"comète IRAS-Araki-Alcock"},orbit:{eccentricity:.9898409731606003,perihelionAu:.9913412593828502,inclinationDeg:73.25000846947029,ascendingNodeDeg:49.10235754476374,argumentOfPerihelionDeg:192.8506176754439,perihelionJd:2.4454757545235856e6},peakMagnitude:1.7,peakOn:"1983-05-11",absoluteMagnitude:9.04,activityExponent:4,note:"Passed 0.031 au from Earth on 11 May 1983, one of the closest cometary approaches on record: it crossed a quarter of the sky in a night, which no other comet in this list did."},{id:"halley-1986",designation:"1P/Halley",name:{en:"Halley's Comet",fr:"comète de Halley"},orbit:{eccentricity:.9672792271749998,perihelionAu:.5871034488173393,inclinationDeg:162.2422242700916,ascendingNodeDeg:58.85993640671803,argumentOfPerihelionDeg:111.8655480539208,perihelionJd:2.4464709589610207e6},peakMagnitude:2.1,peakOn:"1986-03-10",absoluteMagnitude:2.71,activityExponent:4,note:"The worst-placed return in two thousand years — famous, expected, and for most observers a faint smudge."},{id:"hyakutake-1996",designation:"C/1996 B2",name:{en:"Comet Hyakutake",fr:"comète Hyakutake"},orbit:{eccentricity:.9997295133739305,perihelionAu:.2302272039470452,inclinationDeg:124.923592343765,ascendingNodeDeg:188.0454295899424,argumentOfPerihelionDeg:130.1724036582639,perihelionJd:2.4502048946148166e6},peakMagnitude:0,peakOn:"1996-03-25",absoluteMagnitude:4.75,activityExponent:4,tailLengthDeg:80,tailLengthAu:1,note:"Passed 0.10 au from Earth in March 1996, five weeks BEFORE perihelion, with a tail measured at some 80 degrees — the longest of the modern era."},{id:"hale-bopp-1997",designation:"C/1995 O1",name:{en:"Comet Hale-Bopp",fr:"comète Hale-Bopp"},orbit:{eccentricity:.9951314746156615,perihelionAu:.9141695067003724,inclinationDeg:89.43017155012492,ascendingNodeDeg:282.470602866853,argumentOfPerihelionDeg:130.5872524854533,perihelionJd:2450539633099368e-9},peakMagnitude:-.8,peakOn:"1997-04-01",absoluteMagnitude:-1.06,activityExponent:4,tailLengthDeg:20,tailLengthAu:.9938,note:"Visible to the naked eye for about eighteen months, longer than any comet on record."},{id:"mcnaught-2007",designation:"C/2006 P1",name:{en:"Comet McNaught",fr:"comète McNaught"},orbit:{eccentricity:1.00001811603225,perihelionAu:.1707325614080681,inclinationDeg:77.83726446452654,ascendingNodeDeg:267.4149080498975,argumentOfPerihelionDeg:155.9756130642756,perihelionJd:2454113298753579e-9},peakMagnitude:-5.5,peakOn:"2007-01-13",absoluteMagnitude:2.53,activityExponent:4,tailLengthDeg:35,tailLengthAu:.5009,note:"The brightest comet since Ikeya-Seki, seen in daylight beside the Sun in January 2007."},{id:"lovejoy-2011",designation:"C/2011 W3",name:{en:"Comet Lovejoy",fr:"comète Lovejoy"},orbit:{eccentricity:.999915056276912,perihelionAu:.005553783989325053,inclinationDeg:134.3558712062691,ascendingNodeDeg:326.3693517957772,argumentOfPerihelionDeg:53.50991655176601,perihelionJd:2455911511809431e-9},peakMagnitude:-3,peakOn:"2011-12-16",alsoRecordedMagnitude:1.5,alsoRecordedOn:"2011-12-22",absoluteMagnitude:3.51,activityExponent:1.194,note:"A sungrazer that was expected to be destroyed at perihelion and came out the other side, to stand in the southern dawn sky for the rest of December — which is the second magnitude recorded here."},{id:"panstarrs-2013",designation:"C/2011 L4",name:{en:"Comet PANSTARRS",fr:"comète PANSTARRS"},orbit:{eccentricity:1.000032542889696,perihelionAu:.301544229714915,inclinationDeg:84.2081978367921,ascendingNodeDeg:65.66588626213694,argumentOfPerihelionDeg:333.6516444379993,perihelionJd:2456361669960698e-9},peakMagnitude:1,peakOn:"2013-03-10",absoluteMagnitude:5.98,activityExponent:4},{id:"neowise-2020",designation:"C/2020 F3",name:{en:"Comet NEOWISE",fr:"comète NEOWISE"},orbit:{eccentricity:.9991782081129224,perihelionAu:.2946512466331692,inclinationDeg:128.9375043020912,ascendingNodeDeg:61.01042991771634,argumentOfPerihelionDeg:37.2786526292898,perihelionJd:2.4590341788972816e6},peakMagnitude:.9,peakOn:"2020-07-08",absoluteMagnitude:5.79,activityExponent:4,tailLengthDeg:10,tailLengthAu:.1808,note:"The first comet since Hale-Bopp that ordinary observers in the northern hemisphere saw without being told where to look."},{id:"tsuchinshan-atlas-2024",designation:"C/2023 A3",name:{en:"Comet Tsuchinshan-ATLAS",fr:"comète Tsuchinshan-ATLAS"},orbit:{eccentricity:1.000020192843226,perihelionAu:.3914228969475176,inclinationDeg:139.1105462619479,ascendingNodeDeg:21.55945689078845,argumentOfPerihelionDeg:308.4913086299446,perihelionJd:2460581242087108e-9},peakMagnitude:0,peakOn:"2024-10-14",absoluteMagnitude:3.97,activityExponent:4,tailLengthDeg:20,tailLengthAu:.1902,note:"Briefly reported far brighter around 9 October 2024, when it stood almost between the observer and the Sun and forward-scattered the light through its own dust — a geometry this catalog's brightness model does not attempt, so what is stored is the ordinary evening-sky peak a few days later."}];class lE{static WINDOW_DAYS=200;static TWILIGHT_ELONGATION_DEG=15;static LIGHT_SPEED_AU_PER_DAY=173.144632674;static orbits=new Map;static aroundDate(e){const t=this.julianDayOf(e);return ng.filter(n=>Math.abs(t-n.orbit.perihelionJd)<=this.WINDOW_DAYS)}static brightestAt(e,t){return this.aroundDate(e).map(n=>this.appearanceOf(n,e,t)).sort((n,i)=>n.magnitude-i.magnitude)[0]}static appearanceOf(e,t,n){const i=qt(t),r=this.earthPositionAt(i),a=this.apparentPositionOf(e,2451545+i.tt,r),o=this.subtract(a,r),l=this.length(a),c=this.length(o),h=this.tailEndAt(e,a,r,l,i,t,n),u=this.horizontalOf(o,i,t,n);return{apparition:e,position:u,...h,heliocentricDistanceAu:l,earthDistanceAu:c,elongationDeg:this.angleBetween(o,this.subtract({x:0,y:0,z:0},r)),magnitude:this.magnitudeAt(e,l,c)}}static magnitudeAt(e,t,n){const i=e.absoluteMagnitude+5*Math.log10(n)+2.5*e.activityExponent*Math.log10(t);return Math.max(i,e.peakMagnitude)}static tailEndAt(e,t,n,i,r,a,o){if(e.tailLengthAu===void 0)return{};const l=1+e.tailLengthAu/i,c=this.subtract({x:t.x*l,y:t.y*l,z:t.z*l},n),h=this.subtract(t,n);return{tailEnd:this.horizontalOf(c,r,a,o),tailLengthDeg:this.angleBetween(h,c)}}static apparentPositionOf(e,t,n){const i=this.orbitOf(e);let r=i.positionAt(t);for(let a=0;a<2;a++){const o=this.length(this.subtract(r,n))/this.LIGHT_SPEED_AU_PER_DAY;r=i.positionAt(t-o)}return r}static horizontalOf(e,t,n,i){const r=Jo(lb(),new gt(e.x,e.y,e.z,t)),a=Jo(cb(t),r),o=zS(t,new nd(i.lat,i.lng,i.elevationM)),l=new gt(a.x-o.x,a.y-o.y,a.z-o.z,t),c=Gm(l);return Nr(c.ra,c.dec,n,i)}static earthPositionAt(e){return Jo(ob(),hs(Se.Earth,e))}static julianDayOf(e){return 2451545+qt(e).tt}static orbitOf(e){const t=this.orbits.get(e.id);if(t)return t;const n=new Pi(e.orbit);return this.orbits.set(e.id,n),n}static subtract(e,t){return{x:e.x-t.x,y:e.y-t.y,z:e.z-t.z}}static length(e){return Math.hypot(e.x,e.y,e.z)}static angleBetween(e,t){const n=(e.x*t.x+e.y*t.y+e.z*t.z)/(this.length(e)*this.length(t)||1);return Math.acos(Math.min(1,Math.max(-1,n)))*180/Math.PI}}const cE=[{id:"quadrantids",code:"QUA",name:{en:"Quadrantids",fr:"Quadrantides"},radiantRaHours:15.33,radiantDecDeg:49.7,start:{month:12,day:28},peak:{month:1,day:3},end:{month:1,day:12},peakZhr:110,velocityKmS:41,populationIndex:2.1},{id:"lyrids",code:"LYR",name:{en:"April Lyrids",fr:"Lyrides d'avril"},radiantRaHours:18.13,radiantDecDeg:33.3,start:{month:4,day:16},peak:{month:4,day:22},end:{month:4,day:25},peakZhr:18,velocityKmS:49,populationIndex:2.1},{id:"eta-aquariids",code:"ETA",name:{en:"eta Aquariids",fr:"Êta Aquarides"},radiantRaHours:22.53,radiantDecDeg:-1,start:{month:4,day:19},peak:{month:5,day:6},end:{month:5,day:28},peakZhr:50,velocityKmS:66,populationIndex:2.4},{id:"alpha-capricornids",code:"CAP",name:{en:"alpha Capricornids",fr:"Alpha Capricornides"},radiantRaHours:20.47,radiantDecDeg:-9.2,start:{month:7,day:3},peak:{month:7,day:30},end:{month:8,day:15},peakZhr:5,velocityKmS:23,populationIndex:2.5},{id:"southern-delta-aquariids",code:"SDA",name:{en:"Southern delta Aquariids",fr:"Delta Aquarides du Sud"},radiantRaHours:22.67,radiantDecDeg:-16.4,start:{month:7,day:12},peak:{month:7,day:30},end:{month:8,day:23},peakZhr:25,velocityKmS:41,populationIndex:3.2},{id:"perseids",code:"PER",name:{en:"Perseids",fr:"Perséides"},radiantRaHours:3.22,radiantDecDeg:58,start:{month:7,day:17},peak:{month:8,day:12},end:{month:8,day:24},peakZhr:100,velocityKmS:59,populationIndex:2.2},{id:"southern-taurids",code:"STA",name:{en:"Southern Taurids",fr:"Taurides du Sud"},radiantRaHours:3.47,radiantDecDeg:13,start:{month:9,day:10},peak:{month:10,day:10},end:{month:11,day:20},peakZhr:5,velocityKmS:27,populationIndex:2.3},{id:"draconids",code:"DRA",name:{en:"October Draconids",fr:"Draconides d'octobre"},radiantRaHours:17.47,radiantDecDeg:54,start:{month:10,day:6},peak:{month:10,day:8},end:{month:10,day:10},peakZhr:10,velocityKmS:20,populationIndex:2.6},{id:"orionids",code:"ORI",name:{en:"Orionids",fr:"Orionides"},radiantRaHours:6.35,radiantDecDeg:15.6,start:{month:10,day:2},peak:{month:10,day:21},end:{month:11,day:7},peakZhr:20,velocityKmS:66,populationIndex:2.5},{id:"northern-taurids",code:"NTA",name:{en:"Northern Taurids",fr:"Taurides du Nord"},radiantRaHours:3.87,radiantDecDeg:22,start:{month:10,day:20},peak:{month:11,day:12},end:{month:12,day:10},peakZhr:5,velocityKmS:29,populationIndex:2.3},{id:"leonids",code:"LEO",name:{en:"Leonids",fr:"Léonides"},radiantRaHours:10.13,radiantDecDeg:21.6,start:{month:11,day:6},peak:{month:11,day:17},end:{month:11,day:30},peakZhr:15,velocityKmS:71,populationIndex:2.5},{id:"geminids",code:"GEM",name:{en:"Geminids",fr:"Géminides"},radiantRaHours:7.47,radiantDecDeg:32.3,start:{month:12,day:4},peak:{month:12,day:14},end:{month:12,day:17},peakZhr:150,velocityKmS:35,populationIndex:2.6},{id:"ursids",code:"URS",name:{en:"Ursids",fr:"Ursides"},radiantRaHours:14.47,radiantDecDeg:75.3,start:{month:12,day:17},peak:{month:12,day:22},end:{month:12,day:26},peakZhr:10,velocityKmS:33,populationIndex:3}],Ml=6.5;class $c{static activeAt(e){return cE.flatMap(t=>{const n=this.nearness(t,e);return n<=0?[]:[{shower:t,zhr:t.peakZhr*n,nearness:n}]})}static nearness(e,t){const n=this.dayOfYear(t),i=this.dayOfYear(this.asDate(e.start)),r=this.dayOfYear(this.asDate(e.peak)),a=this.dayOfYear(this.asDate(e.end)),o=this.wrappedDelta(n,r),l=this.wrappedDelta(r,i),c=this.wrappedDelta(a,r);return o<0?o<-l?0:1+o/l:o>0?o>c?0:1-o/c:1}static observedRatePerHour(e,t,n,i=Ml){if(t<=0)return 0;const r=Ml-i;return e*Math.sin(t*Math.PI/180)/Math.pow(n,r)}static radiantPosition(e,t,n){return Nr(e.radiantRaHours,e.radiantDecDeg,t,n)}static dayOfYear(e){const t=Date.UTC(e.getUTCFullYear(),0,1);return Math.floor((Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate())-t)/864e5)+1}static asDate(e){return new Date(Date.UTC(2001,e.month-1,e.day))}static wrappedDelta(e,t){const n=e-t;return n>182?n-365:n<-182?n+365:n}}class Pt{static QUIET_RATE_PER_HOUR=2;static APEX_RATE_PER_HOUR=8;static POPULATION_INDEX=3;static apexPosition(e,t){const n=qt(e),i=new ed(0,FS(e).elon-90,1),r=Jo(hb(n),Hm(i,n)),a=Gm(r);return Nr(a.ra,a.dec,e,t)}static observedRatePerHour(e,t=Ml){const n=Pt.APEX_RATE_PER_HOUR*Math.max(0,Math.sin(e*Math.PI/180)),i=Ml-t;return(Pt.QUIET_RATE_PER_HOUR+n)/Math.pow(Pt.POPULATION_INDEX,i)}static schedule(e){const t=new Wm(e.seed^1542469173);return Ls.schedule(e).map(n=>{const i=Pt.toCartesian({altitudeDeg:Math.asin(t.next())*180/Math.PI,azimuthDeg:t.between(0,360)}),r=n.fromRadiantDeg*Math.PI/180,a=Pt.turnAround(i,t.between(0,360)),o={x:i.x*Math.cos(r)+a.x*Math.sin(r),y:i.y*Math.cos(r)+a.y*Math.sin(r),z:i.z*Math.cos(r)+a.z*Math.sin(r)};return{...n,radiant:Pt.toHorizontal(o),bearingDeg:Pt.bearingFrom(o,i)}})}static turnAround(e,t){const[n,i]=Pt.basisAround(e),r=t*Math.PI/180;return{x:n.x*Math.cos(r)+i.x*Math.sin(r),y:n.y*Math.cos(r)+i.y*Math.sin(r),z:n.z*Math.cos(r)+i.z*Math.sin(r)}}static bearingFrom(e,t){const[n,i]=Pt.basisAround(e),r=e.x*t.x+e.y*t.y+e.z*t.z,a=Pt.normalise({x:t.x-e.x*r,y:t.y-e.y*r,z:t.z-e.z*r});return(Math.atan2(a.x*i.x+a.y*i.y+a.z*i.z,a.x*n.x+a.y*n.y+a.z*n.z)*180/Math.PI%360+360)%360}static basisAround(e){const t=Math.abs(e.y)<.9?{x:0,y:1,z:0}:{x:1,y:0,z:0},n=Pt.normalise(Pt.cross(e,t));return[n,Pt.normalise(Pt.cross(e,n))]}static toHorizontal(e){const t=Math.hypot(e.x,e.y,e.z)||1;return{altitudeDeg:Math.asin(Math.min(1,Math.max(-1,e.y/t)))*180/Math.PI,azimuthDeg:(Math.atan2(e.x,-e.z)*180/Math.PI%360+360)%360}}static appearanceOf(e){const t=Pt.toCartesian(e.radiant??{altitudeDeg:90,azimuthDeg:0}),n=Pt.turnAround(t,e.bearingDeg),i=e.fromRadiantDeg*Math.PI/180;return Pt.toHorizontal({x:t.x*Math.cos(i)+n.x*Math.sin(i),y:t.y*Math.cos(i)+n.y*Math.sin(i),z:t.z*Math.cos(i)+n.z*Math.sin(i)})}static toCartesian(e){const t=e.altitudeDeg*Math.PI/180,n=e.azimuthDeg*Math.PI/180,i=Math.cos(t);return{x:i*Math.sin(n),y:Math.sin(t),z:-i*Math.cos(n)}}static cross(e,t){return{x:e.y*t.z-e.z*t.y,y:e.z*t.x-e.x*t.z,z:e.x*t.y-e.y*t.x}}static normalise(e){const t=Math.hypot(e.x,e.y,e.z)||1;return{x:e.x/t,y:e.y/t,z:e.z/t}}static TYPICAL_VELOCITY_KM_S=40}class hE{lowerM;upperM;add(e,t){if(!(e<=0)){if(t.behindM!==void 0){const n=mt.sizeMAt(t.behindM,e);this.lowerM=this.lowerM===void 0?n:Math.max(this.lowerM,n)}if(t.inFrontM!==void 0){const n=mt.sizeMAt(t.inFrontM,e);this.upperM=this.upperM===void 0?n:Math.min(this.upperM,n)}}}get sizeRange(){return{minM:this.lowerM,maxM:this.upperM}}get empty(){return this.lowerM===void 0&&this.upperM===void 0}get contradictory(){return this.lowerM!==void 0&&this.upperM!==void 0&&this.lowerM>this.upperM}distanceRangeAt(e){return e<=0?{}:{minM:this.lowerM===void 0?void 0:mt.distanceMAt(this.lowerM,e),maxM:this.upperM===void 0?void 0:mt.distanceMAt(this.upperM,e)}}clear(){this.lowerM=void 0,this.upperM=void 0}}class Tr{static DEG_PER_SECOND=360/86164.0905;static degOver(e){return Math.max(0,e)*Tr.DEG_PER_SECOND}static instants(e,t){if(!(t>0))return 1;const n=Tr.degOver(e)/t;return n<1?1:Math.min(Tr.MAX_INSTANTS,Math.max(2,Math.ceil(n)))}static MAX_INSTANTS=64}class dn{static EYE={apertureMm:7,exposureSeconds:.1,resolutionArcsec:60};static WAVELENGTH_M=55e-8;static ARCSEC_PER_RADIAN=180*3600/Math.PI;static UNKNOWN_CAMERA_FOCAL_MM=50;static UNKNOWN_CAMERA_DETAIL_UM=20;static get skyDriftArcsecPerSecond(){return Tr.DEG_PER_SECOND*3600}static graspOf(e,t={}){const n=t.exposureSeconds??e.exposureSeconds,i=t.fNumber??e.fNumber;if(n===void 0||i===void 0||!(n>0)||!(i>0))return dn.EYE;const r=t.focalLengthMm??e.frame?.focalLengthMm??dn.UNKNOWN_CAMERA_FOCAL_MM,a=r/i,o=dn.resolutionArcsec(e,r,a);return{apertureMm:a,exposureSeconds:Math.min(n,dn.trailLimitedSeconds(o)),resolutionArcsec:o}}static resolutionArcsec(e,t,n){const r=(e.detailUm??dn.UNKNOWN_CAMERA_DETAIL_UM)/1e3/t*dn.ARCSEC_PER_RADIAN,a=1.22*dn.WAVELENGTH_M/(n/1e3)*dn.ARCSEC_PER_RADIAN;return Math.max(r,a)}static trailLimitedSeconds(e){return e/dn.skyDriftArcsecPerSecond}static gainOverEye(e,t={}){const n=dn.graspOf(e,t),i=dn.EYE,r=(n.apertureMm/i.apertureMm)**2,a=n.exposureSeconds/i.exposureSeconds,o=(i.resolutionArcsec/n.resolutionArcsec)**2;return 1.25*Math.log10(r*a*o)}static gainFor(e,t){const n=t.fieldOfViewDeg===void 0?void 0:Ut.focalLengthMmFor(e,t.fieldOfViewDeg);return dn.gainOverEye(e,{fNumber:t.fNumber,focalLengthMm:n,exposureSeconds:t.exposureSeconds})}}class Ii{static PIXELS_PER_INSTANT=2;static INSTANTS_PER_FLASH=2;static MAX_INSTANTS=512;static instants(e,t,n,i,r){if(!(i>0))return 1;const a=r>0?Ii.travelDegOver(e,t,n,n+i*1e3)/r/Ii.PIXELS_PER_INSTANT:0,o=Ii.flashesOver(e,i)*Ii.INSTANTS_PER_FLASH,l=Math.ceil(Math.max(a,o));return l<2?1:Math.min(Ii.MAX_INSTANTS,l)}static travelDegOver(e,t,n,i){let r=0;for(const a of e){if(!a.track||a.track.length<2)continue;const o=Ii.directionAt(a,t,n),l=Ii.directionAt(a,t,i),c=Math.min(1,Math.max(-1,o.x*l.x+o.y*l.y+o.z*l.z));r=Math.max(r,Math.acos(c)*180/Math.PI)}return r}static flashesOver(e,t){let n=0;for(const i of e)for(const r of i.lights??[])r.pattern.kind==="flash"&&(n=Math.max(n,r.pattern.perMinute));return n/60*t}static directionAt(e,t,n){const i=Sl(e,n),r=i.eastM,a=i.altitudeM-t,o=i.northM,l=Math.hypot(r,a,o);return l===0?{x:0,y:1,z:0}:{x:r/l,y:a/l,z:o/l}}}const dp=111320,ra=Math.PI/180,uE=1.02,dE=1;class Ma{static of(e,t){const n=Ma.sightings(e,t);if(n.length<2)return;const i=Ma.baseline(n);if(!i)return;const{near:r,far:a,closedM:o}=i,l=Math.tan(a.widthDeg/2*ra)===0?0:Math.tan(r.widthDeg/2*ra)/Math.tan(a.widthDeg/2*ra);if(l<uE)return;const c=o/(l-1),h=mt.sizeMAt(c,r.widthDeg),u=n.map(d=>({t:d.t,m:mt.distanceMAt(h,d.widthDeg)}));return{widthM:h,distanceM:u,nearestM:Math.min(...u.map(d=>d.m)),fromT:a.t,toT:r.t,closedM:o}}static sightings(e,t){return e.timeline.allKeyframes.flatMap(n=>{const i=n.shapes.find(o=>o.sourceId===t)?.shape,r=i?.angular?.widthDeg,a=Gt(e,n.t);return r===void 0||r<=0||a?.lat===void 0||a.lng===void 0?[]:[{t:n.t,widthDeg:r,lat:a.lat,lng:a.lng,sightAzimuthDeg:i?.aim?.azimuthDeg??a.headingDeg}]}).sort((n,i)=>n.t-i.t)}static baseline(e){let t;for(const n of e)for(const i of e){if(n.t>=i.t)continue;const r=Ma.closedAlongSight(n,i),[a,o,l]=r>=0?[i,n,r]:[n,i,-r];l<dE||a.widthDeg<=o.widthDeg||(!t||l>t.closedM)&&(t={near:a,far:o,closedM:l})}return t}static closedAlongSight(e,t){const n=(t.lat-e.lat)*dp,i=(t.lng-e.lng)*dp*Math.cos(e.lat*ra),r=(e.sightAzimuthDeg??0)*ra;return n*Math.cos(r)+i*Math.sin(r)}}class un{static CONVENTIONAL_M=5;static NEAREST_M=.2;static MARGIN=1.1;static resolve(e){if(e.statedM!==void 0&&e.statedM>0)return{distanceM:un.atLeastNearest(e.statedM),basis:"stated"};if(e.hypothesisM!==void 0&&e.hypothesisM>0)return{distanceM:un.atLeastNearest(e.hypothesisM),basis:"hypothesis"};if(e.derivedM!==void 0&&e.derivedM>0)return{distanceM:un.atLeastNearest(e.derivedM),basis:"derived"};const t=un.largest(e.range?.minM,e.crossing?.behindM),n=un.smallest(e.range?.maxM,e.crossing?.inFrontM),i=t===void 0?void 0:t*un.MARGIN,r=n===void 0?void 0:n/un.MARGIN;return i!==void 0&&r!==void 0?{distanceM:un.atLeastNearest(i<=r?Math.sqrt(i*r):i),basis:"bounded"}:i!==void 0?{distanceM:un.atLeastNearest(i),basis:"bounded"}:r!==void 0&&r<un.CONVENTIONAL_M?{distanceM:un.atLeastNearest(r),basis:"bounded"}:{distanceM:un.CONVENTIONAL_M,basis:"conventional"}}static atLeastNearest(e){return Math.max(un.NEAREST_M,e)}static largest(...e){const t=e.filter(n=>n!==void 0&&n>0);return t.length===0?void 0:Math.max(...t)}static smallest(...e){const t=e.filter(n=>n!==void 0&&n>0);return t.length===0?void 0:Math.min(...t)}}Lp();const fE={sun:{en:"Sun",fr:"Soleil"},moon:{en:"Moon",fr:"Lune"},Venus:{en:"Venus",fr:"Vénus"},Mars:{en:"Mars",fr:"Mars"},Jupiter:{en:"Jupiter",fr:"Jupiter"},Saturn:{en:"Saturn",fr:"Saturne"}},pE=["en","fr"],mE={en:"{name} — mag {mag}, {alt}° above the horizon",fr:"{name} — mag {mag}, {alt}° au-dessus de l'horizon"},gE={en:"{name} — mag {mag}, {alt}° below the horizontal",fr:"{name} — mag {mag}, {alt}° sous l'horizontale"},fp="comet:",vE={building:{en:"Building",fr:"Bâtiment"},tree:{en:"Tree",fr:"Arbre"},crop:{en:"Crop row",fr:"Rang de culture"},mound:{en:"Stone heap",fr:"Tas de pierres"},streetlight:{en:"Streetlight",fr:"Lampadaire"},vehicle:{en:"Vehicle",fr:"Véhicule"},witness:{en:"Witness",fr:"Témoin"},aircraft:{en:"Aircraft",fr:"Aéronef"},entity:{en:"Being",fr:"Être"}},xE=new URL(""+new URL("stars-mag7.5-B43R6Wvg.bin",import.meta.url).href,import.meta.url).href,ME=new URL(""+new URL("stars-mag7.5-9-BLV2tFmZ.bin",import.meta.url).href,import.meta.url).href,_E=-18,yE={sun:{altitudeDeg:-3,azimuthDeg:180,magnitude:-26.7},moon:{altitudeDeg:-90,azimuthDeg:0,phase:{phaseFraction:0,illuminatedFraction:0},magnitude:-12.7},planets:[]},Zc={lat:0,lng:0,elevationM:0,headingDeg:void 0,pitchDeg:0,fovDeg:60};class SE extends HTMLElement{static get observedAttributes(){return["src","star-catalog-src","deep-star-catalog-src","show-compass",Fi,ki]}shadow;stageElement;frameElement;sceneCanvas;ufoElement;sceneRenderer;hoverTooltip;resizeObserver;sizeEstimates=new Map;sizeEstimatesFor;distanceHypotheses=new Map;depths=new Map;directionScratch=new D;meteorScheduleFor;lastTimeMs=0;lastSkyKey;starCatalog;starCatalogRequest=0;starCatalogDepth=0;weatherAudio=new oE;animateWhilePausedValue=!1;set animateWhilePaused(e){e!==this.animateWhilePausedValue&&(this.animateWhilePausedValue=e,this.syncAnimationsToPlayback())}get animateWhilePaused(){return this.animateWhilePausedValue}thunderTimeoutId;handleFullscreenChange=()=>this.resizeToStage();handlePointerMove=e=>{this.sceneRenderer.setCompassHovered(!0);const t=this.ufoElement.canvasElement,n=t.getBoundingClientRect();if(n.width===0||n.height===0)return;const i=(e.clientX-n.left)/n.width*t.width,r=(e.clientY-n.top)/n.height*t.height;if(this.ufoElement.hasVisibleShapeAt(i,r)){this.hoverTooltip.hidden=!0;return}const a=(e.clientX-n.left)/n.width*2-1,o=-((e.clientY-n.top)/n.height*2-1),l=bl(Rr.preferencesFor(this),pE),c=this.sceneRenderer.pickBodyAt(a,o);if(c){this.showHoverTooltip(e,this.bodyName(c,l));return}const h=this.sceneRenderer.pickDecorAt(a,o),u=h?this.ufoElement.sighting.decor.find(f=>f.id===h):void 0;if(u){this.showHoverTooltip(e,this.said.read(u.title)||vE[u.kind][l]);return}const d=this.sceneRenderer.pickStarAt(a,o);if(d){const f=d.star.mag,p=d.altitudeDeg,v=(p<0?gE:mE)[l];this.showHoverTooltip(e,v.replace("{name}",d.star.name[l]).replace("{mag}",f.toLocaleString(void 0,{maximumFractionDigits:Math.abs(f)<1?2:1})).replace("{alt}",String(Math.round(Math.abs(p)))));return}this.hoverTooltip.hidden=!0};bodyName(e,t){const n=e.startsWith(fp)?e.slice(fp.length):void 0;return(n?ng.find(r=>r.id===n):void 0)?.name[t]??fE[e]?.[t]??e}showHoverTooltip(e,t){this.hoverTooltip.textContent=t,this.hoverTooltip.hidden=!1;const n=this.stageElement.getBoundingClientRect();this.hoverTooltip.style.left=`${e.clientX-n.left+12}px`,this.hoverTooltip.style.top=`${e.clientY-n.top+12}px`}handlePointerLeave=()=>{this.hoverTooltip.hidden=!0,this.sceneRenderer.setCompassHovered(!1)};handleLightningFlash=()=>{clearTimeout(this.thunderTimeoutId);const e=(.5+Math.random()*3.5)*1e3;this.thunderTimeoutId=window.setTimeout(()=>this.weatherAudio.playThunder(),e)};handleFirstInteraction=()=>{this.weatherAudio.resume(),this.setWeather(aa(this.ufoElement.sighting,this.lastTimeMs))};handleTimeUpdate=e=>{this.lastTimeMs=e.detail.time,this.syncAnimationsToPlayback(),this.updateAstronomy(this.lastTimeMs)};syncAnimationsToPlayback(){const e=this.ufoElement.playbackState==="playing"||this.animateWhilePaused;this.sceneRenderer.setAnimationsRunning(e),this.weatherAudio.setPaused(!e),e||clearTimeout(this.thunderTimeoutId)}constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${Hg}</style>${Bg}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.frameElement=this.shadow.getElementById("frame"),this.sceneCanvas=this.shadow.getElementById("scene-canvas"),this.sceneRenderer=new li(this.sceneCanvas,void 0,this.handleLightningFlash),this.hoverTooltip=this.shadow.getElementById("hover-tooltip"),this.ufoElement=document.createElement(eh),this.ufoElement.classList.add("ufo-overlay"),this.ufoElement.paintsShapes=!1,this.forwardPlayerAttributes(),this.ufoElement.addEventListener("lookat",t=>this.lookToward(t.detail)),this.ufoElement.style.setProperty("--ufo-canvas-background","transparent"),this.ufoElement.style.setProperty("--ufo-canvas-border","none"),this.ufoElement.fullscreenTarget=this.stageElement,this.shadow.getElementById("ufo-slot").replaceWith(this.ufoElement),this.ufoElement.addEventListener("timeupdate",this.handleTimeUpdate),this.ufoElement.canvasElement.addEventListener("pointermove",this.handlePointerMove),this.ufoElement.canvasElement.addEventListener("pointerleave",this.handlePointerLeave),this.ufoElement.canvasElement.addEventListener("pointerdown",this.handleFirstInteraction,{once:!0})}get said(){return this.saidTexts??=new mi(Rr.preferencesFor(this))}saidTexts;connectedCallback(){this.saidTexts=void 0,this.resizeToStage(),this.updateAstronomy(this.lastTimeMs),this.loadStars(),this.resizeObserver=new ResizeObserver(()=>this.resizeToStage()),this.resizeObserver.observe(this.frameElement),document.addEventListener("fullscreenchange",this.handleFullscreenChange);const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){this.resizeObserver?.disconnect(),document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.sceneRenderer.stopTwinkle(),clearTimeout(this.thunderTimeoutId),this.weatherAudio.dispose()}attributeChangedCallback(e,t,n){e==="src"&&n&&n!==t&&this.isConnected&&this.loadFromSrc(n),(e==="star-catalog-src"||e==="deep-star-catalog-src")&&n!==t&&this.isConnected&&this.loadStars(),e==="show-compass"&&n!==t&&this.sceneRenderer.setShowCompass(this.hasAttribute("show-compass")),(e===Fi||e===ki)&&n!==t&&this.forwardPlayerAttributes()}forwardPlayerAttributes(){for(const e of[Fi,ki])this.ufoElement.toggleAttribute(e,this.hasAttribute(e))}setCompassForced(e){this.sceneRenderer.setCompassForced(e)}lookToward(e){const t=Gt(this.ufoElement.sighting,this.lastTimeMs);if(e.kind==="witness"||t?.lat===void 0||t.lng===void 0||t.headingDeg===void 0){this.setLookOffset(0,0);return}const{x:n,z:i}=rn(e.lat,e.lng,t.lat,t.lng);if(Math.hypot(n,i)<1)return this.setLookOffset(0,0);const r=(Math.atan2(n,-i)*180/Math.PI+360)%360;this.setLookOffset(((r-t.headingDeg)%360+540)%360-180,-t.pitchDeg)}setLookOffset(e,t){this.sceneRenderer.setLookOffset(e,t),this.ufoElement.setLookOffset(e,t),this.updateAstronomy(this.lastTimeMs)}setIndoorLook(e,t){this.sceneRenderer.setIndoorLook(e,t)}setCloudRendering(e){this.sceneRenderer.setCloudRendering(e)}setWeather(e){this.sceneRenderer.setWeather(e),this.weatherAudio.setAmbient(e.precipitationType,e.precipitationIntensity,e.windSpeed)}pickCloudAt(e,t){return this.sceneRenderer.pickCloudAt(e,t)}cloudDirectionAt(e,t){return this.sceneRenderer.cloudDirectionAt(e,t)}pickDecorAt(e,t){return this.sceneRenderer.pickDecorAt(e,t)}resumeWeatherAudio(){this.weatherAudio.resume()}async loadFromSrc(e){this.sightingData=await jo.json(e)}get sightingData(){return this.ufoElement.sightingData}set sightingData(e){this.ufoElement.sightingData=e,this.applyFrameFormat(),this.lastTimeMs=0,this.updateAstronomy(0)}get currentTerrainAttribution(){return this.sceneRenderer.currentTerrainAttribution}setTerrainProviders(e){this.sceneRenderer.setTerrainProviders(e)}setDecorModelProvider(e){this.sceneRenderer.setDecorModelProvider(e)}get decorModelCredits(){return this.sceneRenderer.currentDecorModelCredits}applyFrameFormat(){const e=this.ufoElement.sighting.instrument,t=mt.CANVAS_HEIGHT_PX,n=Ut.frameWidthPx(e,t);this.frameElement.style.setProperty("--frame-aspect",`${n} / ${t}`)}resizeToStage(){const e=this.frameElement.getBoundingClientRect(),t=Math.max(1,Math.round(e.width)),n=Math.max(1,Math.round(e.height));this.sceneCanvas.width=t,this.sceneCanvas.height=n,this.sceneRenderer.resize(t,n)}async loadStars(){const e=[{magnitudeLimit:Yc,url:this.getAttribute("star-catalog-src")??xE},{magnitudeLimit:Kc,url:this.getAttribute("deep-star-catalog-src")??ME}],t=this.instrumentReach(),n=++this.starCatalogRequest;this.starCatalogDepth=t>Yc?Kc:Yc;const i=await ci.upTo(e,t);n===this.starCatalogRequest&&(this.starCatalog=i,this.updateAstronomy(this.lastTimeMs))}ensureStarsDeepEnough(){!this.starCatalog||this.starCatalogDepth>=Kc||this.instrumentReach()<=this.starCatalogDepth||this.loadStars()}instrumentReach(){const e=this.ufoElement.sighting,t=dn.gainFor(e.instrument,{fNumber:Gt(e,0)?.fNumber,fieldOfViewDeg:kn.fovOf(e,0),exposureSeconds:e.exposure});return ym(_E,t)}updateAstronomy(e){this.ensureStarsDeepEnough(),this.applySceneAt(e);const t=this.exposureSeconds(),n=this.degreesPerPixelAt(e),i=Tr.instants(t,n),r=Math.max(i,this.ufoElement.exposureTimes(e).length,Ii.instants(this.ufoElement.sighting.decor,Gt(this.ufoElement.sighting,e)?.elevationM??0,e,t,n));if(r<=1){this.sceneRenderer.setExposure(1);return}const a=t*1e3;this.sceneRenderer.setExposure(r,o=>this.applySceneAt(e+a*o/r,{sky:Math.floor(o*i/r)!==Math.floor((o-1)*i/r),stepMs:a/r}))}exposureSeconds(){return this.ufoElement.sighting.exposure??0}degreesPerPixelAt(e){const t=this.sceneCanvas.height;return t<=0?0:kn.fovOf(this.ufoElement.sighting,e)/t}applySceneAt(e,t){const n=this.ufoElement.sighting;this.setWeather(aa(n,e)),this.sceneRenderer.setInstrument(n.instrument),this.updateMeteorShower(n,e),this.sceneRenderer.setDecor(n.decor);const i=Gt(n,e),r=Gt(n,0),a=aa(n,0),o=Object.fromEntries(Qo(aa(n,e)).map(m=>[m.id,Sd(e,n.weatherTrack,a,r,i,m.id)]));if(this.sceneRenderer.setCloudOffset(Sd(e,n.weatherTrack,a,r,i),o),this.sceneRenderer.setObserverPose(i??Zc),this.sceneRenderer.setLensOptics(this.lensOpticsAt(e)),this.sceneRenderer.setInstrumentGain(dn.gainFor(n.instrument,{fNumber:i?.fNumber,fieldOfViewDeg:kn.fovOf(n,e),exposureSeconds:n.exposure})),this.sceneRenderer.setGait(Ht.of(n)?.offsetAt(e)??Ht.STILL),this.sceneRenderer.updateDecorAnchoring(Gt(n,0),i,e),this.sceneRenderer.updateDecorLitState(e,t?.stepMs??0),this.sceneRenderer.setTerrainOrigin(i?.lat,i?.lng),this.pushPhenomenaAt(e),t&&!t.sky)return;const l=i?.lat??Zc.lat,c=i?.lng??Zc.lng,h=vu(n.event.time??{},c,n.event.utcOffsetHours);if(!h){this.sceneRenderer.setAstronomy(yE);return}const u=new Date(h.getTime()+e),d={lat:l,lng:c,elevationM:i?.elevationM??0},f=`${u.getTime()}|${l}|${c}|${d.elevationM}|${this.starCatalog?this.starCatalogDepth:0}`;if(f===this.lastSkyKey){this.sceneRenderer.render();return}this.lastSkyKey=f;const p={...Rc("Sun",u,d),magnitude:Cc("Sun",u)},v={...Rc("Moon",u,d),phase:db(u),magnitude:Cc("Moon",u)},g=ub.map(m=>({body:m,position:Rc(m,u,d),magnitude:Cc(m,u)}));this.sceneRenderer.setAstronomy({sun:p,moon:v,planets:g,comet:this.cometAt(u,d),stars:this.starCatalog?{catalog:this.starCatalog,date:u,observer:d}:void 0,frame:{date:u,observer:d}}),this.ufoElement.setSunAltitude(p.altitudeDeg)}cometAt(e,t){const n=lE.brightestAt(e,t);if(n)return{id:n.apparition.id,position:n.position,tailEnd:n.tailEnd,magnitude:n.magnitude}}pushPhenomenaAt(e){const t=this.ufoElement.sighting;t!==this.sizeEstimatesFor&&(this.sizeEstimates.clear(),this.distanceHypotheses.clear(),this.sizeEstimatesFor=t);const n=t.timeline,i=this.ufoElement.canvasElement,r=this.ufoElement.frameShiftPx,a=this.projectionAt(e),o=new Map,l=new Map,c=new Set;for(const p of n.sourceIds){const v=n.getInterpolatedShapeAt(e,p);if(!v)continue;const g={...v,bounds:{...v.bounds,x:v.bounds.x+r.x,y:v.bounds.y+r.y}};o.set(p,g);const m=v.aim?this.sceneRenderer.screenPointOf(Yn.directionOf(v.aim,this.directionScratch)):{ndcX:(g.bounds.x+g.bounds.width/2)/i.width*2-1,ndcY:-((g.bounds.y+g.bounds.height/2)/i.height*2-1)},w=m!==void 0&&Math.abs(m.ndcX)<=1&&Math.abs(m.ndcY)<=1,b=w?this.sceneRenderer.decorDistancesAt(m.ndcX,m.ndcY,p):{};c.add(p),(w||v.aim)&&c.delete(p);const _=v.angular?.widthDeg??a.pxToDeg(v.bounds.width),S=this.sizeEstimateOf(p);S.add(_,b);const E=Ma.of(t,p);l.set(p,un.resolve({hypothesisM:this.distanceHypotheses.get(p),derivedM:E&&_>0?mt.distanceMAt(E.widthM,_):void 0,range:S.distanceRangeAt(_),crossing:b}))}for(const[p,v]of o)for(const[g,m]of o){if(g===p||m.transparency>=1||m.bounds.width*m.bounds.height<=v.bounds.width*v.bounds.height||!(v.bounds.x>=m.bounds.x&&v.bounds.y>=m.bounds.y&&v.bounds.x+v.bounds.width<=m.bounds.x+m.bounds.width&&v.bounds.y+v.bounds.height<=m.bounds.y+m.bounds.height))continue;const b=l.get(g);b&&l.set(p,{distanceM:b.distanceM*.999,basis:b.basis});break}this.depths=l;const h=n.sourceIds,u=[];for(const[p,v]of o)u.push({sourceId:p,shape:v,distanceM:l.get(p).distanceM,renderOrder:h.indexOf(p),aim:v.aim,hidden:c.has(p)});const f=(Gt(t,e)?.rollDeg??0)+(Ht.of(t)?.offsetAt(e)??Ht.STILL).rollDeg;this.sceneRenderer.setPhenomena(u,{projection:a,canvasWidthPx:i.width,canvasHeightPx:i.height,scale:Math.max(1,this.sceneCanvas.height/Math.max(1,i.height)),starPoints:Ut.starPointsOf(t.instrument),rollRad:f*Math.PI/180})}setDistanceHypothesis(e,t){t===void 0||!(t>0)?this.distanceHypotheses.delete(e):this.distanceHypotheses.set(e,t),this.updateAstronomy(this.lastTimeMs)}depthOf(e){return this.depths.get(e)}sizeRangeOf(e){return this.sizeEstimateOf(e).sizeRange}distanceRangeAt(e,t){const n=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(t,e);if(!n)return{};const i=n.angular?.widthDeg??this.projectionAt(t).pxToDeg(n.bounds.width);return this.sizeEstimateOf(e).distanceRangeAt(i)}sizeContradictory(e){return this.sizeEstimateOf(e).contradictory}updateMeteorShower(e,t){this.ensureMeteorSchedule(e),this.sceneRenderer.updateMeteors(t)}ensureMeteorSchedule(e){const t=this.meteorInputsOf(e);t!==this.meteorScheduleFor&&(this.meteorScheduleFor=t,this.scheduleMeteors(e))}meteorInputsOf(e){const t=e.event.place?.[0],n=e.event.time;return JSON.stringify([t?.lat,t?.lng,n?.year,n?.month,n?.day,n?.hour,n?.minute,e.event.utcOffsetHours,e.event.durationSeconds,e.timeline.duration])}scheduleMeteors(e){const t=e.event.place?.[0],n=e.event.time,i=t?.lat!==void 0&&t.lng!==void 0&&n?.year!==void 0?vu(n,t.lng,e.event.utcOffsetHours):void 0;if(!i||t?.lat===void 0||t.lng===void 0){this.sceneRenderer.setMeteorShower([],0,0);return}const r={lat:t.lat,lng:t.lng,elevationM:0},a=(e.event.durationSeconds??0)*1e3||e.timeline.duration||2e4,o=Math.round(i.getTime()/1e3)+Math.round(t.lat*1e3),l=Pt.schedule({ratePerHour:Pt.observedRatePerHour(Pt.apexPosition(i,r).altitudeDeg),durationMs:a,velocityKmS:Pt.TYPICAL_VELOCITY_KM_S,seed:o}),c=$c.activeAt(i).map(u=>{const d=$c.radiantPosition(u.shower,i,r);return{entry:u,position:d,rate:$c.observedRatePerHour(u.zhr,d.altitudeDeg,u.shower.populationIndex)}}).sort((u,d)=>d.rate-u.rate)[0];if(!c||c.rate<=0){this.sceneRenderer.setMeteorShower(l,0,0);return}const h=Ls.schedule({ratePerHour:c.rate,durationMs:a,velocityKmS:c.entry.shower.velocityKmS,seed:o+1});this.sceneRenderer.setMeteorShower([...h,...l],c.position.altitudeDeg,c.position.azimuthDeg)}meteorByRank(e){this.ensureMeteorSchedule(this.ufoElement.sighting);const t=[...this.sceneRenderer.meteorSchedule].filter(r=>r.t+r.durationMs<=this.ufoElement.seekableDuration).sort((r,a)=>a.brightness-r.brightness);if(t.length===0)return;const n=t[e%t.length],i=this.sceneRenderer.meteorMidpoint(n);if(i)return{t:Math.round(n.t+n.durationMs*.45),...i}}lensOpticsAt(e){const t=this.ufoElement.sighting,n=t.instrument,i=n.frame,r=Gt(t,e),a=r?.fNumber??n.fNumber;if(!i||a===void 0)return;const o=Ut.focalLengthMmFor(n,kn.fovOf(t,e));if(o!==void 0)return{focalLengthMm:o,fNumber:a,focusDistance:r?.focusDistanceM??0,frameHeightMm:i.heightMm}}projectionAt(e){const t=this.ufoElement.sighting;return Oi.of(t.instrument,mt.CANVAS_HEIGHT_PX,kn.fovOf(t,e))}sizeEstimateOf(e){let t=this.sizeEstimates.get(e);return t||(t=new hE,this.sizeEstimates.set(e,t)),t}}const bu="rr0-scene";function ig(){Lp(),customElements.get(bu)||customElements.define(bu,SE)}const bE={color:"Color",transparency:"Transparency",halo:"Halo",blur:"Blur",brightness:"Brilliance",shapeTitle:"Name",utcOffset:"Time zone",cloudBase:"Cloud base",elevation:"Altitude",heightAboveGround:"Height above ground",duration:"Duration",placeName:"Place",latitude:"Latitude",longitude:"Longitude",heading:"Heading",pitch:"Tilt",roll:"Roll",observationTime:"Observation start",observationEndTime:"Observation end",assessmentGroup:"Assessment",assessmentNames:{coverage:"Witness info"},assessmentVerdicts:{"hynek.nl":"NL — nocturnal light","hynek.dd":"DD — daylight disc","hynek.rv":"RV — radar-visual","hynek.ce1":"CE1 — close encounter","hynek.ce2":"CE2 — with a physical trace","hynek.ce3":"CE3 — with entities"},witnessGroup:"Witness",witnessId:"ID",witnessTitle:"Title",witnessLastName:"Last name",witnessFirstNames:"First names",caseId:"Case ID",tags:"Tags",cloudCover:"Cloud cover",highCloudCover:"Ice cloud (cirrus)",focalLength:"Focal length",fieldOfView:"Field of view",aperture:"Aperture",exposure:"Exposure",focusDistance:"Focused at",iceCrystalAlignment:"Crystal alignment",cloudDarkness:"Cloud darkness",precipitationType:"Precipitation",precipitationNone:"None",precipitationRain:"Rain",precipitationSnow:"Snow",precipitationHail:"Hail",precipitationIntensity:"Intensity",windDirection:"Wind direction",windSpeed:"Wind speed",storm:"Storm",soundKind:"Sound",soundNone:"None (silent)",soundHum:"Hum",soundWhistle:"Whistle",soundRumble:"Rumble",soundCrackle:"Crackle",soundVolume:"Loudness",soundPitch:"Pitch",soundSrc:"Recording",instrument:"Observed through",decorAircraft:"Aircraft",decorEntity:"Being",decorAltitude:"Altitude",decorLights:"Lights",decorLightsNone:"none",decor:"Environment",decorBuilding:"Building",decorTree:"Tree",decorCrop:"Crop row",decorMound:"Stone heap",decorStreetlight:"Streetlight",decorVehicle:"Vehicle",decorWitness:"Other witness",decorEast:"Distance east",decorNorth:"Distance north",decorHeading:"Heading",decorColor:"Colour",decorLit:"Lit",decorTitle:"Name",milestones:"Moments",milestoneLabel:"Label",milestoneNote:"What happens",addMilestone:"Name this moment",deleteMilestone:"Delete moment",confirmAccept:"Delete",confirmDecline:"Cancel",decorWidth:"Width",decorLength:"Length",decorHeight:"Height",decorModel:"3D model",decorModelNone:"Built-in shape",decorModelAdvanced:"Model from an address",decorModelUrl:"glTF/GLB address",decorModelTitle:"Model name",decorModelAuthor:"Author",decorModelLicense:"Licence",decorModelSource:"Where it came from",decorFloors:"Floors",decorOccupiedFloor:"Occupied floor",decorWitnessSide:"Witness location",decorWitnessSideNone:"Not present",decorWindows:"Windows",decorSideFront:"Front",decorSideBehind:"Behind",decorSideLeft:"Left",decorSideRight:"Right",decorSideFrontLeft:"Front-left",decorSideFrontRight:"Front-right",decorSideBehindLeft:"Behind-left",decorSideBehindRight:"Behind-right"},wu={...bE,testimonyBy:"Testimony by",unnamedWitness:"Witness {n}",about:"About",close:"Close",observation:"Observation",date:"Date",location:"Location",case:"Case",description:"Description",credits:"Credits",editThisObservation:"Edit this observation",embed:"Embed",embedReplay:"Replay",embedEdit:"Editor",embedCopy:"Copy",embedCopied:"Copied",showLabels:"Show what it states",hideLabels:"Hide what it states"},wE=Object.freeze(Object.defineProperty({__proto__:null,sightingMessages_en:wu},Symbol.toStringTag,{value:"Module"}));ig();const EE="“Thunder” by Jerimee",AE="https://creativecommons.org/licenses/by/3.0/",TE="CC BY 3.0",RE="https://ufoathome.org",pp=`${RE}/edit/`;class sg extends HTMLElement{static get observedAttributes(){return["src","show-labels",Fi,ki]}shadow;sceneElement;toolbarElement;testimonyElement;testimonyPrefix;witnessText;witnessSelect;infoButton;infoPanel;infoAppLink;infoObservationHeading;infoObservationList;infoCreditsToggle;infoCreditsList;infoCloseButton;infoEmbedToggle;infoEmbedPanel;embedReplayRadio;embedEditRadio;labelEmbedReplay;labelEmbedEdit;embedMarkup;embedCopyButton;labelsToggle;paramSummary;summaryBuilder=new _d(wu,"en",new mi(["en"]),new Go({}));summarySignature="";assessmentEntries=[];assessmentToken=0;supportsPopover=typeof HTMLElement.prototype.showPopover=="function";entries=[];currentSrc;infoOpen=!1;creditsOpen=!1;embedOpen=!1;labelsShown=!1;language="en";messages=wu;constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${fg}</style>${dg}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.sceneElement=document.createElement(bu),this.forwardPlayerAttributes(),this.sceneElement.ufoElement.creditShownExternally=!0,this.shadow.getElementById("ufo-slot").replaceWith(this.sceneElement),this.toolbarElement=this.shadow.getElementById("toolbar"),this.testimonyElement=this.shadow.getElementById("testimony"),this.testimonyPrefix=this.shadow.getElementById("testimony-prefix"),this.witnessText=this.shadow.getElementById("witness-text"),this.witnessSelect=this.shadow.getElementById("witness"),this.infoButton=this.shadow.getElementById("info-button"),this.infoPanel=this.shadow.getElementById("info-panel"),this.infoAppLink=this.shadow.getElementById("info-app-link"),this.infoObservationHeading=this.shadow.getElementById("info-observation-heading"),this.infoObservationList=this.shadow.getElementById("info-observation-list"),this.infoCreditsToggle=this.shadow.getElementById("info-credits-toggle"),this.infoCreditsList=this.shadow.getElementById("info-credits-list"),this.infoCloseButton=this.shadow.getElementById("info-close"),this.labelsToggle=this.shadow.getElementById("info-labels-toggle"),this.paramSummary=this.shadow.getElementById("param-summary"),this.labelsToggle.addEventListener("click",()=>{this.showLabels=!this.showLabels}),this.infoEmbedToggle=this.shadow.getElementById("info-embed-toggle"),this.infoEmbedPanel=this.shadow.getElementById("info-embed"),this.embedReplayRadio=this.shadow.getElementById("embed-kind-replay"),this.embedEditRadio=this.shadow.getElementById("embed-kind-edit"),this.labelEmbedReplay=this.shadow.getElementById("label-embed-replay"),this.labelEmbedEdit=this.shadow.getElementById("label-embed-edit"),this.embedMarkup=this.shadow.getElementById("embed-markup"),this.embedCopyButton=this.shadow.getElementById("embed-copy"),this.witnessSelect.addEventListener("change",()=>this.selectWitness(this.witnessSelect.value)),this.sceneElement.ufoElement.addEventListener("timeupdate",()=>this.refreshParamSummary()),this.supportsPopover?(this.infoPanel.setAttribute("popover","auto"),this.infoPanel.removeAttribute("hidden"),this.infoButton.setAttribute("popovertarget","info-panel"),this.infoPanel.addEventListener("beforetoggle",t=>{t.newState==="open"&&(this.populateInfoPanel(),this.bringInfoButtonIntoView())}),this.infoPanel.addEventListener("toggle",t=>this.syncInfoOpen(t.newState==="open"))):this.infoButton.addEventListener("click",()=>this.toggleInfoPanel()),this.infoCloseButton.addEventListener("click",()=>this.toggleInfoPanel()),this.infoCreditsToggle.addEventListener("click",()=>this.toggleCredits()),this.infoEmbedToggle.addEventListener("click",()=>this.toggleEmbed());for(const t of[this.embedReplayRadio,this.embedEditRadio])t.addEventListener("change",()=>this.refreshEmbedMarkup());this.embedCopyButton.addEventListener("click",()=>void this.copyEmbedMarkup()),this.loadLocaleMessages()}get scene(){return this.sceneElement}async loadLocaleMessages(){this.language=bl(Rr.preferencesFor(this),Ep),this.language!=="en"&&(this.messages=await r1(this.language),this.testimonyPrefix.textContent=this.messages.testimonyBy,this.infoButton.title=this.messages.about,this.infoButton.setAttribute("aria-label",this.messages.about),this.infoCloseButton.setAttribute("aria-label",this.messages.close),this.infoObservationHeading.textContent=this.messages.observation,this.infoCreditsToggle.textContent=this.messages.credits,this.tags=new Go(await a1(this.language)),this.summaryBuilder=new _d(this.messages,this.language==="fr"?"fr":"en",this.said,this.tags),this.syncLabelsToggle(),this.refreshParamSummary(),this.currentSrc&&this.runAssessments(),this.infoEmbedToggle.textContent=this.messages.embed,this.labelEmbedReplay.textContent=this.messages.embedReplay,this.labelEmbedEdit.textContent=this.messages.embedEdit,this.embedCopyButton.textContent=this.messages.embedCopy,this.infoOpen&&this.populateInfoPanel(),this.updateTestimonyLine())}get said(){return this.saidTexts??=new mi(Rr.preferencesFor(this))}saidTexts;tags=new Go({});connectedCallback(){this.saidTexts=void 0;const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){document.removeEventListener("click",this.handleOutsideClick)}attributeChangedCallback(e,t,n){e==="src"&&n&&n!==t&&this.isConnected&&this.loadFromSrc(n),e==="show-labels"&&this.applyLabels(this.hasAttribute("show-labels")),(e===Fi||e===ki)&&this.forwardPlayerAttributes()}forwardPlayerAttributes(){for(const e of[Fi,ki])this.sceneElement.toggleAttribute(e,this.hasAttribute(e))}async loadFromSrc(e){const t=await jo.json(e);Array.isArray(t)?await this.loadWitnessUrls(t.map(n=>new URL(n,new URL(e,location.href)).href)):this.setEntries([{src:e,sighting:t}])}get sightingData(){return this.entries.find(e=>e.src===this.currentSrc)?.sighting}set sightingData(e){this.currentSrc="",this.setEntries([{src:"",sighting:e}])}get witnessUrls(){return this.entries.map(e=>e.src)}set witnessUrls(e){this.loadWitnessUrls(e)}async loadWitnessUrls(e){const t=await Promise.all(e.map(async n=>({src:n,sighting:await jo.json(n)})));this.setEntries(t)}setEntries(e){this.entries=e,this.warnOnMismatchedCaseIds(e),this.toolbarElement.hidden=e.length===0;const t=e.length>1;this.witnessSelect.hidden=!t,this.witnessText.hidden=t,this.witnessSelect.innerHTML="";for(const i of e){const r=document.createElement("option");r.value=i.src,r.textContent=this.witnessDisplayName(i.sighting.witness)??this.messages.unnamedWitness.replace("{n}",String(e.indexOf(i)+1)),this.witnessSelect.appendChild(r)}const n=e.find(i=>i.src===this.currentSrc)??e[0];n?this.selectWitness(n.src):this.updateTestimonyLine()}editorUrl(){if(!this.currentSrc)return pp;const e=new URL(this.currentSrc,location.href);return`${pp}?sighting=${encodeURIComponent(e.href)}`}embedMarkupFor(e){const t=e==="edit"?"rr0-sighting-editor":"rr0-sighting",n=new URL(`${t}.mjs`,import.meta.url).href,i=this.currentSrc?new URL(this.currentSrc,location.href).href:"";return`<script type="module" src="${n}"><\/script>
6318
- <${t} src="${i}"></${t}>`}refreshEmbedMarkup(){this.embedMarkup.value=this.embedMarkupFor(this.embedEditRadio.checked?"edit":"replay")}async copyEmbedMarkup(){try{await navigator.clipboard.writeText(this.embedMarkup.value),this.embedCopyButton.textContent=this.messages.embedCopied,window.setTimeout(()=>this.embedCopyButton.textContent=this.messages.embedCopy,1500)}catch{this.embedMarkup.select()}}warnOnMismatchedCaseIds(e){const t=new Set(e.map(n=>n.sighting.caseId).filter(n=>n!==void 0));t.size>1&&console.warn(`<rr0-sighting>: witnesses declare different case ids (${[...t].join(", ")}) — they may not belong to the same case.`)}selectWitness(e){const t=this.entries.find(n=>n.src===e);t&&(this.currentSrc=e,this.witnessSelect.value=e,this.sceneElement.sightingData=t.sighting,this.updateTestimonyLine(),this.refreshParamSummary(),this.runAssessments(),this.infoOpen&&this.populateInfoPanel())}async runAssessments(){const e=++this.assessmentToken,t=await new zg(this.messages).read(this.sceneElement.ufoElement.sighting);e===this.assessmentToken&&(this.assessmentEntries=t.entries,this.refreshParamSummary())}updateTestimonyLine(){const e=this.entries.find(i=>i.src===this.currentSrc),t=e?this.witnessDisplayName(e.sighting.witness):void 0,n=t!==void 0||this.entries.length>1;this.testimonyElement.hidden=!n,this.witnessText.textContent=t??""}witnessDisplayName(e){if(!e)return;const t=[...e.firstNames??[],e.lastName].filter(Boolean).join(" ");return e.title||t||e.id||e.dirName}formatDate(e){const t=e.place?.[0],n=vu(e.time??{},t?.lng??0,e.utcOffsetHours);if(!n)return;const i=n.getTime()+this.utcOffsetHoursOf(e,t?.lng??0)*36e5;return new Intl.DateTimeFormat(this.language==="fr"?"fr-FR":"en-US",{dateStyle:"long",timeStyle:"short",timeZone:"UTC"}).format(new Date(i))}utcOffsetHoursOf(e,t){return e.utcOffsetHours??Math.round(t/15)}formatLocation(e){const t=e.place?.[0];if(t)return`${t.lat.toFixed(4)}, ${t.lng.toFixed(4)}`}toggleInfoPanel(){const e=!this.infoOpen;if(this.supportsPopover){const t=this.infoPanel.matches(":popover-open");e&&!t?this.infoPanel.showPopover():!e&&t&&this.infoPanel.hidePopover();return}e&&this.bringInfoButtonIntoView(),this.syncInfoOpen(e),this.infoPanel.hidden=!e,e?document.addEventListener("click",this.handleOutsideClick):document.removeEventListener("click",this.handleOutsideClick)}bringInfoButtonIntoView(){const e=this.infoButton.getBoundingClientRect(),t=window.innerHeight||document.documentElement.clientHeight;e.top>=0&&e.bottom<=t||this.infoButton.scrollIntoView({block:"center"})}syncInfoOpen(e){e!==this.infoOpen&&(this.infoOpen=e,this.infoButton.setAttribute("aria-expanded",String(e)),e?this.supportsPopover||this.populateInfoPanel():(this.creditsOpen=!1,this.infoCreditsList.hidden=!0,this.infoCreditsToggle.setAttribute("aria-expanded","false"),this.embedOpen=!1,this.infoEmbedPanel.hidden=!0,this.infoEmbedToggle.setAttribute("aria-expanded","false")))}handleOutsideClick=e=>{const t=e.composedPath();!t.includes(this.infoPanel)&&!t.includes(this.infoButton)&&this.toggleInfoPanel()};toggleCredits(){this.creditsOpen=!this.creditsOpen,this.infoCreditsList.hidden=!this.creditsOpen,this.infoCreditsToggle.setAttribute("aria-expanded",String(this.creditsOpen)),this.creditsOpen&&this.revealInPanel(this.infoCreditsList)}toggleEmbed(){this.embedOpen=!this.embedOpen,this.infoEmbedPanel.hidden=!this.embedOpen,this.infoEmbedToggle.setAttribute("aria-expanded",String(this.embedOpen)),this.embedOpen&&(this.refreshEmbedMarkup(),this.revealInPanel(this.infoEmbedPanel))}revealInPanel(e){e.scrollIntoView?.({block:"nearest"})}get showLabels(){return this.labelsShown}set showLabels(e){this.toggleAttribute("show-labels",e)}applyLabels(e){this.labelsShown=e,this.syncLabelsToggle(),this.refreshParamSummary(),this.populateInfoPanel()}syncLabelsToggle(){this.labelsToggle.textContent=this.labelsShown?this.messages.hideLabels:this.messages.showLabels,this.labelsToggle.setAttribute("aria-pressed",String(this.labelsShown))}refreshParamSummary(){if(this.paramSummary.hidden=!this.labelsShown,!this.labelsShown){this.paramSummary.replaceChildren(),this.summarySignature="";return}const e=this.sceneElement.ufoElement.sighting,t=[...this.summaryBuilder.entriesFor(e,this.sceneElement.ufoElement.currentTime),...this.assessmentEntries],n=t.map(a=>`${a.field}=${a.label}=${a.value}${a.unit}${a.fromSource?"*":""}`).join("|");if(n===this.summarySignature)return;this.summarySignature=n;const i=[];let r;for(const a of t){r&&r.group!==a.group&&(r=void 0);const o=a.group==="witness"?this.messages.witnessGroup:a.group==="assessment"?this.messages.assessmentGroup:void 0;if(o!==void 0&&!r){const c=document.createElement("span");c.className="param-nest";const h=document.createElement("span");h.className="param-nest-label",h.textContent=o,c.append(h),r={group:a.group,element:c},i.push(c)}const l=this.paramItem(a);r?r.element.append(l):i.push(l)}this.paramSummary.replaceChildren(...i)}paramItem(e){const t=document.createElement("span");t.className=e.fromSource?"param-label from-source":"param-label";const n=document.createElement("span");if(n.className="param-label-label",n.textContent=`${e.label} `,t.append(n),e.color!==void 0){const r=document.createElement("span");r.className="param-label-swatch",r.style.background=e.color,t.append(r)}const i=document.createElement("span");return i.className="param-label-value",i.textContent=e.unit===""?e.value:`${e.value} ${e.unit}`,t.append(i),t}populateInfoPanel(){const e=this.entries.find(a=>a.src===this.currentSrc);if(this.infoObservationList.innerHTML="",e){if(!this.labelsShown){const o=this.formatDate(e.sighting);o&&this.appendInfoRow(this.infoObservationList,this.messages.date,o);const l=this.formatLocation(e.sighting);l&&this.appendInfoRow(this.infoObservationList,this.messages.location,l),e.sighting.caseId&&this.appendInfoRow(this.infoObservationList,this.messages.case,e.sighting.caseId)}const a=this.said.read(e.sighting.description);a&&this.appendInfoRow(this.infoObservationList,this.messages.description,a),!this.labelsShown&&e.sighting.tags&&e.sighting.tags.length>0&&this.appendInfoRow(this.infoObservationList,this.messages.tags,e.sighting.tags.map(o=>this.tags.name(o)).join(", "))}this.refreshEmbedMarkup(),this.infoAppLink.href=this.editorUrl(),this.infoAppLink.textContent="UFO@home v0.57.0",this.infoAppLink.title=this.messages.editThisObservation,this.infoAppLink.setAttribute("aria-label",this.messages.editThisObservation),this.infoCreditsList.innerHTML="";const t=this.sceneElement.currentTerrainAttribution;if(t){const a=document.createElement("li");a.textContent=t,this.infoCreditsList.appendChild(a)}const n=this.sceneElement.ufoElement.witnessMapCredit;if(n&&!t?.includes(n)){const a=document.createElement("li");a.textContent=n,this.infoCreditsList.appendChild(a)}for(const a of this.sceneElement.decorModelCredits){const o=document.createElement("li"),l=a.author?` — ${a.author}`:"";if(a.sourceUrl){const c=document.createElement("a");c.href=a.sourceUrl,c.target="_blank",c.rel="noopener",c.textContent=a.title,o.append(c,document.createTextNode(`${l} (${a.license})`))}else o.textContent=`${a.title}${l} (${a.license})`;this.infoCreditsList.appendChild(o)}const i=document.createElement("li");i.textContent=`${EE} (`;const r=document.createElement("a");r.href=AE,r.target="_blank",r.rel="noopener",r.textContent=TE,i.appendChild(r),i.appendChild(document.createTextNode(")")),this.infoCreditsList.appendChild(i)}appendInfoRow(e,t,n){const i=document.createElement("dt");i.textContent=t;const r=document.createElement("dd");r.textContent=n,e.appendChild(i),e.appendChild(r)}}const mp="rr0-sighting",gp="rr0-eyewitness";class CE extends sg{}function DE(){ig(),customElements.get(mp)||customElements.define(mp,sg),customElements.get(gp)||customElements.define(gp,CE)}DE();export{NE as $,Kn as A,dt as B,le as C,w2 as D,Bi as E,HE as F,lt as G,wt as H,UE as I,OE as J,Ye as K,Na as L,zE as M,qa as N,yt as O,S2 as P,ps as Q,wa as R,Ma as S,PE as T,FE as U,Pe as V,tm as W,kE as X,Ko as Y,an as Z,Sn as _,LE as a,kr as a0,em as a1,BE as a2,Wv as a3,sl as a4,Hh as a5,cl as a6,Qt as a7,om as a8,Wu as a9,Xu as aa,je as ab,ds as ac,La as ad,yi as ae,Vi as af,IE as b,Rc as c,WE as d,al as e,Dn as f,VE as g,Xe as h,D as i,M0 as j,GE as k,XE as l,Bv as m,Ds as n,zl as o,Qg as p,X1 as q,_t as r,vu as s,Vt as t,hh as u,mn as v,nm as w,Wi as x,Zv as y,i2 as z};
6318
+ <${t} src="${i}"></${t}>`}refreshEmbedMarkup(){this.embedMarkup.value=this.embedMarkupFor(this.embedEditRadio.checked?"edit":"replay")}async copyEmbedMarkup(){try{await navigator.clipboard.writeText(this.embedMarkup.value),this.embedCopyButton.textContent=this.messages.embedCopied,window.setTimeout(()=>this.embedCopyButton.textContent=this.messages.embedCopy,1500)}catch{this.embedMarkup.select()}}warnOnMismatchedCaseIds(e){const t=new Set(e.map(n=>n.sighting.caseId).filter(n=>n!==void 0));t.size>1&&console.warn(`<rr0-sighting>: witnesses declare different case ids (${[...t].join(", ")}) — they may not belong to the same case.`)}selectWitness(e){const t=this.entries.find(n=>n.src===e);t&&(this.currentSrc=e,this.witnessSelect.value=e,this.sceneElement.sightingData=t.sighting,this.updateTestimonyLine(),this.refreshParamSummary(),this.runAssessments(),this.infoOpen&&this.populateInfoPanel())}async runAssessments(){const e=++this.assessmentToken,t=await new zg(this.messages).read(this.sceneElement.ufoElement.sighting);e===this.assessmentToken&&(this.assessmentEntries=t.entries,this.refreshParamSummary())}updateTestimonyLine(){const e=this.entries.find(i=>i.src===this.currentSrc),t=e?this.witnessDisplayName(e.sighting.witness):void 0,n=t!==void 0||this.entries.length>1;this.testimonyElement.hidden=!n,this.witnessText.textContent=t??""}witnessDisplayName(e){if(!e)return;const t=[...e.firstNames??[],e.lastName].filter(Boolean).join(" ");return e.title||t||e.id||e.dirName}formatDate(e){const t=e.place?.[0],n=vu(e.time??{},t?.lng??0,e.utcOffsetHours);if(!n)return;const i=n.getTime()+this.utcOffsetHoursOf(e,t?.lng??0)*36e5;return new Intl.DateTimeFormat(this.language==="fr"?"fr-FR":"en-US",{dateStyle:"long",timeStyle:"short",timeZone:"UTC"}).format(new Date(i))}utcOffsetHoursOf(e,t){return e.utcOffsetHours??Math.round(t/15)}formatLocation(e){const t=e.place?.[0];if(t)return`${t.lat.toFixed(4)}, ${t.lng.toFixed(4)}`}toggleInfoPanel(){const e=!this.infoOpen;if(this.supportsPopover){const t=this.infoPanel.matches(":popover-open");e&&!t?this.infoPanel.showPopover():!e&&t&&this.infoPanel.hidePopover();return}e&&this.bringInfoButtonIntoView(),this.syncInfoOpen(e),this.infoPanel.hidden=!e,e?document.addEventListener("click",this.handleOutsideClick):document.removeEventListener("click",this.handleOutsideClick)}bringInfoButtonIntoView(){const e=this.infoButton.getBoundingClientRect(),t=window.innerHeight||document.documentElement.clientHeight;e.top>=0&&e.bottom<=t||this.infoButton.scrollIntoView({block:"center"})}syncInfoOpen(e){e!==this.infoOpen&&(this.infoOpen=e,this.infoButton.setAttribute("aria-expanded",String(e)),e?this.supportsPopover||this.populateInfoPanel():(this.creditsOpen=!1,this.infoCreditsList.hidden=!0,this.infoCreditsToggle.setAttribute("aria-expanded","false"),this.embedOpen=!1,this.infoEmbedPanel.hidden=!0,this.infoEmbedToggle.setAttribute("aria-expanded","false")))}handleOutsideClick=e=>{const t=e.composedPath();!t.includes(this.infoPanel)&&!t.includes(this.infoButton)&&this.toggleInfoPanel()};toggleCredits(){this.creditsOpen=!this.creditsOpen,this.infoCreditsList.hidden=!this.creditsOpen,this.infoCreditsToggle.setAttribute("aria-expanded",String(this.creditsOpen)),this.creditsOpen&&this.revealInPanel(this.infoCreditsList)}toggleEmbed(){this.embedOpen=!this.embedOpen,this.infoEmbedPanel.hidden=!this.embedOpen,this.infoEmbedToggle.setAttribute("aria-expanded",String(this.embedOpen)),this.embedOpen&&(this.refreshEmbedMarkup(),this.revealInPanel(this.infoEmbedPanel))}revealInPanel(e){e.scrollIntoView?.({block:"nearest"})}get showLabels(){return this.labelsShown}set showLabels(e){this.toggleAttribute("show-labels",e)}applyLabels(e){this.labelsShown=e,this.syncLabelsToggle(),this.refreshParamSummary(),this.populateInfoPanel()}syncLabelsToggle(){this.labelsToggle.textContent=this.labelsShown?this.messages.hideLabels:this.messages.showLabels,this.labelsToggle.setAttribute("aria-pressed",String(this.labelsShown))}refreshParamSummary(){if(this.paramSummary.hidden=!this.labelsShown,!this.labelsShown){this.paramSummary.replaceChildren(),this.summarySignature="";return}const e=this.sceneElement.ufoElement.sighting,t=[...this.summaryBuilder.entriesFor(e,this.sceneElement.ufoElement.currentTime),...this.assessmentEntries],n=t.map(a=>`${a.field}=${a.label}=${a.value}${a.unit}${a.fromSource?"*":""}`).join("|");if(n===this.summarySignature)return;this.summarySignature=n;const i=[];let r;for(const a of t){r&&r.group!==a.group&&(r=void 0);const o=a.group==="witness"?this.messages.witnessGroup:a.group==="assessment"?this.messages.assessmentGroup:void 0;if(o!==void 0&&!r){const c=document.createElement("span");c.className="param-nest";const h=document.createElement("span");h.className="param-nest-label",h.textContent=o,c.append(h),r={group:a.group,element:c},i.push(c)}const l=this.paramItem(a);r?r.element.append(l):i.push(l)}this.paramSummary.replaceChildren(...i)}paramItem(e){const t=document.createElement("span");t.className=e.fromSource?"param-label from-source":"param-label";const n=document.createElement("span");if(n.className="param-label-label",n.textContent=`${e.label} `,t.append(n),e.color!==void 0){const r=document.createElement("span");r.className="param-label-swatch",r.style.background=e.color,t.append(r)}const i=document.createElement("span");return i.className="param-label-value",i.textContent=e.unit===""?e.value:`${e.value} ${e.unit}`,t.append(i),t}populateInfoPanel(){const e=this.entries.find(a=>a.src===this.currentSrc);if(this.infoObservationList.innerHTML="",e){if(!this.labelsShown){const o=this.formatDate(e.sighting);o&&this.appendInfoRow(this.infoObservationList,this.messages.date,o);const l=this.formatLocation(e.sighting);l&&this.appendInfoRow(this.infoObservationList,this.messages.location,l),e.sighting.caseId&&this.appendInfoRow(this.infoObservationList,this.messages.case,e.sighting.caseId)}const a=this.said.read(e.sighting.description);a&&this.appendInfoRow(this.infoObservationList,this.messages.description,a),!this.labelsShown&&e.sighting.tags&&e.sighting.tags.length>0&&this.appendInfoRow(this.infoObservationList,this.messages.tags,e.sighting.tags.map(o=>this.tags.name(o)).join(", "))}this.refreshEmbedMarkup(),this.infoAppLink.href=this.editorUrl(),this.infoAppLink.textContent="UFO@home v0.57.2",this.infoAppLink.title=this.messages.editThisObservation,this.infoAppLink.setAttribute("aria-label",this.messages.editThisObservation),this.infoCreditsList.innerHTML="";const t=this.sceneElement.currentTerrainAttribution;if(t){const a=document.createElement("li");a.textContent=t,this.infoCreditsList.appendChild(a)}const n=this.sceneElement.ufoElement.witnessMapCredit;if(n&&!t?.includes(n)){const a=document.createElement("li");a.textContent=n,this.infoCreditsList.appendChild(a)}for(const a of this.sceneElement.decorModelCredits){const o=document.createElement("li"),l=a.author?` — ${a.author}`:"";if(a.sourceUrl){const c=document.createElement("a");c.href=a.sourceUrl,c.target="_blank",c.rel="noopener",c.textContent=a.title,o.append(c,document.createTextNode(`${l} (${a.license})`))}else o.textContent=`${a.title}${l} (${a.license})`;this.infoCreditsList.appendChild(o)}const i=document.createElement("li");i.textContent=`${EE} (`;const r=document.createElement("a");r.href=AE,r.target="_blank",r.rel="noopener",r.textContent=TE,i.appendChild(r),i.appendChild(document.createTextNode(")")),this.infoCreditsList.appendChild(i)}appendInfoRow(e,t,n){const i=document.createElement("dt");i.textContent=t;const r=document.createElement("dd");r.textContent=n,e.appendChild(i),e.appendChild(r)}}const mp="rr0-sighting",gp="rr0-eyewitness";class CE extends sg{}function DE(){ig(),customElements.get(mp)||customElements.define(mp,sg),customElements.get(gp)||customElements.define(gp,CE)}DE();export{NE as $,Kn as A,dt as B,le as C,w2 as D,Bi as E,HE as F,lt as G,wt as H,UE as I,OE as J,Ye as K,Na as L,zE as M,qa as N,yt as O,S2 as P,ps as Q,wa as R,Ma as S,PE as T,FE as U,Pe as V,tm as W,kE as X,Ko as Y,an as Z,Sn as _,LE as a,kr as a0,em as a1,BE as a2,Wv as a3,sl as a4,Hh as a5,cl as a6,Qt as a7,om as a8,Wu as a9,Xu as aa,je as ab,ds as ac,La as ad,yi as ae,Vi as af,IE as b,Rc as c,WE as d,al as e,Dn as f,VE as g,Xe as h,D as i,M0 as j,GE as k,XE as l,Bv as m,Ds as n,zl as o,Qg as p,X1 as q,_t as r,vu as s,Vt as t,hh as u,mn as v,nm as w,Wi as x,Zv as y,i2 as z};
@@ -7302,7 +7302,7 @@ void main()
7302
7302
  `+i.vertexShader,i.vertexShader=i.vertexShader.replace("#include <project_vertex>",`#include <project_vertex>
7303
7303
  cloudPoint = (modelMatrix * vec4(transformed, 1.0)).xyz - cameraPosition;`);let s=`varying vec3 cloudPoint;
7304
7304
  `,r="";t.forEach((o,l)=>{const c=`cloud${l}_`;for(const[h,d]of Object.entries(o.uniforms))i.uniforms[c+h]=d;s+=ZS(c),r+=`diffuseColor.a *= ${c}transmissionAt(normalize(cloudPoint), length(cloudPoint));
7305
- `}),i.fragmentShader=s+i.fragmentShader,i.fragmentShader=i.fragmentShader.replace("#include <opaque_fragment>",r+"#include <opaque_fragment>")},e.needsUpdate=!0}meshes=new Map;signatures=new Map;extents=new Map;placed=[];frame;direction=new P;up=new P;lookAt=new qe;vertex=new P;centre=new P;right=new P;above=new P;set(e,t){this.placed=e,this.frame=t;const n=new Set(e.map(i=>i.sourceId));for(const[i,s]of this.meshes)n.has(i)||(this.dispose(s),this.meshes.delete(i),this.signatures.delete(i),this.extents.delete(i));for(const i of e){let s=this.meshes.get(i.sourceId);s||(s=new Ke(new es(1,1,jn.SEGMENTS,jn.SEGMENTS),new Yi({transparent:!0,depthWrite:!1,depthTest:!0,fog:!1,toneMapped:!1})),this.configureCloudMaterial(s.material),s.frustumCulled=!1,s.layers.set(nv),this.scene.add(s),this.meshes.set(i.sourceId,s)),s.renderOrder=h3+i.renderOrder,s.visible=!i.hidden&&i.shape.transparency<1,s.visible&&this.paint(s,i,t)}}place(e,t,n){const i=this.frame;if(i)for(const s of this.placed){const r=this.meshes.get(s.sourceId);if(!r||!r.visible)continue;const o=this.extents.get(s.sourceId);if(!o)continue;const{bounds:l}=s.shape;let c=l.x+l.width/2,h=l.y+l.height/2,d=!0;if(s.aim){const u=n(jn.directionOf(s.aim,this.direction));u&&Math.abs(u.ndcX)<jn.FURTHEST_NDC&&Math.abs(u.ndcY)<jn.FURTHEST_NDC?(c=(u.ndcX+1)/2*i.canvasWidthPx,h=(1-u.ndcY)/2*i.canvasHeightPx):d=!1}d?this.curve(r,e,t,i,o,c,h,s.distanceM):this.flat(r,e,i,o,s.distanceM)}}static FURTHEST_NDC=4;curve(e,t,n,i,s,r,o,l){const c=r-s.width/2,h=o-s.height/2,d=e.geometry.attributes.position,u=jn.SEGMENTS;let f=0;for(let p=0;p<=u;p++){const v=h+p/u*s.height;for(let m=0;m<=u;m++){const g=c+m/u*s.width;n(g/i.canvasWidthPx*2-1,-(v/i.canvasHeightPx*2-1),this.direction),this.vertex.copy(t.position).addScaledVector(this.direction,l),d.setXYZ(f++,this.vertex.x,this.vertex.y,this.vertex.z)}}d.needsUpdate=!0,e.matrixAutoUpdate=!1,e.matrix.identity(),e.matrixWorldNeedsUpdate=!0,e.scale.set(et.sizeMAt(l,i.projection.pxToDeg(s.width)),et.sizeMAt(l,i.projection.pxToDeg(s.height)),1)}flat(e,t,n,i,s){const r=e.geometry.attributes.position,o=jn.SEGMENTS,l=et.sizeMAt(s,n.projection.pxToDeg(i.width)),c=et.sizeMAt(s,n.projection.pxToDeg(i.height));this.up.set(0,1,0).applyQuaternion(t.quaternion),this.centre.copy(t.position).addScaledVector(this.direction,s),this.lookAt.lookAt(t.position,this.centre,this.up),this.right.setFromMatrixColumn(this.lookAt,0),this.above.setFromMatrixColumn(this.lookAt,1);let h=0;for(let d=0;d<=o;d++){const u=.5-d/o;for(let f=0;f<=o;f++){const p=f/o-.5;this.vertex.copy(this.centre).addScaledVector(this.right,p*l).addScaledVector(this.above,u*c),r.setXYZ(h++,this.vertex.x,this.vertex.y,this.vertex.z)}}r.needsUpdate=!0,e.matrixAutoUpdate=!1,e.matrix.identity(),e.matrixWorldNeedsUpdate=!0,e.scale.set(l,c,1)}static SEGMENTS=16;static directionOf(e,t){const n=e.azimuthDeg*Math.PI/180,i=e.altitudeDeg*Math.PI/180;return t.set(Math.sin(n)*Math.cos(i),Math.sin(i),-Math.cos(n)*Math.cos(i))}get any(){for(const e of this.meshes.values())if(e.visible)return!0;return!1}get furthestM(){return this.placed.reduce((e,t)=>Math.max(e,t.distanceM),0)}paint(e,t,n){const{shape:i}=t,s=Oh.paintExtent(i);this.extents.set(t.sourceId,s);const r=jn.signatureOf(i,n);if(this.signatures.get(t.sourceId)===r&&e.material.map)return;this.signatures.set(t.sourceId,r);const o=Math.min(n.scale,d3/Math.max(s.width,s.height,1)),l=Math.max(1,Math.ceil(s.width*o)),c=Math.max(1,Math.ceil(s.height*o)),h=e.material.map,d=h?.image??document.createElement("canvas"),u=d.width!==l||d.height!==c;u&&(d.width=l,d.height=c);const f=d.getContext("2d");if(!f)return;f.clearRect(0,0,l,c);const p=new Oh(f);if(p.setStarPoints(n.starPoints),p.setRoll(n.rollRad),p.paintInto(i,s,o),h&&!u){h.needsUpdate=!0;return}h?.dispose();const v=new Ri(d);v.colorSpace=Fn,v.minFilter=At,v.generateMipmaps=!1,e.material.map=v,e.material.needsUpdate=!0}static signatureOf(e,t){const{bounds:n}=e;return JSON.stringify([e.kind,Math.round(n.width*10),Math.round(n.height*10),e.color,e.angle,e.transparency,e.haloScale,e.blur??0,e.brightness??0,e.kind==="polygon"?e.points:void 0,t.scale,t.starPoints,t.rollRad])}dispose(e){e.removeFromParent(),e.geometry.dispose(),e.material.map?.dispose(),e.material.dispose()}clear(){for(const e of this.meshes.values())this.dispose(e);this.meshes.clear(),this.signatures.clear(),this.extents.clear(),this.placed=[]}}function u3(a,e){return JSON.stringify(a.cloudLayers)===JSON.stringify(e.cloudLayers)&&a.cloudCover===e.cloudCover&&a.cloudDarkness===e.cloudDarkness&&a.cloudBaseM===e.cloudBaseM&&a.highCloudCover===e.highCloudCover&&a.iceCrystalAlignment===e.iceCrystalAlignment&&a.lowerCloudCover===e.lowerCloudCover&&a.precipitationType===e.precipitationType&&a.precipitationIntensity===e.precipitationIntensity&&a.windDirectionDeg===e.windDirectionDeg&&a.windSpeed===e.windSpeed&&a.storm===e.storm}const al=900,fh=1,I0=.5,Fr=900,f3=6371e3,p3=3e4;function D0(a){const e=Math.sqrt(2*f3*Math.max(a,0));return Math.max(Fr,Math.min(e,p3))}const ph=.5,C0=850,m3=.03,rl=850,mh=4,R0=1.5,P0=-1,g3=6,cu=-4,L0=.2,ol=2600,v3=.97,y3=.38,N0=cu,b3=3,x3=.15,w3=.6,M3=40,S3=30,_3=[0,45,90,135,180,225,270,315],E3={en:["N","NE","E","SE","S","SW","W","NW"],fr:["N","NE","E","SE","S","SO","O","NO"]},T3=["en","fr"],A3=880,gh=40,I3=60,D3=10,C3=1,R3=150,P3=55,L3=.5,N3=2.05,O0=.265,k0=[[0,0],...Array.from({length:8},(a,e)=>{const t=e*Math.PI/4;return[Math.cos(t)*O0,Math.sin(t)*O0]})],vh=700,yh=250/1e3,O3=12,F0=5,bh=6,Ns=[.92,.92,.95],xh=[.15,.15,.19],U0={snow:{fallSpeedMPerS:2,size:.3,color:new le(1,1,1),driftSensitivity:1,radiusM:25,topYM:20,opacity:.75,poolSize:2400},hail:{fallSpeedMPerS:14,size:.5,color:new le(.95,.98,1),driftSensitivity:.25,radiusM:25,topYM:10,opacity:.95,poolSize:1200}},Pa=0,wh=0,k3=150,B0=3e3,Dr=20,F3=15,z0=Pa,U3=40,H0=1,B3=9;function G0(a){return H0+(B3-H0)*a}const z3=new le(.75,.82,.92),H3=10,G3=.5;function V3(a){return Zl(a/H3,G3,1)}const Aa=200,V0=.18,W0=.32,W3=.35,X3=new le(.85,.9,.98),X0=5,q0=.85,Y0=.01;function Mh(a,e){return Math.round(a*(Y0+(1-Y0)*e))}const K0=230,$0=.7,Z0=.05,q3=.6,Y3=.7,K3=.15,J0=.35,$3=3,Z3=1/12,J3=.5,j0=8,Q0=25,em=.12,j3={Venus:new le(1,.96,.85),Mars:new le(1,.55,.4),Jupiter:new le(.95,.87,.72),Saturn:new le(.92,.86,.68)};class mi{renderer;scene=new nc;phenomena=new jn(this.scene);camera;celestialGroup=new fn;skyMesh;groundMesh;terrainMesh;terrainProviders;terrainOrigin;terrainBuildToken=0;terrainAttribution;decorModelProvider=El[0].create();decorModelToken=0;decorModelCredits=new Map;starTiers=[];bodyMeshes=new Map;hitAreas=new Map;glareSprites=new Map;decorObjects=[];decorGroups=new Map;decorReferencePose;decorCurrentPose;decorTime=0;celestialLight=new Nb(16777215,0);celestialLightTarget=new It;skyLight=new Db(16777215,0,0);streetlightLights=new Map;compassSprites=[];showCompass=!1;compassHovered=!1;compassForced=!1;animationFrameId=null;raycaster=new Yc;weather=ym;observerElevationM=0;groundRadius=Fr;terrainRadius=Fr;cloudRendering="surface";layeredClouds;cloudLayerOffsetsM={};cloudOffsetM=new P;cloudFieldOffset=new P;cloudMesh;cirrusMesh;cirrusMaterial;cirrusUniforms;cloudMaterial;cloudUniforms;precipitationPoints;precipitationPositions;precipitationPhase;precipitationSpeedJitter;precipitationWobbleFreqJitter;precipitationWobbleAmpJitter;precipitationBounceRemaining;precipitationBounceHeight;precipitationBounceDuration;precipitationBounceVelX;precipitationBounceVelZ;precipitationUniforms;rainSystem;rainSplashSystem;rainCameraDirection=new P;rainLastVerticalFacing=-1;rainViewportSize=new Re;lightningArmed=!1;nextLightningAtS=null;lightningFlashRemainingS=0;baseFogColor=[0,0,0];lastSunPosition;lensFlare;sunCloudTransmission=1;sunUnhiddenFraction=1;lensFlareArtifactIntensity=0;sunWorldPosition=new P;sunVisible=!1;lensFlareScratch=new P;sunOcclusionRaycaster=new Yc;sunOcclusionDirectionScratch=new P;sunOcclusionRightScratch=new P;sunOcclusionUpScratch=new P;ufoOcclusionRaycaster=new Yc;projectionKind="rectilinear";starPoints=0;namedStars=[];equidistantPass;depthOfFieldPass;exposureAccumulation;exposureInstants=1;get developingExposure(){return this.exposureInstants>1&&this.exposureInstantAt!==void 0}static EXPOSURE_BUDGET_MS=12;exposureFrameId=null;exposureInstantsDone=0;exposureInstantAt;restatingExposure=!1;lensOptics;instrumentMagnitudeGain=0;meteorSystem;cometTail;iceHalos;rainbow;skyGlow;cometKey;onLightningFlash;constructor(e,t=A1(),n){this.renderer=new HS({canvas:e,antialias:!0}),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio||1,2)),this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=Ur,this.camera=new An(60,e.width/Math.max(e.height,1),.1,al*1.2),this.camera.position.set(0,1.6,0),this.terrainProviders=t,this.onLightningFlash=n,this.celestialLight.shadow.mapSize.set(1024,1024),this.celestialLight.shadow.camera.left=-120,this.celestialLight.shadow.camera.right=120,this.celestialLight.shadow.camera.top=120,this.celestialLight.shadow.camera.bottom=-120,this.celestialLight.shadow.camera.near=1,this.celestialLight.shadow.camera.far=1e3,this.celestialLight.shadow.bias=-.0015,this.celestialLight.target=this.celestialLightTarget,this.scene.add(this.celestialLight,this.celestialLightTarget,this.skyLight),this.scene.add(this.celestialGroup)}get currentTerrainAttribution(){return this.terrainAttribution}resize(e,t){this.renderer.setSize(e,t,!1),this.camera.aspect=e/Math.max(t,1),this.camera.updateProjectionMatrix(),this.render()}setCloudRendering(e){e!==this.cloudRendering&&(this.cloudRendering=e,this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.buildClouds(),this.buildCirrus(),this.render())}setCloudOffset(e,t={}){this.cloudOffsetM.set(e.x,0,e.z),this.cloudLayerOffsetsM=t,this.layeredClouds?.setOffsets(e,t),this.cloudFieldOffset.set(e.x*yh,0,e.z*yh);for(const n of[this.cloudUniforms,this.cirrusUniforms])n?.fieldOffset.value.copy(this.cloudFieldOffset);this.iceHalos?.setCloudOffset(this.layeredClouds?.cirrusMask?.offset??this.cloudFieldOffset)}setObserverPose(e){const t=((e.rollDeg??0)+this.gaitOffset.rollDeg)*Pn,n=(e.pitchDeg+this.lookPitchDeg+this.gaitOffset.pitchDeg)*Pn;if(e.headingDeg!==void 0?this.camera.rotation.set(n,-(e.headingDeg+this.lookYawDeg+this.gaitOffset.yawDeg)*Pn,t,"YXZ"):this.camera.rotation.set(n,this.camera.rotation.y,t,"YXZ"),e.elevationM!==this.observerElevationM&&(this.observerElevationM=e.elevationM,this.syncCloudLayer(),Math.abs(D0(e.elevationM)-this.groundRadius)>1&&(this.buildGround(),this.celestialGroup.scale.setScalar(this.groundRadius/Fr),this.camera.far=Math.max(al*1.2,this.groundRadius*2.5),this.camera.updateProjectionMatrix())),this.terrainMesh&&this.terrainOrigin&&e.lat!==void 0&&e.lng!==void 0){const i=un(this.terrainOrigin.lat,this.terrainOrigin.lng,e.lat,e.lng);this.terrainMesh.position.x=i.x,this.terrainMesh.position.z=i.z}this.poseCameraY=this.groundYUnder(0,0)+1.6+e.elevationM,this.camera.position.y=this.poseCameraY,this.celestialGroup.position.y=this.camera.position.y,this.camera.fov!==e.fovDeg&&(this.camera.fov=e.fovDeg,this.camera.updateProjectionMatrix(),this.updateCompassScale())}setTerrainProviders(e){this.terrainProviders=e,this.disposeMesh(this.terrainMesh),this.terrainMesh=void 0,this.terrainOrigin=void 0,this.terrainAttribution=void 0,this.applyGroundDepthWrite(),this.terrainBuildToken++}setTerrainOrigin(e,t,n){if(e===void 0||t===void 0)return;const i=this.groundRadius;if(this.terrainOrigin&&Math.abs(this.terrainRadius-i)<i*.1){const{x:l,z:c}=un(e,t,this.terrainOrigin.lat,this.terrainOrigin.lng);if(Math.sqrt(l*l+c*c)<R3*(i/Fr))return}const s=this.terrainOrigin,r=this.terrainRadius;this.terrainOrigin={lat:e,lng:t},this.terrainRadius=i;const o=++this.terrainBuildToken;RE(e,t,this.terrainProviders,i).then(({mesh:l,attribution:c})=>{if(o!==this.terrainBuildToken)return;const h=this.terrainMesh,d=s?un(e,t,s.lat,s.lng):void 0;h&&d&&Math.hypot(d.x,d.z)<=r&&(l.position.y=h.position.y+this.groundYOfPatch(h,d.x,d.z)),this.disposeMesh(this.terrainMesh),l.renderOrder=C3,this.terrainMesh=l,this.terrainAttribution=c,this.scene.add(l),this.applyGroundDepthWrite(),this.decorCurrentPose&&(this.setObserverPose(this.decorCurrentPose),this.updateDecorAnchoring(this.decorReferencePose,this.decorCurrentPose,this.decorTime)),this.render(),n?.()}).catch(l=>{console.warn("Terrain build failed, keeping the flat ground fallback:",l),n?.()})}setShowCompass(e){this.showCompass!==e&&(this.showCompass=e,this.disposeCompassLabels(),e&&this.buildCompassLabels(),this.render())}applyLensFlareTint(e){if(!this.lensFlare)return;const t=P3*this.sunCloudTransmission;this.lensFlare.uniforms.uColorGain.value.setRGB(t*e[0],t*e[1],t*e[2]),this.applyDazzleStrength()}applyDazzleStrength(){if(!this.lensFlare)return;const e=this.lastSunPosition?.altitudeDeg??-90,t=x_(e)*this.sunCloudTransmission*this.sunUnhiddenFraction,n=Ps(e);this.lensFlare.uniforms.uDazzleColour.value.setRGB(n[0],n[1],n[2]),this.lensFlare.uniforms.uVeilStrength.value=N3**2*Math.max(0,t)}setCompassHovered(e){this.compassHovered!==e&&(this.compassHovered=e,this.updateCompassVisibility())}setCompassForced(e){this.compassForced!==e&&(this.compassForced=e,this.updateCompassVisibility())}updateCompassVisibility(){const e=this.compassHovered||this.compassForced;for(const t of this.compassSprites)t.visible=e;this.render()}setWeather(e){u3(this.weather,e)||(this.weather=e,this.buildClouds(),this.buildCirrus(),this.buildPrecipitation(),this.lightningArmed=e.storm&&e.cloudDarkness>=J3,this.lightningArmed||(this.nextLightningAtS=null,this.lightningFlashRemainingS=0,this.restoreFogColor()),this.syncAnimationLoop(),this.render())}setDecor(e){if(this.decorObjects!==e){this.decorObjects=e,this.decorModelToken++,this.decorModelCredits.clear();for(const t of this.decorGroups.values())t.removeFromParent(),tn.dispose(t);this.decorGroups.clear(),this.streetlightLights.clear();for(const t of e){const n=tn.build(t,t.lit??!1);this.scene.add(n),this.decorGroups.set(t.id,n),t.kind==="streetlight"&&this.addStreetlightLight(t.id,n),this.loadDecorModel(t,this.decorModelToken)}this.celestialLight.castShadow=this.decorGroups.size>0}}setDecorModelProvider(e){this.decorModelProvider=e;const t=this.decorObjects;this.decorObjects=[],this.setDecor(t)}get currentDecorModelCredits(){return[...this.decorModelCredits.values()]}async loadDecorModel(e,t){const n=e.model;if(!(!n||!tn.usesModel(e)))try{const i=n.url?void 0:n.id?await this.decorModelProvider.entry(n.id):void 0,s=n.url??i?.url,r=n.credit??i?.credit;if(!s||!r)return;const o=await c3(s);if(t!==this.decorModelToken)return;const l=this.decorGroups.get(e.id);if(!l)return;tn.applyModel(l,e,o,{headingOffsetDeg:n.headingOffsetDeg??i?.headingOffsetDeg,depictedSizeM:i?.sizeM}),this.decorModelCredits.set(e.id,r),this.render()}catch(i){console.warn(`Keeping the built-in shape for decor "${e.id}":`,i)}}updateDecorAnchoring(e,t,n=0){this.decorReferencePose=e,this.decorCurrentPose=t,this.decorTime=n;const i=e?.lat!==void 0&&e.lng!==void 0&&t?.lat!==void 0&&t?.lng!==void 0?un(e.lat,e.lng,t.lat,t.lng):{x:0,z:0},s=this.decorObjects.find(c=>c.witnessSide!==void 0&&Na(c.kind));s||(i.x-=this.gaitOffset.eastM,i.z+=this.gaitOffset.northM,this.camera.position.y=this.poseCameraY+this.gaitOffset.upM,this.celestialGroup.position.y=this.camera.position.y);const r={x:0,z:0};let o=0;if(s){const c=tn.occupantView(s),h=-(s.headingDeg??0)*Pn,d=c.x*Math.cos(h)+c.z*Math.sin(h),u=-c.x*Math.sin(h)+c.z*Math.cos(h),f=s.eastM+i.x,p=-s.northM+i.z;r.x=-(f+d),r.z=-(p+u),this.camera.position.y=this.groundYUnder(f,p)+c.eyeY,this.camera.rotation.set(this.indoorLookPitchDeg*Pn,-(c.headingDeg+this.indoorLookYawDeg)*Pn,0,"YXZ")}for(const c of this.decorObjects){const h=this.decorGroups.get(c.id);if(!h)continue;const d=Qa(c,n),u=d.eastM+i.x+r.x,f=-d.northM+i.z+r.z;if(h.position.set(u,this.groundUnderFootprint(c,u,f,d.headingDeg)+d.altitudeM,f),c.kind==="crop"){const p=Math.hypot(u,f);h.visible=p<=k3}if(d.headingDeg!==void 0&&(h.rotation.y=-d.headingDeg*Pn),c.kind==="crop"&&h.visible){const p=this.terrainMesh,v=[p?.geometry.uuid,u-(p?.position.x??0),f-(p?.position.z??0),h.position.y-(p?.position.y??0),d.headingDeg,d.altitudeM].map(m=>typeof m=="number"?m.toFixed(4):m).join(":");h.userData.cropGroundKey!==v&&(tn.fitCropToGround(h,(m,g)=>this.groundYUnder(m,g)+d.altitudeM),h.userData.cropGroundKey=v)}o=Math.max(o,h.position.distanceTo(this.camera.position))}const l=Math.max(al*1.2,this.groundRadius*2.5,o*1.2);Math.abs(this.camera.far-l)>1&&(this.camera.far=l,this.camera.updateProjectionMatrix())}groundYUnder(e,t){const n=this.terrainMesh;return n?n.position.y+this.groundYOfPatch(n,e-n.position.x,t-n.position.z):wh}groundYOfPatch(e,t,n){const i=e.geometry.getAttribute("position"),s=Math.round(Math.sqrt(i.count));if(s<2||s*s!==i.count)return wh;const r=i.getX(0),o=i.getX(s-1),l=i.getZ(0),c=i.getZ((s-1)*s),h=Zl((t-r)/(o-r)*(s-1),0,s-1),d=Zl((n-l)/(c-l)*(s-1),0,s-1);if(!Number.isFinite(h)||!Number.isFinite(d))return wh;const u=Math.min(Math.floor(h),s-2),f=Math.min(Math.floor(d),s-2),p=h-u,v=d-f,m=(w,E)=>i.getY(w*s+E),g=m(f,u),_=m(f,u+1),M=m(f+1,u),x=m(f+1,u+1);return p+v<=1?g+(_-g)*p+(M-g)*v:x+(M-x)*(1-p)+(_-x)*(1-v)}groundUnderFootprint(e,t,n,i){return tn.groundUnderFootprint(e,t,n,i,(s,r)=>this.groundYUnder(s,r))}lookYawDeg=0;lookPitchDeg=0;poseCameraY=1.6;setGait(e){this.gaitOffset=e}gaitOffset={eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0};setLookOffset(e,t){this.lookYawDeg=e,this.lookPitchDeg=t}indoorLookYawDeg=0;indoorLookPitchDeg=0;setIndoorLook(e,t){this.indoorLookYawDeg=e,this.indoorLookPitchDeg=t}updateDecorLitState(e,t=0){for(const n of this.decorObjects){const i=this.decorGroups.get(n.id);if(i&&n.lights?.length&&tn.setLights(i,n.lights,e,i.position.distanceTo(this.camera.position),t),n.kind!=="streetlight"&&n.kind!=="vehicle")continue;const s=this.decorGroups.get(n.id);if(!s)continue;const r=Rl(n,e);tn.setLit(s,n.kind,r);const o=this.streetlightLights.get(n.id);o&&(o.visible=r)}}addStreetlightLight(e,t){const n=tn.bodyOf(t),i=n.children.find(r=>r.userData.emissive);if(!i)return;const s=new Pb(16764006,M3,S3);s.position.copy(i.position).multiply(n.scale),s.castShadow=!0,s.shadow.mapSize.set(512,512),s.shadow.bias=-.002,t.add(s),this.streetlightLights.set(e,s)}setAstronomy(e){const t=zd(e.sun.altitudeDeg),n=t.horizon;this.baseFogColor=n,this.lastSunPosition=e.sun,this.buildSky(e.sun),this.buildGround(),this.updateCloudLighting(e.sun,n),this.updateCelestialLight(e,t.zenith,n);const i=Hr(e.sun.altitudeDeg,this.instrumentMagnitudeGain);this.buildStars(e.stars,i),this.setBodyMesh("sun",e.sun,mh,new le(1,.96,.88),e.sun.magnitude),this.setMoonMesh(e.moon,i),this.buildPlanets(e.planets,i),this.buildComet(e.comet,i),this.buildIceHalos(e.sun,e.moon),this.buildRainbow(e.sun,e.moon),this.buildSkyGlow(e,t.zenith),this.scene.fog=new Du(new le(...n),this.groundRadius*.2,this.groundRadius),this.syncAnimationLoop(),this.render()}updateCelestialLight(e,t,n){this.skyLight.color.setRGB(t[0],t[1],t[2]),this.skyLight.groundColor.setRGB(n[0],n[1],n[2]),this.skyLight.intensity=w3;const i=e.sun.altitudeDeg>=N0,s=!i&&e.moon.altitudeDeg>=N0;if(!i&&!s){this.celestialLight.intensity=0;return}const r=i?e.sun:e.moon,{x:o,y:l,z:c}=bn(r.altitudeDeg,r.azimuthDeg,rl);this.celestialLight.position.set(o,l,c);const h=Ps(r.altitudeDeg);this.celestialLight.color.setRGB(h[0],h[1],h[2]);const d=Math.max(0,Math.sin(Math.max(r.altitudeDeg,0)*Pn));this.celestialLight.intensity=(i?b3:x3)*d,this.celestialLight.castShadow=this.decorGroups.size>0}setMeteorShower(e,t,n){this.meteorSystem||(this.meteorSystem=new Qt,this.celestialGroup.add(this.meteorSystem.object)),this.meteorSystem.setShower(e,t,n)}get meteorSchedule(){return this.meteorSystem?.schedule??[]}meteorMidpoint(e){return this.meteorSystem?.midpointOf(e)}updateMeteors(e){this.meteorSystem?.update(e)}setInstrument(e){this.projectionKind=e.projection;const t=st.starPointsOf(e),n=st.flareArtifactsOf(e);t===this.starPoints&&n===this.lensFlareArtifactIntensity||(this.starPoints=t,this.lensFlareArtifactIntensity=n,this.lensFlare&&(this.lensFlare.uniforms.uStarPoints.value=t,this.lensFlare.uniforms.uFlareIntensity.value=n),this.render())}setInstrumentGain(e){this.instrumentMagnitudeGain=Number.isFinite(e)?e:0}render(){this.restatingExposure||(this.renderOnce(),this.developingExposure&&this.startExposure())}setExposure(e,t){const n=t?Math.max(1,Math.round(e)):1;if(n===this.exposureInstants&&(n===1||t===this.exposureInstantAt)){this.exposureInstantAt=t;return}this.exposureInstants=n,this.exposureInstantAt=t,n===1&&(this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0),this.render()}renderOnce(e){const t=this.usableEquidistantPass();this.phenomena.setCloudLayers(this.layeredClouds?.volumes??[]),this.phenomena.place(this.camera,(s,r,o)=>this.directionAtScreenPoint(s,r,o),s=>this.screenPointOf(s));const n=this.phenomena.furthestM*1.2;n>this.camera.far&&(this.camera.far=n,this.camera.updateProjectionMatrix());const i=this.renderer.getRenderTarget();if(!t){this.updateLensFlarePosition();const s=this.usableDepthOfFieldPass();s?.setEncodesOutput(e===void 0),this.skyGlow?.setDestinationEncoded(e===void 0&&!s),e&&this.renderer.setRenderTarget(e),s?s.render(this.renderer,this.scene,this.camera,()=>this.renderPhenomenaPass()):(this.renderer.render(this.scene,this.camera),this.renderPhenomenaPass()),e&&this.renderer.setRenderTarget(i);return}t.setEncodesOutput(e===void 0),this.skyGlow?.setDestinationEncoded(!1),e&&this.renderer.setRenderTarget(e),t.render(this.renderer,this.scene,this.camera,this.camera.fov,()=>this.updateLensFlarePosition(),()=>this.renderPhenomenaPass()),e&&this.renderer.setRenderTarget(i)}renderPhenomenaPass(){if(!this.phenomena.any)return;const e=this.renderer.autoClear,t=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,this.renderer.clearDepth();for(const n of this.decorObjects){const i=this.decorGroups.get(n.id);i&&mi.markDecorDepth(i,n.kind!=="crop")}this.camera.layers.set(fh),this.scene.overrideMaterial=this.decorDepthMaterial,this.renderer.render(this.scene,this.camera),this.scene.overrideMaterial=null,this.camera.layers.set(nv),this.renderer.render(this.scene,this.camera),this.camera.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=t}decorDepthMaterial=new Yi({colorWrite:!1});static markDecorDepth(e,t){e.traverse(n=>{if(!(n instanceof Ke))return;const i=Array.isArray(n.material)?n.material[0]:n.material;t&&i.depthWrite!==!1&&i.blending!==ai?n.layers.enable(fh):n.layers.disable(fh)})}startExposure(){this.cancelExposure();const e=this.renderer.getDrawingBufferSize(new Re),t=Math.max(1,Math.round(e.x)),n=Math.max(1,Math.round(e.y));this.exposureAccumulation||(this.exposureAccumulation=new jS(t,n)),this.exposureAccumulation.resize(t,n),this.exposureAccumulation.open(this.renderer),this.exposureInstantsDone=0,this.exposureFrameId=requestAnimationFrame(()=>this.developExposure())}developExposure(){this.exposureFrameId=null;const e=this.exposureInstantAt,t=this.exposureAccumulation;if(!e||!t)return;const n=1/this.exposureInstants,i=performance.now()+mi.EXPOSURE_BUDGET_MS;do this.restateAt(e,this.exposureInstantsDone),this.renderOnce(t.instantTarget),t.add(this.renderer,n),this.exposureInstantsDone++;while(this.exposureInstantsDone<this.exposureInstants&&performance.now()<i);this.restateAt(e,0),t.develop(this.renderer,this.exposureInstants/this.exposureInstantsDone),this.exposureInstantsDone<this.exposureInstants&&(this.exposureFrameId=requestAnimationFrame(()=>this.developExposure()))}restateAt(e,t){this.restatingExposure=!0;try{e(t)}finally{this.restatingExposure=!1}}cancelExposure(){this.exposureFrameId!==null&&(cancelAnimationFrame(this.exposureFrameId),this.exposureFrameId=null)}setLensOptics(e){const t=this.lensOptics;this.lensOptics=e,(t===void 0!=(e===void 0)||t&&e&&(t.focalLengthMm!==e.focalLengthMm||t.fNumber!==e.fNumber||t.focusDistance!==e.focusDistance||t.frameHeightMm!==e.frameHeightMm))&&(e&&this.depthOfFieldPass&&this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.render())}usableDepthOfFieldPass(){const e=this.lensOptics;if(!e)return;const t=this.renderer.getDrawingBufferSize(new Re),n=Math.max(1,Math.round(t.x)),i=Math.max(1,Math.round(t.y));return this.depthOfFieldPass||(this.depthOfFieldPass=new Vr(n,i)),this.depthOfFieldPass.resize(n,i),this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.depthOfFieldPass}usableEquidistantPass(){if(this.projectionKind!=="equidistant")return;const e=this.renderer.getDrawingBufferSize(new Re);if(Gr.supports(this.camera.fov,e.x/Math.max(e.y,1)))return this.equidistantPass?this.equidistantPass.resize(e.x,e.y):this.equidistantPass=new Gr(e.x,e.y),this.equidistantPass}aimAtScreenPoint(e,t,n){const i=this.projectionKind==="equidistant"?this.equidistantPass:void 0;if(!i){e.setFromCamera(new Re(t,n),this.camera);return}const s=i.directionFor(t,n,this.camera.fov);this.camera.updateMatrixWorld(),e.ray.origin.setFromMatrixPosition(this.camera.matrixWorld),e.ray.direction.set(s.x,s.y,s.z).applyQuaternion(this.camera.quaternion).normalize(),e.camera=this.camera}pickCloudAt(e,t){return this.layeredClouds?.pickInstance(this.cloudDirectionAt(e,t))}cloudDirectionAt(e,t){return this.directionAtScreenPoint(e,t,new P)}directionAtScreenPoint(e,t,n){return this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),n.copy(this.ufoOcclusionRaycaster.ray.direction)}screenPointOf(e){this.camera.updateMatrixWorld();const t=this.screenPointScratch.copy(e).applyQuaternion(this.screenPointQuaternion.copy(this.camera.quaternion).invert());if(t.z>=0)return;const n=this.renderer.getDrawingBufferSize(this.screenPointSize),i=n.x/Math.max(n.y,1);if(this.projectionKind==="equidistant"&&this.equidistantPass)return Gr.ndcFor(t,this.camera.fov,i);const s=Math.tan(this.camera.fov/2*Pn);return{ndcX:t.x/-t.z/(i*s),ndcY:t.y/-t.z/s}}screenPointScratch=new P;screenPointQuaternion=new _s;screenPointSize=new Re;updateLensFlarePosition(){const e=this.lensFlare;if(!e)return;if(!this.sunVisible){e.mesh.visible=!1;return}if(this.camera.updateMatrixWorld(),this.lensFlareScratch.copy(this.sunWorldPosition).applyMatrix4(this.camera.matrixWorldInverse),this.lensFlareScratch.z>0){e.mesh.visible=!1;return}const t=this.sunVisibleFraction();if(t<=0){e.mesh.visible=!1;return}e.mesh.visible=!0,this.sunUnhiddenFraction=t,this.applyDazzleStrength();const n=this.lensFlareScratch.copy(this.sunWorldPosition).project(this.camera);e.uniforms.uLensPosition.value.set(n.x,n.y);const i=this.renderer.domElement.width,s=this.renderer.domElement.height;e.uniforms.uResolution.value.set(i,s),e.uniforms.uTanHalfFov.value=Math.tan(this.camera.fov*Math.PI/360)}sunVisibleFraction(){let e=0;for(const t of k0)this.isSunOccluded(t[0],t[1])||e++;return e/k0.length}raycastableDecor(){const e=[];for(const t of this.decorObjects){if(t.kind==="crop")continue;const n=this.decorGroups.get(t.id);n&&e.push(n)}return e}isSunOccluded(e=0,t=0){this.scene.updateMatrixWorld();const n=[];this.groundMesh&&n.push(this.groundMesh),this.terrainMesh&&n.push(this.terrainMesh);for(const o of this.raycastableDecor())n.push(o);if(n.length===0)return!1;const i=this.sunOcclusionDirectionScratch.copy(this.sunWorldPosition).sub(this.camera.position),s=i.length();if(i.normalize(),e!==0||t!==0){const o=Math.PI/180,l=this.sunOcclusionRightScratch.set(i.z,0,-i.x);l.lengthSq()<1e-9&&l.set(1,0,0),l.normalize();const c=this.sunOcclusionUpScratch.crossVectors(l,i).normalize();i.addScaledVector(l,e*o).addScaledVector(c,t*o).normalize()}this.sunOcclusionRaycaster.set(this.camera.position,i);const r=this.sunOcclusionRaycaster.intersectObjects(n,!0)[0];return r!==void 0&&r.distance<s}setPhenomena(e,t){this.phenomena.set(e,t)}decorDistancesAt(e,t,n){this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=I0;let i,s;for(const r of this.decorObjects){if(r.kind==="crop")continue;const o=this.decorGroups.get(r.id);if(!o)continue;const l=this.ufoOcclusionRaycaster.intersectObject(o,!0)[0];l&&(r.occludesSourceIds?.includes(n)?i=i===void 0?l.distance:Math.max(i,l.distance):s=s===void 0?l.distance:Math.min(s,l.distance))}return{behindM:i,inFrontM:s}}pickBodyAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const n=[...this.hitAreas.entries()],i=this.raycaster.intersectObjects(n.map(([,s])=>s))[0];if(i&&!this.groundHides(e,t))return n.find(([,s])=>s===i.object)?.[0]}pickStarAt(e,t){if(this.namedStars.length===0)return;this.aimAtScreenPoint(this.raycaster,e,t);const n=this.raycaster.ray.direction,i=Math.cos(m3*this.camera.fov*Math.PI/180);let s,r=i;for(const o of this.namedStars){const l=o.direction.dot(n);l>r&&(r=l,s={star:o.star,altitudeDeg:o.altitudeDeg})}return s&&this.groundHides(e,t)?void 0:s}groundHides(e,t){const n=[this.terrainMesh,this.groundMesh].filter(i=>i!==void 0);return n.length===0?!1:(this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=I0,this.ufoOcclusionRaycaster.intersectObjects(n,!0).length>0)}pickDecorAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const n=[...this.decorGroups.entries()],i=this.raycaster.intersectObjects(n.map(([,r])=>r),!0)[0];if(!i)return;let s=i.object;for(;s&&!n.some(([,r])=>r===s);)s=s.parent;return n.find(([,r])=>r===s)?.[0]}dispose(){this.stopTwinkle(),this.phenomena.clear(),this.terrainBuildToken++,this.disposeMesh(this.skyMesh),this.disposeMesh(this.groundMesh),this.disposeMesh(this.terrainMesh),this.disposeCloudSystem(),this.disposeCirrus(),this.disposePrecipitationPoints(),this.disposeRain(),this.disposeStarTiers(),this.meteorSystem?.dispose(),this.meteorSystem=void 0,this.iceHalos?.dispose(),this.iceHalos=void 0,this.rainbow?.dispose(),this.rainbow=void 0,this.skyGlow?.dispose(),this.skyGlow=void 0,this.depthOfFieldPass?.dispose(),this.depthOfFieldPass=void 0,this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0,this.cometTail?.dispose(),this.cometTail=void 0;for(const e of this.bodyMeshes.values())this.disposeMesh(e);this.bodyMeshes.clear();for(const e of[...this.hitAreas.keys()])this.disposeHitArea(e);for(const e of[...this.glareSprites.keys()])this.disposeGlare(e);this.disposeCompassLabels();for(const e of this.decorGroups.values())tn.dispose(e);this.decorGroups.clear(),this.streetlightLights.clear(),this.lensFlare&&(this.lensFlare.mesh.removeFromParent(),this.lensFlare.mesh.geometry.dispose(),this.lensFlare.mesh.material.dispose(),this.lensFlare=void 0),this.renderer.dispose()}animationsRunning=!1;startTwinkle(){if(this.animationFrameId!==null||!this.needsAnimationLoop())return;let e;const t=n=>{const i=e===void 0?0:Math.min((n-e)/1e3,Z3);e=n,this.updateTwinkle(n/1e3),this.updatePrecipitation(n/1e3,i),this.updateRain(i),this.updateLightning(n/1e3,i),this.lensFlare&&(this.lensFlare.uniforms.uTime.value=n/1e3),this.developingExposure||this.render(),this.animationFrameId=requestAnimationFrame(t)};this.animationFrameId=requestAnimationFrame(t)}setAnimationsRunning(e){e!==this.animationsRunning&&(this.animationsRunning=e,e?this.nextLightningAtS=null:this.lightningFlashRemainingS>0&&(this.lightningFlashRemainingS=0,this.restoreFogColor()),this.syncAnimationLoop(),e||this.render())}stopTwinkle(){this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}restoreFogColor(){this.scene.fog&&this.scene.fog.color.setRGB(...this.baseFogColor)}needsAnimationLoop(){return this.animationsRunning&&(this.starTiers.length>0||this.precipitationPoints!==void 0||this.rainSystem!==void 0||this.lightningArmed||this.lensFlare!==void 0&&this.sunVisible)}syncAnimationLoop(){this.needsAnimationLoop()?this.startTwinkle():this.stopTwinkle()}buildSky(e){this.disposeMesh(this.skyMesh);const t=new mn(al,32,16),n=t.attributes.position,i=[];for(let r=0;r<n.count;r++){const{altitudeDeg:o,azimuthDeg:l}=t_(n.getX(r),n.getY(r),n.getZ(r)),c=c_(o,l,e.azimuthDeg,e.altitudeDeg);i.push(c[0],c[1],c[2])}t.setAttribute("color",new Dt(i,3));const s=new Yi({vertexColors:!0,side:Vt,fog:!1,depthWrite:!1});this.skyMesh=new Ke(t,s),this.skyMesh.renderOrder=-1,this.celestialGroup.add(this.skyMesh)}buildGround(){this.disposeMesh(this.groundMesh),this.groundRadius=D0(this.observerElevationM);const e=new Pu(this.groundRadius,48),t=new ro({color:new le(ph,ph,ph),fog:!0});this.groundMesh=new Ke(e,t),this.groundMesh.rotation.x=-Math.PI/2,this.groundMesh.position.y=0,this.groundMesh.receiveShadow=!0,this.scene.add(this.groundMesh),this.applyGroundDepthWrite()}applyGroundDepthWrite(){const e=this.groundMesh?.material;if(!e)return;const t=this.terrainMesh===void 0;e.depthWrite!==t&&(e.depthWrite=t,e.needsUpdate=!0)}cloudTransmission(e){const t=bn(e.altitudeDeg,e.azimuthDeg,1);if(this.layeredClouds)return this.layeredClouds.transmissionAt(t);let n=1;const i=this.lowerCloudCover();i>0&&(n*=1-kt.alphaAt(t,Math.abs(this.cloudLayerOffset()),i,this.cloudFieldOffset)*v3);const s=this.weather.highCloudCover??0;return s>0&&(n*=1-kt.alphaAt(t,ol,s)*y3),Math.max(0,Math.min(1,n))}setBodyMesh(e,t,n,i,s){if(this.disposeMesh(this.bodyMeshes.get(e)),this.disposeHitArea(e),this.disposeGlare(e),t.altitudeDeg<cu){this.bodyMeshes.delete(e),e==="sun"&&(this.sunVisible=!1);return}const{x:r,y:o,z:l}=bn(t.altitudeDeg,t.azimuthDeg,rl),c=Ps(t.altitudeDeg),h=this.cloudTransmission(t),d=new le(i.r*c[0]*h,i.g*c[1]*h,i.b*c[2]*h),u=new mn(n,16,16),f=new Yi({color:d,fog:!1}),p=new Ke(u,f);p.position.set(r,o,l),this.celestialGroup.add(p),this.bodyMeshes.set(e,p),this.setHitArea(e,r,o,l,n);const v=s-2.5*Math.log10(Math.max(h,.001));if(e==="sun"&&(this.sunCloudTransmission=h),e!=="sun"&&this.setGlare(e,r,o,l,v,d),e==="sun"){this.sunVisible=!0;const m=this.celestialGroup.scale.x;this.sunWorldPosition.set(r*m,o*m+this.celestialGroup.position.y,l*m),this.lensFlare||(this.lensFlare=XE(),this.lensFlare.uniforms.uOpacity.value=L3,this.lensFlare.uniforms.uFlareIntensity.value=this.lensFlareArtifactIntensity,this.lensFlare.uniforms.uStarPoints.value=this.starPoints,this.scene.add(this.lensFlare.mesh)),this.applyLensFlareTint(c)}}setMoonMesh(e,t){const n="moon";if(this.disposeMesh(this.bodyMeshes.get(n)),this.disposeHitArea(n),this.disposeGlare(n),e.magnitude>t||e.altitudeDeg<cu){this.bodyMeshes.delete(n);return}const{x:i,y:s,z:r}=bn(e.altitudeDeg,e.azimuthDeg,rl),o=Ps(e.altitudeDeg),l=new le(o[0],o[1],o[2]),c=new Lr({map:lT(e.phase),color:l,fog:!1}),h=new Do(c);h.position.set(i,s,r);const d=mh*2;h.scale.set(d,d,1),this.celestialGroup.add(h),this.bodyMeshes.set(n,h),this.setHitArea(n,i,s,r,mh),this.setGlare(n,i,s,r,e.magnitude,l)}setHitArea(e,t,n,i,s){const r=new Lr({transparent:!0,opacity:0,depthTest:!1,depthWrite:!1,fog:!1}),o=new Do(r);o.position.set(t,n,i);const l=s*g3;o.scale.set(l,l,1),this.celestialGroup.add(o),this.hitAreas.set(e,o)}disposeHitArea(e){const t=this.hitAreas.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.hitAreas.delete(e))}setGlare(e,t,n,i,s,r){const o=u_(s);if(o<=0){this.disposeGlare(e);return}const l=m_(o),c=this.glareSprites.get(e),h=c??new Do(new Lr({map:oT(),transparent:!0,blending:ai,depthWrite:!1,fog:!1}));h.material.color.copy(r),h.material.opacity=y_(o),h.position.set(t,n,i),h.scale.set(l*2,l*2,1),c||(this.celestialGroup.add(h),this.glareSprites.set(e,h))}disposeGlare(e){const t=this.glareSprites.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.glareSprites.delete(e))}buildComet(e,t){const n=e&&`comet:${e.id}`;if(!e||!n||e.magnitude>t){this.disposeComet();return}this.cometKey&&this.cometKey!==n&&this.disposeComet();const i=nh(e.magnitude,t),s=ih(i);this.cometKey=n,this.setBodyMesh(n,e.position,R0*(.5+.5*i),new le(s,s,s),e.magnitude),this.cometTail||(this.cometTail=new Nn(rl),this.celestialGroup.add(this.cometTail.object)),this.cometTail.set(e.position,e.tailEnd,i)}buildIceHalos(e,t){this.iceHalos||(this.iceHalos=new pi,this.iceHalos.setCloudOffset(this.cloudFieldOffset),this.iceHalos.onReady=()=>this.render(),this.celestialGroup.add(this.iceHalos.object));const n=this.highCloudCover(),i=this.layeredClouds?.cirrusMask;if(this.iceHalos.setCloudOffset(i?.offset??this.cloudFieldOffset),n===void 0){this.iceHalos.update({x:0,y:1,z:0},-1,0,[1,1,1],{cover:0,layerHeight:ol},0);return}const s=this.lowerCloudCover(),r=je.deckLitUntilDeg(je.DECK_HEIGHT_M),o=e.altitudeDeg>-r?e:t,l=je.strength(n,s,o.altitudeDeg,r)*(o===e?1:L0),{x:c,y:h,z:d}=bn(o.altitudeDeg,o.azimuthDeg,1),u=Ps(o.altitudeDeg);this.iceHalos.update({x:c,y:h,z:d},o.altitudeDeg,l,[u[0],u[1],u[2]],{cover:i?.cover??n,layerHeight:i?.layerHeight??ol},i?.iceCrystalAlignment??this.weather.iceCrystalAlignment??.65)}buildRainbow(e,t){this.rainbow||(this.rainbow=new Wr,this.celestialGroup.add(this.rainbow.object));const n=this.weather.precipitationType==="rain"?this.weather.precipitationIntensity:0,i=e.altitudeDeg>0,s=i?e:t,r=this.lowerCloudCover(),o=L0*sn.moonlightShare(t.magnitude),l=sn.strength(n,r,s.altitudeDeg)*(i?1:o);if(l<=0){this.rainbow.update({x:0,y:1,z:0},0,[1,1,1],!0);return}const{x:c,y:h,z:d}=bn(s.altitudeDeg,s.azimuthDeg,1),u=Ps(s.altitudeDeg);this.rainbow.update({x:c,y:h,z:d},l,[u[0],u[1],u[2]],i)}buildSkyGlow(e,t){if(!e.frame){this.skyGlow?.hide();return}this.skyGlow||(this.skyGlow=new Jn,this.skyGlow.onReady=()=>this.render(),this.celestialGroup.add(this.skyGlow.object));const{date:n,observer:i}=e.frame,s=kn.galactic(n,i),r=mi.directionOf(s.centre),o=mi.directionOf(s.rotation),l=mi.directionOf(s.pole),c=new Be().set(r.x,r.y,r.z,o.x,o.y,o.z,l.x,l.y,l.z),h=mi.directionOf(kn.eclipticPole(n,i)),d=mi.directionOf(e.sun),u=d.clone().addScaledVector(h,-d.dot(h)).normalize();this.skyGlow.update({galactic:c,eclipticPole:h,sunLongitude:u,sunDirection:d,sunAltitudeDeg:e.sun.altitudeDeg,moon:{direction:mi.directionOf(e.moon),altitudeDeg:e.moon.altitudeDeg,phaseAngleDeg:We.phaseAngleOf(e.moon.phase.illuminatedFraction)},skyColor:new P(t[0],t[1],t[2])})}static directionOf(e){const{x:t,y:n,z:i}=bn(e.altitudeDeg,e.azimuthDeg,1);return new P(t,n,i).normalize()}disposeComet(){this.cometTail?.set(void 0,void 0,0),this.cometKey&&(this.disposeMesh(this.bodyMeshes.get(this.cometKey)),this.bodyMeshes.delete(this.cometKey),this.disposeHitArea(this.cometKey),this.disposeGlare(this.cometKey),this.cometKey=void 0)}buildPlanets(e,t){const n=new Set(["sun","moon",...this.cometKey?[this.cometKey]:[]]);for(const i of e){if(i.magnitude>t)continue;n.add(i.body);const s=nh(i.magnitude,t),r=ih(s),o=j3[i.body]??new le(1,1,1),l=new le(o.r*r,o.g*r,o.b*r),c=R0*(.5+.5*s);this.setBodyMesh(i.body,i.position,c,l,i.magnitude)}for(const i of[...this.bodyMeshes.keys()])n.has(i)||(this.disposeMesh(this.bodyMeshes.get(i)),this.bodyMeshes.delete(i),this.disposeHitArea(i),this.disposeGlare(i))}buildStars(e,t){if(this.disposeStarTiers(),this.namedStars=[],!e||e.catalog.count===0){this.syncAnimationLoop();return}const{catalog:n,date:i,observer:s}=e,r=Sh(1337),o=[];for(let l=0;l<n.count;l++){const c=n.mag[l];if(c>t)break;const{altitudeDeg:h,azimuthDeg:d}=rr(n.ra[l],n.dec[l],i,s);if(h<P0)continue;const{x:u,y:f,z:p}=bn(h,d,C0);o.push({x:u,y:f,z:p,brightness:nh(c,t),phase:r()*Math.PI*2,speedFactor:.7+r()*.6})}for(const l of EE){if(l.mag>t)continue;const{altitudeDeg:c,azimuthDeg:h}=rr(l.raHours,l.decDeg,i,s);if(c<P0)continue;const{x:d,y:u,z:f}=bn(c,h,C0);this.namedStars.push({star:l,direction:new P(d,u,f).normalize(),altitudeDeg:c})}this.starTiers=_g.map((l,c)=>{const h=o.filter(M=>M_(M.brightness)===c),d=new Float32Array(h.length*3),u=new Float32Array(h.length),f=new Float32Array(h.length),p=new Float32Array(h.length);h.forEach((M,x)=>{d[x*3]=M.x,d[x*3+1]=M.y,d[x*3+2]=M.z,u[x]=M.brightness,f[x]=M.phase,p[x]=M.speedFactor});const v=new Ct;v.setAttribute("position",new vt(d,3));const m=new vt(new Float32Array(h.length*3),3);v.setAttribute("color",m);const g=new sg({vertexColors:!0,size:l.size,sizeAttenuation:!1,fog:!1});Gs.apply(g);const _=new wl(v,g);return this.celestialGroup.add(_),{points:_,colorAttribute:m,brightness:u,phase:f,speedFactor:p}}),this.updateTwinkle(0),this.startTwinkle()}updateTwinkle(e){for(const t of this.starTiers){const n=t.colorAttribute.array;for(let i=0;i<t.brightness.length;i++){const s=E_(t.brightness[i],{phase:t.phase[i],speedFactor:t.speedFactor[i]},e),r=ih(t.brightness[i])*s;n[i*3]=r,n[i*3+1]=r,n[i*3+2]=r}t.colorAttribute.needsUpdate=!0}}buildClouds(){if(this.cloudRendering==="volume"||this.weather.cloudLayers!==void 0){this.layeredClouds||(this.disposeCloudSystem(),this.layeredClouds=new JS(this.celestialGroup,vh,this.cloudRendering)),this.disposeCirrus(),this.layeredClouds.update(this.weather,this.observerElevationM+1.6),this.layeredClouds.setOffsets(this.cloudOffsetM,this.cloudLayerOffsetsM),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}this.disposeCloudSystem();const e=this.lowerCloudCover();if(e<=0)return;const t=this.weather.cloudDarkness,n=new le(Ns[0]+(xh[0]-Ns[0])*t,Ns[1]+(xh[1]-Ns[1])*t,Ns[2]+(xh[2]-Ns[2])*t),{material:i,uniforms:s}=Od(n,e,Math.abs(this.cloudLayerOffset()));this.cloudMaterial=i,this.cloudUniforms=s,s.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);const r=kd(vh);this.cloudMesh=new Ke(r,i),this.cloudLayerOffset()<0&&(this.cloudMesh.scale.y=-1),this.cloudMesh.renderOrder=F0,this.celestialGroup.add(this.cloudMesh)}lowerCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(e=>e.type!=="cirrus").reduce((e,t)=>e*(1-t.coverage),1):this.weather.lowerCloudCover??this.weather.cloudCover}highCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(e=>e.type==="cirrus").reduce((e,t)=>e*(1-t.coverage),1):this.weather.highCloudCover}buildCirrus(){if(this.disposeCirrus(),this.layeredClouds)return;const e=this.weather.highCloudCover??0;if(e<=0)return;const{material:t,uniforms:n}=Od(new le(...Ns),e,ol,1);this.cirrusMaterial=t,this.cirrusUniforms=n,n.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.cirrusMesh=new Ke(kd(vh*1.04),t),this.cirrusMesh.renderOrder=F0-1,this.celestialGroup.add(this.cirrusMesh)}disposeCirrus(){this.cirrusMesh&&(this.cirrusMesh.removeFromParent(),this.cirrusMesh.geometry.dispose()),this.cirrusMaterial?.dispose(),this.cirrusMesh=void 0,this.cirrusMaterial=void 0,this.cirrusUniforms=void 0}syncCloudLayer(){this.layeredClouds?.update(this.weather,this.observerElevationM+1.6);const e=this.cloudLayerOffset();this.cloudUniforms&&(this.cloudUniforms.layerHeight.value=Math.abs(e)),this.cloudMesh&&(this.cloudMesh.scale.y=e<0?-1:1)}cloudLayerOffset(){const t=((this.weather.cloudBaseM??1e3)-this.observerElevationM)*yh;return Math.sign(t||1)*Math.max(Math.abs(t),O3)}updateCloudLighting(e,t){const n=[this.cloudUniforms,this.cirrusUniforms].filter(c=>c!==void 0);if(n.length===0&&!this.layeredClouds)return;const{x:i,y:s,z:r}=bn(e.altitudeDeg,e.azimuthDeg,1),o=Ps(e.altitudeDeg),l=Math.max(0,Math.sin(Math.max(e.altitudeDeg,0)*Pn));this.layeredClouds?.setLighting(new P(i,s,r),new le(o[0]*l,.96*o[1]*l,.88*o[2]*l),new le(...t),new le(...t));for(const c of n)c.sunDir.value.set(i,s,r),c.sunColor.value.setRGB(o[0]*l,.96*o[1]*l,.88*o[2]*l),c.ambientColor.value.setRGB(t[0],t[1],t[2])}disposeCloudSystem(){this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.cloudMesh&&(this.cloudMesh.removeFromParent(),this.cloudMesh.geometry.dispose()),this.cloudMaterial?.dispose(),this.cloudMesh=void 0,this.cloudMaterial=void 0,this.cloudUniforms=void 0}disposePrecipitationPoints(){this.precipitationPoints&&(this.precipitationPoints.removeFromParent(),this.precipitationPoints.geometry.dispose(),this.precipitationPoints.material.dispose()),this.precipitationPoints=void 0,this.precipitationPositions=void 0,this.precipitationPhase=void 0,this.precipitationSpeedJitter=void 0,this.precipitationWobbleFreqJitter=void 0,this.precipitationWobbleAmpJitter=void 0,this.precipitationBounceRemaining=void 0,this.precipitationBounceHeight=void 0,this.precipitationBounceDuration=void 0,this.precipitationBounceVelX=void 0,this.precipitationBounceVelZ=void 0,this.precipitationUniforms=void 0}buildPrecipitation(){this.disposePrecipitationPoints(),this.disposeRain();const e=this.weather.precipitationType;if(e==="none")return;if(e==="rain"){this.buildRain();return}const t=U0[e],n=t.poolSize,i=Sh(9001),s=new Float32Array(n*3),r=new Float32Array(n),o=new Float32Array(n),l=new Float32Array(n),c=new Float32Array(n),h=new Float32Array(n),d=new Float32Array(n),u=new Float32Array(n),f=new Float32Array(n),p=new Float32Array(n);for(let M=0;M<n;M++){const x=i()*Math.PI*2,w=i()*t.radiusM;s[M*3]=Math.cos(x)*w,s[M*3+1]=Pa+i()*(t.topYM-Pa),s[M*3+2]=Math.sin(x)*w,r[M]=i()*Math.PI*2,o[M]=.7+i()*.6,l[M]=.6+i()*.8,c[M]=.4+i()*1.2}const v=new Ct;v.setAttribute("position",new vt(s,3)),v.setDrawRange(0,Mh(n,this.weather.precipitationIntensity));const m={uSize:{value:t.size},uScale:{value:.5*this.renderer.domElement.height},uOpacity:{value:t.opacity},uColor:{value:t.color},uHazeColor:{value:new le(...this.baseFogColor)},uTexture:{value:Q3(e)},uNearFocusDistance:{value:X0},uHazeDistance:{value:t.radiusM*q0}},g=new Rt({uniforms:m,vertexShader:aT,fragmentShader:rT,transparent:!0,depthWrite:!1});this.precipitationUniforms=m;const _=new wl(v,g);_.renderOrder=bh,this.scene.add(_),this.precipitationPoints=_,this.precipitationPositions=s,this.precipitationPhase=r,this.precipitationSpeedJitter=o,this.precipitationWobbleFreqJitter=l,this.precipitationWobbleAmpJitter=c,this.precipitationBounceRemaining=h,this.precipitationBounceHeight=d,this.precipitationBounceDuration=u,this.precipitationBounceVelX=f,this.precipitationBounceVelZ=p}updatePrecipitation(e,t){if(!this.precipitationPoints||!this.precipitationPositions||!this.precipitationPhase||!this.precipitationSpeedJitter||(this.precipitationUniforms?.uHazeColor.value.setRGB(...this.baseFogColor),t<=0))return;const n=this.weather.precipitationType;if(n==="none"||n==="rain")return;const i=U0[n],s=this.weather.windDirectionDeg*Pn,r=Math.sin(s)*this.weather.windSpeed*i.driftSensitivity,o=-Math.cos(s)*this.weather.windSpeed*i.driftSensitivity,l=this.precipitationPositions,c=this.precipitationPhase,h=this.precipitationSpeedJitter,d=this.precipitationWobbleFreqJitter,u=this.precipitationWobbleAmpJitter,f=this.precipitationBounceRemaining,p=this.precipitationBounceHeight,v=this.precipitationBounceDuration,m=this.precipitationBounceVelX,g=this.precipitationBounceVelZ,_=n==="snow"&&d&&u,M=n==="hail"&&f&&p&&v&&m&&g;for(let x=0,w=0;x<l.length;x+=3,w++){if(M&&f[w]>0){if(f[w]-=t,f[w]<=0){const y=Math.random()*Math.PI*2,T=Math.sqrt(Math.random())*i.radiusM;l[x]=Math.cos(y)*T,l[x+1]=i.topYM,l[x+2]=Math.sin(y)*T,f[w]=0}else{const y=1-f[w]/v[w];l[x+1]=Pa+Math.sin(Math.PI*y)*p[w],l[x]=cl(l[x]+(r+m[w])*t,i.radiusM),l[x+2]=cl(l[x+2]+(o+g[w])*t,i.radiusM)}continue}let E=0,D=0;if(_){const y=q3*d[w],T=Y3*u[w];E=Math.sin(e*y*Math.PI*2+c[w])*T,D=Math.sin(e*y*Math.PI*2+c[w]+Math.PI/2)*T}if(l[x]+=(r+E)*t,l[x+1]-=i.fallSpeedMPerS*h[w]*t,l[x+2]+=(o+D)*t,l[x]=cl(l[x],i.radiusM),l[x+2]=cl(l[x+2],i.radiusM),l[x+1]<Pa){if(M){p[w]=J0*(.2+Math.random()*1.6),v[w]=K3*(.5+Math.random()),f[w]=v[w];const A=Math.random()*Math.PI*2,I=$3*(p[w]/J0);m[w]=Math.cos(A)*I,g[w]=Math.sin(A)*I,l[x+1]=Pa;continue}const y=Math.random()*Math.PI*2,T=Math.sqrt(Math.random())*i.radiusM;l[x]=Math.cos(y)*T,l[x+1]=i.topYM,l[x+2]=Math.sin(y)*T}}this.precipitationPoints.geometry.attributes.position.needsUpdate=!0}buildRain(){const e=G0(this.weather.precipitationIntensity);this.rainSystem=HE({count:B0,radiusM:Dr,heightM:F3,bottomYM:z0,overallSpeed:U3,color:z3,opacity:.85,visibleCount:Mh(B0,this.weather.precipitationIntensity),speedStreak:V3(e),pixelSize:K0,seed:9001,nearFocusDistanceM:X0,hazeDistanceM:Dr*q0,hazeColor:new le(...this.baseFogColor)}),this.rainLastVerticalFacing=-1,this.syncRainSlant(),this.rainSystem.points.renderOrder=bh,this.scene.add(this.rainSystem.points),this.buildRainSplashes()}buildRainSplashes(){const e=Sh(4242),t=new Float32Array(Aa*3),n=new Float32Array(Aa),i=new Float32Array(Aa),s=new Float32Array(Aa);for(let h=0;h<Aa;h++){const d=e()*Math.PI*2,u=Math.sqrt(e())*Dr;t[h*3]=Math.cos(d)*u,t[h*3+1]=z0,t[h*3+2]=Math.sin(d)*u,i[h]=ll(V0,W0),n[h]=e()*i[h],s[h]=n[h]/i[h]}const r=new Ct;r.setAttribute("position",new vt(t,3));const o=new vt(s,1);r.setAttribute("aLife",o),r.setDrawRange(0,Mh(Aa,this.weather.precipitationIntensity));const l=new Rt({uniforms:{uMaxSize:{value:W3},uScale:{value:.5*this.renderer.domElement.height},uColor:{value:X3},uTexture:{value:nT()}},vertexShader:iT,fragmentShader:sT,transparent:!0,depthWrite:!1}),c=new wl(r,l);c.renderOrder=bh,this.scene.add(c),this.rainSplashSystem={points:c,positions:t,life:n,duration:i,lifeAttribute:o}}disposeRain(){this.rainSystem&&(this.rainSystem.points.removeFromParent(),this.rainSystem.points.geometry.dispose(),this.rainSystem.points.material.dispose()),this.rainSystem=void 0,this.disposeRainSplashes()}disposeRainSplashes(){this.rainSplashSystem&&(this.rainSplashSystem.points.removeFromParent(),this.rainSplashSystem.points.geometry.dispose(),this.rainSplashSystem.points.material.dispose()),this.rainSplashSystem=void 0}syncRainSlant(){const e=this.rainSystem;if(!e)return;const t=this.weather.windDirectionDeg*Pn;e.uniforms.uDropVelocity.value.set(Math.sin(t)*this.weather.windSpeed,-G0(this.weather.precipitationIntensity),-Math.cos(t)*this.weather.windSpeed);const n=this.renderer.getSize(this.rainViewportSize);e.uniforms.uAspect.value=n.x/Math.max(n.y,1)}updateRain(e){const t=this.rainSystem;if(!t)return;t.uniforms.uTime.value+=e,t.uniforms.uHazeColor.value.setRGB(...this.baseFogColor);const n=this.weather.windDirectionDeg*Pn,i=Math.sin(n)*this.weather.windSpeed,s=-Math.cos(n)*this.weather.windSpeed,r=Dr,o=c=>(c%(r*2)+r*3)%(r*2)-r;t.uniforms.uWindOffset.value.set(o(t.uniforms.uWindOffset.value.x+i*e),o(t.uniforms.uWindOffset.value.y+s*e)),this.syncRainSlant(),this.camera.getWorldDirection(this.rainCameraDirection);const l=Math.abs(this.rainCameraDirection.y);if(Math.abs(l-this.rainLastVerticalFacing)>.001){this.rainLastVerticalFacing=l;const c=$0+(1-$0)*(1-l),h=Z0+(1-Z0)*(1-l);t.uniforms.uUvSquash.value=h,t.uniforms.uPixelSize.value=K0*c*(.5+.5*h)}this.updateRainSplashes(e)}updateRainSplashes(e){const t=this.rainSplashSystem;if(!t||e<=0)return;const{positions:n,life:i,duration:s,lifeAttribute:r}=t,o=r.array;for(let l=0,c=0;l<n.length;l+=3,c++){if(i[c]+=e,i[c]>=s[c]){const h=Math.random()*Math.PI*2,d=Math.sqrt(Math.random())*Dr;n[l]=Math.cos(h)*d,n[l+2]=Math.sin(h)*d,s[c]=ll(V0,W0),i[c]=0}o[c]=i[c]/s[c]}t.points.geometry.attributes.position.needsUpdate=!0,r.needsUpdate=!0}updateLightning(e,t){if(this.lightningArmed){if(this.lightningFlashRemainingS>0){this.lightningFlashRemainingS=Math.max(0,this.lightningFlashRemainingS-t);const n=this.lightningFlashRemainingS/em;this.scene.fog&&this.scene.fog.color.setRGB(this.baseFogColor[0]+(1-this.baseFogColor[0])*n,this.baseFogColor[1]+(1-this.baseFogColor[1])*n,this.baseFogColor[2]+(1-this.baseFogColor[2])*n);return}if(this.nextLightningAtS===null){this.nextLightningAtS=e+ll(j0,Q0);return}e>=this.nextLightningAtS&&(this.lightningFlashRemainingS=em,this.nextLightningAtS=e+ll(j0,Q0),this.onLightningFlash?.())}}buildCompassLabels(){const e=za(navigator.languages,T3),t=E3[e];this.compassSprites=_3.map((n,i)=>{const s=t[i],r=new Lr({map:cT(s),depthTest:!1,fog:!1}),o=new Do(r),{x:l,y:c,z:h}=bn(0,n,A3);return o.position.set(l,c,h),o.scale.set(gh,gh,1),o.renderOrder=D3,o.visible=this.compassHovered||this.compassForced,this.celestialGroup.add(o),o}),this.updateCompassScale()}updateCompassScale(){const e=this.camera.fov*Math.PI/360,t=I3*Math.PI/360,n=gh*Math.tan(e)/Math.tan(t);for(const i of this.compassSprites)i.scale.set(n,n,1)}disposeCompassLabels(){for(const e of this.compassSprites)e.removeFromParent(),e.material.map?.dispose(),e.material.dispose();this.compassSprites=[]}disposeStarTiers(){for(const e of this.starTiers)this.disposeMesh(e.points);this.starTiers=[]}disposeMesh(e){if(!e)return;e.removeFromParent(),"geometry"in e&&e.geometry.dispose();const t=e.material;for(const n of Array.isArray(t)?t:[t]){const i=n.map;i&&i.dispose(),n.dispose()}}}const Pn=Math.PI/180;function Zl(a,e,t){return Math.max(e,Math.min(t,a))}function ll(a,e){return a+Math.random()*(e-a)}function cl(a,e){return(a%(e*2)+e*3)%(e*2)-e}let hl,dl;function Q3(a){switch(a){case"snow":return eT();case"hail":return tT()}}function eT(){if(hl)return hl;const a=64,e=document.createElement("canvas");e.width=a,e.height=a;const t=e.getContext("2d"),n=t.createRadialGradient(a/2,a/2,0,a/2,a/2,a/2);return n.addColorStop(0,"rgba(255,255,255,0.95)"),n.addColorStop(.5,"rgba(255,255,255,0.55)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,a,a),hl=new Ri(e),hl}function tT(){if(dl)return dl;const a=64,e=document.createElement("canvas");e.width=a,e.height=a;const t=e.getContext("2d"),n=t.createRadialGradient(a/2,a/2,0,a/2,a/2,a/2);return n.addColorStop(0,"rgba(255,255,255,1)"),n.addColorStop(.55,"rgba(255,255,255,0.95)"),n.addColorStop(.8,"rgba(255,255,255,0.4)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,a,a),dl=new Ri(e),dl}let ul;function nT(){if(ul)return ul;const a=64,e=document.createElement("canvas");e.width=a,e.height=a;const t=e.getContext("2d"),n=t.createRadialGradient(a/2,a/2,0,a/2,a/2,a/2);return n.addColorStop(0,"rgba(255,255,255,0)"),n.addColorStop(.4,"rgba(255,255,255,0)"),n.addColorStop(.6,"rgba(255,255,255,0.9)"),n.addColorStop(.8,"rgba(255,255,255,0.25)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,a,a),ul=new Ri(e),ul}const iT=`
7305
+ `}),i.fragmentShader=s+i.fragmentShader,i.fragmentShader=i.fragmentShader.replace("#include <opaque_fragment>",r+"#include <opaque_fragment>")},e.needsUpdate=!0}meshes=new Map;signatures=new Map;extents=new Map;placed=[];frame;direction=new P;up=new P;lookAt=new qe;vertex=new P;centre=new P;right=new P;above=new P;set(e,t){this.placed=e,this.frame=t;const n=new Set(e.map(i=>i.sourceId));for(const[i,s]of this.meshes)n.has(i)||(this.dispose(s),this.meshes.delete(i),this.signatures.delete(i),this.extents.delete(i));for(const i of e){let s=this.meshes.get(i.sourceId);s||(s=new Ke(new es(1,1,jn.SEGMENTS,jn.SEGMENTS),new Yi({transparent:!0,depthWrite:!1,depthTest:!0,fog:!1,toneMapped:!1})),this.configureCloudMaterial(s.material),s.frustumCulled=!1,s.layers.set(nv),this.scene.add(s),this.meshes.set(i.sourceId,s)),s.renderOrder=h3+i.renderOrder,s.visible=!i.hidden&&i.shape.transparency<1,s.visible&&this.paint(s,i,t)}}place(e,t,n){const i=this.frame;if(i)for(const s of this.placed){const r=this.meshes.get(s.sourceId);if(!r||!r.visible)continue;const o=this.extents.get(s.sourceId);if(!o)continue;const{bounds:l}=s.shape;let c=l.x+l.width/2,h=l.y+l.height/2,d=!0;if(s.aim){const u=n(jn.directionOf(s.aim,this.direction));u&&Math.abs(u.ndcX)<jn.FURTHEST_NDC&&Math.abs(u.ndcY)<jn.FURTHEST_NDC?(c=(u.ndcX+1)/2*i.canvasWidthPx,h=(1-u.ndcY)/2*i.canvasHeightPx):d=!1}d?this.curve(r,e,t,i,o,c,h,s.distanceM):this.flat(r,e,i,o,s.distanceM)}}static FURTHEST_NDC=4;curve(e,t,n,i,s,r,o,l){const c=r-s.width/2,h=o-s.height/2,d=e.geometry.attributes.position,u=jn.SEGMENTS;let f=0;for(let p=0;p<=u;p++){const v=h+p/u*s.height;for(let m=0;m<=u;m++){const g=c+m/u*s.width;n(g/i.canvasWidthPx*2-1,-(v/i.canvasHeightPx*2-1),this.direction),this.vertex.copy(t.position).addScaledVector(this.direction,l),d.setXYZ(f++,this.vertex.x,this.vertex.y,this.vertex.z)}}d.needsUpdate=!0,e.matrixAutoUpdate=!1,e.matrix.identity(),e.matrixWorldNeedsUpdate=!0,e.scale.set(et.sizeMAt(l,i.projection.pxToDeg(s.width)),et.sizeMAt(l,i.projection.pxToDeg(s.height)),1)}flat(e,t,n,i,s){const r=e.geometry.attributes.position,o=jn.SEGMENTS,l=et.sizeMAt(s,n.projection.pxToDeg(i.width)),c=et.sizeMAt(s,n.projection.pxToDeg(i.height));this.up.set(0,1,0).applyQuaternion(t.quaternion),this.centre.copy(t.position).addScaledVector(this.direction,s),this.lookAt.lookAt(t.position,this.centre,this.up),this.right.setFromMatrixColumn(this.lookAt,0),this.above.setFromMatrixColumn(this.lookAt,1);let h=0;for(let d=0;d<=o;d++){const u=.5-d/o;for(let f=0;f<=o;f++){const p=f/o-.5;this.vertex.copy(this.centre).addScaledVector(this.right,p*l).addScaledVector(this.above,u*c),r.setXYZ(h++,this.vertex.x,this.vertex.y,this.vertex.z)}}r.needsUpdate=!0,e.matrixAutoUpdate=!1,e.matrix.identity(),e.matrixWorldNeedsUpdate=!0,e.scale.set(l,c,1)}static SEGMENTS=16;static directionOf(e,t){const n=e.azimuthDeg*Math.PI/180,i=e.altitudeDeg*Math.PI/180;return t.set(Math.sin(n)*Math.cos(i),Math.sin(i),-Math.cos(n)*Math.cos(i))}get any(){for(const e of this.meshes.values())if(e.visible)return!0;return!1}get furthestM(){return this.placed.reduce((e,t)=>Math.max(e,t.distanceM),0)}paint(e,t,n){const{shape:i}=t,s=Oh.paintExtent(i);this.extents.set(t.sourceId,s);const r=jn.signatureOf(i,n);if(this.signatures.get(t.sourceId)===r&&e.material.map)return;this.signatures.set(t.sourceId,r);const o=Math.min(n.scale,d3/Math.max(s.width,s.height,1)),l=Math.max(1,Math.ceil(s.width*o)),c=Math.max(1,Math.ceil(s.height*o)),h=e.material.map,d=h?.image??document.createElement("canvas"),u=d.width!==l||d.height!==c;u&&(d.width=l,d.height=c);const f=d.getContext("2d");if(!f)return;f.clearRect(0,0,l,c);const p=new Oh(f);if(p.setStarPoints(n.starPoints),p.setRoll(n.rollRad),p.paintInto(i,s,o),h&&!u){h.needsUpdate=!0;return}h?.dispose();const v=new Ri(d);v.colorSpace=Fn,v.minFilter=At,v.generateMipmaps=!1,e.material.map=v,e.material.needsUpdate=!0}static signatureOf(e,t){const{bounds:n}=e;return JSON.stringify([e.kind,Math.round(n.width*10),Math.round(n.height*10),e.color,e.angle,e.transparency,e.haloScale,e.blur??0,e.brightness??0,e.kind==="polygon"?e.points:void 0,t.scale,t.starPoints,t.rollRad])}dispose(e){e.removeFromParent(),e.geometry.dispose(),e.material.map?.dispose(),e.material.dispose()}clear(){for(const e of this.meshes.values())this.dispose(e);this.meshes.clear(),this.signatures.clear(),this.extents.clear(),this.placed=[]}}function u3(a,e){return JSON.stringify(a.cloudLayers)===JSON.stringify(e.cloudLayers)&&a.cloudCover===e.cloudCover&&a.cloudDarkness===e.cloudDarkness&&a.cloudBaseM===e.cloudBaseM&&a.highCloudCover===e.highCloudCover&&a.iceCrystalAlignment===e.iceCrystalAlignment&&a.lowerCloudCover===e.lowerCloudCover&&a.precipitationType===e.precipitationType&&a.precipitationIntensity===e.precipitationIntensity&&a.windDirectionDeg===e.windDirectionDeg&&a.windSpeed===e.windSpeed&&a.storm===e.storm}const al=900,fh=1,I0=.5,Fr=900,f3=6371e3,p3=3e4;function D0(a){const e=Math.sqrt(2*f3*Math.max(a,0));return Math.max(Fr,Math.min(e,p3))}const ph=.5,C0=850,m3=.03,rl=850,mh=4,R0=1.5,P0=-1,g3=6,cu=-4,L0=.2,ol=2600,v3=.97,y3=.38,N0=cu,b3=3,x3=.15,w3=.6,M3=40,S3=30,_3=[0,45,90,135,180,225,270,315],E3={en:["N","NE","E","SE","S","SW","W","NW"],fr:["N","NE","E","SE","S","SO","O","NO"]},T3=["en","fr"],A3=880,gh=40,I3=60,D3=10,C3=1,R3=150,P3=55,L3=.5,N3=2.05,O0=.265,k0=[[0,0],...Array.from({length:8},(a,e)=>{const t=e*Math.PI/4;return[Math.cos(t)*O0,Math.sin(t)*O0]})],vh=700,yh=250/1e3,O3=12,F0=5,bh=6,Ns=[.92,.92,.95],xh=[.15,.15,.19],U0={snow:{fallSpeedMPerS:2,size:.3,color:new le(1,1,1),driftSensitivity:1,radiusM:25,topYM:20,opacity:.75,poolSize:2400},hail:{fallSpeedMPerS:14,size:.5,color:new le(.95,.98,1),driftSensitivity:.25,radiusM:25,topYM:10,opacity:.95,poolSize:1200}},Pa=0,wh=0,k3=150,B0=3e3,Dr=20,F3=15,z0=Pa,U3=40,H0=1,B3=9;function G0(a){return H0+(B3-H0)*a}const z3=new le(.75,.82,.92),H3=10,G3=.5;function V3(a){return Zl(a/H3,G3,1)}const Aa=200,V0=.18,W0=.32,W3=.35,X3=new le(.85,.9,.98),X0=5,q0=.85,Y0=.01;function Mh(a,e){return Math.round(a*(Y0+(1-Y0)*e))}const K0=230,$0=.7,Z0=.05,q3=.6,Y3=.7,K3=.15,J0=.35,$3=3,Z3=1/12,J3=.5,j0=8,Q0=25,em=.12,j3={Venus:new le(1,.96,.85),Mars:new le(1,.55,.4),Jupiter:new le(.95,.87,.72),Saturn:new le(.92,.86,.68)};class mi{renderer;scene=new nc;phenomena=new jn(this.scene);camera;celestialGroup=new fn;skyMesh;groundMesh;terrainMesh;terrainProviders;terrainOrigin;terrainBuildToken=0;terrainAttribution;decorModelProvider=El[0].create();decorModelToken=0;decorModelCredits=new Map;starTiers=[];bodyMeshes=new Map;hitAreas=new Map;glareSprites=new Map;decorObjects=[];decorGroups=new Map;decorReferencePose;decorCurrentPose;decorTime=0;celestialLight=new Nb(16777215,0);celestialLightTarget=new It;skyLight=new Db(16777215,0,0);streetlightLights=new Map;compassSprites=[];showCompass=!1;compassHovered=!1;compassForced=!1;animationFrameId=null;raycaster=new Yc;weather=ym;observerElevationM=0;groundRadius=Fr;terrainRadius=Fr;cloudRendering="volume";layeredClouds;cloudLayerOffsetsM={};cloudOffsetM=new P;cloudFieldOffset=new P;cloudMesh;cirrusMesh;cirrusMaterial;cirrusUniforms;cloudMaterial;cloudUniforms;precipitationPoints;precipitationPositions;precipitationPhase;precipitationSpeedJitter;precipitationWobbleFreqJitter;precipitationWobbleAmpJitter;precipitationBounceRemaining;precipitationBounceHeight;precipitationBounceDuration;precipitationBounceVelX;precipitationBounceVelZ;precipitationUniforms;rainSystem;rainSplashSystem;rainCameraDirection=new P;rainLastVerticalFacing=-1;rainViewportSize=new Re;lightningArmed=!1;nextLightningAtS=null;lightningFlashRemainingS=0;baseFogColor=[0,0,0];lastSunPosition;lensFlare;sunCloudTransmission=1;sunUnhiddenFraction=1;lensFlareArtifactIntensity=0;sunWorldPosition=new P;sunVisible=!1;lensFlareScratch=new P;sunOcclusionRaycaster=new Yc;sunOcclusionDirectionScratch=new P;sunOcclusionRightScratch=new P;sunOcclusionUpScratch=new P;ufoOcclusionRaycaster=new Yc;projectionKind="rectilinear";starPoints=0;namedStars=[];equidistantPass;depthOfFieldPass;exposureAccumulation;exposureInstants=1;get developingExposure(){return this.exposureInstants>1&&this.exposureInstantAt!==void 0}static EXPOSURE_BUDGET_MS=12;exposureFrameId=null;exposureInstantsDone=0;exposureInstantAt;restatingExposure=!1;lensOptics;instrumentMagnitudeGain=0;meteorSystem;cometTail;iceHalos;rainbow;skyGlow;cometKey;onLightningFlash;constructor(e,t=A1(),n){this.renderer=new HS({canvas:e,antialias:!0}),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio||1,2)),this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=Ur,this.camera=new An(60,e.width/Math.max(e.height,1),.1,al*1.2),this.camera.position.set(0,1.6,0),this.terrainProviders=t,this.onLightningFlash=n,this.celestialLight.shadow.mapSize.set(1024,1024),this.celestialLight.shadow.camera.left=-120,this.celestialLight.shadow.camera.right=120,this.celestialLight.shadow.camera.top=120,this.celestialLight.shadow.camera.bottom=-120,this.celestialLight.shadow.camera.near=1,this.celestialLight.shadow.camera.far=1e3,this.celestialLight.shadow.bias=-.0015,this.celestialLight.target=this.celestialLightTarget,this.scene.add(this.celestialLight,this.celestialLightTarget,this.skyLight),this.scene.add(this.celestialGroup)}get currentTerrainAttribution(){return this.terrainAttribution}resize(e,t){this.renderer.setSize(e,t,!1),this.camera.aspect=e/Math.max(t,1),this.camera.updateProjectionMatrix(),this.render()}setCloudRendering(e){e!==this.cloudRendering&&(this.cloudRendering=e,this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.buildClouds(),this.buildCirrus(),this.render())}setCloudOffset(e,t={}){this.cloudOffsetM.set(e.x,0,e.z),this.cloudLayerOffsetsM=t,this.layeredClouds?.setOffsets(e,t),this.cloudFieldOffset.set(e.x*yh,0,e.z*yh);for(const n of[this.cloudUniforms,this.cirrusUniforms])n?.fieldOffset.value.copy(this.cloudFieldOffset);this.iceHalos?.setCloudOffset(this.layeredClouds?.cirrusMask?.offset??this.cloudFieldOffset)}setObserverPose(e){const t=((e.rollDeg??0)+this.gaitOffset.rollDeg)*Pn,n=(e.pitchDeg+this.lookPitchDeg+this.gaitOffset.pitchDeg)*Pn;if(e.headingDeg!==void 0?this.camera.rotation.set(n,-(e.headingDeg+this.lookYawDeg+this.gaitOffset.yawDeg)*Pn,t,"YXZ"):this.camera.rotation.set(n,this.camera.rotation.y,t,"YXZ"),e.elevationM!==this.observerElevationM&&(this.observerElevationM=e.elevationM,this.syncCloudLayer(),Math.abs(D0(e.elevationM)-this.groundRadius)>1&&(this.buildGround(),this.celestialGroup.scale.setScalar(this.groundRadius/Fr),this.camera.far=Math.max(al*1.2,this.groundRadius*2.5),this.camera.updateProjectionMatrix())),this.terrainMesh&&this.terrainOrigin&&e.lat!==void 0&&e.lng!==void 0){const i=un(this.terrainOrigin.lat,this.terrainOrigin.lng,e.lat,e.lng);this.terrainMesh.position.x=i.x,this.terrainMesh.position.z=i.z}this.poseCameraY=this.groundYUnder(0,0)+1.6+e.elevationM,this.camera.position.y=this.poseCameraY,this.celestialGroup.position.y=this.camera.position.y,this.camera.fov!==e.fovDeg&&(this.camera.fov=e.fovDeg,this.camera.updateProjectionMatrix(),this.updateCompassScale())}setTerrainProviders(e){this.terrainProviders=e,this.disposeMesh(this.terrainMesh),this.terrainMesh=void 0,this.terrainOrigin=void 0,this.terrainAttribution=void 0,this.applyGroundDepthWrite(),this.terrainBuildToken++}setTerrainOrigin(e,t,n){if(e===void 0||t===void 0)return;const i=this.groundRadius;if(this.terrainOrigin&&Math.abs(this.terrainRadius-i)<i*.1){const{x:l,z:c}=un(e,t,this.terrainOrigin.lat,this.terrainOrigin.lng);if(Math.sqrt(l*l+c*c)<R3*(i/Fr))return}const s=this.terrainOrigin,r=this.terrainRadius;this.terrainOrigin={lat:e,lng:t},this.terrainRadius=i;const o=++this.terrainBuildToken;RE(e,t,this.terrainProviders,i).then(({mesh:l,attribution:c})=>{if(o!==this.terrainBuildToken)return;const h=this.terrainMesh,d=s?un(e,t,s.lat,s.lng):void 0;h&&d&&Math.hypot(d.x,d.z)<=r&&(l.position.y=h.position.y+this.groundYOfPatch(h,d.x,d.z)),this.disposeMesh(this.terrainMesh),l.renderOrder=C3,this.terrainMesh=l,this.terrainAttribution=c,this.scene.add(l),this.applyGroundDepthWrite(),this.decorCurrentPose&&(this.setObserverPose(this.decorCurrentPose),this.updateDecorAnchoring(this.decorReferencePose,this.decorCurrentPose,this.decorTime)),this.render(),n?.()}).catch(l=>{console.warn("Terrain build failed, keeping the flat ground fallback:",l),n?.()})}setShowCompass(e){this.showCompass!==e&&(this.showCompass=e,this.disposeCompassLabels(),e&&this.buildCompassLabels(),this.render())}applyLensFlareTint(e){if(!this.lensFlare)return;const t=P3*this.sunCloudTransmission;this.lensFlare.uniforms.uColorGain.value.setRGB(t*e[0],t*e[1],t*e[2]),this.applyDazzleStrength()}applyDazzleStrength(){if(!this.lensFlare)return;const e=this.lastSunPosition?.altitudeDeg??-90,t=x_(e)*this.sunCloudTransmission*this.sunUnhiddenFraction,n=Ps(e);this.lensFlare.uniforms.uDazzleColour.value.setRGB(n[0],n[1],n[2]),this.lensFlare.uniforms.uVeilStrength.value=N3**2*Math.max(0,t)}setCompassHovered(e){this.compassHovered!==e&&(this.compassHovered=e,this.updateCompassVisibility())}setCompassForced(e){this.compassForced!==e&&(this.compassForced=e,this.updateCompassVisibility())}updateCompassVisibility(){const e=this.compassHovered||this.compassForced;for(const t of this.compassSprites)t.visible=e;this.render()}setWeather(e){u3(this.weather,e)||(this.weather=e,this.buildClouds(),this.buildCirrus(),this.buildPrecipitation(),this.lightningArmed=e.storm&&e.cloudDarkness>=J3,this.lightningArmed||(this.nextLightningAtS=null,this.lightningFlashRemainingS=0,this.restoreFogColor()),this.syncAnimationLoop(),this.render())}setDecor(e){if(this.decorObjects!==e){this.decorObjects=e,this.decorModelToken++,this.decorModelCredits.clear();for(const t of this.decorGroups.values())t.removeFromParent(),tn.dispose(t);this.decorGroups.clear(),this.streetlightLights.clear();for(const t of e){const n=tn.build(t,t.lit??!1);this.scene.add(n),this.decorGroups.set(t.id,n),t.kind==="streetlight"&&this.addStreetlightLight(t.id,n),this.loadDecorModel(t,this.decorModelToken)}this.celestialLight.castShadow=this.decorGroups.size>0}}setDecorModelProvider(e){this.decorModelProvider=e;const t=this.decorObjects;this.decorObjects=[],this.setDecor(t)}get currentDecorModelCredits(){return[...this.decorModelCredits.values()]}async loadDecorModel(e,t){const n=e.model;if(!(!n||!tn.usesModel(e)))try{const i=n.url?void 0:n.id?await this.decorModelProvider.entry(n.id):void 0,s=n.url??i?.url,r=n.credit??i?.credit;if(!s||!r)return;const o=await c3(s);if(t!==this.decorModelToken)return;const l=this.decorGroups.get(e.id);if(!l)return;tn.applyModel(l,e,o,{headingOffsetDeg:n.headingOffsetDeg??i?.headingOffsetDeg,depictedSizeM:i?.sizeM}),this.decorModelCredits.set(e.id,r),this.render()}catch(i){console.warn(`Keeping the built-in shape for decor "${e.id}":`,i)}}updateDecorAnchoring(e,t,n=0){this.decorReferencePose=e,this.decorCurrentPose=t,this.decorTime=n;const i=e?.lat!==void 0&&e.lng!==void 0&&t?.lat!==void 0&&t?.lng!==void 0?un(e.lat,e.lng,t.lat,t.lng):{x:0,z:0},s=this.decorObjects.find(c=>c.witnessSide!==void 0&&Na(c.kind));s||(i.x-=this.gaitOffset.eastM,i.z+=this.gaitOffset.northM,this.camera.position.y=this.poseCameraY+this.gaitOffset.upM,this.celestialGroup.position.y=this.camera.position.y);const r={x:0,z:0};let o=0;if(s){const c=tn.occupantView(s),h=-(s.headingDeg??0)*Pn,d=c.x*Math.cos(h)+c.z*Math.sin(h),u=-c.x*Math.sin(h)+c.z*Math.cos(h),f=s.eastM+i.x,p=-s.northM+i.z;r.x=-(f+d),r.z=-(p+u),this.camera.position.y=this.groundYUnder(f,p)+c.eyeY,this.camera.rotation.set(this.indoorLookPitchDeg*Pn,-(c.headingDeg+this.indoorLookYawDeg)*Pn,0,"YXZ")}for(const c of this.decorObjects){const h=this.decorGroups.get(c.id);if(!h)continue;const d=Qa(c,n),u=d.eastM+i.x+r.x,f=-d.northM+i.z+r.z;if(h.position.set(u,this.groundUnderFootprint(c,u,f,d.headingDeg)+d.altitudeM,f),c.kind==="crop"){const p=Math.hypot(u,f);h.visible=p<=k3}if(d.headingDeg!==void 0&&(h.rotation.y=-d.headingDeg*Pn),c.kind==="crop"&&h.visible){const p=this.terrainMesh,v=[p?.geometry.uuid,u-(p?.position.x??0),f-(p?.position.z??0),h.position.y-(p?.position.y??0),d.headingDeg,d.altitudeM].map(m=>typeof m=="number"?m.toFixed(4):m).join(":");h.userData.cropGroundKey!==v&&(tn.fitCropToGround(h,(m,g)=>this.groundYUnder(m,g)+d.altitudeM),h.userData.cropGroundKey=v)}o=Math.max(o,h.position.distanceTo(this.camera.position))}const l=Math.max(al*1.2,this.groundRadius*2.5,o*1.2);Math.abs(this.camera.far-l)>1&&(this.camera.far=l,this.camera.updateProjectionMatrix())}groundYUnder(e,t){const n=this.terrainMesh;return n?n.position.y+this.groundYOfPatch(n,e-n.position.x,t-n.position.z):wh}groundYOfPatch(e,t,n){const i=e.geometry.getAttribute("position"),s=Math.round(Math.sqrt(i.count));if(s<2||s*s!==i.count)return wh;const r=i.getX(0),o=i.getX(s-1),l=i.getZ(0),c=i.getZ((s-1)*s),h=Zl((t-r)/(o-r)*(s-1),0,s-1),d=Zl((n-l)/(c-l)*(s-1),0,s-1);if(!Number.isFinite(h)||!Number.isFinite(d))return wh;const u=Math.min(Math.floor(h),s-2),f=Math.min(Math.floor(d),s-2),p=h-u,v=d-f,m=(w,E)=>i.getY(w*s+E),g=m(f,u),_=m(f,u+1),M=m(f+1,u),x=m(f+1,u+1);return p+v<=1?g+(_-g)*p+(M-g)*v:x+(M-x)*(1-p)+(_-x)*(1-v)}groundUnderFootprint(e,t,n,i){return tn.groundUnderFootprint(e,t,n,i,(s,r)=>this.groundYUnder(s,r))}lookYawDeg=0;lookPitchDeg=0;poseCameraY=1.6;setGait(e){this.gaitOffset=e}gaitOffset={eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0};setLookOffset(e,t){this.lookYawDeg=e,this.lookPitchDeg=t}indoorLookYawDeg=0;indoorLookPitchDeg=0;setIndoorLook(e,t){this.indoorLookYawDeg=e,this.indoorLookPitchDeg=t}updateDecorLitState(e,t=0){for(const n of this.decorObjects){const i=this.decorGroups.get(n.id);if(i&&n.lights?.length&&tn.setLights(i,n.lights,e,i.position.distanceTo(this.camera.position),t),n.kind!=="streetlight"&&n.kind!=="vehicle")continue;const s=this.decorGroups.get(n.id);if(!s)continue;const r=Rl(n,e);tn.setLit(s,n.kind,r);const o=this.streetlightLights.get(n.id);o&&(o.visible=r)}}addStreetlightLight(e,t){const n=tn.bodyOf(t),i=n.children.find(r=>r.userData.emissive);if(!i)return;const s=new Pb(16764006,M3,S3);s.position.copy(i.position).multiply(n.scale),s.castShadow=!0,s.shadow.mapSize.set(512,512),s.shadow.bias=-.002,t.add(s),this.streetlightLights.set(e,s)}setAstronomy(e){const t=zd(e.sun.altitudeDeg),n=t.horizon;this.baseFogColor=n,this.lastSunPosition=e.sun,this.buildSky(e.sun),this.buildGround(),this.updateCloudLighting(e.sun,n),this.updateCelestialLight(e,t.zenith,n);const i=Hr(e.sun.altitudeDeg,this.instrumentMagnitudeGain);this.buildStars(e.stars,i),this.setBodyMesh("sun",e.sun,mh,new le(1,.96,.88),e.sun.magnitude),this.setMoonMesh(e.moon,i),this.buildPlanets(e.planets,i),this.buildComet(e.comet,i),this.buildIceHalos(e.sun,e.moon),this.buildRainbow(e.sun,e.moon),this.buildSkyGlow(e,t.zenith),this.scene.fog=new Du(new le(...n),this.groundRadius*.2,this.groundRadius),this.syncAnimationLoop(),this.render()}updateCelestialLight(e,t,n){this.skyLight.color.setRGB(t[0],t[1],t[2]),this.skyLight.groundColor.setRGB(n[0],n[1],n[2]),this.skyLight.intensity=w3;const i=e.sun.altitudeDeg>=N0,s=!i&&e.moon.altitudeDeg>=N0;if(!i&&!s){this.celestialLight.intensity=0;return}const r=i?e.sun:e.moon,{x:o,y:l,z:c}=bn(r.altitudeDeg,r.azimuthDeg,rl);this.celestialLight.position.set(o,l,c);const h=Ps(r.altitudeDeg);this.celestialLight.color.setRGB(h[0],h[1],h[2]);const d=Math.max(0,Math.sin(Math.max(r.altitudeDeg,0)*Pn));this.celestialLight.intensity=(i?b3:x3)*d,this.celestialLight.castShadow=this.decorGroups.size>0}setMeteorShower(e,t,n){this.meteorSystem||(this.meteorSystem=new Qt,this.celestialGroup.add(this.meteorSystem.object)),this.meteorSystem.setShower(e,t,n)}get meteorSchedule(){return this.meteorSystem?.schedule??[]}meteorMidpoint(e){return this.meteorSystem?.midpointOf(e)}updateMeteors(e){this.meteorSystem?.update(e)}setInstrument(e){this.projectionKind=e.projection;const t=st.starPointsOf(e),n=st.flareArtifactsOf(e);t===this.starPoints&&n===this.lensFlareArtifactIntensity||(this.starPoints=t,this.lensFlareArtifactIntensity=n,this.lensFlare&&(this.lensFlare.uniforms.uStarPoints.value=t,this.lensFlare.uniforms.uFlareIntensity.value=n),this.render())}setInstrumentGain(e){this.instrumentMagnitudeGain=Number.isFinite(e)?e:0}render(){this.restatingExposure||(this.renderOnce(),this.developingExposure&&this.startExposure())}setExposure(e,t){const n=t?Math.max(1,Math.round(e)):1;if(n===this.exposureInstants&&(n===1||t===this.exposureInstantAt)){this.exposureInstantAt=t;return}this.exposureInstants=n,this.exposureInstantAt=t,n===1&&(this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0),this.render()}renderOnce(e){const t=this.usableEquidistantPass();this.phenomena.setCloudLayers(this.layeredClouds?.volumes??[]),this.phenomena.place(this.camera,(s,r,o)=>this.directionAtScreenPoint(s,r,o),s=>this.screenPointOf(s));const n=this.phenomena.furthestM*1.2;n>this.camera.far&&(this.camera.far=n,this.camera.updateProjectionMatrix());const i=this.renderer.getRenderTarget();if(!t){this.updateLensFlarePosition();const s=this.usableDepthOfFieldPass();s?.setEncodesOutput(e===void 0),this.skyGlow?.setDestinationEncoded(e===void 0&&!s),e&&this.renderer.setRenderTarget(e),s?s.render(this.renderer,this.scene,this.camera,()=>this.renderPhenomenaPass()):(this.renderer.render(this.scene,this.camera),this.renderPhenomenaPass()),e&&this.renderer.setRenderTarget(i);return}t.setEncodesOutput(e===void 0),this.skyGlow?.setDestinationEncoded(!1),e&&this.renderer.setRenderTarget(e),t.render(this.renderer,this.scene,this.camera,this.camera.fov,()=>this.updateLensFlarePosition(),()=>this.renderPhenomenaPass()),e&&this.renderer.setRenderTarget(i)}renderPhenomenaPass(){if(!this.phenomena.any)return;const e=this.renderer.autoClear,t=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,this.renderer.clearDepth();for(const n of this.decorObjects){const i=this.decorGroups.get(n.id);i&&mi.markDecorDepth(i,n.kind!=="crop")}this.camera.layers.set(fh),this.scene.overrideMaterial=this.decorDepthMaterial,this.renderer.render(this.scene,this.camera),this.scene.overrideMaterial=null,this.camera.layers.set(nv),this.renderer.render(this.scene,this.camera),this.camera.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=t}decorDepthMaterial=new Yi({colorWrite:!1});static markDecorDepth(e,t){e.traverse(n=>{if(!(n instanceof Ke))return;const i=Array.isArray(n.material)?n.material[0]:n.material;t&&i.depthWrite!==!1&&i.blending!==ai?n.layers.enable(fh):n.layers.disable(fh)})}startExposure(){this.cancelExposure();const e=this.renderer.getDrawingBufferSize(new Re),t=Math.max(1,Math.round(e.x)),n=Math.max(1,Math.round(e.y));this.exposureAccumulation||(this.exposureAccumulation=new jS(t,n)),this.exposureAccumulation.resize(t,n),this.exposureAccumulation.open(this.renderer),this.exposureInstantsDone=0,this.exposureFrameId=requestAnimationFrame(()=>this.developExposure())}developExposure(){this.exposureFrameId=null;const e=this.exposureInstantAt,t=this.exposureAccumulation;if(!e||!t)return;const n=1/this.exposureInstants,i=performance.now()+mi.EXPOSURE_BUDGET_MS;do this.restateAt(e,this.exposureInstantsDone),this.renderOnce(t.instantTarget),t.add(this.renderer,n),this.exposureInstantsDone++;while(this.exposureInstantsDone<this.exposureInstants&&performance.now()<i);this.restateAt(e,0),t.develop(this.renderer,this.exposureInstants/this.exposureInstantsDone),this.exposureInstantsDone<this.exposureInstants&&(this.exposureFrameId=requestAnimationFrame(()=>this.developExposure()))}restateAt(e,t){this.restatingExposure=!0;try{e(t)}finally{this.restatingExposure=!1}}cancelExposure(){this.exposureFrameId!==null&&(cancelAnimationFrame(this.exposureFrameId),this.exposureFrameId=null)}setLensOptics(e){const t=this.lensOptics;this.lensOptics=e,(t===void 0!=(e===void 0)||t&&e&&(t.focalLengthMm!==e.focalLengthMm||t.fNumber!==e.fNumber||t.focusDistance!==e.focusDistance||t.frameHeightMm!==e.frameHeightMm))&&(e&&this.depthOfFieldPass&&this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.render())}usableDepthOfFieldPass(){const e=this.lensOptics;if(!e)return;const t=this.renderer.getDrawingBufferSize(new Re),n=Math.max(1,Math.round(t.x)),i=Math.max(1,Math.round(t.y));return this.depthOfFieldPass||(this.depthOfFieldPass=new Vr(n,i)),this.depthOfFieldPass.resize(n,i),this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.depthOfFieldPass}usableEquidistantPass(){if(this.projectionKind!=="equidistant")return;const e=this.renderer.getDrawingBufferSize(new Re);if(Gr.supports(this.camera.fov,e.x/Math.max(e.y,1)))return this.equidistantPass?this.equidistantPass.resize(e.x,e.y):this.equidistantPass=new Gr(e.x,e.y),this.equidistantPass}aimAtScreenPoint(e,t,n){const i=this.projectionKind==="equidistant"?this.equidistantPass:void 0;if(!i){e.setFromCamera(new Re(t,n),this.camera);return}const s=i.directionFor(t,n,this.camera.fov);this.camera.updateMatrixWorld(),e.ray.origin.setFromMatrixPosition(this.camera.matrixWorld),e.ray.direction.set(s.x,s.y,s.z).applyQuaternion(this.camera.quaternion).normalize(),e.camera=this.camera}pickCloudAt(e,t){return this.layeredClouds?.pickInstance(this.cloudDirectionAt(e,t))}cloudDirectionAt(e,t){return this.directionAtScreenPoint(e,t,new P)}directionAtScreenPoint(e,t,n){return this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),n.copy(this.ufoOcclusionRaycaster.ray.direction)}screenPointOf(e){this.camera.updateMatrixWorld();const t=this.screenPointScratch.copy(e).applyQuaternion(this.screenPointQuaternion.copy(this.camera.quaternion).invert());if(t.z>=0)return;const n=this.renderer.getDrawingBufferSize(this.screenPointSize),i=n.x/Math.max(n.y,1);if(this.projectionKind==="equidistant"&&this.equidistantPass)return Gr.ndcFor(t,this.camera.fov,i);const s=Math.tan(this.camera.fov/2*Pn);return{ndcX:t.x/-t.z/(i*s),ndcY:t.y/-t.z/s}}screenPointScratch=new P;screenPointQuaternion=new _s;screenPointSize=new Re;updateLensFlarePosition(){const e=this.lensFlare;if(!e)return;if(!this.sunVisible){e.mesh.visible=!1;return}if(this.camera.updateMatrixWorld(),this.lensFlareScratch.copy(this.sunWorldPosition).applyMatrix4(this.camera.matrixWorldInverse),this.lensFlareScratch.z>0){e.mesh.visible=!1;return}const t=this.sunVisibleFraction();if(t<=0){e.mesh.visible=!1;return}e.mesh.visible=!0,this.sunUnhiddenFraction=t,this.applyDazzleStrength();const n=this.lensFlareScratch.copy(this.sunWorldPosition).project(this.camera);e.uniforms.uLensPosition.value.set(n.x,n.y);const i=this.renderer.domElement.width,s=this.renderer.domElement.height;e.uniforms.uResolution.value.set(i,s),e.uniforms.uTanHalfFov.value=Math.tan(this.camera.fov*Math.PI/360)}sunVisibleFraction(){let e=0;for(const t of k0)this.isSunOccluded(t[0],t[1])||e++;return e/k0.length}raycastableDecor(){const e=[];for(const t of this.decorObjects){if(t.kind==="crop")continue;const n=this.decorGroups.get(t.id);n&&e.push(n)}return e}isSunOccluded(e=0,t=0){this.scene.updateMatrixWorld();const n=[];this.groundMesh&&n.push(this.groundMesh),this.terrainMesh&&n.push(this.terrainMesh);for(const o of this.raycastableDecor())n.push(o);if(n.length===0)return!1;const i=this.sunOcclusionDirectionScratch.copy(this.sunWorldPosition).sub(this.camera.position),s=i.length();if(i.normalize(),e!==0||t!==0){const o=Math.PI/180,l=this.sunOcclusionRightScratch.set(i.z,0,-i.x);l.lengthSq()<1e-9&&l.set(1,0,0),l.normalize();const c=this.sunOcclusionUpScratch.crossVectors(l,i).normalize();i.addScaledVector(l,e*o).addScaledVector(c,t*o).normalize()}this.sunOcclusionRaycaster.set(this.camera.position,i);const r=this.sunOcclusionRaycaster.intersectObjects(n,!0)[0];return r!==void 0&&r.distance<s}setPhenomena(e,t){this.phenomena.set(e,t)}decorDistancesAt(e,t,n){this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=I0;let i,s;for(const r of this.decorObjects){if(r.kind==="crop")continue;const o=this.decorGroups.get(r.id);if(!o)continue;const l=this.ufoOcclusionRaycaster.intersectObject(o,!0)[0];l&&(r.occludesSourceIds?.includes(n)?i=i===void 0?l.distance:Math.max(i,l.distance):s=s===void 0?l.distance:Math.min(s,l.distance))}return{behindM:i,inFrontM:s}}pickBodyAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const n=[...this.hitAreas.entries()],i=this.raycaster.intersectObjects(n.map(([,s])=>s))[0];if(i&&!this.groundHides(e,t))return n.find(([,s])=>s===i.object)?.[0]}pickStarAt(e,t){if(this.namedStars.length===0)return;this.aimAtScreenPoint(this.raycaster,e,t);const n=this.raycaster.ray.direction,i=Math.cos(m3*this.camera.fov*Math.PI/180);let s,r=i;for(const o of this.namedStars){const l=o.direction.dot(n);l>r&&(r=l,s={star:o.star,altitudeDeg:o.altitudeDeg})}return s&&this.groundHides(e,t)?void 0:s}groundHides(e,t){const n=[this.terrainMesh,this.groundMesh].filter(i=>i!==void 0);return n.length===0?!1:(this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=I0,this.ufoOcclusionRaycaster.intersectObjects(n,!0).length>0)}pickDecorAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const n=[...this.decorGroups.entries()],i=this.raycaster.intersectObjects(n.map(([,r])=>r),!0)[0];if(!i)return;let s=i.object;for(;s&&!n.some(([,r])=>r===s);)s=s.parent;return n.find(([,r])=>r===s)?.[0]}dispose(){this.stopTwinkle(),this.phenomena.clear(),this.terrainBuildToken++,this.disposeMesh(this.skyMesh),this.disposeMesh(this.groundMesh),this.disposeMesh(this.terrainMesh),this.disposeCloudSystem(),this.disposeCirrus(),this.disposePrecipitationPoints(),this.disposeRain(),this.disposeStarTiers(),this.meteorSystem?.dispose(),this.meteorSystem=void 0,this.iceHalos?.dispose(),this.iceHalos=void 0,this.rainbow?.dispose(),this.rainbow=void 0,this.skyGlow?.dispose(),this.skyGlow=void 0,this.depthOfFieldPass?.dispose(),this.depthOfFieldPass=void 0,this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0,this.cometTail?.dispose(),this.cometTail=void 0;for(const e of this.bodyMeshes.values())this.disposeMesh(e);this.bodyMeshes.clear();for(const e of[...this.hitAreas.keys()])this.disposeHitArea(e);for(const e of[...this.glareSprites.keys()])this.disposeGlare(e);this.disposeCompassLabels();for(const e of this.decorGroups.values())tn.dispose(e);this.decorGroups.clear(),this.streetlightLights.clear(),this.lensFlare&&(this.lensFlare.mesh.removeFromParent(),this.lensFlare.mesh.geometry.dispose(),this.lensFlare.mesh.material.dispose(),this.lensFlare=void 0),this.renderer.dispose()}animationsRunning=!1;startTwinkle(){if(this.animationFrameId!==null||!this.needsAnimationLoop())return;let e;const t=n=>{const i=e===void 0?0:Math.min((n-e)/1e3,Z3);e=n,this.updateTwinkle(n/1e3),this.updatePrecipitation(n/1e3,i),this.updateRain(i),this.updateLightning(n/1e3,i),this.lensFlare&&(this.lensFlare.uniforms.uTime.value=n/1e3),this.developingExposure||this.render(),this.animationFrameId=requestAnimationFrame(t)};this.animationFrameId=requestAnimationFrame(t)}setAnimationsRunning(e){e!==this.animationsRunning&&(this.animationsRunning=e,e?this.nextLightningAtS=null:this.lightningFlashRemainingS>0&&(this.lightningFlashRemainingS=0,this.restoreFogColor()),this.syncAnimationLoop(),e||this.render())}stopTwinkle(){this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}restoreFogColor(){this.scene.fog&&this.scene.fog.color.setRGB(...this.baseFogColor)}needsAnimationLoop(){return this.animationsRunning&&(this.starTiers.length>0||this.precipitationPoints!==void 0||this.rainSystem!==void 0||this.lightningArmed||this.lensFlare!==void 0&&this.sunVisible)}syncAnimationLoop(){this.needsAnimationLoop()?this.startTwinkle():this.stopTwinkle()}buildSky(e){this.disposeMesh(this.skyMesh);const t=new mn(al,32,16),n=t.attributes.position,i=[];for(let r=0;r<n.count;r++){const{altitudeDeg:o,azimuthDeg:l}=t_(n.getX(r),n.getY(r),n.getZ(r)),c=c_(o,l,e.azimuthDeg,e.altitudeDeg);i.push(c[0],c[1],c[2])}t.setAttribute("color",new Dt(i,3));const s=new Yi({vertexColors:!0,side:Vt,fog:!1,depthWrite:!1});this.skyMesh=new Ke(t,s),this.skyMesh.renderOrder=-1,this.celestialGroup.add(this.skyMesh)}buildGround(){this.disposeMesh(this.groundMesh),this.groundRadius=D0(this.observerElevationM);const e=new Pu(this.groundRadius,48),t=new ro({color:new le(ph,ph,ph),fog:!0});this.groundMesh=new Ke(e,t),this.groundMesh.rotation.x=-Math.PI/2,this.groundMesh.position.y=0,this.groundMesh.receiveShadow=!0,this.scene.add(this.groundMesh),this.applyGroundDepthWrite()}applyGroundDepthWrite(){const e=this.groundMesh?.material;if(!e)return;const t=this.terrainMesh===void 0;e.depthWrite!==t&&(e.depthWrite=t,e.needsUpdate=!0)}cloudTransmission(e){const t=bn(e.altitudeDeg,e.azimuthDeg,1);if(this.layeredClouds)return this.layeredClouds.transmissionAt(t);let n=1;const i=this.lowerCloudCover();i>0&&(n*=1-kt.alphaAt(t,Math.abs(this.cloudLayerOffset()),i,this.cloudFieldOffset)*v3);const s=this.weather.highCloudCover??0;return s>0&&(n*=1-kt.alphaAt(t,ol,s)*y3),Math.max(0,Math.min(1,n))}setBodyMesh(e,t,n,i,s){if(this.disposeMesh(this.bodyMeshes.get(e)),this.disposeHitArea(e),this.disposeGlare(e),t.altitudeDeg<cu){this.bodyMeshes.delete(e),e==="sun"&&(this.sunVisible=!1);return}const{x:r,y:o,z:l}=bn(t.altitudeDeg,t.azimuthDeg,rl),c=Ps(t.altitudeDeg),h=this.cloudTransmission(t),d=new le(i.r*c[0]*h,i.g*c[1]*h,i.b*c[2]*h),u=new mn(n,16,16),f=new Yi({color:d,fog:!1}),p=new Ke(u,f);p.position.set(r,o,l),this.celestialGroup.add(p),this.bodyMeshes.set(e,p),this.setHitArea(e,r,o,l,n);const v=s-2.5*Math.log10(Math.max(h,.001));if(e==="sun"&&(this.sunCloudTransmission=h),e!=="sun"&&this.setGlare(e,r,o,l,v,d),e==="sun"){this.sunVisible=!0;const m=this.celestialGroup.scale.x;this.sunWorldPosition.set(r*m,o*m+this.celestialGroup.position.y,l*m),this.lensFlare||(this.lensFlare=XE(),this.lensFlare.uniforms.uOpacity.value=L3,this.lensFlare.uniforms.uFlareIntensity.value=this.lensFlareArtifactIntensity,this.lensFlare.uniforms.uStarPoints.value=this.starPoints,this.scene.add(this.lensFlare.mesh)),this.applyLensFlareTint(c)}}setMoonMesh(e,t){const n="moon";if(this.disposeMesh(this.bodyMeshes.get(n)),this.disposeHitArea(n),this.disposeGlare(n),e.magnitude>t||e.altitudeDeg<cu){this.bodyMeshes.delete(n);return}const{x:i,y:s,z:r}=bn(e.altitudeDeg,e.azimuthDeg,rl),o=Ps(e.altitudeDeg),l=new le(o[0],o[1],o[2]),c=new Lr({map:lT(e.phase),color:l,fog:!1}),h=new Do(c);h.position.set(i,s,r);const d=mh*2;h.scale.set(d,d,1),this.celestialGroup.add(h),this.bodyMeshes.set(n,h),this.setHitArea(n,i,s,r,mh),this.setGlare(n,i,s,r,e.magnitude,l)}setHitArea(e,t,n,i,s){const r=new Lr({transparent:!0,opacity:0,depthTest:!1,depthWrite:!1,fog:!1}),o=new Do(r);o.position.set(t,n,i);const l=s*g3;o.scale.set(l,l,1),this.celestialGroup.add(o),this.hitAreas.set(e,o)}disposeHitArea(e){const t=this.hitAreas.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.hitAreas.delete(e))}setGlare(e,t,n,i,s,r){const o=u_(s);if(o<=0){this.disposeGlare(e);return}const l=m_(o),c=this.glareSprites.get(e),h=c??new Do(new Lr({map:oT(),transparent:!0,blending:ai,depthWrite:!1,fog:!1}));h.material.color.copy(r),h.material.opacity=y_(o),h.position.set(t,n,i),h.scale.set(l*2,l*2,1),c||(this.celestialGroup.add(h),this.glareSprites.set(e,h))}disposeGlare(e){const t=this.glareSprites.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.glareSprites.delete(e))}buildComet(e,t){const n=e&&`comet:${e.id}`;if(!e||!n||e.magnitude>t){this.disposeComet();return}this.cometKey&&this.cometKey!==n&&this.disposeComet();const i=nh(e.magnitude,t),s=ih(i);this.cometKey=n,this.setBodyMesh(n,e.position,R0*(.5+.5*i),new le(s,s,s),e.magnitude),this.cometTail||(this.cometTail=new Nn(rl),this.celestialGroup.add(this.cometTail.object)),this.cometTail.set(e.position,e.tailEnd,i)}buildIceHalos(e,t){this.iceHalos||(this.iceHalos=new pi,this.iceHalos.setCloudOffset(this.cloudFieldOffset),this.iceHalos.onReady=()=>this.render(),this.celestialGroup.add(this.iceHalos.object));const n=this.highCloudCover(),i=this.layeredClouds?.cirrusMask;if(this.iceHalos.setCloudOffset(i?.offset??this.cloudFieldOffset),n===void 0){this.iceHalos.update({x:0,y:1,z:0},-1,0,[1,1,1],{cover:0,layerHeight:ol},0);return}const s=this.lowerCloudCover(),r=je.deckLitUntilDeg(je.DECK_HEIGHT_M),o=e.altitudeDeg>-r?e:t,l=je.strength(n,s,o.altitudeDeg,r)*(o===e?1:L0),{x:c,y:h,z:d}=bn(o.altitudeDeg,o.azimuthDeg,1),u=Ps(o.altitudeDeg);this.iceHalos.update({x:c,y:h,z:d},o.altitudeDeg,l,[u[0],u[1],u[2]],{cover:i?.cover??n,layerHeight:i?.layerHeight??ol},i?.iceCrystalAlignment??this.weather.iceCrystalAlignment??.65)}buildRainbow(e,t){this.rainbow||(this.rainbow=new Wr,this.celestialGroup.add(this.rainbow.object));const n=this.weather.precipitationType==="rain"?this.weather.precipitationIntensity:0,i=e.altitudeDeg>0,s=i?e:t,r=this.lowerCloudCover(),o=L0*sn.moonlightShare(t.magnitude),l=sn.strength(n,r,s.altitudeDeg)*(i?1:o);if(l<=0){this.rainbow.update({x:0,y:1,z:0},0,[1,1,1],!0);return}const{x:c,y:h,z:d}=bn(s.altitudeDeg,s.azimuthDeg,1),u=Ps(s.altitudeDeg);this.rainbow.update({x:c,y:h,z:d},l,[u[0],u[1],u[2]],i)}buildSkyGlow(e,t){if(!e.frame){this.skyGlow?.hide();return}this.skyGlow||(this.skyGlow=new Jn,this.skyGlow.onReady=()=>this.render(),this.celestialGroup.add(this.skyGlow.object));const{date:n,observer:i}=e.frame,s=kn.galactic(n,i),r=mi.directionOf(s.centre),o=mi.directionOf(s.rotation),l=mi.directionOf(s.pole),c=new Be().set(r.x,r.y,r.z,o.x,o.y,o.z,l.x,l.y,l.z),h=mi.directionOf(kn.eclipticPole(n,i)),d=mi.directionOf(e.sun),u=d.clone().addScaledVector(h,-d.dot(h)).normalize();this.skyGlow.update({galactic:c,eclipticPole:h,sunLongitude:u,sunDirection:d,sunAltitudeDeg:e.sun.altitudeDeg,moon:{direction:mi.directionOf(e.moon),altitudeDeg:e.moon.altitudeDeg,phaseAngleDeg:We.phaseAngleOf(e.moon.phase.illuminatedFraction)},skyColor:new P(t[0],t[1],t[2])})}static directionOf(e){const{x:t,y:n,z:i}=bn(e.altitudeDeg,e.azimuthDeg,1);return new P(t,n,i).normalize()}disposeComet(){this.cometTail?.set(void 0,void 0,0),this.cometKey&&(this.disposeMesh(this.bodyMeshes.get(this.cometKey)),this.bodyMeshes.delete(this.cometKey),this.disposeHitArea(this.cometKey),this.disposeGlare(this.cometKey),this.cometKey=void 0)}buildPlanets(e,t){const n=new Set(["sun","moon",...this.cometKey?[this.cometKey]:[]]);for(const i of e){if(i.magnitude>t)continue;n.add(i.body);const s=nh(i.magnitude,t),r=ih(s),o=j3[i.body]??new le(1,1,1),l=new le(o.r*r,o.g*r,o.b*r),c=R0*(.5+.5*s);this.setBodyMesh(i.body,i.position,c,l,i.magnitude)}for(const i of[...this.bodyMeshes.keys()])n.has(i)||(this.disposeMesh(this.bodyMeshes.get(i)),this.bodyMeshes.delete(i),this.disposeHitArea(i),this.disposeGlare(i))}buildStars(e,t){if(this.disposeStarTiers(),this.namedStars=[],!e||e.catalog.count===0){this.syncAnimationLoop();return}const{catalog:n,date:i,observer:s}=e,r=Sh(1337),o=[];for(let l=0;l<n.count;l++){const c=n.mag[l];if(c>t)break;const{altitudeDeg:h,azimuthDeg:d}=rr(n.ra[l],n.dec[l],i,s);if(h<P0)continue;const{x:u,y:f,z:p}=bn(h,d,C0);o.push({x:u,y:f,z:p,brightness:nh(c,t),phase:r()*Math.PI*2,speedFactor:.7+r()*.6})}for(const l of EE){if(l.mag>t)continue;const{altitudeDeg:c,azimuthDeg:h}=rr(l.raHours,l.decDeg,i,s);if(c<P0)continue;const{x:d,y:u,z:f}=bn(c,h,C0);this.namedStars.push({star:l,direction:new P(d,u,f).normalize(),altitudeDeg:c})}this.starTiers=_g.map((l,c)=>{const h=o.filter(M=>M_(M.brightness)===c),d=new Float32Array(h.length*3),u=new Float32Array(h.length),f=new Float32Array(h.length),p=new Float32Array(h.length);h.forEach((M,x)=>{d[x*3]=M.x,d[x*3+1]=M.y,d[x*3+2]=M.z,u[x]=M.brightness,f[x]=M.phase,p[x]=M.speedFactor});const v=new Ct;v.setAttribute("position",new vt(d,3));const m=new vt(new Float32Array(h.length*3),3);v.setAttribute("color",m);const g=new sg({vertexColors:!0,size:l.size,sizeAttenuation:!1,fog:!1});Gs.apply(g);const _=new wl(v,g);return this.celestialGroup.add(_),{points:_,colorAttribute:m,brightness:u,phase:f,speedFactor:p}}),this.updateTwinkle(0),this.startTwinkle()}updateTwinkle(e){for(const t of this.starTiers){const n=t.colorAttribute.array;for(let i=0;i<t.brightness.length;i++){const s=E_(t.brightness[i],{phase:t.phase[i],speedFactor:t.speedFactor[i]},e),r=ih(t.brightness[i])*s;n[i*3]=r,n[i*3+1]=r,n[i*3+2]=r}t.colorAttribute.needsUpdate=!0}}buildClouds(){if(this.cloudRendering==="volume"||this.weather.cloudLayers!==void 0){this.layeredClouds||(this.disposeCloudSystem(),this.layeredClouds=new JS(this.celestialGroup,vh,this.cloudRendering)),this.disposeCirrus(),this.layeredClouds.update(this.weather,this.observerElevationM+1.6),this.layeredClouds.setOffsets(this.cloudOffsetM,this.cloudLayerOffsetsM),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}this.disposeCloudSystem();const e=this.lowerCloudCover();if(e<=0)return;const t=this.weather.cloudDarkness,n=new le(Ns[0]+(xh[0]-Ns[0])*t,Ns[1]+(xh[1]-Ns[1])*t,Ns[2]+(xh[2]-Ns[2])*t),{material:i,uniforms:s}=Od(n,e,Math.abs(this.cloudLayerOffset()));this.cloudMaterial=i,this.cloudUniforms=s,s.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);const r=kd(vh);this.cloudMesh=new Ke(r,i),this.cloudLayerOffset()<0&&(this.cloudMesh.scale.y=-1),this.cloudMesh.renderOrder=F0,this.celestialGroup.add(this.cloudMesh)}lowerCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(e=>e.type!=="cirrus").reduce((e,t)=>e*(1-t.coverage),1):this.weather.lowerCloudCover??this.weather.cloudCover}highCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(e=>e.type==="cirrus").reduce((e,t)=>e*(1-t.coverage),1):this.weather.highCloudCover}buildCirrus(){if(this.disposeCirrus(),this.layeredClouds)return;const e=this.weather.highCloudCover??0;if(e<=0)return;const{material:t,uniforms:n}=Od(new le(...Ns),e,ol,1);this.cirrusMaterial=t,this.cirrusUniforms=n,n.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.cirrusMesh=new Ke(kd(vh*1.04),t),this.cirrusMesh.renderOrder=F0-1,this.celestialGroup.add(this.cirrusMesh)}disposeCirrus(){this.cirrusMesh&&(this.cirrusMesh.removeFromParent(),this.cirrusMesh.geometry.dispose()),this.cirrusMaterial?.dispose(),this.cirrusMesh=void 0,this.cirrusMaterial=void 0,this.cirrusUniforms=void 0}syncCloudLayer(){this.layeredClouds?.update(this.weather,this.observerElevationM+1.6);const e=this.cloudLayerOffset();this.cloudUniforms&&(this.cloudUniforms.layerHeight.value=Math.abs(e)),this.cloudMesh&&(this.cloudMesh.scale.y=e<0?-1:1)}cloudLayerOffset(){const t=((this.weather.cloudBaseM??1e3)-this.observerElevationM)*yh;return Math.sign(t||1)*Math.max(Math.abs(t),O3)}updateCloudLighting(e,t){const n=[this.cloudUniforms,this.cirrusUniforms].filter(c=>c!==void 0);if(n.length===0&&!this.layeredClouds)return;const{x:i,y:s,z:r}=bn(e.altitudeDeg,e.azimuthDeg,1),o=Ps(e.altitudeDeg),l=Math.max(0,Math.sin(Math.max(e.altitudeDeg,0)*Pn));this.layeredClouds?.setLighting(new P(i,s,r),new le(o[0]*l,.96*o[1]*l,.88*o[2]*l),new le(...t),new le(...t));for(const c of n)c.sunDir.value.set(i,s,r),c.sunColor.value.setRGB(o[0]*l,.96*o[1]*l,.88*o[2]*l),c.ambientColor.value.setRGB(t[0],t[1],t[2])}disposeCloudSystem(){this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.cloudMesh&&(this.cloudMesh.removeFromParent(),this.cloudMesh.geometry.dispose()),this.cloudMaterial?.dispose(),this.cloudMesh=void 0,this.cloudMaterial=void 0,this.cloudUniforms=void 0}disposePrecipitationPoints(){this.precipitationPoints&&(this.precipitationPoints.removeFromParent(),this.precipitationPoints.geometry.dispose(),this.precipitationPoints.material.dispose()),this.precipitationPoints=void 0,this.precipitationPositions=void 0,this.precipitationPhase=void 0,this.precipitationSpeedJitter=void 0,this.precipitationWobbleFreqJitter=void 0,this.precipitationWobbleAmpJitter=void 0,this.precipitationBounceRemaining=void 0,this.precipitationBounceHeight=void 0,this.precipitationBounceDuration=void 0,this.precipitationBounceVelX=void 0,this.precipitationBounceVelZ=void 0,this.precipitationUniforms=void 0}buildPrecipitation(){this.disposePrecipitationPoints(),this.disposeRain();const e=this.weather.precipitationType;if(e==="none")return;if(e==="rain"){this.buildRain();return}const t=U0[e],n=t.poolSize,i=Sh(9001),s=new Float32Array(n*3),r=new Float32Array(n),o=new Float32Array(n),l=new Float32Array(n),c=new Float32Array(n),h=new Float32Array(n),d=new Float32Array(n),u=new Float32Array(n),f=new Float32Array(n),p=new Float32Array(n);for(let M=0;M<n;M++){const x=i()*Math.PI*2,w=i()*t.radiusM;s[M*3]=Math.cos(x)*w,s[M*3+1]=Pa+i()*(t.topYM-Pa),s[M*3+2]=Math.sin(x)*w,r[M]=i()*Math.PI*2,o[M]=.7+i()*.6,l[M]=.6+i()*.8,c[M]=.4+i()*1.2}const v=new Ct;v.setAttribute("position",new vt(s,3)),v.setDrawRange(0,Mh(n,this.weather.precipitationIntensity));const m={uSize:{value:t.size},uScale:{value:.5*this.renderer.domElement.height},uOpacity:{value:t.opacity},uColor:{value:t.color},uHazeColor:{value:new le(...this.baseFogColor)},uTexture:{value:Q3(e)},uNearFocusDistance:{value:X0},uHazeDistance:{value:t.radiusM*q0}},g=new Rt({uniforms:m,vertexShader:aT,fragmentShader:rT,transparent:!0,depthWrite:!1});this.precipitationUniforms=m;const _=new wl(v,g);_.renderOrder=bh,this.scene.add(_),this.precipitationPoints=_,this.precipitationPositions=s,this.precipitationPhase=r,this.precipitationSpeedJitter=o,this.precipitationWobbleFreqJitter=l,this.precipitationWobbleAmpJitter=c,this.precipitationBounceRemaining=h,this.precipitationBounceHeight=d,this.precipitationBounceDuration=u,this.precipitationBounceVelX=f,this.precipitationBounceVelZ=p}updatePrecipitation(e,t){if(!this.precipitationPoints||!this.precipitationPositions||!this.precipitationPhase||!this.precipitationSpeedJitter||(this.precipitationUniforms?.uHazeColor.value.setRGB(...this.baseFogColor),t<=0))return;const n=this.weather.precipitationType;if(n==="none"||n==="rain")return;const i=U0[n],s=this.weather.windDirectionDeg*Pn,r=Math.sin(s)*this.weather.windSpeed*i.driftSensitivity,o=-Math.cos(s)*this.weather.windSpeed*i.driftSensitivity,l=this.precipitationPositions,c=this.precipitationPhase,h=this.precipitationSpeedJitter,d=this.precipitationWobbleFreqJitter,u=this.precipitationWobbleAmpJitter,f=this.precipitationBounceRemaining,p=this.precipitationBounceHeight,v=this.precipitationBounceDuration,m=this.precipitationBounceVelX,g=this.precipitationBounceVelZ,_=n==="snow"&&d&&u,M=n==="hail"&&f&&p&&v&&m&&g;for(let x=0,w=0;x<l.length;x+=3,w++){if(M&&f[w]>0){if(f[w]-=t,f[w]<=0){const y=Math.random()*Math.PI*2,T=Math.sqrt(Math.random())*i.radiusM;l[x]=Math.cos(y)*T,l[x+1]=i.topYM,l[x+2]=Math.sin(y)*T,f[w]=0}else{const y=1-f[w]/v[w];l[x+1]=Pa+Math.sin(Math.PI*y)*p[w],l[x]=cl(l[x]+(r+m[w])*t,i.radiusM),l[x+2]=cl(l[x+2]+(o+g[w])*t,i.radiusM)}continue}let E=0,D=0;if(_){const y=q3*d[w],T=Y3*u[w];E=Math.sin(e*y*Math.PI*2+c[w])*T,D=Math.sin(e*y*Math.PI*2+c[w]+Math.PI/2)*T}if(l[x]+=(r+E)*t,l[x+1]-=i.fallSpeedMPerS*h[w]*t,l[x+2]+=(o+D)*t,l[x]=cl(l[x],i.radiusM),l[x+2]=cl(l[x+2],i.radiusM),l[x+1]<Pa){if(M){p[w]=J0*(.2+Math.random()*1.6),v[w]=K3*(.5+Math.random()),f[w]=v[w];const A=Math.random()*Math.PI*2,I=$3*(p[w]/J0);m[w]=Math.cos(A)*I,g[w]=Math.sin(A)*I,l[x+1]=Pa;continue}const y=Math.random()*Math.PI*2,T=Math.sqrt(Math.random())*i.radiusM;l[x]=Math.cos(y)*T,l[x+1]=i.topYM,l[x+2]=Math.sin(y)*T}}this.precipitationPoints.geometry.attributes.position.needsUpdate=!0}buildRain(){const e=G0(this.weather.precipitationIntensity);this.rainSystem=HE({count:B0,radiusM:Dr,heightM:F3,bottomYM:z0,overallSpeed:U3,color:z3,opacity:.85,visibleCount:Mh(B0,this.weather.precipitationIntensity),speedStreak:V3(e),pixelSize:K0,seed:9001,nearFocusDistanceM:X0,hazeDistanceM:Dr*q0,hazeColor:new le(...this.baseFogColor)}),this.rainLastVerticalFacing=-1,this.syncRainSlant(),this.rainSystem.points.renderOrder=bh,this.scene.add(this.rainSystem.points),this.buildRainSplashes()}buildRainSplashes(){const e=Sh(4242),t=new Float32Array(Aa*3),n=new Float32Array(Aa),i=new Float32Array(Aa),s=new Float32Array(Aa);for(let h=0;h<Aa;h++){const d=e()*Math.PI*2,u=Math.sqrt(e())*Dr;t[h*3]=Math.cos(d)*u,t[h*3+1]=z0,t[h*3+2]=Math.sin(d)*u,i[h]=ll(V0,W0),n[h]=e()*i[h],s[h]=n[h]/i[h]}const r=new Ct;r.setAttribute("position",new vt(t,3));const o=new vt(s,1);r.setAttribute("aLife",o),r.setDrawRange(0,Mh(Aa,this.weather.precipitationIntensity));const l=new Rt({uniforms:{uMaxSize:{value:W3},uScale:{value:.5*this.renderer.domElement.height},uColor:{value:X3},uTexture:{value:nT()}},vertexShader:iT,fragmentShader:sT,transparent:!0,depthWrite:!1}),c=new wl(r,l);c.renderOrder=bh,this.scene.add(c),this.rainSplashSystem={points:c,positions:t,life:n,duration:i,lifeAttribute:o}}disposeRain(){this.rainSystem&&(this.rainSystem.points.removeFromParent(),this.rainSystem.points.geometry.dispose(),this.rainSystem.points.material.dispose()),this.rainSystem=void 0,this.disposeRainSplashes()}disposeRainSplashes(){this.rainSplashSystem&&(this.rainSplashSystem.points.removeFromParent(),this.rainSplashSystem.points.geometry.dispose(),this.rainSplashSystem.points.material.dispose()),this.rainSplashSystem=void 0}syncRainSlant(){const e=this.rainSystem;if(!e)return;const t=this.weather.windDirectionDeg*Pn;e.uniforms.uDropVelocity.value.set(Math.sin(t)*this.weather.windSpeed,-G0(this.weather.precipitationIntensity),-Math.cos(t)*this.weather.windSpeed);const n=this.renderer.getSize(this.rainViewportSize);e.uniforms.uAspect.value=n.x/Math.max(n.y,1)}updateRain(e){const t=this.rainSystem;if(!t)return;t.uniforms.uTime.value+=e,t.uniforms.uHazeColor.value.setRGB(...this.baseFogColor);const n=this.weather.windDirectionDeg*Pn,i=Math.sin(n)*this.weather.windSpeed,s=-Math.cos(n)*this.weather.windSpeed,r=Dr,o=c=>(c%(r*2)+r*3)%(r*2)-r;t.uniforms.uWindOffset.value.set(o(t.uniforms.uWindOffset.value.x+i*e),o(t.uniforms.uWindOffset.value.y+s*e)),this.syncRainSlant(),this.camera.getWorldDirection(this.rainCameraDirection);const l=Math.abs(this.rainCameraDirection.y);if(Math.abs(l-this.rainLastVerticalFacing)>.001){this.rainLastVerticalFacing=l;const c=$0+(1-$0)*(1-l),h=Z0+(1-Z0)*(1-l);t.uniforms.uUvSquash.value=h,t.uniforms.uPixelSize.value=K0*c*(.5+.5*h)}this.updateRainSplashes(e)}updateRainSplashes(e){const t=this.rainSplashSystem;if(!t||e<=0)return;const{positions:n,life:i,duration:s,lifeAttribute:r}=t,o=r.array;for(let l=0,c=0;l<n.length;l+=3,c++){if(i[c]+=e,i[c]>=s[c]){const h=Math.random()*Math.PI*2,d=Math.sqrt(Math.random())*Dr;n[l]=Math.cos(h)*d,n[l+2]=Math.sin(h)*d,s[c]=ll(V0,W0),i[c]=0}o[c]=i[c]/s[c]}t.points.geometry.attributes.position.needsUpdate=!0,r.needsUpdate=!0}updateLightning(e,t){if(this.lightningArmed){if(this.lightningFlashRemainingS>0){this.lightningFlashRemainingS=Math.max(0,this.lightningFlashRemainingS-t);const n=this.lightningFlashRemainingS/em;this.scene.fog&&this.scene.fog.color.setRGB(this.baseFogColor[0]+(1-this.baseFogColor[0])*n,this.baseFogColor[1]+(1-this.baseFogColor[1])*n,this.baseFogColor[2]+(1-this.baseFogColor[2])*n);return}if(this.nextLightningAtS===null){this.nextLightningAtS=e+ll(j0,Q0);return}e>=this.nextLightningAtS&&(this.lightningFlashRemainingS=em,this.nextLightningAtS=e+ll(j0,Q0),this.onLightningFlash?.())}}buildCompassLabels(){const e=za(navigator.languages,T3),t=E3[e];this.compassSprites=_3.map((n,i)=>{const s=t[i],r=new Lr({map:cT(s),depthTest:!1,fog:!1}),o=new Do(r),{x:l,y:c,z:h}=bn(0,n,A3);return o.position.set(l,c,h),o.scale.set(gh,gh,1),o.renderOrder=D3,o.visible=this.compassHovered||this.compassForced,this.celestialGroup.add(o),o}),this.updateCompassScale()}updateCompassScale(){const e=this.camera.fov*Math.PI/360,t=I3*Math.PI/360,n=gh*Math.tan(e)/Math.tan(t);for(const i of this.compassSprites)i.scale.set(n,n,1)}disposeCompassLabels(){for(const e of this.compassSprites)e.removeFromParent(),e.material.map?.dispose(),e.material.dispose();this.compassSprites=[]}disposeStarTiers(){for(const e of this.starTiers)this.disposeMesh(e.points);this.starTiers=[]}disposeMesh(e){if(!e)return;e.removeFromParent(),"geometry"in e&&e.geometry.dispose();const t=e.material;for(const n of Array.isArray(t)?t:[t]){const i=n.map;i&&i.dispose(),n.dispose()}}}const Pn=Math.PI/180;function Zl(a,e,t){return Math.max(e,Math.min(t,a))}function ll(a,e){return a+Math.random()*(e-a)}function cl(a,e){return(a%(e*2)+e*3)%(e*2)-e}let hl,dl;function Q3(a){switch(a){case"snow":return eT();case"hail":return tT()}}function eT(){if(hl)return hl;const a=64,e=document.createElement("canvas");e.width=a,e.height=a;const t=e.getContext("2d"),n=t.createRadialGradient(a/2,a/2,0,a/2,a/2,a/2);return n.addColorStop(0,"rgba(255,255,255,0.95)"),n.addColorStop(.5,"rgba(255,255,255,0.55)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,a,a),hl=new Ri(e),hl}function tT(){if(dl)return dl;const a=64,e=document.createElement("canvas");e.width=a,e.height=a;const t=e.getContext("2d"),n=t.createRadialGradient(a/2,a/2,0,a/2,a/2,a/2);return n.addColorStop(0,"rgba(255,255,255,1)"),n.addColorStop(.55,"rgba(255,255,255,0.95)"),n.addColorStop(.8,"rgba(255,255,255,0.4)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,a,a),dl=new Ri(e),dl}let ul;function nT(){if(ul)return ul;const a=64,e=document.createElement("canvas");e.width=a,e.height=a;const t=e.getContext("2d"),n=t.createRadialGradient(a/2,a/2,0,a/2,a/2,a/2);return n.addColorStop(0,"rgba(255,255,255,0)"),n.addColorStop(.4,"rgba(255,255,255,0)"),n.addColorStop(.6,"rgba(255,255,255,0.9)"),n.addColorStop(.8,"rgba(255,255,255,0.25)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,a,a),ul=new Ri(e),ul}const iT=`
7306
7306
  uniform float uMaxSize;
7307
7307
  uniform float uScale;
7308
7308
  attribute float aLife;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rr0/ufoathome",
3
3
  "type": "module",
4
- "version": "0.57.1",
4
+ "version": "0.57.3",
5
5
  "description": "UFO@home — record and replay a UFO sighting's shape, movement and appearance",
6
6
  "author": "Jérôme Beau <rr0@rr0.org> (https://rr0.org)",
7
7
  "license": "MIT",