@rr0/ufoathome 0.70.0 → 0.70.1

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.
@@ -2143,7 +2143,7 @@ input[type=range] {
2143
2143
  pointer-events: none;
2144
2144
  white-space: nowrap;
2145
2145
  }
2146
- `;class qa{constructor(e){this.points=e}static STATIONARY_M=5;static of(e){const t=[];for(const i of e.observerTrack.allKeyframes){const{lat:n,lng:s,headingDeg:r}=i.pose;n===void 0||s===void 0||t.push({t:i.t,lat:n,lng:s,headingDeg:r})}if(t.length===0){const i=e.event.place?.[0];if(!i)return;t.push({t:0,lat:i.lat,lng:i.lng})}return new qa(t)}static TRAVEL_M=50;get travels(){return this.spanM>qa.TRAVEL_M}get moved(){return this.spanM>qa.STATIONARY_M}get spanM(){const e=this.box,t=(e.south+e.north)/2,i=(e.west+e.east)/2;return Math.max(Math.abs(li(t,e.east,t,e.west).x),Math.abs(li(e.north,i,e.south,i).z))}get center(){const e=this.box;return{lat:(e.south+e.north)/2,lng:(e.west+e.east)/2}}boundsAround(e,t){const{lat:i,lng:n}=this.center,s=Math.max(this.spanM*(1+t),e)/2;return{north:Os(0,-s,i,n).lat,south:Os(0,s,i,n).lat,east:Os(s,0,i,n).lng,west:Os(-s,0,i,n).lng}}get box(){const e=this.points.map(i=>i.lat),t=this.points.map(i=>i.lng);return{south:Math.min(...e),north:Math.max(...e),west:Math.min(...t),east:Math.max(...t)}}}class En{constructor(e,t){this.rotationPassed=e,this.scale=t}static SWAY_M=.012;static BREATH_M=.003;static DRIFT_YAW_DEG=.5;static DRIFT_PITCH_DEG=.4;static DRIFT_ROLL_DEG=.3;static GAZE_DRIFT_SHARE=.35;static HAND_HELD_S=.5;static HZ=[.11,.23,.17,.29,.37,.07];static of(e){const t=e.event.tags?.includes("paralysis")||(e.exposure??0)>En.HAND_HELD_S,i=e.sway??(t?0:1);if(i>0)return new En(Math.max(1-(e.instrument.stabilization??0),En.GAZE_DRIFT_SHARE),i)}offsetAt(e){const t=e/1e3,i=this.scale,n=(d,u)=>Math.sin(2*Math.PI*d*t+u),[s,r,o,l,c,h]=En.HZ;return{eastM:i*En.SWAY_M*(.7*n(s,.3)+.3*n(l,1.9)),northM:i*En.SWAY_M*(.6*n(o,2.2)+.4*n(c,.8)),upM:i*En.BREATH_M*n(r,0),yawDeg:i*this.rotationPassed*En.DRIFT_YAW_DEG*(.6*n(h,1.1)+.4*n(l,2.7)),pitchDeg:i*this.rotationPassed*En.DRIFT_PITCH_DEG*(.5*n(r,1.6)+.5*n(o,.4)),rollDeg:i*this.rotationPassed*En.DRIFT_ROLL_DEG*n(s,2.9)}}}class Et{constructor(e,t){this.stretches=e,this.rotationPassed=t}static REFERENCE_SPEED_M_PER_S=1.4;static REFERENCE_STEP_HZ=1.9;static CADENCE_EXPONENT=.43;static RISE_M_PER_M_PER_S=.0175;static SWAY_M=.0175;static SLOWEST_WALK_M_PER_S=.2;static FASTEST_WALK_M_PER_S=2.2;static HEAD_ROLL_DEG=1.5;static HEAD_PITCH_DEG=1.25;static HEAD_YAW_DEG=1;static STOP_LURCH_M=.035;static STOP_PITCH_DEG=3;static START_LURCH_M=.015;static START_PITCH_DEG=1.2;static JOLT_HZ=1.4;static JOLT_DECAY_S=.35;static JOLT_LASTS_MS=1500;static STILL=Object.freeze({eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0});static of(e){const t=qa.of(e);if(!t||t.points.length<2)return;const i=[];let n=0;for(let s=1;s<t.points.length;s++){const r=t.points[s-1],o=t.points[s],l=(o.t-r.t)/1e3;if(l<=0)continue;const c=li(o.lat,o.lng,r.lat,r.lng),h=c.x,d=-c.z,u=Math.hypot(h,d),f=u/l,p=Et.stepHzFor(f);i.push({startMs:r.t,endMs:o.t,speedMPerS:f,eastUnit:u>0?h/u:0,northUnit:u>0?d/u:0,stepHz:p,stepsBefore:n,rampsIn:!0,rampsOut:!0}),n+=p*l}for(let s=0;s<i.length;s++){const r=i[s-1],o=i[s+1];i[s].rampsIn=r===void 0||r.stepHz===0,i[s].rampsOut=o===void 0||o.stepHz===0}if(i.some(s=>s.stepHz>0))return new Et(i,1-(e.instrument.stabilization??0))}static bodyAt(e,t,i=!1){const n=Et.of(e)?.offsetAt(t)??Et.STILL;return i?n:Et.add(n,En.of(e)?.offsetAt(t))}static stepHzFor(e){return e<Et.SLOWEST_WALK_M_PER_S||e>Et.FASTEST_WALK_M_PER_S?0:Et.REFERENCE_STEP_HZ*Math.pow(e/Et.REFERENCE_SPEED_M_PER_S,Et.CADENCE_EXPONENT)}offsetAt(e){return Et.add(this.cycleAt(e),this.joltAt(e))}joltAt(e){for(const t of this.stretches){if(t.stepHz===0)continue;const i=t.speedMPerS/Et.REFERENCE_SPEED_M_PER_S,n=(o,l,c,h)=>{if(o<0||o>Et.JOLT_LASTS_MS)return;const d=o/1e3,u=Math.exp(-d/Et.JOLT_DECAY_S)*Math.sin(2*Math.PI*Et.JOLT_HZ*d),f=h*l*i*u;return{eastM:f*t.eastUnit,northM:f*t.northUnit,upM:-Math.abs(f)*.3,rollDeg:0,pitchDeg:-h*c*i*u*this.rotationPassed,yawDeg:0}},s=t.rampsOut?n(e-t.endMs,Et.STOP_LURCH_M,Et.STOP_PITCH_DEG,1):void 0;if(s)return s;const r=t.rampsIn?n(e-t.startMs,Et.START_LURCH_M,Et.START_PITCH_DEG,-1):void 0;if(r)return r}}static add(e,t){return t?{eastM:e.eastM+t.eastM,northM:e.northM+t.northM,upM:e.upM+t.upM,rollDeg:e.rollDeg+t.rollDeg,pitchDeg:e.pitchDeg+t.pitchDeg,yawDeg:e.yawDeg+t.yawDeg}:e}cycleAt(e){const t=this.stretches.find(l=>e>=l.startMs&&e<=l.endMs);if(!t||t.stepHz===0)return Et.STILL;const i=t.stepsBefore+t.stepHz*(e-t.startMs)/1e3,n=2*Math.PI*i,s=this.amplitudeAt(t,e),r=Et.SWAY_M*s*Math.cos(n/2),o=s*this.rotationPassed*t.speedMPerS/Et.REFERENCE_SPEED_M_PER_S;return{eastM:r*t.northUnit,northM:-r*t.eastUnit,upM:Et.RISE_M_PER_M_PER_S*t.speedMPerS*s*Math.cos(n),rollDeg:Et.HEAD_ROLL_DEG*o*Math.cos(n/2),pitchDeg:-1.25*o*Math.cos(n),yawDeg:Et.HEAD_YAW_DEG*o*Math.cos(n/2)}}amplitudeAt(e,t){const i=1e3/e.stepHz,n=Math.min(i,(e.endMs-e.startMs)/2);if(n<=0)return 1;const s=t-e.startMs,r=e.endMs-t,o=Math.min(e.rampsIn?s/n:1,e.rampsOut?r/n:1,1);return(1-Math.cos(Math.PI*Math.max(o,0)))/2}}class fy{constructor(e,t){this.timeline=e,this.onFrame=t}rafId=null;state="stopped";currentT=0;lastWallTime=0;playbackRate=1;loop=!1;onEnded;durationOverrideMs=0;get seekableDuration(){return Math.max(this.timeline.duration,this.durationOverrideMs)}play(){if(this.state==="playing")return;this.currentT>=this.seekableDuration&&(this.currentT=0,this.resolveFrame(0)),this.state="playing",this.lastWallTime=performance.now();const e=()=>{if(this.state!=="playing")return;const t=performance.now();if(this.currentT+=(t-this.lastWallTime)*this.playbackRate,this.lastWallTime=t,this.currentT>=this.seekableDuration){if(this.loop&&this.seekableDuration>0){this.currentT%=this.seekableDuration,this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(e);return}this.currentT=this.seekableDuration,this.stop(),this.resolveFrame(this.currentT),this.onEnded?.();return}this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(e)};this.rafId=requestAnimationFrame(e)}pause(){this.state==="playing"&&(this.state="paused",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null))}stop(){this.state="stopped",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}seek(e){this.currentT=Math.max(0,Math.min(e,this.seekableDuration)),this.resolveFrame(this.currentT)}get playbackState(){return this.state}get time(){return this.currentT}resolveFrame(e){const t=new Map;for(const i of this.timeline.sourceIds){const n=this.timeline.getInterpolatedShapeAt(e,i);n&&t.set(i,n)}this.onFrame(e,t)}}const f0=.05,p0=.08,m0=2,g0=3,py=14,my=.02;class gy{context;voice;voiceToken=0;buffers=new Map;noiseBuffer;crackleBuffer;requested;resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(e){console.warn("SightingAudio: Web Audio unavailable, the sighting stays silent:",e);return}}this.context.state==="suspended"&&this.context.resume()}setSound(e){if(this.requested=e,!this.context)return;const t=this.keyFor(e);if(!t){this.silence();return}if(this.voice?.key!==t){this.stopVoice();const i=++this.voiceToken;t.startsWith("src:")?this.buildRecordedVoice(e.src,t,i):this.voice=this.buildSynthesizedVoice(e,t)}this.applyTo(this.voice,e)}silence(){this.voiceToken++,this.stopVoice()}dispose(){this.silence(),this.context?.close(),this.context=void 0,this.buffers.clear(),this.noiseBuffer=void 0,this.crackleBuffer=void 0}keyFor(e){if(!(e.volume<=0))return e.src?`src:${e.src}`:e.kind==="none"?void 0:e.kind}applyTo(e,t){const i=this.context;if(!e||!i)return;const n=i.currentTime;e.volumeParam.setTargetAtTime(Math.max(0,Math.min(1,t.volume))*e.gainScale,n,f0);for(const{param:s,ratio:r}of e.pitch)s.setTargetAtTime(Math.min(t.pitchHz*r,i.sampleRate/2-1),n,f0)}buildSynthesizedVoice(e,t){const i=this.context;if(i)switch(e.kind){case"hum":return this.buildHum(i,t);case"whistle":return this.buildWhistle(i,t);case"rumble":return this.buildRumble(i,t);case"crackle":return this.buildCrackle(i,t);default:return}}buildHum(e,t){const i=e.createOscillator();i.type="sawtooth";const n=e.createOscillator();n.type="sawtooth";const s=e.createBiquadFilter();s.type="lowpass",s.Q.value=1;const r=e.createGain();return r.gain.value=0,i.connect(s),n.connect(s),s.connect(r).connect(e.destination),i.start(),n.start(),{key:t,nodes:[s,r],sources:[i,n],volumeParam:r.gain,gainScale:.16,pitch:[{param:i.frequency,ratio:1},{param:n.frequency,ratio:1.006},{param:s.frequency,ratio:6}]}}buildWhistle(e,t){const i=e.createOscillator();i.type="sine";const n=e.createOscillator();n.type="sine",n.frequency.value=5;const s=e.createGain(),r=e.createGain();return r.gain.value=0,n.connect(s).connect(i.frequency),i.connect(r).connect(e.destination),i.start(),n.start(),{key:t,nodes:[s,r],sources:[i,n],volumeParam:r.gain,gainScale:.22,pitch:[{param:i.frequency,ratio:1},{param:s.gain,ratio:.012}]}}buildRumble(e,t){const i=e.createBufferSource();i.buffer=this.brownNoise(e),i.loop=!0;const n=e.createBiquadFilter();n.type="lowpass",n.Q.value=.8;const s=e.createGain();return s.gain.value=0,i.connect(n).connect(s).connect(e.destination),i.start(),{key:t,nodes:[n,s],sources:[i],volumeParam:s.gain,gainScale:1.4,pitch:[{param:n.frequency,ratio:1}]}}buildCrackle(e,t){const i=e.createBufferSource();i.buffer=this.whiteNoise(e),i.loop=!0;const n=e.createBiquadFilter();n.type="bandpass",n.Q.value=1.2;const s=e.createGain();s.gain.value=0;const r=e.createBufferSource();r.buffer=this.crackleEnvelope(e),r.loop=!0;const o=e.createGain();return o.gain.value=0,r.connect(o).connect(s.gain),i.connect(n).connect(s).connect(e.destination),i.start(),r.start(),{key:t,nodes:[n,s,o],sources:[i,r],volumeParam:o.gain,gainScale:.9,pitch:[{param:n.frequency,ratio:4}]}}async buildRecordedVoice(e,t,i){const n=this.context;if(!n)return;let s;try{s=await this.getBuffer(e)}catch(l){console.warn("SightingAudio: the recorded sound failed to load, staying silent:",l);return}if(i!==this.voiceToken||!this.context)return;const r=n.createBufferSource();r.buffer=s,r.loop=!0;const o=n.createGain();o.gain.value=0,r.connect(o).connect(n.destination),r.start(),this.voice={key:t,nodes:[o],sources:[r],volumeParam:o.gain,gainScale:1,pitch:[]},this.requested&&this.applyTo(this.voice,this.requested)}async getBuffer(e){const t=this.context;if(!t)throw new Error("SightingAudio: AudioContext not ready — resume() must be called first");let i=this.buffers.get(e);return i||(i=fetch(e).then(n=>{if(!n.ok)throw new Error(`Audio fetch failed (${n.status}): ${e}`);return n.arrayBuffer()}).then(n=>t.decodeAudioData(n)),this.buffers.set(e,i)),i}whiteNoise(e){if(!this.noiseBuffer){const t=e.createBuffer(1,Math.floor(e.sampleRate*m0),e.sampleRate),i=t.getChannelData(0);for(let n=0;n<i.length;n++)i[n]=Math.random()*2-1;this.noiseBuffer=t}return this.noiseBuffer}brownNoise(e){const t=e.createBuffer(1,Math.floor(e.sampleRate*m0),e.sampleRate),i=t.getChannelData(0);let n=0,s=0;for(let r=0;r<i.length;r++)n=(n+.02*(Math.random()*2-1))/1.02,i[r]=n,s=Math.max(s,Math.abs(n));if(s>0)for(let r=0;r<i.length;r++)i[r]/=s;return t}crackleEnvelope(e){if(!this.crackleBuffer){const t=e.createBuffer(1,Math.floor(e.sampleRate*g0),e.sampleRate),i=t.getChannelData(0),n=Math.max(1,Math.floor(my*e.sampleRate)),s=Math.round(g0*py);for(let r=0;r<s;r++){const o=Math.floor(Math.random()*i.length),l=.4+Math.random()*.6;for(let c=0;c<n&&o+c<i.length;c++)i[o+c]=Math.max(i[o+c],l*(1-c/n))}this.crackleBuffer=t}return this.crackleBuffer}stopVoice(){const e=this.voice,t=this.context;if(this.voice=void 0,!e||!t)return;const i=t.currentTime;e.volumeParam.cancelScheduledValues(i),e.volumeParam.setTargetAtTime(0,i,p0/3);const n=i+p0;for(const s of e.sources){s.onended=()=>{s.disconnect();for(const r of e.nodes)r.disconnect()};try{s.stop(n)}catch{s.disconnect();for(const r of e.nodes)r.disconnect()}}}}function ao(a){return[...a].sort((e,t)=>e.t-t.t)}function v0(a,e){let t;for(const i of ao(a)){if(i.t>e)break;t=i}return t}const Vh=Math.PI/180,Ll=180/Math.PI;class Gn{constructor(e,t,i){this.kind=e,this.canvasHeightPx=t,this.fovDeg=i;const n=i*Vh/2;this.focalPx=e==="equidistant"?t/2/n:t/2/Math.tan(n)}focalPx;static of(e,t,i){return new Gn(e.projection,t,i)}degToPx(e){const t=e*Vh;return this.kind==="equidistant"?this.focalPx*t:2*this.focalPx*Math.tan(t/2)}pxToDeg(e){return this.kind==="equidistant"?e/this.focalPx*Ll:2*Math.atan(e/(2*this.focalPx))*Ll}angleDegToRadiusPx(e){const t=e*Vh;return this.kind==="equidistant"?this.focalPx*t:this.focalPx*Math.tan(t)}halfWidthAngleDeg(e){return this.radiusPxToAngleDeg(this.canvasHeightPx*e/2)}radiusPxToAngleDeg(e){return this.kind==="equidistant"?e/this.focalPx*Ll:Math.atan(e/this.focalPx)*Ll}ofBounds(e){return{widthDeg:this.pxToDeg(e.width),heightDeg:this.pxToDeg(e.height)}}toBoundsSize(e){return{width:this.degToPx(e.widthDeg),height:this.degToPx(e.heightDeg)}}widthPx(e){return this.degToPx(it.angularWidthDeg(e))}}class gi{static fovOf(e,t){return nt(e,t)?.fovDeg??Mt.fieldOfViewDeg(e.instrument)}static toAngular(e){this.eachKeyframe(e,(t,i)=>({...t,angular:i.ofBounds(t.bounds)}))}static toBounds(e){this.eachKeyframe(e,(t,i)=>{if(!t.angular)return t;const{width:n,height:s}=i.toBoundsSize(t.angular),r={x:t.bounds.x+(t.bounds.width-n)/2,y:t.bounds.y+(t.bounds.height-s)/2,width:n,height:s};if(t.kind!=="polygon")return{...t,bounds:r};const o=t.bounds.width===0?1:n/t.bounds.width,l=t.bounds.height===0?1:s/t.bounds.height;return{...t,bounds:r,points:t.points.map(c=>({x:c.x*o,y:c.y*l}))}})}static toAim(e){this.eachKeyframe(e,(t,i,n)=>{const s=t.aim&&this.positionOf(e,t.aim,t.bounds,i,n);if(s&&Math.abs(s.x-t.bounds.x)<gi.UNMOVED_PX&&Math.abs(s.y-t.bounds.y)<gi.UNMOVED_PX)return t;const r=this.aimFrom(e,i,n,t.bounds);return r?{...t,aim:r}:t})}static UNMOVED_PX=.01;static aimOf(e,t,i){const n=Gn.of(e.instrument,it.CANVAS_HEIGHT_PX,this.fovOf(e,t));return this.aimFrom(e,n,nt(e,t),i)}static aimFrom(e,t,i,n){if(i?.headingDeg===void 0)return;const s=this.frameCentre(e),r=t.radiusPxToAngleDeg(n.x+n.width/2-s.x),o=t.radiusPxToAngleDeg(s.y-(n.y+n.height/2));return{azimuthDeg:((i.headingDeg+r)%360+360)%360,altitudeDeg:i.pitchDeg+o}}static toPosition(e){this.eachKeyframe(e,(t,i,n)=>{const s=t.aim&&this.positionOf(e,t.aim,t.bounds,i,n);return s?{...t,bounds:{...t.bounds,...s}}:t})}static positionOf(e,t,i,n,s){if(s?.headingDeg===void 0)return;const r=this.frameCentre(e),o=this.shortestArc(t.azimuthDeg-s.headingDeg),l=t.altitudeDeg-s.pitchDeg;return{x:r.x+this.offAxisPx(n,o)-i.width/2,y:r.y-this.offAxisPx(n,l)-i.height/2}}static frameCentre(e){return{x:Mt.frameWidthPx(e.instrument,it.CANVAS_HEIGHT_PX)/2,y:it.CANVAS_HEIGHT_PX/2}}static shortestArc(e){return(e%360+540)%360-180}static offAxisPx(e,t){return Math.abs(t)>=gi.OFF_CANVAS_DEG?Math.sign(t)*gi.OFF_CANVAS_PX:e.angleDegToRadiusPx(t)}static OFF_CANVAS_DEG=89;static OFF_CANVAS_PX=1e5;static reproject(e,t,i){const n=Mt.frameWidthPx(t,it.CANVAS_HEIGHT_PX)/2,s=Mt.frameWidthPx(e.instrument,it.CANVAS_HEIGHT_PX)/2,r=it.CANVAS_HEIGHT_PX/2;for(const o of[...e.timeline.allKeyframes]){const l=this.fovOf(e,o.t),c=i?.get(o.t)??l,h=Gn.of(t,it.CANVAS_HEIGHT_PX,c),d=Gn.of(e.instrument,it.CANVAS_HEIGHT_PX,l);e.timeline.addKeyframe(o.t,o.shapes.map(u=>{const{bounds:f}=u.shape,p=f.x+f.width/2-n,v=f.y+f.height/2-r,m=Math.hypot(p,v),g=m===0?1:d.angleDegToRadiusPx(h.radiusPxToAngleDeg(m))/m,y={...f,x:s+p*g-f.width/2,y:r+v*g-f.height/2};return{...u,shape:{...u.shape,bounds:y}}}))}this.toBounds(e)}static eachKeyframe(e,t){const{timeline:i}=e;for(const n of[...i.allKeyframes]){const s=nt(e,n.t),r=this.fovOf(e,n.t),o=Gn.of(e.instrument,it.CANVAS_HEIGHT_PX,r);i.addKeyframe(n.t,n.shapes.map(l=>({...l,shape:t(l.shape,o,s)})))}}}function vy(a){return mn.restore(yu(a),a.provenance)}function yu(a){return gi.toAngular(a),gi.toAim(a),{version:1,id:a.id,time:a.event.time,endTime:a.event.endTime,durationSeconds:a.event.durationSeconds,utcOffsetHours:a.event.utcOffsetHours,timeZone:a.event.timeZone,place:a.event.place,observer:a.observer,account:a.account,sway:a.sway,vehicle:a.vehicle,description:a.event.description,tags:a.event.tags,timeline:a.timeline.toJSON(),observerTrack:a.observerTrack.toJSON(),weatherTrack:a.weatherTrack.toJSON(),soundTrack:a.soundTrack.toJSON(),weather:a.weather,decor:a.decor,milestones:a.milestones.length>0?a.milestones:void 0,references:a.references.length>0?a.references:void 0,roads:a.roads.length>0?a.roads:void 0,weatherSource:a.weatherSource,instrument:a.instrumentId,exposureSeconds:a.exposureSeconds,iso:a.iso,interpretation:a.interpretation}}function by(a){const{recording:e,provenance:t}=mn.strip(a),i=yy(e);return i.provenance=t,i}function yy(a){const e=new xh({eventType:"sighting",time:a.time,endTime:a.endTime,durationSeconds:a.durationSeconds,utcOffsetHours:a.utcOffsetHours,timeZone:a.timeZone,place:a.place,description:a.description,tags:a.tags},wh.fromJSON(a.timeline),a.observerTrack?cl.fromJSON(a.observerTrack):new cl,a.weatherTrack?hl.fromJSON(a.weatherTrack):new hl,a.soundTrack?dl.fromJSON(a.soundTrack):new dl,a.observer&&{id:a.observer.id,title:a.observer.title,lastName:a.observer.lastName,firstNames:a.observer.firstNames},a.id,a.weather,a.decor??[],a.weatherSource,a.instrument,a.exposureSeconds??a.observerTrack?.keyframes.map(t=>t.pose.exposureSeconds).find(t=>t!==void 0),ao(a.milestones??[]),a.references??[],a.roads??[]);return e.account=a.account,e.sway=a.sway,e.iso=a.iso,e.vehicle=a.vehicle,e.interpretation=a.interpretation,gi.toBounds(e),gi.toPosition(e),e}class Un{static PIXELS_PER_INSTANT=2;static INSTANTS_PER_FLASH=2;static MAX_INSTANTS=512;static windowEndingAt(e,t){const i=Number.isFinite(t)?Math.max(0,t):0,n=Math.max(0,e-i*1e3),s=Math.max(0,e-n);return{fromMs:n,toMs:e,ms:s,seconds:s/1e3}}static instants(e,t,i,n,s){if(!(n>0))return 1;const r=s>0?Un.travelDegOver(e,t,i,i+n*1e3)/s/Un.PIXELS_PER_INSTANT:0,o=Un.flashesOver(e,n)*Un.INSTANTS_PER_FLASH,l=Math.ceil(Math.max(r,o));return l<2?1:Math.min(Un.MAX_INSTANTS,l)}static travelDegOver(e,t,i,n){let s=0;for(const r of e){if(!r.track||r.track.length<2)continue;const o=Un.directionAt(r,t,i),l=Un.directionAt(r,t,n),c=Math.min(1,Math.max(-1,o.x*l.x+o.y*l.y+o.z*l.z));s=Math.max(s,Math.acos(c)*180/Math.PI)}return s}static flashesOver(e,t){let i=0;for(const n of e)for(const s of n.lights??[])s.pattern.kind==="flash"&&(i=Math.max(i,s.pattern.perMinute));return i/60*t}static directionAt(e,t,i){const n=vr(e,i),s=n.eastM,r=n.altitudeM-t,o=n.northM,l=Math.hypot(s,r,o);return l===0?{x:0,y:1,z:0}:{x:s/l,y:r/l,z:o/l}}}function oo(a,e){for(const t of a){const i=t.toLowerCase().split("-")[0];if(e.includes(i))return i}return"en"}class pr{static preferencesFor(e){const t=navigator.languages??[],i=this.declaredFor(e);return i?[i,...t]:t}static declaredFor(e){for(let t=e;t;){const i=t.closest("[lang]")?.getAttribute("lang")?.trim();if(i)return i;const n=t.getRootNode();t=n instanceof ShadowRoot?n.host:void 0}}}class us{constructor(e){this.preferences=e}read(e){if(e===void 0||typeof e=="string")return e===""?void 0:e;for(const i of this.preferences){const n=e[i]??e[us.base(i)];if(n)return n}const t=new Set(this.preferences.map(i=>us.base(i)));for(const[i,n]of Object.entries(e))if(n&&t.has(us.base(i)))return n;return Object.values(e).find(i=>i)??void 0}write(e,t,i){const n=t?.trim()?t.trim():void 0;if(e===void 0||typeof e=="string")return n;const s={...e},r=Object.keys(s).find(o=>o===i)??Object.keys(s).find(o=>us.base(o)===us.base(i))??i;return n===void 0?delete s[r]:s[r]=n,Object.keys(s).length===0?void 0:s}static base(e){return e.toLowerCase().split("-")[0]}}const Mu=["en","fr"],My={en:()=>Mn(()=>Promise.resolve().then(()=>_y),void 0,import.meta.url).then(a=>a.ufoMessages_en),fr:()=>Mn(()=>import("./UfoMessages_fr-w9ZrScvP.js"),[],import.meta.url).then(a=>a.ufoMessages_fr)};function wy(a){return My[a]()}const xy={en:()=>Mn(()=>Promise.resolve().then(()=>hI),void 0,import.meta.url).then(a=>a.sightingEditorMessages_en),fr:()=>Mn(()=>import("./SightingEditorMessages_fr-JjttH6zH.js"),[],import.meta.url).then(a=>a.sightingEditorMessages_fr)};function Sy(a){return xy[a]()}function Ey(a){return a==="fr"?Mn(()=>import("./TagNames_fr-Dnqq6HQ5.js"),[],import.meta.url).then(e=>e.tagNames_fr):Promise.resolve({})}const _v={play:"Play",pause:"Pause",noDuration:"No observation duration",currentPosition:"Current position",duration:"Duration",switchToElapsed:"click to show elapsed time",switchToClockTime:"click to show the time of day",fullscreen:"Fullscreen",exitFullscreen:"Exit fullscreen",showObserverMap:"Show where the observer was",hideObserverMap:"Hide where the observer was",mapImageryUnavailable:"Aerial imagery unavailable",zoomMapIn:"Zoom in",zoomMapOut:"Zoom out",fitMap:"Back to the whole path",placeObserverHere:"Put the observer here",showReferences:"Show the pictures of the place",hideReferences:"Hide the pictures of the place",referenceOpacity:"Picture opacity",showMilestones:"Show the account's moments",hideMilestones:"Hide the account's moments",observerHere:"The observer, here",decorHere:"Scenery"},_y=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:_v},Symbol.toStringTag,{value:"Module"})),Av=Math.PI/180,Ay=180/Math.PI,Ty=256,Tv=19,Iy=1.25;function Iv(a,e){return 156543.03392*Math.cos(a*Av)/2**e}function Dv(a,e){return Iv(a,e)*Ty}function Dy(a,e){let t=0;for(;t<Tv&&Dv(a,t+1)>=e;)t++;return t}function Cv(a,e){return Dv(a,e)}function Cy(a,e){const t=e*Iy;let i=0;for(;i<Tv&&Iv(a,i)>t;)i++;return i}function Lc(a){const e=a*Av;return(1-Math.log(Math.tan(e)+1/Math.cos(e))/Math.PI)/2}function Rv(a,e,t){const i=2**t;return{x:(a+180)/360*i,y:Lc(e)*i}}function Pv(a,e,t){const i=Lc(a.north),n=Lc(a.south);return{x:(e-a.west)/(a.east-a.west),y:(Lc(t)-i)/(n-i)}}function Ry(a,e,t){const{x:i,y:n}=Rv(a,e,t);return{x:Math.floor(i),y:Math.floor(n),z:t}}function Py(a){const e=2**a.z,t=a.x/e*360-180,i=(a.x+1)/e*360-180,n=b0(a.y,e);return{south:b0(a.y+1,e),north:n,west:t,east:i}}function b0(a,e){const t=a/e;return Math.atan(Math.sinh(Math.PI*(1-2*t)))*Ay}function Lv(a,e,t,i){const n=Ry(a,e,t),s=Math.floor(i/2),r=[];for(let c=-s;c<=s;c++)for(let h=-s;h<=s;h++)r.push({x:n.x+h,y:n.y+c,z:t});const o=r.map(Py),l={south:Math.min(...o.map(c=>c.south)),north:Math.max(...o.map(c=>c.north)),west:Math.min(...o.map(c=>c.west)),east:Math.max(...o.map(c=>c.east))};return{tiles:r,bounds:l}}class Fr{constructor(e){this.ctx=e}static SCALE_STEPS_M=[5e3,2e3,1e3,500,200,100,50,20,10,5];static MARKER_RADIUS_PX=8.5;static ON_MARKER_M=3;targets=[];hitTest(e,t){let i,n=1/0;for(const s of this.targets){const r=Math.hypot(s.x-e,s.y-t);r>s.radius||r>n||(i=s,n=r)}return i}get width(){return this.ctx.canvas.width}get height(){return this.ctx.canvas.height}paint(e){const{ctx:t}=this;t.save(),this.targets=[],t.clearRect(0,0,this.width,this.height),this.paintGround(e),this.paintNight(e.nightFraction),this.paintPath(e),e.position?(this.paintCone(e,e.position),this.paintDecor(e),this.paintMarkers(e),this.paintObserver(e,e.position)):(this.paintDecor(e),this.paintMarkers(e)),this.paintNorth(),this.paintFooter(e.bounds,e.attribution),t.restore()}toCanvas(e,t,i){const n=Pv(e,i,t);return{x:n.x*this.width,y:n.y*this.height}}paintGround(e){const{ctx:t}=this;t.fillStyle="#1d2321",t.fillRect(0,0,this.width,this.height);const i=e.imagery;if(!i)return;const n=this.toCanvas(e.bounds,i.bounds.north,i.bounds.west),s=this.toCanvas(e.bounds,i.bounds.south,i.bounds.east);t.drawImage(i.source,n.x,n.y,s.x-n.x,s.y-n.y)}paintNight(e=0){if(e<=0)return;const{ctx:t}=this;t.save(),t.fillStyle=`rgba(6, 12, 30, ${Math.min(e,1)*.78})`,t.fillRect(0,0,this.width,this.height),t.restore()}paintDecor(e){const{ctx:t}=this;for(const i of e.decor){const n=this.toCanvas(e.bounds,i.lat,i.lng);if(i.label&&this.targets.push({kind:"decor",label:i.label,lat:i.lat,lng:i.lng,x:n.x,y:n.y,radius:7}),t.beginPath(),t.rect(n.x-3.5,n.y-3.5,7,7),t.fillStyle="rgba(120, 220, 255, 0.85)",t.fill(),t.lineWidth=1.5,t.strokeStyle="rgba(0, 0, 0, 0.7)",t.stroke(),i.headingDeg===void 0)continue;const s=(i.headingDeg-90)*Math.PI/180;t.beginPath(),t.moveTo(n.x,n.y),t.lineTo(n.x+Math.cos(s)*10,n.y+Math.sin(s)*10),t.lineWidth=3,t.strokeStyle="rgba(0, 0, 0, 0.6)",t.stroke(),t.lineWidth=1.5,t.strokeStyle="rgba(120, 220, 255, 0.9)",t.stroke()}}paintPath(e){if(!e.path.moved)return;const{ctx:t}=this,i=e.path.points.map(n=>this.toCanvas(e.bounds,n.lat,n.lng));t.beginPath(),t.moveTo(i[0].x,i[0].y);for(const n of i.slice(1))t.lineTo(n.x,n.y);t.lineJoin="round",t.lineCap="round",t.strokeStyle="rgba(0, 0, 0, 0.65)",t.lineWidth=5,t.stroke(),t.strokeStyle="rgba(255, 255, 255, 0.9)",t.lineWidth=2,t.stroke()}paintCone(e,t){const{headingDeg:i,coneHalfAngleDeg:n}=e;if(i===void 0||n===void 0)return;const{ctx:s}=this,r=this.toCanvas(e.bounds,t.lat,t.lng),o=Math.hypot(this.width,this.height),l=(i-90)*Math.PI/180,c=n*Math.PI/180;s.save(),s.beginPath(),s.moveTo(r.x,r.y),s.arc(r.x,r.y,o,l-c,l+c),s.closePath();const h=s.createRadialGradient(r.x,r.y,0,r.x,r.y,o);h.addColorStop(0,"rgba(255, 224, 130, 0.55)"),h.addColorStop(.35,"rgba(255, 224, 130, 0.22)"),h.addColorStop(1,"rgba(255, 224, 130, 0)"),s.fillStyle=h,s.fill(),s.restore()}paintMarkers(e){const{ctx:t}=this;t.textAlign="center",t.textBaseline="middle",t.font="bold 10px sans-serif";for(const i of[...e.markers].sort((n,s)=>Number(n.current)-Number(s.current))){const n=this.toCanvas(e.bounds,i.lat,i.lng);this.targets.push({kind:"milestone",label:i.note?`${i.label} — ${i.note}`:i.label,lat:i.lat,lng:i.lng,t:i.t,x:n.x,y:n.y,radius:Fr.MARKER_RADIUS_PX}),t.beginPath(),t.arc(n.x,n.y,Fr.MARKER_RADIUS_PX,0,Math.PI*2),t.fillStyle=i.current?"rgba(255, 224, 130, 0.95)":"rgba(0, 0, 0, 0.55)",t.fill(),t.lineWidth=2,t.strokeStyle="rgba(255, 255, 255, 0.9)",t.stroke(),t.fillStyle=i.current?"#1d2321":"#fff",t.fillText(i.label,n.x,n.y)}}paintObserver(e,t){const{ctx:i}=this,n=this.toCanvas(e.bounds,t.lat,t.lng);e.observerLabel&&this.targets.push({kind:"observer",label:e.observerLabel,lat:t.lat,lng:t.lng,x:n.x,y:n.y,radius:8});const s=e.markers.some(r=>{if(!r.current)return!1;const o=li(r.lat,r.lng,t.lat,t.lng);return Math.hypot(o.x,o.z)<=Fr.ON_MARKER_M});i.beginPath(),i.arc(n.x,n.y,s?Fr.MARKER_RADIUS_PX+2.5:5.5,0,Math.PI*2),s||(i.fillStyle="#ff5a3c",i.fill()),i.lineWidth=4,i.strokeStyle="rgba(0, 0, 0, 0.5)",i.stroke(),i.lineWidth=s?3:2.5,i.strokeStyle=s?"#ff5a3c":"#fff",i.stroke()}paintNorth(){const{ctx:e}=this,t=this.width-14,i=16;e.beginPath(),e.moveTo(t,i-9),e.lineTo(t-4.5,i+5),e.lineTo(t,i+2),e.lineTo(t+4.5,i+5),e.closePath(),e.fillStyle="rgba(255, 255, 255, 0.92)",e.strokeStyle="rgba(0, 0, 0, 0.6)",e.lineWidth=1,e.fill(),e.stroke(),e.font="bold 9px sans-serif",e.textAlign="center",e.textBaseline="top",e.strokeText("N",t,i+6),e.fillText("N",t,i+6)}paintFooter(e,t){const{ctx:i}=this;i.font="9px sans-serif",i.textBaseline="bottom";const n=t?this.wrap(t,this.width-20):[];let s=this.height-4;i.textAlign="right";for(const f of n.slice().reverse())this.paintOutlinedText(f,this.width-6,s),s-=11;const r=(e.south+e.north)/2,l=Math.abs(li(r,e.east,r,e.west).x)/this.width,c=Fr.SCALE_STEPS_M.find(f=>f/l<=this.width/3);if(c===void 0)return;const h=c/l,d=8,u=s-3;i.lineWidth=3,i.strokeStyle="rgba(0, 0, 0, 0.6)",i.beginPath(),i.moveTo(d,u),i.lineTo(d+h,u),i.stroke(),i.lineWidth=1.5,i.strokeStyle="rgba(255, 255, 255, 0.95)",i.stroke(),i.textAlign="left",this.paintOutlinedText(c>=1e3?`${c/1e3} km`:`${c} m`,d,u-3)}paintOutlinedText(e,t,i){const{ctx:n}=this;n.lineWidth=3,n.strokeStyle="rgba(0, 0, 0, 0.75)",n.strokeText(e,t,i),n.fillStyle="#fff",n.fillText(e,t,i)}wrap(e,t){const i=[];let n="";for(const s of e.split(" ")){const r=n?`${n} ${s}`:s;n&&this.ctx.measureText(r).width>t?(i.push(n),n=s):n=r}return n&&i.push(n),i}}class xi{static MIN_ZOOM=.25;static MAX_ZOOM=64;zoom=1;centerX=.5;centerY=.5;get changed(){return this.zoom!==1||this.centerX!==.5||this.centerY!==.5}get zoomFactor(){return this.zoom}reset(){this.zoom=1,this.centerX=.5,this.centerY=.5}zoomAt(e,t,i){const n=Math.min(xi.MAX_ZOOM,Math.max(xi.MIN_ZOOM,this.zoom*i)),s=this.centerX+(e-.5)/this.zoom,r=this.centerY+(t-.5)/this.zoom;this.centerX=s-(e-.5)/n,this.centerY=r-(t-.5)/n,this.zoom=n}panBy(e,t){this.centerX-=e/this.zoom,this.centerY-=t/this.zoom}refit(e,t){if(!this.changed)return;const i=this.boundsWithin(e),n=xi.mercatorY01(t.north),s=xi.mercatorY01(t.south),r=xi.mercatorY01(i.north),o=xi.mercatorY01(i.south);this.zoom=(t.east-t.west)/(i.east-i.west),this.centerX=((i.west+i.east)/2-t.west)/(t.east-t.west),this.centerY=((r+o)/2-n)/(s-n)}boundsWithin(e){if(!this.changed)return e;const t=.5/this.zoom,i=xi.mercatorY01(e.north),n=xi.mercatorY01(e.south),s=e.east-e.west;return{west:e.west+(this.centerX-t)*s,east:e.west+(this.centerX+t)*s,north:xi.latitudeAt(i+(this.centerY-t)*(n-i)),south:xi.latitudeAt(i+(this.centerY+t)*(n-i))}}static pointAt(e,t,i){const n=xi.mercatorY01(e.north),s=xi.mercatorY01(e.south);return{lat:xi.latitudeAt(n+i*(s-n)),lng:e.west+t*(e.east-e.west)}}static mercatorY01(e){const t=e*Math.PI/180;return(1-Math.log(Math.tan(t)+1/Math.cos(t))/Math.PI)/2}static latitudeAt(e){return Math.atan(Math.sinh(Math.PI*(1-2*e)))*180/Math.PI}}const xn=256,y0=3,Ly=32768;class Ov{fetchImpl;tileUrlTemplate;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=e.tileUrlTemplate??"https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png"}async getElevationGrid(e,t){const i=(e.south+e.north)/2,n=(e.west+e.east)/2,s=Math.abs(li(i,e.east,i,e.west).x),r=Math.abs(li(e.north,n,e.south,n).z),o=Dy(i,Math.max(s,r)),{tiles:l}=Lv(n,i,o,y0),c=y0*xn,h=new Float32Array(c*c),d=l[0];await Promise.all(l.map(f=>this.decodeTileInto(f,d,h,c)));const u=new Float32Array(t.width*t.height);for(let f=0;f<t.height;f++){const p=e.north+(e.south-e.north)*(f/(t.height-1));for(let v=0;v<t.width;v++){const m=e.west+(e.east-e.west)*(v/(t.width-1));u[f*t.width+v]=this.sampleAt(p,m,o,d,h,c)}}return{heights:u,width:t.width,height:t.height,bounds:e}}async decodeTileInto(e,t,i,n){const s=this.tileUrlTemplate.replace("{z}",String(e.z)).replace("{x}",String(e.x)).replace("{y}",String(e.y)),r=await this.fetchImpl(s);if(!r.ok)throw new Error(`Elevation tile fetch failed (${r.status}): ${s}`);const o=await createImageBitmap(await r.blob()),l=document.createElement("canvas");l.width=xn,l.height=xn;const c=l.getContext("2d");if(!c)throw new Error("2D canvas context unavailable");c.drawImage(o,0,0);const{data:h}=c.getImageData(0,0,xn,xn),d=(e.x-t.x)*xn,u=(e.y-t.y)*xn;for(let f=0;f<xn;f++)for(let p=0;p<xn;p++){const v=(f*xn+p)*4,m=h[v]*256+h[v+1]+h[v+2]/256-Ly,g=d+p,y=u+f;i[y*n+g]=m}}sampleAt(e,t,i,n,s,r){const{x:o,y:l}=Rv(t,e,i),c=(o-n.x)*xn,h=(l-n.y)*xn,d=Math.max(0,Math.min(r-1,Math.floor(c))),u=Math.max(0,Math.min(r-1,Math.floor(h))),f=Math.min(r-1,d+1),p=Math.min(r-1,u+1),v=c-d,m=h-u,g=s[u*r+d],y=s[u*r+f],M=s[p*r+d],b=s[p*r+f],x=g+(y-g)*v,E=M+(b-M)*v;return x+(E-x)*m}}const Oc=256,Oy=5;async function kv(a,e,t,i){const n=(a.south+a.north)/2,s=(a.west+a.east)/2,r=Math.abs(li(n,a.east,n,a.west).x),o=Math.abs(li(a.north,s,a.south,s).z),l=Math.max(r,o),{zoom:c,gridSize:h}=ky(n,l,Math.max(e.width,e.height)),{tiles:d,bounds:u}=Lv(s,n,c,h),f=h*Oc,p=document.createElement("canvas");p.width=f,p.height=f;const v=p.getContext("2d");if(!v)throw new Error("2D canvas context unavailable");const m=d[0];await Promise.all(d.map(async b=>{const x=t(b),E=await i(x);if(!E.ok)throw new Error(`Imagery tile fetch failed (${E.status}): ${x}`);const I=await createImageBitmap(await E.blob());v.drawImage(I,(b.x-m.x)*Oc,(b.y-m.y)*Oc)}));const g=Math.min(Math.max(e.width,e.height),f);if(g===f)return{source:p,width:f,height:f,bounds:u};const y=document.createElement("canvas");y.width=g,y.height=g;const M=y.getContext("2d");if(!M)throw new Error("2D canvas context unavailable");return M.drawImage(p,0,0,f,f,0,0,g,g),{source:y,width:g,height:g,bounds:u}}function ky(a,e,t){let i=Cy(a,e/Math.max(1,t)),n=M0(a,i,e);for(;n>Oy&&i>0;)i--,n=M0(a,i,e);return{zoom:i,gridSize:n,mPerPixel:Cv(a,i)/Oc}}function M0(a,e,t){const i=Math.ceil(t/2/Cv(a,e));return Math.max(3,2*i+1)}class Nv{attribution="Imagery © Esri, Maxar, Earthstar Geographics, and the GIS User Community";fetchImpl;tileUrlTemplate;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=e.tileUrlTemplate??"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"}async getImageryTexture(e,t){return kv(e,t,i=>this.tileUrlTemplate.replace("{z}",String(i.z)).replace("{y}",String(i.y)).replace("{x}",String(i.x)),this.fetchImpl)}}class On{attribution="Roads © OpenStreetMap contributors, as surveyed today";contemporary=!0;static DRIVABLE=["motorway","trunk","primary","secondary","tertiary","unclassified","residential","service","track","motorway_link","trunk_link","primary_link","secondary_link","tertiary_link"];static WIDTH_M={motorway:11,trunk:9,primary:8,secondary:7,tertiary:6.5,unclassified:5.5,residential:5.5,service:4,track:3.5};static DEFAULT_WIDTH_M=5;static ENDPOINTS=["https://overpass-api.de/api/interpreter","https://overpass.kumi.systems/api/interpreter","https://overpass.private.coffee/api/interpreter"];fetchImpl;endpoints;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.endpoints=e.endpoints??On.ENDPOINTS}static queue=Promise.resolve();static RETRY_MS=4e3;async getRoads(e){const t=`${e.south},${e.west},${e.north},${e.east}`,i=`[out:json][timeout:30];way["highway"~"^(${On.DRIVABLE.join("|")})$"](${t});out geom;`;return this.waysFrom(await this.queued(()=>this.ask(i)))}waysFrom(e){const t=[];for(const i of e.elements??[]){const n=i.geometry,s=i.tags;!s||!n||n.length<2||t.push({id:`osm-${i.id??t.length}`,name:s.name,surface:On.surfaceOf(s),widthM:On.widthOf(s),points:n.map(r=>({lat:r.lat,lng:r.lon}))})}return t}queued(e){const t=On.queue.then(e,e);return On.queue=t.catch(()=>{}),t}async ask(e){let t;for(const i of this.endpoints)for(let n=0;n<2;n++){try{const s=await this.fetchImpl(`${i}?data=${encodeURIComponent(e)}`);if(s.ok)return await s.json();if(t=new Error(`${new URL(i).host} refused (${s.status})`),s.status!==429&&s.status!==504)break}catch(s){t=new Error(`${new URL(i).host} unreachable (${String(s)})`);break}await new Promise(s=>setTimeout(s,On.RETRY_MS))}throw t??new Error("No Overpass instance answered")}static widthOf(e){const t=Number.parseFloat(e.width??e.est_width??"");if(Number.isFinite(t)&&t>0)return t;const i=Number.parseInt(e.lanes??"",10);return Number.isFinite(i)&&i>0?i*3.5:On.WIDTH_M[e.highway]??On.DEFAULT_WIDTH_M}static surfaceOf(e){const t=e.surface;return t==="dirt"||t==="earth"||t==="mud"?"dirt":t==="gravel"||t==="fine_gravel"||t==="compacted"||t==="ground"||t==="sand"||t==="unpaved"?"gravel":t?"paved":e.highway==="track"?"gravel":"paved"}}const Wh="https://ufoathome.org/roads/index.json";class Qf{attributionRead;contemporaryRead;fetchImpl;indexUrls;fallback;index;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.indexUrls=e.indexUrls??Qf.defaultIndexUrls(),this.fallback=e.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Roads © OpenStreetMap contributors"}get contemporary(){return this.contemporaryRead??this.fallback?.contemporary??!0}async getRoads(e){const t=await this.held(e);if(t)return t;if(!this.fallback)return[];const i=await this.fallback.getRoads(e);return this.attributionRead=this.fallback.attribution,this.contemporaryRead=this.fallback.contemporary,i}async held(e){let t;try{t=await this.load()}catch{return}const i=t.find(({entry:n})=>n.north>=e.north&&n.south<=e.south&&n.east>=e.east&&n.west<=e.west);if(i)try{const n=await this.fetchImpl(new URL(i.entry.file,i.indexUrl).href);if(!n.ok)return;const s=await n.json();return Array.isArray(s?.ways)?(this.attributionRead=s.attribution,this.contemporaryRead=s.contemporary,s.ways):void 0}catch{return}}load(){return this.index??=this.fetchFirstAvailable(),this.index}async fetchFirstAvailable(){for(const e of this.indexUrls)try{const t=await this.fetchImpl(e);if(!t.ok)continue;const i=await t.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:e}))}catch{}return[]}static defaultIndexUrls(){const e=`?v=${encodeURIComponent("0.69.2")}`,t=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(t&&t!==Wh?[t,Wh]:[Wh]).map(i=>i+e)}}function Ny(){return{elevation:new Ov,imagery:Fv(),roads:Fy()}}function Fv(){return new Nv}function Fy(){return new Qf({fallback:new On})}const Uy=new Set,Zr="show-observer-map",$a="hide-milestones";class Li extends HTMLElement{static get observedAttributes(){return["src",Zr,$a]}shadow;stageElement;canvas;canvasRenderer;tooltip;toolbar;playPauseButton;static OBSERVER_MAP_MIN_SPAN_M=400;static OBSERVER_MAP_MARGIN=.6;static OBSERVER_MAP_IMAGERY_PX=768;fullscreenButton;observerMapButton;referencesButton;referenceOpacityInput;referencesShownState=!0;referenceOpacityTouched=!1;milestonesButton;observerMapPanel;observerMapCanvas;observerMapRenderer;mapZoomInButton;mapZoomOutButton;mapFitButton;observerMapView=new xi;observerMapDrag;suppressObserverMapClick=!1;observerMapImageryTimer;observerPlacing=!1;seekInput;playbackFlash;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;observerPath;observerMapBounds;observerMapImagery;observerMapImageryBounds;observerMapImageryCredit;observerMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=xh.create();sightingAudio=new gy;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;steadyObserver=!1;selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=_v;realDurationMs;realStartMs;showClockTime=!0;handleFullscreenChange=()=>{this.updateFullscreenButton(),this.resizeObserverMap()};observerMapResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.resizeObserverMap());resizeObserverMap(){this.observerMapPanel.hidden||(this.sizeObserverMapCanvas(),this.paintObserverMap(this.currentTime))}simulatedFullscreen=!1;styleBeforeSimulatedFullscreen;bodyOverflowBeforeSimulatedFullscreen;handleSimulatedFullscreenKey=e=>{e.key==="Escape"&&this.exitSimulatedFullscreen()};handlePointerMove=e=>{const t=this.canvasPointFromEvent(e),i=t&&this.shapeAt(t.x,t.y),n=this.said.read(i?.shape.title);if(!n){this.tooltip.hidden=!0;return}this.tooltip.textContent=n,this.tooltip.hidden=!1;const s=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${e.clientX-s.left+12}px`,this.tooltip.style.top=`${e.clientY-s.top+12}px`};handleObserverMapPointerMove=e=>{if(this.dragObserverMap(e))return;const t=this.observerMapTargetFrom(e);if(!t){if(!this.observerPlacing){this.tooltip.hidden=!0,this.observerMapCanvas.style.cursor="grab";return}this.observerMapCanvas.style.cursor="crosshair",this.showObserverMapTooltip(e,this.messages.placeObserverHere);return}this.observerMapCanvas.style.cursor="pointer",this.showObserverMapTooltip(e,t.label)};showObserverMapTooltip(e,t){this.tooltip.textContent=t,this.tooltip.hidden=!1;const i=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${e.clientX-i.left+12}px`,this.tooltip.style.top=`${e.clientY-i.top+12}px`}handleObserverMapClick=e=>{if(this.suppressObserverMapClick){this.suppressObserverMapClick=!1;return}const t=this.observerMapTargetFrom(e);if(!t){this.observerPlacing&&this.placeObserverFrom(e);return}if(t.kind==="milestone"&&t.t!==void 0){this.player.seek(t.t);return}this.dispatchEvent(new CustomEvent("lookat",{detail:{lat:t.lat,lng:t.lng,kind:t.kind},bubbles:!0,composed:!0}))};observerMapTargetFrom(e){const t=this.observerMapCanvas.getBoundingClientRect();if(!(t.width===0||t.height===0))return this.observerMapRenderer.hitTest((e.clientX-t.left)/t.width*this.observerMapCanvas.width,(e.clientY-t.top)/t.height*this.observerMapCanvas.height)}handlePointerLeave=()=>{this.tooltip.hidden=!0};handleObserverMapPointerDown=e=>{e.button===0&&(this.suppressObserverMapClick=!1,this.observerMapDrag={pointerId:e.pointerId,startX:e.clientX,startY:e.clientY,lastX:e.clientX,lastY:e.clientY,moved:!1})};handleObserverMapPointerUp=e=>{const t=this.observerMapDrag;!t||t.pointerId!==e.pointerId||(this.observerMapDrag=void 0,this.observerMapCanvas.classList.remove("dragging"),t.moved&&(this.suppressObserverMapClick=!0,this.observerMapCanvas.hasPointerCapture?.(e.pointerId)&&this.observerMapCanvas.releasePointerCapture(e.pointerId)))};dragObserverMap(e){const t=this.observerMapDrag;if(!t||t.pointerId!==e.pointerId)return!1;if(!t.moved){if(Math.hypot(e.clientX-t.startX,e.clientY-t.startY)<Li.OBSERVER_MAP_DRAG_PX)return!1;t.moved=!0,this.tooltip.hidden=!0,this.observerMapCanvas.classList.add("dragging"),this.observerMapCanvas.setPointerCapture?.(e.pointerId)}const i=this.observerMapCanvas.getBoundingClientRect();return i.width>0&&i.height>0&&(this.observerMapView.panBy((e.clientX-t.lastX)/i.width,(e.clientY-t.lastY)/i.height),this.observerMapViewChanged()),t.lastX=e.clientX,t.lastY=e.clientY,!0}static OBSERVER_MAP_DRAG_PX=4;handleObserverMapWheel=e=>{e.preventDefault();const t=this.observerMapCanvas.getBoundingClientRect();if(t.width===0||t.height===0)return;const i=e.deltaMode===0?e.deltaY:e.deltaY*40;this.zoomObserverMap((e.clientX-t.left)/t.width,(e.clientY-t.top)/t.height,Math.exp(-i*.002))};zoomObserverMap(e,t,i){this.observerMapView.zoomAt(e,t,i),this.observerMapViewChanged()}observerMapViewChanged(){this.mapFitButton.hidden=!this.observerMapView.changed,this.mapZoomInButton.disabled=this.observerMapView.zoomFactor>=xi.MAX_ZOOM,this.mapZoomOutButton.disabled=this.observerMapView.zoomFactor<=xi.MIN_ZOOM,this.paintObserverMap(this.currentTime),clearTimeout(this.observerMapImageryTimer),this.observerMapImageryTimer=setTimeout(()=>void this.loadObserverMapImagery(),Li.OBSERVER_MAP_IMAGERY_DELAY_MS)}static OBSERVER_MAP_IMAGERY_DELAY_MS=300;get observerMapViewBounds(){return this.observerMapBounds&&this.observerMapView.boundsWithin(this.observerMapBounds)}placeObserverFrom(e){const t=this.observerMapViewBounds,i=this.observerMapCanvas.getBoundingClientRect();if(!t||i.width===0||i.height===0)return;const n=xi.pointAt(t,(e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height);this.dispatchEvent(new CustomEvent("observerplace",{detail:n,bubbles:!0,composed:!0}))}constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${uy}</style>${dy}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new ul(this.canvas.getContext("2d")),this.tooltip=this.shadow.getElementById("tooltip"),this.toolbar=this.shadow.getElementById("toolbar"),this.playPauseButton=this.shadow.getElementById("play-pause"),this.fullscreenButton=this.shadow.getElementById("fullscreen"),this.observerMapButton=this.shadow.getElementById("observer-map"),this.referencesButton=this.shadow.getElementById("references"),this.referenceOpacityInput=this.shadow.getElementById("reference-opacity"),this.milestonesButton=this.shadow.getElementById("milestones"),this.observerMapPanel=this.shadow.getElementById("observer-map-panel"),this.observerMapCanvas=this.shadow.getElementById("observer-map-canvas"),this.observerMapRenderer=new Fr(this.observerMapCanvas.getContext("2d")),this.mapZoomInButton=this.shadow.getElementById("map-zoom-in"),this.mapZoomOutButton=this.shadow.getElementById("map-zoom-out"),this.mapFitButton=this.shadow.getElementById("map-fit"),this.seekInput=this.shadow.getElementById("seek"),this.playbackFlash=this.shadow.getElementById("playback-flash"),this.milestoneMarks=this.shadow.getElementById("milestone-marks"),this.milestoneCaption=this.shadow.getElementById("milestone-caption"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end");for(const t of[this.timeStartLabel,this.timeEndLabel])t.addEventListener("click",()=>this.toggleTimeDisplay()),t.addEventListener("keydown",i=>{i.key!=="Enter"&&i.key!==" "||(i.preventDefault(),this.toggleTimeDisplay())});this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.observerMapButton.addEventListener("click",()=>this.toggleObserverMap()),this.referencesButton.addEventListener("click",()=>this.toggleReferences()),this.referenceOpacityInput.addEventListener("input",()=>{this.referenceOpacityTouched=!0,this.dispatchReferenceView()}),this.milestonesButton.addEventListener("click",()=>this.toggleMilestones()),this.observerMapCanvas.addEventListener("pointermove",this.handleObserverMapPointerMove),this.observerMapCanvas.addEventListener("pointerleave",this.handlePointerLeave),this.observerMapCanvas.addEventListener("click",this.handleObserverMapClick),this.observerMapCanvas.addEventListener("pointerdown",this.handleObserverMapPointerDown),this.observerMapCanvas.addEventListener("pointerup",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("pointercancel",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("wheel",this.handleObserverMapWheel,{passive:!1}),this.mapZoomInButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,2)),this.mapZoomOutButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,.5)),this.mapFitButton.addEventListener("click",()=>{this.observerMapView.reset(),this.observerMapViewChanged()}),this.seekInput.addEventListener("input",()=>this.player.seek(this.snapSeekToMark(Number(this.seekInput.value)))),this.seekInput.addEventListener("pointerdown",t=>{this.seekSnapArmed=!0,this.nameMarkUnder(t)}),this.seekInput.addEventListener("pointerup",()=>{this.seekSnapArmed=!1}),this.seekInput.addEventListener("pointermove",t=>this.nameMarkUnder(t)),this.seekInput.addEventListener("pointerleave",()=>this.seekInput.removeAttribute("title")),this.seekInput.addEventListener("keydown",this.handleSeekKey),this.canvas.addEventListener("click",t=>{this.enableClickToPlay&&(t.detail<=1&&(this.playbackBeforeClick={state:this.playbackState,time:this.currentTime}),this.togglePlayPause())}),this.canvas.addEventListener("dblclick",t=>{this.enableClickToPlay&&(t.preventDefault(),this.restorePlayback(),this.toggleFullscreen())}),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerleave",this.handlePointerLeave),document.addEventListener("fullscreenchange",this.handleFullscreenChange),this.observerMapResizeObserver?.observe(this.observerMapPanel),this.hostControls(void 0),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateMilestonesButton(),this.refresh(),this.loadLocaleMessages()}connectedCallback(){this.saidTexts=void 0;const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.observerMapResizeObserver?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(e,t,i){e==="src"&&i&&i!==t&&this.isConnected&&this.loadFromSrc(i),e===Zr&&this.applyObserverMapDefault(),e===$a&&this.setMilestonesShown(!this.hasAttribute($a))}async loadFromSrc(e){this.sightingData=await Zf.json(e)}get sightingData(){return vy(this.currentSighting)}set sightingData(e){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=by(e),this.observerMapView.reset(),this.mapFitButton.hidden=!0,this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyObserverMapDefault()}get sighting(){return this.currentSighting}previewSound(e){this.soundPreview=e,this.sightingAudio.resume(),this.sightingAudio.setSound(e)}stopSoundPreview(){this.soundPreview=void 0,this.sightingAudio.silence()}get canvasElement(){return this.canvas}get renderer(){return this.canvasRenderer}get currentTime(){return this.player.time}set currentTime(e){this.player.seek(e)}get seekableDuration(){return this.player.seekableDuration}get autoReplayEnabled(){return this.loopEnabled}set autoReplayEnabled(e){e!==this.loopEnabled&&this.toggleLoop()}play(){this.player.seekableDuration<=0||this.playbackState==="playing"||this.togglePlayPause()}pause(){this.playbackState==="playing"&&this.togglePlayPause()}get positionLabel(){return this.timeStartLabel.textContent??""}get durationLabel(){return this.timeEndLabel.textContent??""}get showingClockTime(){return this.canShowClockTime}get canSwitchTimeDisplay(){return this.realStartMs!==void 0}toggleTimeDisplay(){this.canSwitchTimeDisplay&&(this.showClockTime=!this.showClockTime,this.updateTimeLabels(),this.updateTimeLabelTitles(),this.dispatchEvent(new CustomEvent("timedisplaychange",{bubbles:!0,composed:!0})))}get canShowClockTime(){return this.realStartMs!==void 0&&this.showClockTime}set showToolbar(e){this.toolbar.classList.toggle("hidden",!e)}get playbackState(){return this.player.playbackState}get selectedSourceIds(){return this.highlightedSourceIds}get durationSeconds(){return this.currentSighting.event.durationSeconds}set durationSeconds(e){this.currentSighting.event.durationSeconds=e,this.updateTimeLabels(),this.refresh(),this.updatePlayPauseButton()}set selectedSourceIds(e){const t=new Set(e);t.size===this.highlightedSourceIds.size&&[...t].every(n=>this.highlightedSourceIds.has(n))||(this.highlightedSourceIds=t,this.refresh())}hasVisibleShapeAt(e,t){return this.shapeAt(e,t)!==void 0}refresh(){this.applyFrameFormat(),this.updateTimeLabels(),this.seekInput.max=String(this.player.seekableDuration),this.refreshMilestoneMarks(),this.updateMilestonesButton(),this.updateObserverMap(),this.updateReferences(),this.player.seek(this.player.time)}hostControls(e){const t=[this.milestonesButton,this.referenceOpacityInput,this.referencesButton,this.observerMapButton];if(e)for(const i of t)e.appendChild(i);else for(const i of t)this.toolbar.appendChild(i)}get referencesShown(){return this.referencesShownState}get referenceOpacity(){return Number(this.referenceOpacityInput.value)}toggleReferences(){this.referencesShownState=!this.referencesShownState,this.updateReferencesButton(),this.dispatchReferenceView()}updateReferences(){const e=this.currentSighting.references;!this.referenceOpacityTouched&&e.length>0&&(this.referenceOpacityInput.value=String(e[0].opacity)),this.updateReferencesButton()}updateReferencesButton(){const e=this.currentSighting.references.length>0;this.referencesButton.hidden=!e,this.referenceOpacityInput.hidden=!e||!this.referencesShownState,this.referencesButton.setAttribute("aria-pressed",String(this.referencesShownState));const t=this.referencesShownState?this.messages.hideReferences:this.messages.showReferences;this.referencesButton.title=t,this.referencesButton.setAttribute("aria-label",t),this.referenceOpacityInput.title=this.messages.referenceOpacity,this.referenceOpacityInput.setAttribute("aria-label",this.messages.referenceOpacity)}dispatchReferenceView(){this.dispatchEvent(new CustomEvent("referenceview",{detail:{shown:this.referencesShown,opacity:this.referenceOpacity}}))}refreshMilestoneMarks(){const e=this.player.seekableDuration,t=e>0?ao(this.sighting.milestones):[];this.milestoneMarks.replaceChildren(...t.map(i=>{const n=document.createElement("button");n.type="button",n.className="milestone-mark",n.style.left=`${Math.min(Math.max(i.t/e,0),1)*100}%`;const s=this.said.read(i.label)??"",r=this.said.read(i.note),o=r?`${s} — ${r}`:s;return n.title=o,n.setAttribute("aria-label",o),n.dataset.t=String(i.t),n.addEventListener("click",()=>this.player.seek(i.t)),n}))}seekSnapArmed=!1;static MARK_SNAP_PX=6;markNear(e){const t=this.player.seekableDuration,i=this.seekInput.getBoundingClientRect().width;if(t<=0||i<=0)return;const n=Li.MARK_SNAP_PX/i*t;let s;for(const r of this.milestoneMarks.children){const o=Number(r.dataset.t);Math.abs(o-e)>n||(!s||Math.abs(o-e)<Math.abs(s.t-e))&&(s={t:o,name:r.title})}return s}snapSeekToMark(e){return this.seekSnapArmed?(this.seekSnapArmed=!1,this.markNear(e)?.t??e):e}nameMarkUnder(e){const t=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(t.width<=0||i<=0)return;const n=(e.clientX-t.left)/t.width*i,s=this.markNear(n);s?this.seekInput.title=s.name:this.seekInput.removeAttribute("title")}showMilestoneAt(e){const t=this.milestonesShown&&this.sighting.milestones.length>0?v0(this.sighting.milestones,e):void 0;if(this.milestoneCaption.hidden=t===void 0,!t)return;const i=document.createElement("b");i.textContent=this.said.read(t.label)??"";const n=this.said.read(t.note),s=n?` — ${n}`:"";this.milestoneCaption.replaceChildren(i,document.createTextNode(s))}exposureInstants(e){const t=this.exposureTimes(e),i=1/t.length;return t.map(n=>({shapes:this.shapesAt(n),share:i}))}exposureTimes(e=this.currentTime){const t=Un.windowEndingAt(e,this.currentSighting.exposure??0);if(t.ms<Li.SHORTEST_VISIBLE_EXPOSURE_MS)return[e];const i=Math.min(Li.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(t.ms/Li.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(t.fromMs,t.ms)/Li.EXPOSURE_STEP_PX),s=Math.min(Li.MAX_TRAVEL_STEPS,Math.max(i,n)),r=[];for(let o=0;o<s;o++)r.push(t.fromMs+t.ms*o/(s-1));return r}travelPxOver(e,t){const i=this.shapesAt(e),n=this.shapesAt(e+t);let s=0;for(const[r,o]of i){const l=n.get(r);if(!l)continue;const c=l.bounds.x+l.bounds.width/2-(o.bounds.x+o.bounds.width/2),h=l.bounds.y+l.bounds.height/2-(o.bounds.y+o.bounds.height/2);s=Math.max(s,Math.hypot(c,h))}return s}shapeAt(e,t,i){for(const n of this.exposureTimes()){const s=this.currentSighting.timeline.hitTest(n,e,t,i);if(s)return s}}shapesAt(e){const t=new Map;for(const i of this.currentSighting.timeline.sourceIds){const n=this.currentSighting.timeline.getInterpolatedShapeAt(e,i);n&&t.set(i,n)}return t}static SHORTEST_VISIBLE_EXPOSURE_MS=20;static MAX_EXPOSURE_STEPS=48;static EXPOSURE_STEP_PX=2;static MAX_TRAVEL_STEPS=320;applyFrameFormat(){const e=Mt.frameWidthPx(this.currentSighting.instrument,this.canvas.height);if(this.canvas.width===e)return;this.canvas.width=e,this.canvas.parentElement?.style.setProperty("--frame-aspect",`${e} / ${this.canvas.height}`)}canvasPointFromEvent(e){const t=this.canvas.getBoundingClientRect();if(!(t.width===0||t.height===0))return{x:(e.clientX-t.left)/t.width*this.canvas.width,y:(e.clientY-t.top)/t.height*this.canvas.height}}onFrame(e,t){this.canvasRenderer.clear(this.canvas.width,this.canvas.height);const i=this.playbackState!=="playing"?this.highlightedSourceIds:Uy;this.canvasRenderer.setStarPoints(Mt.starPointsOf(this.sighting.instrument));const n=(nt(this.sighting,e)?.rollDeg??0)+this.gaitAt(e).rollDeg;this.canvasRenderer.setRoll(n*Math.PI/180);const s=this.exposureInstants(e),r=this.frameShift;if(this.paintsShapes)for(const o of s)for(const[,l]of o.shapes){const c=o.share,h=c===1?l:{...l,transparency:1-(1-l.transparency)*c};this.canvasRenderer.paintShape(this.shifted(h,r))}for(const[o,l]of s[0].shapes)!this.selectionShown||!i.has(o)||(this.paintsShapes?i.size===1?this.canvasRenderer.paintShape({...l,selected:!0}):this.canvasRenderer.paintMemberOutline(l):this.canvasRenderer.paintSelectionOnly(this.shifted(l,r)));if(this.selectionShown&&i.size>1){const o=gt.groupBoundsFor([...t].filter(([l])=>i.has(l)).map(([,l])=>l.bounds));this.canvasRenderer.paintGroupHandles(o)}this.overlayPainter?.(this.canvasRenderer),this.mapShapeBounds=s.flatMap(o=>[...o.shapes.values()].filter(l=>l.transparency<1).map(l=>this.shifted(l,r).bounds)),this.keepObserverMapClear(),this.seekInput.value=String(e),this.timeStartLabel.textContent=this.formatPosition(e),this.showMilestoneAt(e),this.paintObserverMap(e),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(Kf(this.currentSighting,e))):this.soundPreview?this.sightingAudio.setSound(this.soundPreview):this.sightingAudio.silence(),this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("timeupdate",{detail:{time:e}}))}shifted(e,t){return t.x===0&&t.y===0?e:{...e,bounds:{...e.bounds,x:e.bounds.x+t.x,y:e.bounds.y+t.y}}}createPlayer(){const e=new fy(this.currentSighting.timeline,(t,i)=>this.onFrame(t,i));return e.loop=this.loopEnabled,e.onEnded=()=>{this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("ended",{bubbles:!0,composed:!0}))},e}static SEEK_KEY_STEP_MS=5e3;handleSeekKey=e=>{if(e.altKey||e.ctrlKey||e.metaKey)return;const t=e.key==="ArrowLeft"?-1:e.key==="ArrowRight"?1:0;if(t){e.preventDefault();const i=this.player.seekableDuration;this.player.seek(Math.min(i,Math.max(0,this.player.time+t*Li.SEEK_KEY_STEP_MS)))}else e.key===" "&&(e.preventDefault(),this.togglePlayPause())};togglePlayPause(){this.player.seekableDuration<=0||(this.player.playbackState==="playing"?(this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh()):(this.sightingAudio.resume(),this.player.play()),this.updatePlayPauseButton(),this.flashPlayback())}flashPlayback(){const e=this.playbackFlash;e.textContent=this.player.playbackState==="playing"?"▶":"⏸",e.classList.remove("flashing"),e.offsetWidth,e.classList.add("flashing")}updatePlayPauseButton(){const e=this.player.playbackState==="playing";this.playPauseButton.textContent=e?"⏸":"▶";const t=this.player.seekableDuration>0;this.playPauseButton.disabled=!t;const i=t?e?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=i,this.playPauseButton.setAttribute("aria-label",i)}toggleLoop(){this.loopEnabled=!this.loopEnabled,this.player.loop=this.loopEnabled}restorePlayback(){const e=this.playbackBeforeClick;e&&(this.currentTime=e.time,e.state==="playing"?this.play():this.pause())}get canUseNativeFullscreen(){return typeof this.fullscreenTarget.requestFullscreen=="function"&&document.fullscreenEnabled}toggleFullscreen(){if(!this.canUseNativeFullscreen){this.simulatedFullscreen?this.exitSimulatedFullscreen():this.enterSimulatedFullscreen();return}document.fullscreenElement?document.exitFullscreen():this.fullscreenTarget.requestFullscreen().catch(e=>{console.error("<rr0-ufo>: requestFullscreen() failed —",e)})}enterSimulatedFullscreen(){const e=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen=e.getAttribute("style")??"",this.bodyOverflowBeforeSimulatedFullscreen=document.body.style.overflow;const t=e.style;t.setProperty("position","fixed"),t.setProperty("inset","0"),t.setProperty("margin","0"),t.setProperty("max-width","none"),t.setProperty("max-height","none"),t.setProperty("aspect-ratio","auto"),t.setProperty("z-index","2147483647"),t.setProperty("background","#000"),t.setProperty("width","100vw"),t.setProperty("width","100dvw"),t.setProperty("height","100vh"),t.setProperty("height","100dvh"),document.body.style.overflow="hidden",this.simulatedFullscreen=!0,document.addEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}exitSimulatedFullscreen(){if(!this.simulatedFullscreen)return;const e=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen?e.setAttribute("style",this.styleBeforeSimulatedFullscreen):e.removeAttribute("style"),document.body.style.overflow=this.bodyOverflowBeforeSimulatedFullscreen??"",this.simulatedFullscreen=!1,document.removeEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}toggleObserverMap(){this.setObserverMapOpen(this.observerMapPanel.hidden)}applyObserverMapDefault(){const e=this.getAttribute(Zr),t=e===null?this.observerPath?.travels===!0:e!=="false";this.setObserverMapOpen(t&&this.observerPath!==void 0)}setObserverMapOpen(e){this.observerMapPanel.hidden=!e,this.observerMapPanel.removeAttribute("title"),this.observerMapButton.setAttribute("aria-pressed",String(e)),this.updateObserverMapButton(),e&&(this.sizeObserverMapCanvas(),this.loadObserverMapImagery(),this.paintObserverMap(this.currentTime))}updateObserverMapButton(){const t=!this.observerMapPanel.hidden?this.messages.hideObserverMap:this.messages.showObserverMap;this.observerMapButton.title=t,this.observerMapButton.setAttribute("aria-label",t);const i=[[this.mapZoomInButton,this.messages.zoomMapIn],[this.mapZoomOutButton,this.messages.zoomMapOut],[this.mapFitButton,this.messages.fitMap]];for(const[n,s]of i)n.title=s,n.setAttribute("aria-label",s)}updateObserverMap(){const e=this.observerPath!==void 0;if(this.observerPath=qa.of(this.currentSighting),this.observerMapButton.hidden=this.observerPath===void 0,!e&&this.observerPath&&this.applyObserverMapDefault(),!this.observerPath){this.setObserverMapOpen(!1),this.observerMapBounds=void 0;return}const t=this.observerPath.boundsAround(Li.OBSERVER_MAP_MIN_SPAN_M,Li.OBSERVER_MAP_MARGIN);(!this.observerMapBounds||!this.sameGround(this.observerMapBounds,t))&&(this.observerMapBounds&&this.observerMapView.refit(this.observerMapBounds,t),this.observerMapBounds=t,this.observerMapImagery=void 0,this.observerMapImageryCredit=void 0,this.observerMapImageryFailed=!1,this.observerMapImageryBounds=void 0,this.observerMapPanel.hidden||this.loadObserverMapImagery())}sameGround(e,t){const i=Math.abs(e.east-e.west)/20;return Math.abs(e.north-t.north)<i&&Math.abs(e.south-t.south)<i&&Math.abs(e.west-t.west)<i&&Math.abs(e.east-t.east)<i}async loadObserverMapImagery(){const e=this.observerMapViewBounds;if(!e||this.observerMapPanel.hidden||!this.observerMapImageryNeededFor(e))return;this.observerMapImageryBounds=e;const t=Fv();try{const i=await t.getImageryTexture(e,{width:Li.OBSERVER_MAP_IMAGERY_PX,height:Li.OBSERVER_MAP_IMAGERY_PX});if(this.observerMapImageryBounds!==e)return;this.observerMapImagery=i,this.observerMapImageryCredit=t.attribution,this.observerMapImageryFailed=!1}catch{if(this.observerMapImageryBounds!==e)return;this.observerMapImageryFailed=this.observerMapImagery===void 0}this.paintObserverMap(this.currentTime)}observerMapImageryNeededFor(e){const t=this.observerMapImageryBounds;if(!t)return!0;const i=this.observerMapImagery?.bounds??t,n=e.west>=i.west&&e.east<=i.east&&e.south>=i.south&&e.north<=i.north,s=e.east-e.west>(t.east-t.west)/2;return!n||!s}get observerMapCredit(){return this.observerMapImageryCredit}get observerMapFooterLine(){return this.observerMapImageryFailed?this.messages.mapImageryUnavailable:this.creditShownExternally?void 0:this.observerMapImageryCredit}mapShapeBounds=[];mapSceneBounds=[];setMapSubjectBounds(e){this.mapSceneBounds=e.map(t=>({x:t.x*this.canvas.width,y:t.y*this.canvas.height,width:t.width*this.canvas.width,height:t.height*this.canvas.height})),this.keepObserverMapClear()}keepObserverMapClear(){if(this.observerMapPanel.hidden)return;const e=this.observerMapBoxPx;if(!e)return;const t=[...this.mapShapeBounds,...this.mapSceneBounds],i=(c,h,d)=>{for(const u of t)if(!(u.x+u.width<c-d||u.x>h+d)&&!(u.y>e.bottom+d||u.y+u.height<e.top-d))return!0;return!1},n=[this.canvas.width-e.width,this.canvas.width],s=[0,e.width],r=Li.OBSERVER_MAP_CLEARANCE_PX,o=i(...n,0),l=i(...s,0);if(this.observerMapPanel.classList.toggle("subject-overlap",o&&l),this.observerMapPanel.classList.contains("on-the-left")){!o&&(l||!i(n[0],n[1],r))&&this.observerMapPanel.classList.remove("on-the-left");return}i(n[0],n[1],0)&&!i(s[0],s[1],0)&&this.observerMapPanel.classList.add("on-the-left")}observerMapBoxPx;static OBSERVER_MAP_CLEARANCE_PX=24;sizeObserverMapCanvas(){const e=this.observerMapPanel.clientWidth;if(e===0)return;const t=Math.round(e*(globalThis.devicePixelRatio??1));this.measureObserverMapBox(),this.observerMapCanvas.width!==t&&(this.observerMapCanvas.width=t,this.observerMapCanvas.height=t)}measureObserverMapBox(){const e=this.observerMapPanel.getBoundingClientRect(),t=this.canvas.getBoundingClientRect();if(t.width===0||t.height===0)return;const i=this.canvas.width/t.width,n=this.canvas.height/t.height;this.observerMapBoxPx={width:e.width*i,top:(e.top-t.top)*n,bottom:(e.bottom-t.top)*n}}paintObserverMap(e){if(this.observerMapPanel.hidden||!this.observerPath||!this.observerMapBounds)return;const t=nt(this.currentSighting,e),i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?v0(this.currentSighting.milestones,e):void 0;for(const r of this.milestonesShown?ao(this.currentSighting.milestones):[]){const o=nt(this.currentSighting,r.t);o?.lat===void 0||o.lng===void 0||n.push({label:this.said.read(r.label)??"",note:this.said.read(r.note),t:r.t,lat:o.lat,lng:o.lng,current:r===s})}this.observerMapRenderer.paint({bounds:this.observerMapViewBounds,imagery:this.observerMapImagery,path:this.observerPath,position:t?.lat!==void 0&&t.lng!==void 0?{lat:t.lat,lng:t.lng}:void 0,headingDeg:t?.headingDeg===void 0?void 0:t.headingDeg+this.lookYawDeg,coneHalfAngleDeg:t?Gn.of(i,this.canvas.height,t.fovDeg).halfWidthAngleDeg(Mt.aspectOf(i)):void 0,markers:n,decor:this.observerMapDecorAt(e),observerLabel:this.said.read(this.currentSighting.observer?.title)??this.messages.observerHere,nightFraction:this.observerMapNightFraction,attribution:this.observerMapFooterLine})}toggleMilestones(){this.setMilestonesShown(!this.milestonesShown)}setMilestonesShown(e){this.milestonesShown=e,this.milestoneMarks.hidden=!e,this.milestonesButton.setAttribute("aria-pressed",String(e)),this.updateMilestonesButton(),this.showMilestoneAt(this.currentTime),this.paintObserverMap(this.currentTime)}updateMilestonesButton(){this.milestonesButton.hidden=this.currentSighting.milestones.length===0;const e=this.milestonesShown?this.messages.hideMilestones:this.messages.showMilestones;this.milestonesButton.title=e,this.milestonesButton.setAttribute("aria-label",e)}observerMapDecorAt(e){const t=nt(this.currentSighting,0);return t?.lat===void 0||t.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=vr(i,e),{lat:s,lng:r}=Os(n.eastM,-n.northM,t.lat,t.lng);return{lat:s,lng:r,headingDeg:n.headingDeg,label:this.said.read(i.title)??this.messages.decorHere}})}observerMapNightFraction;setSunAltitude(e){const t=e===void 0?void 0:Math.max(0,Math.min(1,-e/12));t!==this.observerMapNightFraction&&(this.observerMapNightFraction=t,this.paintObserverMap(this.currentTime))}setLookOffset(e,t){e===this.lookYawDeg&&t===this.lookPitchDeg||(this.lookYawDeg=e,this.lookPitchDeg=t,this.refresh())}get frameShiftPx(){return this.frameShift}get frameShift(){const e=this.gaitAt(this.currentTime),t=this.lookYawDeg+e.yawDeg,i=this.lookPitchDeg+e.pitchDeg;if(t===0&&i===0)return{x:0,y:0};const n=nt(this.currentSighting,this.currentTime),s=Gn.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(t),y:s.angleDegToRadiusPx(i)}}gaitAt(e){return Et.bodyAt(this.currentSighting,e,this.steadyObserver)}updateFullscreenButton(){const e=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;this.fullscreenButton.title=e?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}get said(){return this.saidTexts??=new us(pr.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const e=oo(pr.preferencesFor(this),Mu);e!=="en"&&this.applyMessages(await wy(e))}updateTimeLabelTitles(){const e=this.showClockTime?this.messages.switchToElapsed:this.messages.switchToClockTime,t=this.canSwitchTimeDisplay?` — ${e}`:"";this.timeStartLabel.title=this.messages.currentPosition+t,this.timeEndLabel.title=this.messages.duration+t;for(const i of[this.timeStartLabel,this.timeEndLabel])i.classList.toggle("switchable",this.canSwitchTimeDisplay),this.canSwitchTimeDisplay?(i.setAttribute("role","button"),i.setAttribute("tabindex","0")):(i.removeAttribute("role"),i.removeAttribute("tabindex"))}applyMessages(e){this.messages=e,this.updateTimeLabelTitles(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateMilestonesButton()}updateTimeLabels(){const e=this.currentSighting.event,t=ro(e);this.realDurationMs=t!==void 0&&t>0?t:void 0,this.realStartMs=e.time?uu(e.time):void 0;const i=this.currentSighting.timeline.duration;this.player.playbackRate=this.realDurationMs!==void 0&&i>0?i/this.realDurationMs:1,this.player.durationOverrideMs=i>0?0:this.realDurationMs??0,this.timeEndLabel.textContent=this.formatEndOfTimeline(),this.timeStartLabel.textContent=this.formatPosition(this.player.time),this.updateTimeLabelTitles()}formatPosition(e){if(this.realDurationMs===void 0)return Ol(e);const t=this.currentSighting.timeline.duration,i=t>0&&e<=t?e/t*this.realDurationMs:e;return this.canShowClockTime?x0(w0(this.realStartMs+i)):Ol(i)}formatEndOfTimeline(){return this.realDurationMs===void 0?Ol(this.currentSighting.timeline.duration):this.canShowClockTime?x0(w0(this.realStartMs+this.realDurationMs)):Ol(this.realDurationMs)}}function w0(a){const e=new Date(a);return{hour:e.getUTCHours(),minute:e.getUTCMinutes(),second:e.getUTCSeconds()}}function x0(a){if(a.hour===void 0)return"0:00";const e=t=>String(t).padStart(2,"0");return a.second?`${e(a.hour)}:${e(a.minute??0)}:${e(a.second)}`:`${e(a.hour)}:${e(a.minute??0)}`}function Ol(a){const e=Math.round(a/1e3),t=Math.floor(e/60),i=e%60;return`${t}:${String(i).padStart(2,"0")}`}const wu="rr0-ufo";function Sh(){customElements.get(wu)||customElements.define(wu,Li)}class Qo{constructor(e,t){this.seekInput=e,this.layer=t,e.addEventListener("pointerdown",i=>{this.snapArmed=!0,this.nameMarkUnder(i)}),e.addEventListener("pointerup",()=>this.snapArmed=!1),e.addEventListener("pointermove",i=>this.nameMarkUnder(i)),e.addEventListener("pointerleave",()=>e.removeAttribute("title"))}static SNAP_PX=6;marks=[];duration=0;drawn="";snapArmed=!1;show(e,t){const i=t>0?[...e].sort((s,r)=>s.t-r.t):[],n=`${t}|${i.map(s=>`${s.kind}:${s.t}:${s.label}`).join("|")}`;n!==this.drawn&&(this.drawn=n,this.marks=i,this.duration=t,this.layer.replaceChildren(...i.map(s=>{const r=document.createElement("span");return r.className=`timeline-mark ${s.kind}`,r.style.left=`${Math.min(Math.max(s.t/t,0),1)*100}%`,r})))}snap(e){return this.snapArmed?(this.snapArmed=!1,this.markNear(e)?.t??e):e}next(e){return this.marks.find(t=>t.t>e+Qo.SAME_INSTANT)?.t}previous(e){return[...this.marks].reverse().find(t=>t.t<e-Qo.SAME_INSTANT)?.t}static SAME_INSTANT=.5;markNear(e){const t=this.seekInput.getBoundingClientRect().width;if(this.duration<=0||t<=0)return;const i=Qo.SNAP_PX/t*this.duration;let n;for(const s of this.marks)Math.abs(s.t-e)>i||(!n||Math.abs(s.t-e)<Math.abs(n.t-e)||s.t===n.t&&s.kind==="milestone")&&(n=s);return n}nameMarkUnder(e){const t=this.seekInput.getBoundingClientRect();if(t.width<=0||this.duration<=0)return;const i=this.marksNear((e.clientX-t.left)/t.width*this.duration);i?this.seekInput.title=i:this.seekInput.removeAttribute("title")}marksNear(e){const t=this.markNear(e);if(t)return[...new Set(this.marks.filter(i=>i.t===t.t).map(i=>i.label))].join(" · ")}}const By=.08,S0=.15,E0=2,zy=2e3;class Hy{context;noiseBuffer;voices=new Map;paused=!0;requested=[];resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(e){console.warn("VehicleAudio: Web Audio unavailable, vehicles stay silent:",e);return}}this.context.state==="suspended"&&this.context.resume(),this.apply()}setPaused(e){e!==this.paused&&(this.paused=e,this.apply())}setVoices(e){this.requested=e,this.apply()}dispose(){for(const e of[...this.voices.keys()])this.release(e);this.context?.close(),this.context=void 0}apply(){const e=this.context;if(!e)return;const t=this.paused?[]:this.requested.filter(n=>n.inside||n.distanceM<zy),i=new Set(t.map(n=>n.id));for(const n of[...this.voices.keys()])i.has(n)||this.release(n);for(const n of t){const s=this.voices.get(n.id)??this.build(e,n.id);this.retarget(e,s,n)}}build(e,t){const i=e.createGain();i.gain.value=0;const n=e.createBiquadFilter();n.type="lowpass",n.connect(i).connect(e.destination);const s=e.createOscillator();s.type="sawtooth";const r=e.createOscillator();r.type="sine";const o=e.createGain(),l=e.createBiquadFilter();l.type="lowpass",l.frequency.value=900,s.connect(l),r.connect(l),l.connect(o).connect(n);const c=()=>{const x=e.createBufferSource();return x.buffer=this.noise(e),x.loop=!0,x.loopStart=Math.random()*E0*.5,x},h=c(),d=e.createBiquadFilter();d.type="bandpass",d.Q.value=4;const u=e.createGain();h.connect(d).connect(u).connect(n);const f=c(),p=e.createBiquadFilter();p.type="lowpass",p.frequency.value=600;const v=e.createGain();f.connect(p).connect(v).connect(n);const m=c(),g=e.createBiquadFilter();g.type="bandpass",g.frequency.value=1400,g.Q.value=.7;const y=e.createGain();m.connect(g).connect(y).connect(n);const M=[s,r,h,f,m];for(const x of M)x.start();const b={nodes:[i,n,o,l,d,u,p,v,g,y,...M],sources:M,firing:s,crank:r,knock:d,engineGain:o,knockGain:u,roadGain:v,windGain:y,cabin:n,output:i};return this.voices.set(t,b),b}retarget(e,t,{profile:i,state:n,noise:s,inside:r,windowsOpen:o,distanceM:l}){const c=e.currentTime,h=(y,M)=>y.setTargetAtTime(M,c,By),d=n.rpm/60,u=d*i.cylinders/2,f=Math.min(1,n.rpm/i.shiftUpRpm),p=Math.min(1.5,n.speedMps/30);h(t.firing.frequency,u),h(t.crank.frequency,d),h(t.knock.frequency,u*3),h(t.engineGain.gain,i.engineGain*(.25+.75*n.load)*(.5+.5*f)*.3),h(t.knockGain.gain,i.roughness*(.2+.8*n.load)*.4),h(t.roadGain.gain,i.roadGain*p**1.5*.8);const v=!r||o;h(t.windGain.gain,p**2*(v?.5:.06));const m=r?o?3500:700:8e3/(1+l/60);h(t.cabin.frequency,m);const g=r?.5:Math.min(1,8/Math.max(l,1));h(t.output.gain,g*s)}release(e){const t=this.voices.get(e);if(!t)return;this.voices.delete(e);const i=this.context;i&&(t.output.gain.setTargetAtTime(0,i.currentTime,S0/3),setTimeout(()=>{for(const n of t.sources)try{n.stop()}catch{}for(const n of t.nodes)n.disconnect()},S0*1e3*3))}noise(e){if(this.noiseBuffer)return this.noiseBuffer;const t=e.createBuffer(1,e.sampleRate*E0,e.sampleRate),i=t.getChannelData(0);for(let n=0;n<i.length;n++)i[n]=Math.random()*2-1;return this.noiseBuffer=t,t}}class fl{static BY_KIND={car:{cylinders:4,idleRpm:800,kmhPer1000Rpm:[8,14,21,29,37,45],shiftUpRpm:3e3,shiftDownRpm:1300,engineGain:.6,roadGain:.5,roughness:.15},generic:{cylinders:4,idleRpm:800,kmhPer1000Rpm:[8,14,21,29,37,45],shiftUpRpm:3e3,shiftDownRpm:1300,engineGain:.6,roadGain:.5,roughness:.15},van:{cylinders:4,idleRpm:750,kmhPer1000Rpm:[7,12,19,27,35,42],shiftUpRpm:2600,shiftDownRpm:1200,engineGain:.8,roadGain:.7,roughness:.45},truck:{cylinders:6,idleRpm:600,kmhPer1000Rpm:[5,8,12,17,23,30,38,48],shiftUpRpm:1900,shiftDownRpm:1e3,engineGain:1,roadGain:.9,roughness:.55},motorcycle:{cylinders:2,idleRpm:1100,kmhPer1000Rpm:[12,18,24,30,35,40],shiftUpRpm:6e3,shiftDownRpm:2500,engineGain:.9,roadGain:.3,roughness:.3}};static of(e){return fl.BY_KIND[e??"generic"]??fl.BY_KIND.generic}}class Vr{constructor(e,t){this.samples=e,this.startMs=t}static SAMPLE_MS=100;static STANDING_MPS=.3;static of(e,t,i,n){const s=Vr.SAMPLE_MS,r=[];for(let c=i;c<=n+s/2;c+=s){const h=t(c-s/2),d=t(c+s/2);if(!h||!d)return;r.push(Math.hypot(d.eastM-h.eastM,d.northM-h.northM)/(s/1e3))}const o=[];let l=1;for(let c=0;c<r.length;c++){const h=r[c],d=(r[Math.min(c+1,r.length-1)]-r[Math.max(c-1,0)])/(2*s/1e3);if(h<Vr.STANDING_MPS){l=1,o.push({speedMps:h,rpm:e.idleRpm,load:.1,gear:0});continue}const u=h*3.6,f=g=>u/e.kmhPer1000Rpm[g-1]*1e3;for(;l<e.kmhPer1000Rpm.length&&f(l)>e.shiftUpRpm;)l++;for(;l>1&&f(l)<e.shiftDownRpm;)l--;const p=Math.max(f(l),e.idleRpm*(1+.3*Math.min(1,h/3))),v=.15+.5*Math.min(1,(h/35)**2),m=d>.15?Math.min(1,v+d/2.5):d<-.3?.05:v;o.push({speedMps:h,rpm:p,load:m,gear:l})}return new Vr(o,i)}at(e){const t=(e-this.startMs)/Vr.SAMPLE_MS,i=Math.min(Math.max(Math.floor(t),0),this.samples.length-1),n=this.samples[i],s=this.samples[Math.min(i+1,this.samples.length-1)],r=Math.min(Math.max(t-i,0),1);return{speedMps:n.speedMps+(s.speedMps-n.speedMps)*r,rpm:n.rpm+(s.rpm-n.rpm)*r,load:n.load+(s.load-n.load)*r,gear:r<.5?n.gear:s.gear}}}class jc{drives=new Map;at(e,t){const i=[],n=e.event.place?.[0],s=c=>{const h=e.observerTrack.getInterpolatedPoseAt(c),d=h?.lat??n?.lat,u=h?.lng??n?.lng;if(d===void 0||u===void 0||!n)return;const f=li(d,u,n.lat,n.lng);return{eastM:f.x,northM:-f.z}},r=Math.max(e.observerTrack.duration,(e.event.durationSeconds??0)*1e3),o=e.vehicle;if(o){const c=fl.of(o.kind),h=this.drive(`observer:${o.kind}`,jc.trackKey(e),()=>Vr.of(c,s,0,r));h&&i.push({id:"observer",profile:c,state:h.at(t),noise:o.noise??1,inside:!0,windowsOpen:o.windowsOpen===!0,distanceM:0})}const l=s(t);for(const c of e.decor){if(!c.engine||!l)continue;const h=fl.of(c.engine.kind),d=v=>{const m=vr(c,v);return{eastM:m.eastM,northM:m.northM}},u=this.drive(`decor:${c.id}`,jc.decorKey(c,r),()=>Vr.of(h,d,0,r));if(!u)continue;const f=vr(c,t),p=Math.hypot(f.eastM-l.eastM,f.northM-l.northM,f.altitudeM);i.push({id:`decor:${c.id}`,profile:h,state:u.at(t),noise:c.engine.noise??1,inside:!1,windowsOpen:!0,distanceM:p})}return i}drive(e,t,i){const n=this.drives.get(e);if(n&&n.key===t)return n.drive;const s=i();return this.drives.set(e,{key:t,drive:s}),s}static trackKey(e){return e.observerTrack.allKeyframes.map(i=>`${i.t}:${i.pose.lat}:${i.pose.lng}`).join(";")}static decorKey(e,t){return`${t}|${e.eastM},${e.northM}|`+(e.track??[]).map(i=>`${i.t}:${i.eastM}:${i.northM}`).join(";")}}const Gy=`
2146
+ `;class qa{constructor(e){this.points=e}static STATIONARY_M=5;static of(e){const t=[];for(const i of e.observerTrack.allKeyframes){const{lat:n,lng:s,headingDeg:r}=i.pose;n===void 0||s===void 0||t.push({t:i.t,lat:n,lng:s,headingDeg:r})}if(t.length===0){const i=e.event.place?.[0];if(!i)return;t.push({t:0,lat:i.lat,lng:i.lng})}return new qa(t)}static TRAVEL_M=50;get travels(){return this.spanM>qa.TRAVEL_M}get moved(){return this.spanM>qa.STATIONARY_M}get spanM(){const e=this.box,t=(e.south+e.north)/2,i=(e.west+e.east)/2;return Math.max(Math.abs(li(t,e.east,t,e.west).x),Math.abs(li(e.north,i,e.south,i).z))}get center(){const e=this.box;return{lat:(e.south+e.north)/2,lng:(e.west+e.east)/2}}boundsAround(e,t){const{lat:i,lng:n}=this.center,s=Math.max(this.spanM*(1+t),e)/2;return{north:Os(0,-s,i,n).lat,south:Os(0,s,i,n).lat,east:Os(s,0,i,n).lng,west:Os(-s,0,i,n).lng}}get box(){const e=this.points.map(i=>i.lat),t=this.points.map(i=>i.lng);return{south:Math.min(...e),north:Math.max(...e),west:Math.min(...t),east:Math.max(...t)}}}class En{constructor(e,t){this.rotationPassed=e,this.scale=t}static SWAY_M=.012;static BREATH_M=.003;static DRIFT_YAW_DEG=.5;static DRIFT_PITCH_DEG=.4;static DRIFT_ROLL_DEG=.3;static GAZE_DRIFT_SHARE=.35;static HAND_HELD_S=.5;static HZ=[.11,.23,.17,.29,.37,.07];static of(e){const t=e.event.tags?.includes("paralysis")||(e.exposure??0)>En.HAND_HELD_S,i=e.sway??(t?0:1);if(i>0)return new En(Math.max(1-(e.instrument.stabilization??0),En.GAZE_DRIFT_SHARE),i)}offsetAt(e){const t=e/1e3,i=this.scale,n=(d,u)=>Math.sin(2*Math.PI*d*t+u),[s,r,o,l,c,h]=En.HZ;return{eastM:i*En.SWAY_M*(.7*n(s,.3)+.3*n(l,1.9)),northM:i*En.SWAY_M*(.6*n(o,2.2)+.4*n(c,.8)),upM:i*En.BREATH_M*n(r,0),yawDeg:i*this.rotationPassed*En.DRIFT_YAW_DEG*(.6*n(h,1.1)+.4*n(l,2.7)),pitchDeg:i*this.rotationPassed*En.DRIFT_PITCH_DEG*(.5*n(r,1.6)+.5*n(o,.4)),rollDeg:i*this.rotationPassed*En.DRIFT_ROLL_DEG*n(s,2.9)}}}class Et{constructor(e,t){this.stretches=e,this.rotationPassed=t}static REFERENCE_SPEED_M_PER_S=1.4;static REFERENCE_STEP_HZ=1.9;static CADENCE_EXPONENT=.43;static RISE_M_PER_M_PER_S=.0175;static SWAY_M=.0175;static SLOWEST_WALK_M_PER_S=.2;static FASTEST_WALK_M_PER_S=2.2;static HEAD_ROLL_DEG=1.5;static HEAD_PITCH_DEG=1.25;static HEAD_YAW_DEG=1;static STOP_LURCH_M=.035;static STOP_PITCH_DEG=3;static START_LURCH_M=.015;static START_PITCH_DEG=1.2;static JOLT_HZ=1.4;static JOLT_DECAY_S=.35;static JOLT_LASTS_MS=1500;static STILL=Object.freeze({eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0});static of(e){const t=qa.of(e);if(!t||t.points.length<2)return;const i=[];let n=0;for(let s=1;s<t.points.length;s++){const r=t.points[s-1],o=t.points[s],l=(o.t-r.t)/1e3;if(l<=0)continue;const c=li(o.lat,o.lng,r.lat,r.lng),h=c.x,d=-c.z,u=Math.hypot(h,d),f=u/l,p=Et.stepHzFor(f);i.push({startMs:r.t,endMs:o.t,speedMPerS:f,eastUnit:u>0?h/u:0,northUnit:u>0?d/u:0,stepHz:p,stepsBefore:n,rampsIn:!0,rampsOut:!0}),n+=p*l}for(let s=0;s<i.length;s++){const r=i[s-1],o=i[s+1];i[s].rampsIn=r===void 0||r.stepHz===0,i[s].rampsOut=o===void 0||o.stepHz===0}if(i.some(s=>s.stepHz>0))return new Et(i,1-(e.instrument.stabilization??0))}static bodyAt(e,t,i=!1){const n=Et.of(e)?.offsetAt(t)??Et.STILL;return i?n:Et.add(n,En.of(e)?.offsetAt(t))}static stepHzFor(e){return e<Et.SLOWEST_WALK_M_PER_S||e>Et.FASTEST_WALK_M_PER_S?0:Et.REFERENCE_STEP_HZ*Math.pow(e/Et.REFERENCE_SPEED_M_PER_S,Et.CADENCE_EXPONENT)}offsetAt(e){return Et.add(this.cycleAt(e),this.joltAt(e))}joltAt(e){for(const t of this.stretches){if(t.stepHz===0)continue;const i=t.speedMPerS/Et.REFERENCE_SPEED_M_PER_S,n=(o,l,c,h)=>{if(o<0||o>Et.JOLT_LASTS_MS)return;const d=o/1e3,u=Math.exp(-d/Et.JOLT_DECAY_S)*Math.sin(2*Math.PI*Et.JOLT_HZ*d),f=h*l*i*u;return{eastM:f*t.eastUnit,northM:f*t.northUnit,upM:-Math.abs(f)*.3,rollDeg:0,pitchDeg:-h*c*i*u*this.rotationPassed,yawDeg:0}},s=t.rampsOut?n(e-t.endMs,Et.STOP_LURCH_M,Et.STOP_PITCH_DEG,1):void 0;if(s)return s;const r=t.rampsIn?n(e-t.startMs,Et.START_LURCH_M,Et.START_PITCH_DEG,-1):void 0;if(r)return r}}static add(e,t){return t?{eastM:e.eastM+t.eastM,northM:e.northM+t.northM,upM:e.upM+t.upM,rollDeg:e.rollDeg+t.rollDeg,pitchDeg:e.pitchDeg+t.pitchDeg,yawDeg:e.yawDeg+t.yawDeg}:e}cycleAt(e){const t=this.stretches.find(l=>e>=l.startMs&&e<=l.endMs);if(!t||t.stepHz===0)return Et.STILL;const i=t.stepsBefore+t.stepHz*(e-t.startMs)/1e3,n=2*Math.PI*i,s=this.amplitudeAt(t,e),r=Et.SWAY_M*s*Math.cos(n/2),o=s*this.rotationPassed*t.speedMPerS/Et.REFERENCE_SPEED_M_PER_S;return{eastM:r*t.northUnit,northM:-r*t.eastUnit,upM:Et.RISE_M_PER_M_PER_S*t.speedMPerS*s*Math.cos(n),rollDeg:Et.HEAD_ROLL_DEG*o*Math.cos(n/2),pitchDeg:-1.25*o*Math.cos(n),yawDeg:Et.HEAD_YAW_DEG*o*Math.cos(n/2)}}amplitudeAt(e,t){const i=1e3/e.stepHz,n=Math.min(i,(e.endMs-e.startMs)/2);if(n<=0)return 1;const s=t-e.startMs,r=e.endMs-t,o=Math.min(e.rampsIn?s/n:1,e.rampsOut?r/n:1,1);return(1-Math.cos(Math.PI*Math.max(o,0)))/2}}class fy{constructor(e,t){this.timeline=e,this.onFrame=t}rafId=null;state="stopped";currentT=0;lastWallTime=0;playbackRate=1;loop=!1;onEnded;durationOverrideMs=0;get seekableDuration(){return Math.max(this.timeline.duration,this.durationOverrideMs)}play(){if(this.state==="playing")return;this.currentT>=this.seekableDuration&&(this.currentT=0,this.resolveFrame(0)),this.state="playing",this.lastWallTime=performance.now();const e=()=>{if(this.state!=="playing")return;const t=performance.now();if(this.currentT+=(t-this.lastWallTime)*this.playbackRate,this.lastWallTime=t,this.currentT>=this.seekableDuration){if(this.loop&&this.seekableDuration>0){this.currentT%=this.seekableDuration,this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(e);return}this.currentT=this.seekableDuration,this.stop(),this.resolveFrame(this.currentT),this.onEnded?.();return}this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(e)};this.rafId=requestAnimationFrame(e)}pause(){this.state==="playing"&&(this.state="paused",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null))}stop(){this.state="stopped",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}seek(e){this.currentT=Math.max(0,Math.min(e,this.seekableDuration)),this.resolveFrame(this.currentT)}get playbackState(){return this.state}get time(){return this.currentT}resolveFrame(e){const t=new Map;for(const i of this.timeline.sourceIds){const n=this.timeline.getInterpolatedShapeAt(e,i);n&&t.set(i,n)}this.onFrame(e,t)}}const f0=.05,p0=.08,m0=2,g0=3,py=14,my=.02;class gy{context;voice;voiceToken=0;buffers=new Map;noiseBuffer;crackleBuffer;requested;resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(e){console.warn("SightingAudio: Web Audio unavailable, the sighting stays silent:",e);return}}this.context.state==="suspended"&&this.context.resume()}setSound(e){if(this.requested=e,!this.context)return;const t=this.keyFor(e);if(!t){this.silence();return}if(this.voice?.key!==t){this.stopVoice();const i=++this.voiceToken;t.startsWith("src:")?this.buildRecordedVoice(e.src,t,i):this.voice=this.buildSynthesizedVoice(e,t)}this.applyTo(this.voice,e)}silence(){this.voiceToken++,this.stopVoice()}dispose(){this.silence(),this.context?.close(),this.context=void 0,this.buffers.clear(),this.noiseBuffer=void 0,this.crackleBuffer=void 0}keyFor(e){if(!(e.volume<=0))return e.src?`src:${e.src}`:e.kind==="none"?void 0:e.kind}applyTo(e,t){const i=this.context;if(!e||!i)return;const n=i.currentTime;e.volumeParam.setTargetAtTime(Math.max(0,Math.min(1,t.volume))*e.gainScale,n,f0);for(const{param:s,ratio:r}of e.pitch)s.setTargetAtTime(Math.min(t.pitchHz*r,i.sampleRate/2-1),n,f0)}buildSynthesizedVoice(e,t){const i=this.context;if(i)switch(e.kind){case"hum":return this.buildHum(i,t);case"whistle":return this.buildWhistle(i,t);case"rumble":return this.buildRumble(i,t);case"crackle":return this.buildCrackle(i,t);default:return}}buildHum(e,t){const i=e.createOscillator();i.type="sawtooth";const n=e.createOscillator();n.type="sawtooth";const s=e.createBiquadFilter();s.type="lowpass",s.Q.value=1;const r=e.createGain();return r.gain.value=0,i.connect(s),n.connect(s),s.connect(r).connect(e.destination),i.start(),n.start(),{key:t,nodes:[s,r],sources:[i,n],volumeParam:r.gain,gainScale:.16,pitch:[{param:i.frequency,ratio:1},{param:n.frequency,ratio:1.006},{param:s.frequency,ratio:6}]}}buildWhistle(e,t){const i=e.createOscillator();i.type="sine";const n=e.createOscillator();n.type="sine",n.frequency.value=5;const s=e.createGain(),r=e.createGain();return r.gain.value=0,n.connect(s).connect(i.frequency),i.connect(r).connect(e.destination),i.start(),n.start(),{key:t,nodes:[s,r],sources:[i,n],volumeParam:r.gain,gainScale:.22,pitch:[{param:i.frequency,ratio:1},{param:s.gain,ratio:.012}]}}buildRumble(e,t){const i=e.createBufferSource();i.buffer=this.brownNoise(e),i.loop=!0;const n=e.createBiquadFilter();n.type="lowpass",n.Q.value=.8;const s=e.createGain();return s.gain.value=0,i.connect(n).connect(s).connect(e.destination),i.start(),{key:t,nodes:[n,s],sources:[i],volumeParam:s.gain,gainScale:1.4,pitch:[{param:n.frequency,ratio:1}]}}buildCrackle(e,t){const i=e.createBufferSource();i.buffer=this.whiteNoise(e),i.loop=!0;const n=e.createBiquadFilter();n.type="bandpass",n.Q.value=1.2;const s=e.createGain();s.gain.value=0;const r=e.createBufferSource();r.buffer=this.crackleEnvelope(e),r.loop=!0;const o=e.createGain();return o.gain.value=0,r.connect(o).connect(s.gain),i.connect(n).connect(s).connect(e.destination),i.start(),r.start(),{key:t,nodes:[n,s,o],sources:[i,r],volumeParam:o.gain,gainScale:.9,pitch:[{param:n.frequency,ratio:4}]}}async buildRecordedVoice(e,t,i){const n=this.context;if(!n)return;let s;try{s=await this.getBuffer(e)}catch(l){console.warn("SightingAudio: the recorded sound failed to load, staying silent:",l);return}if(i!==this.voiceToken||!this.context)return;const r=n.createBufferSource();r.buffer=s,r.loop=!0;const o=n.createGain();o.gain.value=0,r.connect(o).connect(n.destination),r.start(),this.voice={key:t,nodes:[o],sources:[r],volumeParam:o.gain,gainScale:1,pitch:[]},this.requested&&this.applyTo(this.voice,this.requested)}async getBuffer(e){const t=this.context;if(!t)throw new Error("SightingAudio: AudioContext not ready — resume() must be called first");let i=this.buffers.get(e);return i||(i=fetch(e).then(n=>{if(!n.ok)throw new Error(`Audio fetch failed (${n.status}): ${e}`);return n.arrayBuffer()}).then(n=>t.decodeAudioData(n)),this.buffers.set(e,i)),i}whiteNoise(e){if(!this.noiseBuffer){const t=e.createBuffer(1,Math.floor(e.sampleRate*m0),e.sampleRate),i=t.getChannelData(0);for(let n=0;n<i.length;n++)i[n]=Math.random()*2-1;this.noiseBuffer=t}return this.noiseBuffer}brownNoise(e){const t=e.createBuffer(1,Math.floor(e.sampleRate*m0),e.sampleRate),i=t.getChannelData(0);let n=0,s=0;for(let r=0;r<i.length;r++)n=(n+.02*(Math.random()*2-1))/1.02,i[r]=n,s=Math.max(s,Math.abs(n));if(s>0)for(let r=0;r<i.length;r++)i[r]/=s;return t}crackleEnvelope(e){if(!this.crackleBuffer){const t=e.createBuffer(1,Math.floor(e.sampleRate*g0),e.sampleRate),i=t.getChannelData(0),n=Math.max(1,Math.floor(my*e.sampleRate)),s=Math.round(g0*py);for(let r=0;r<s;r++){const o=Math.floor(Math.random()*i.length),l=.4+Math.random()*.6;for(let c=0;c<n&&o+c<i.length;c++)i[o+c]=Math.max(i[o+c],l*(1-c/n))}this.crackleBuffer=t}return this.crackleBuffer}stopVoice(){const e=this.voice,t=this.context;if(this.voice=void 0,!e||!t)return;const i=t.currentTime;e.volumeParam.cancelScheduledValues(i),e.volumeParam.setTargetAtTime(0,i,p0/3);const n=i+p0;for(const s of e.sources){s.onended=()=>{s.disconnect();for(const r of e.nodes)r.disconnect()};try{s.stop(n)}catch{s.disconnect();for(const r of e.nodes)r.disconnect()}}}}function ao(a){return[...a].sort((e,t)=>e.t-t.t)}function v0(a,e){let t;for(const i of ao(a)){if(i.t>e)break;t=i}return t}const Vh=Math.PI/180,Ll=180/Math.PI;class Gn{constructor(e,t,i){this.kind=e,this.canvasHeightPx=t,this.fovDeg=i;const n=i*Vh/2;this.focalPx=e==="equidistant"?t/2/n:t/2/Math.tan(n)}focalPx;static of(e,t,i){return new Gn(e.projection,t,i)}degToPx(e){const t=e*Vh;return this.kind==="equidistant"?this.focalPx*t:2*this.focalPx*Math.tan(t/2)}pxToDeg(e){return this.kind==="equidistant"?e/this.focalPx*Ll:2*Math.atan(e/(2*this.focalPx))*Ll}angleDegToRadiusPx(e){const t=e*Vh;return this.kind==="equidistant"?this.focalPx*t:this.focalPx*Math.tan(t)}halfWidthAngleDeg(e){return this.radiusPxToAngleDeg(this.canvasHeightPx*e/2)}radiusPxToAngleDeg(e){return this.kind==="equidistant"?e/this.focalPx*Ll:Math.atan(e/this.focalPx)*Ll}ofBounds(e){return{widthDeg:this.pxToDeg(e.width),heightDeg:this.pxToDeg(e.height)}}toBoundsSize(e){return{width:this.degToPx(e.widthDeg),height:this.degToPx(e.heightDeg)}}widthPx(e){return this.degToPx(it.angularWidthDeg(e))}}class gi{static fovOf(e,t){return nt(e,t)?.fovDeg??Mt.fieldOfViewDeg(e.instrument)}static toAngular(e){this.eachKeyframe(e,(t,i)=>({...t,angular:i.ofBounds(t.bounds)}))}static toBounds(e){this.eachKeyframe(e,(t,i)=>{if(!t.angular)return t;const{width:n,height:s}=i.toBoundsSize(t.angular),r={x:t.bounds.x+(t.bounds.width-n)/2,y:t.bounds.y+(t.bounds.height-s)/2,width:n,height:s};if(t.kind!=="polygon")return{...t,bounds:r};const o=t.bounds.width===0?1:n/t.bounds.width,l=t.bounds.height===0?1:s/t.bounds.height;return{...t,bounds:r,points:t.points.map(c=>({x:c.x*o,y:c.y*l}))}})}static toAim(e){this.eachKeyframe(e,(t,i,n)=>{const s=t.aim&&this.positionOf(e,t.aim,t.bounds,i,n);if(s&&Math.abs(s.x-t.bounds.x)<gi.UNMOVED_PX&&Math.abs(s.y-t.bounds.y)<gi.UNMOVED_PX)return t;const r=this.aimFrom(e,i,n,t.bounds);return r?{...t,aim:r}:t})}static UNMOVED_PX=.01;static aimOf(e,t,i){const n=Gn.of(e.instrument,it.CANVAS_HEIGHT_PX,this.fovOf(e,t));return this.aimFrom(e,n,nt(e,t),i)}static aimFrom(e,t,i,n){if(i?.headingDeg===void 0)return;const s=this.frameCentre(e),r=t.radiusPxToAngleDeg(n.x+n.width/2-s.x),o=t.radiusPxToAngleDeg(s.y-(n.y+n.height/2));return{azimuthDeg:((i.headingDeg+r)%360+360)%360,altitudeDeg:i.pitchDeg+o}}static toPosition(e){this.eachKeyframe(e,(t,i,n)=>{const s=t.aim&&this.positionOf(e,t.aim,t.bounds,i,n);return s?{...t,bounds:{...t.bounds,...s}}:t})}static positionOf(e,t,i,n,s){if(s?.headingDeg===void 0)return;const r=this.frameCentre(e),o=this.shortestArc(t.azimuthDeg-s.headingDeg),l=t.altitudeDeg-s.pitchDeg;return{x:r.x+this.offAxisPx(n,o)-i.width/2,y:r.y-this.offAxisPx(n,l)-i.height/2}}static frameCentre(e){return{x:Mt.frameWidthPx(e.instrument,it.CANVAS_HEIGHT_PX)/2,y:it.CANVAS_HEIGHT_PX/2}}static shortestArc(e){return(e%360+540)%360-180}static offAxisPx(e,t){return Math.abs(t)>=gi.OFF_CANVAS_DEG?Math.sign(t)*gi.OFF_CANVAS_PX:e.angleDegToRadiusPx(t)}static OFF_CANVAS_DEG=89;static OFF_CANVAS_PX=1e5;static reproject(e,t,i){const n=Mt.frameWidthPx(t,it.CANVAS_HEIGHT_PX)/2,s=Mt.frameWidthPx(e.instrument,it.CANVAS_HEIGHT_PX)/2,r=it.CANVAS_HEIGHT_PX/2;for(const o of[...e.timeline.allKeyframes]){const l=this.fovOf(e,o.t),c=i?.get(o.t)??l,h=Gn.of(t,it.CANVAS_HEIGHT_PX,c),d=Gn.of(e.instrument,it.CANVAS_HEIGHT_PX,l);e.timeline.addKeyframe(o.t,o.shapes.map(u=>{const{bounds:f}=u.shape,p=f.x+f.width/2-n,v=f.y+f.height/2-r,m=Math.hypot(p,v),g=m===0?1:d.angleDegToRadiusPx(h.radiusPxToAngleDeg(m))/m,y={...f,x:s+p*g-f.width/2,y:r+v*g-f.height/2};return{...u,shape:{...u.shape,bounds:y}}}))}this.toBounds(e)}static eachKeyframe(e,t){const{timeline:i}=e;for(const n of[...i.allKeyframes]){const s=nt(e,n.t),r=this.fovOf(e,n.t),o=Gn.of(e.instrument,it.CANVAS_HEIGHT_PX,r);i.addKeyframe(n.t,n.shapes.map(l=>({...l,shape:t(l.shape,o,s)})))}}}function vy(a){return mn.restore(yu(a),a.provenance)}function yu(a){return gi.toAngular(a),gi.toAim(a),{version:1,id:a.id,time:a.event.time,endTime:a.event.endTime,durationSeconds:a.event.durationSeconds,utcOffsetHours:a.event.utcOffsetHours,timeZone:a.event.timeZone,place:a.event.place,observer:a.observer,account:a.account,sway:a.sway,vehicle:a.vehicle,description:a.event.description,tags:a.event.tags,timeline:a.timeline.toJSON(),observerTrack:a.observerTrack.toJSON(),weatherTrack:a.weatherTrack.toJSON(),soundTrack:a.soundTrack.toJSON(),weather:a.weather,decor:a.decor,milestones:a.milestones.length>0?a.milestones:void 0,references:a.references.length>0?a.references:void 0,roads:a.roads.length>0?a.roads:void 0,weatherSource:a.weatherSource,instrument:a.instrumentId,exposureSeconds:a.exposureSeconds,iso:a.iso,interpretation:a.interpretation}}function by(a){const{recording:e,provenance:t}=mn.strip(a),i=yy(e);return i.provenance=t,i}function yy(a){const e=new xh({eventType:"sighting",time:a.time,endTime:a.endTime,durationSeconds:a.durationSeconds,utcOffsetHours:a.utcOffsetHours,timeZone:a.timeZone,place:a.place,description:a.description,tags:a.tags},wh.fromJSON(a.timeline),a.observerTrack?cl.fromJSON(a.observerTrack):new cl,a.weatherTrack?hl.fromJSON(a.weatherTrack):new hl,a.soundTrack?dl.fromJSON(a.soundTrack):new dl,a.observer&&{id:a.observer.id,title:a.observer.title,lastName:a.observer.lastName,firstNames:a.observer.firstNames},a.id,a.weather,a.decor??[],a.weatherSource,a.instrument,a.exposureSeconds??a.observerTrack?.keyframes.map(t=>t.pose.exposureSeconds).find(t=>t!==void 0),ao(a.milestones??[]),a.references??[],a.roads??[]);return e.account=a.account,e.sway=a.sway,e.iso=a.iso,e.vehicle=a.vehicle,e.interpretation=a.interpretation,gi.toBounds(e),gi.toPosition(e),e}class Un{static PIXELS_PER_INSTANT=2;static INSTANTS_PER_FLASH=2;static MAX_INSTANTS=512;static windowEndingAt(e,t){const i=Number.isFinite(t)?Math.max(0,t):0,n=Math.max(0,e-i*1e3),s=Math.max(0,e-n);return{fromMs:n,toMs:e,ms:s,seconds:s/1e3}}static instants(e,t,i,n,s){if(!(n>0))return 1;const r=s>0?Un.travelDegOver(e,t,i,i+n*1e3)/s/Un.PIXELS_PER_INSTANT:0,o=Un.flashesOver(e,n)*Un.INSTANTS_PER_FLASH,l=Math.ceil(Math.max(r,o));return l<2?1:Math.min(Un.MAX_INSTANTS,l)}static travelDegOver(e,t,i,n){let s=0;for(const r of e){if(!r.track||r.track.length<2)continue;const o=Un.directionAt(r,t,i),l=Un.directionAt(r,t,n),c=Math.min(1,Math.max(-1,o.x*l.x+o.y*l.y+o.z*l.z));s=Math.max(s,Math.acos(c)*180/Math.PI)}return s}static flashesOver(e,t){let i=0;for(const n of e)for(const s of n.lights??[])s.pattern.kind==="flash"&&(i=Math.max(i,s.pattern.perMinute));return i/60*t}static directionAt(e,t,i){const n=vr(e,i),s=n.eastM,r=n.altitudeM-t,o=n.northM,l=Math.hypot(s,r,o);return l===0?{x:0,y:1,z:0}:{x:s/l,y:r/l,z:o/l}}}function oo(a,e){for(const t of a){const i=t.toLowerCase().split("-")[0];if(e.includes(i))return i}return"en"}class pr{static preferencesFor(e){const t=navigator.languages??[],i=this.declaredFor(e);return i?[i,...t]:t}static declaredFor(e){for(let t=e;t;){const i=t.closest("[lang]")?.getAttribute("lang")?.trim();if(i)return i;const n=t.getRootNode();t=n instanceof ShadowRoot?n.host:void 0}}}class us{constructor(e){this.preferences=e}read(e){if(e===void 0||typeof e=="string")return e===""?void 0:e;for(const i of this.preferences){const n=e[i]??e[us.base(i)];if(n)return n}const t=new Set(this.preferences.map(i=>us.base(i)));for(const[i,n]of Object.entries(e))if(n&&t.has(us.base(i)))return n;return Object.values(e).find(i=>i)??void 0}write(e,t,i){const n=t?.trim()?t.trim():void 0;if(e===void 0||typeof e=="string")return n;const s={...e},r=Object.keys(s).find(o=>o===i)??Object.keys(s).find(o=>us.base(o)===us.base(i))??i;return n===void 0?delete s[r]:s[r]=n,Object.keys(s).length===0?void 0:s}static base(e){return e.toLowerCase().split("-")[0]}}const Mu=["en","fr"],My={en:()=>Mn(()=>Promise.resolve().then(()=>_y),void 0,import.meta.url).then(a=>a.ufoMessages_en),fr:()=>Mn(()=>import("./UfoMessages_fr-w9ZrScvP.js"),[],import.meta.url).then(a=>a.ufoMessages_fr)};function wy(a){return My[a]()}const xy={en:()=>Mn(()=>Promise.resolve().then(()=>hI),void 0,import.meta.url).then(a=>a.sightingEditorMessages_en),fr:()=>Mn(()=>import("./SightingEditorMessages_fr-JjttH6zH.js"),[],import.meta.url).then(a=>a.sightingEditorMessages_fr)};function Sy(a){return xy[a]()}function Ey(a){return a==="fr"?Mn(()=>import("./TagNames_fr-Dnqq6HQ5.js"),[],import.meta.url).then(e=>e.tagNames_fr):Promise.resolve({})}const _v={play:"Play",pause:"Pause",noDuration:"No observation duration",currentPosition:"Current position",duration:"Duration",switchToElapsed:"click to show elapsed time",switchToClockTime:"click to show the time of day",fullscreen:"Fullscreen",exitFullscreen:"Exit fullscreen",showObserverMap:"Show where the observer was",hideObserverMap:"Hide where the observer was",mapImageryUnavailable:"Aerial imagery unavailable",zoomMapIn:"Zoom in",zoomMapOut:"Zoom out",fitMap:"Back to the whole path",placeObserverHere:"Put the observer here",showReferences:"Show the pictures of the place",hideReferences:"Hide the pictures of the place",referenceOpacity:"Picture opacity",showMilestones:"Show the account's moments",hideMilestones:"Hide the account's moments",observerHere:"The observer, here",decorHere:"Scenery"},_y=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:_v},Symbol.toStringTag,{value:"Module"})),Av=Math.PI/180,Ay=180/Math.PI,Ty=256,Tv=19,Iy=1.25;function Iv(a,e){return 156543.03392*Math.cos(a*Av)/2**e}function Dv(a,e){return Iv(a,e)*Ty}function Dy(a,e){let t=0;for(;t<Tv&&Dv(a,t+1)>=e;)t++;return t}function Cv(a,e){return Dv(a,e)}function Cy(a,e){const t=e*Iy;let i=0;for(;i<Tv&&Iv(a,i)>t;)i++;return i}function Lc(a){const e=a*Av;return(1-Math.log(Math.tan(e)+1/Math.cos(e))/Math.PI)/2}function Rv(a,e,t){const i=2**t;return{x:(a+180)/360*i,y:Lc(e)*i}}function Pv(a,e,t){const i=Lc(a.north),n=Lc(a.south);return{x:(e-a.west)/(a.east-a.west),y:(Lc(t)-i)/(n-i)}}function Ry(a,e,t){const{x:i,y:n}=Rv(a,e,t);return{x:Math.floor(i),y:Math.floor(n),z:t}}function Py(a){const e=2**a.z,t=a.x/e*360-180,i=(a.x+1)/e*360-180,n=b0(a.y,e);return{south:b0(a.y+1,e),north:n,west:t,east:i}}function b0(a,e){const t=a/e;return Math.atan(Math.sinh(Math.PI*(1-2*t)))*Ay}function Lv(a,e,t,i){const n=Ry(a,e,t),s=Math.floor(i/2),r=[];for(let c=-s;c<=s;c++)for(let h=-s;h<=s;h++)r.push({x:n.x+h,y:n.y+c,z:t});const o=r.map(Py),l={south:Math.min(...o.map(c=>c.south)),north:Math.max(...o.map(c=>c.north)),west:Math.min(...o.map(c=>c.west)),east:Math.max(...o.map(c=>c.east))};return{tiles:r,bounds:l}}class Fr{constructor(e){this.ctx=e}static SCALE_STEPS_M=[5e3,2e3,1e3,500,200,100,50,20,10,5];static MARKER_RADIUS_PX=8.5;static ON_MARKER_M=3;targets=[];hitTest(e,t){let i,n=1/0;for(const s of this.targets){const r=Math.hypot(s.x-e,s.y-t);r>s.radius||r>n||(i=s,n=r)}return i}get width(){return this.ctx.canvas.width}get height(){return this.ctx.canvas.height}paint(e){const{ctx:t}=this;t.save(),this.targets=[],t.clearRect(0,0,this.width,this.height),this.paintGround(e),this.paintNight(e.nightFraction),this.paintPath(e),e.position?(this.paintCone(e,e.position),this.paintDecor(e),this.paintMarkers(e),this.paintObserver(e,e.position)):(this.paintDecor(e),this.paintMarkers(e)),this.paintNorth(),this.paintFooter(e.bounds,e.attribution),t.restore()}toCanvas(e,t,i){const n=Pv(e,i,t);return{x:n.x*this.width,y:n.y*this.height}}paintGround(e){const{ctx:t}=this;t.fillStyle="#1d2321",t.fillRect(0,0,this.width,this.height);const i=e.imagery;if(!i)return;const n=this.toCanvas(e.bounds,i.bounds.north,i.bounds.west),s=this.toCanvas(e.bounds,i.bounds.south,i.bounds.east);t.drawImage(i.source,n.x,n.y,s.x-n.x,s.y-n.y)}paintNight(e=0){if(e<=0)return;const{ctx:t}=this;t.save(),t.fillStyle=`rgba(6, 12, 30, ${Math.min(e,1)*.78})`,t.fillRect(0,0,this.width,this.height),t.restore()}paintDecor(e){const{ctx:t}=this;for(const i of e.decor){const n=this.toCanvas(e.bounds,i.lat,i.lng);if(i.label&&this.targets.push({kind:"decor",label:i.label,lat:i.lat,lng:i.lng,x:n.x,y:n.y,radius:7}),t.beginPath(),t.rect(n.x-3.5,n.y-3.5,7,7),t.fillStyle="rgba(120, 220, 255, 0.85)",t.fill(),t.lineWidth=1.5,t.strokeStyle="rgba(0, 0, 0, 0.7)",t.stroke(),i.headingDeg===void 0)continue;const s=(i.headingDeg-90)*Math.PI/180;t.beginPath(),t.moveTo(n.x,n.y),t.lineTo(n.x+Math.cos(s)*10,n.y+Math.sin(s)*10),t.lineWidth=3,t.strokeStyle="rgba(0, 0, 0, 0.6)",t.stroke(),t.lineWidth=1.5,t.strokeStyle="rgba(120, 220, 255, 0.9)",t.stroke()}}paintPath(e){if(!e.path.moved)return;const{ctx:t}=this,i=e.path.points.map(n=>this.toCanvas(e.bounds,n.lat,n.lng));t.beginPath(),t.moveTo(i[0].x,i[0].y);for(const n of i.slice(1))t.lineTo(n.x,n.y);t.lineJoin="round",t.lineCap="round",t.strokeStyle="rgba(0, 0, 0, 0.65)",t.lineWidth=5,t.stroke(),t.strokeStyle="rgba(255, 255, 255, 0.9)",t.lineWidth=2,t.stroke()}paintCone(e,t){const{headingDeg:i,coneHalfAngleDeg:n}=e;if(i===void 0||n===void 0)return;const{ctx:s}=this,r=this.toCanvas(e.bounds,t.lat,t.lng),o=Math.hypot(this.width,this.height),l=(i-90)*Math.PI/180,c=n*Math.PI/180;s.save(),s.beginPath(),s.moveTo(r.x,r.y),s.arc(r.x,r.y,o,l-c,l+c),s.closePath();const h=s.createRadialGradient(r.x,r.y,0,r.x,r.y,o);h.addColorStop(0,"rgba(255, 224, 130, 0.55)"),h.addColorStop(.35,"rgba(255, 224, 130, 0.22)"),h.addColorStop(1,"rgba(255, 224, 130, 0)"),s.fillStyle=h,s.fill(),s.restore()}paintMarkers(e){const{ctx:t}=this;t.textAlign="center",t.textBaseline="middle",t.font="bold 10px sans-serif";for(const i of[...e.markers].sort((n,s)=>Number(n.current)-Number(s.current))){const n=this.toCanvas(e.bounds,i.lat,i.lng);this.targets.push({kind:"milestone",label:i.note?`${i.label} — ${i.note}`:i.label,lat:i.lat,lng:i.lng,t:i.t,x:n.x,y:n.y,radius:Fr.MARKER_RADIUS_PX}),t.beginPath(),t.arc(n.x,n.y,Fr.MARKER_RADIUS_PX,0,Math.PI*2),t.fillStyle=i.current?"rgba(255, 224, 130, 0.95)":"rgba(0, 0, 0, 0.55)",t.fill(),t.lineWidth=2,t.strokeStyle="rgba(255, 255, 255, 0.9)",t.stroke(),t.fillStyle=i.current?"#1d2321":"#fff",t.fillText(i.label,n.x,n.y)}}paintObserver(e,t){const{ctx:i}=this,n=this.toCanvas(e.bounds,t.lat,t.lng);e.observerLabel&&this.targets.push({kind:"observer",label:e.observerLabel,lat:t.lat,lng:t.lng,x:n.x,y:n.y,radius:8});const s=e.markers.some(r=>{if(!r.current)return!1;const o=li(r.lat,r.lng,t.lat,t.lng);return Math.hypot(o.x,o.z)<=Fr.ON_MARKER_M});i.beginPath(),i.arc(n.x,n.y,s?Fr.MARKER_RADIUS_PX+2.5:5.5,0,Math.PI*2),s||(i.fillStyle="#ff5a3c",i.fill()),i.lineWidth=4,i.strokeStyle="rgba(0, 0, 0, 0.5)",i.stroke(),i.lineWidth=s?3:2.5,i.strokeStyle=s?"#ff5a3c":"#fff",i.stroke()}paintNorth(){const{ctx:e}=this,t=this.width-14,i=16;e.beginPath(),e.moveTo(t,i-9),e.lineTo(t-4.5,i+5),e.lineTo(t,i+2),e.lineTo(t+4.5,i+5),e.closePath(),e.fillStyle="rgba(255, 255, 255, 0.92)",e.strokeStyle="rgba(0, 0, 0, 0.6)",e.lineWidth=1,e.fill(),e.stroke(),e.font="bold 9px sans-serif",e.textAlign="center",e.textBaseline="top",e.strokeText("N",t,i+6),e.fillText("N",t,i+6)}paintFooter(e,t){const{ctx:i}=this;i.font="9px sans-serif",i.textBaseline="bottom";const n=t?this.wrap(t,this.width-20):[];let s=this.height-4;i.textAlign="right";for(const f of n.slice().reverse())this.paintOutlinedText(f,this.width-6,s),s-=11;const r=(e.south+e.north)/2,l=Math.abs(li(r,e.east,r,e.west).x)/this.width,c=Fr.SCALE_STEPS_M.find(f=>f/l<=this.width/3);if(c===void 0)return;const h=c/l,d=8,u=s-3;i.lineWidth=3,i.strokeStyle="rgba(0, 0, 0, 0.6)",i.beginPath(),i.moveTo(d,u),i.lineTo(d+h,u),i.stroke(),i.lineWidth=1.5,i.strokeStyle="rgba(255, 255, 255, 0.95)",i.stroke(),i.textAlign="left",this.paintOutlinedText(c>=1e3?`${c/1e3} km`:`${c} m`,d,u-3)}paintOutlinedText(e,t,i){const{ctx:n}=this;n.lineWidth=3,n.strokeStyle="rgba(0, 0, 0, 0.75)",n.strokeText(e,t,i),n.fillStyle="#fff",n.fillText(e,t,i)}wrap(e,t){const i=[];let n="";for(const s of e.split(" ")){const r=n?`${n} ${s}`:s;n&&this.ctx.measureText(r).width>t?(i.push(n),n=s):n=r}return n&&i.push(n),i}}class xi{static MIN_ZOOM=.25;static MAX_ZOOM=64;zoom=1;centerX=.5;centerY=.5;get changed(){return this.zoom!==1||this.centerX!==.5||this.centerY!==.5}get zoomFactor(){return this.zoom}reset(){this.zoom=1,this.centerX=.5,this.centerY=.5}zoomAt(e,t,i){const n=Math.min(xi.MAX_ZOOM,Math.max(xi.MIN_ZOOM,this.zoom*i)),s=this.centerX+(e-.5)/this.zoom,r=this.centerY+(t-.5)/this.zoom;this.centerX=s-(e-.5)/n,this.centerY=r-(t-.5)/n,this.zoom=n}panBy(e,t){this.centerX-=e/this.zoom,this.centerY-=t/this.zoom}refit(e,t){if(!this.changed)return;const i=this.boundsWithin(e),n=xi.mercatorY01(t.north),s=xi.mercatorY01(t.south),r=xi.mercatorY01(i.north),o=xi.mercatorY01(i.south);this.zoom=(t.east-t.west)/(i.east-i.west),this.centerX=((i.west+i.east)/2-t.west)/(t.east-t.west),this.centerY=((r+o)/2-n)/(s-n)}boundsWithin(e){if(!this.changed)return e;const t=.5/this.zoom,i=xi.mercatorY01(e.north),n=xi.mercatorY01(e.south),s=e.east-e.west;return{west:e.west+(this.centerX-t)*s,east:e.west+(this.centerX+t)*s,north:xi.latitudeAt(i+(this.centerY-t)*(n-i)),south:xi.latitudeAt(i+(this.centerY+t)*(n-i))}}static pointAt(e,t,i){const n=xi.mercatorY01(e.north),s=xi.mercatorY01(e.south);return{lat:xi.latitudeAt(n+i*(s-n)),lng:e.west+t*(e.east-e.west)}}static mercatorY01(e){const t=e*Math.PI/180;return(1-Math.log(Math.tan(t)+1/Math.cos(t))/Math.PI)/2}static latitudeAt(e){return Math.atan(Math.sinh(Math.PI*(1-2*e)))*180/Math.PI}}const xn=256,y0=3,Ly=32768;class Ov{fetchImpl;tileUrlTemplate;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=e.tileUrlTemplate??"https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png"}async getElevationGrid(e,t){const i=(e.south+e.north)/2,n=(e.west+e.east)/2,s=Math.abs(li(i,e.east,i,e.west).x),r=Math.abs(li(e.north,n,e.south,n).z),o=Dy(i,Math.max(s,r)),{tiles:l}=Lv(n,i,o,y0),c=y0*xn,h=new Float32Array(c*c),d=l[0];await Promise.all(l.map(f=>this.decodeTileInto(f,d,h,c)));const u=new Float32Array(t.width*t.height);for(let f=0;f<t.height;f++){const p=e.north+(e.south-e.north)*(f/(t.height-1));for(let v=0;v<t.width;v++){const m=e.west+(e.east-e.west)*(v/(t.width-1));u[f*t.width+v]=this.sampleAt(p,m,o,d,h,c)}}return{heights:u,width:t.width,height:t.height,bounds:e}}async decodeTileInto(e,t,i,n){const s=this.tileUrlTemplate.replace("{z}",String(e.z)).replace("{x}",String(e.x)).replace("{y}",String(e.y)),r=await this.fetchImpl(s);if(!r.ok)throw new Error(`Elevation tile fetch failed (${r.status}): ${s}`);const o=await createImageBitmap(await r.blob()),l=document.createElement("canvas");l.width=xn,l.height=xn;const c=l.getContext("2d");if(!c)throw new Error("2D canvas context unavailable");c.drawImage(o,0,0);const{data:h}=c.getImageData(0,0,xn,xn),d=(e.x-t.x)*xn,u=(e.y-t.y)*xn;for(let f=0;f<xn;f++)for(let p=0;p<xn;p++){const v=(f*xn+p)*4,m=h[v]*256+h[v+1]+h[v+2]/256-Ly,g=d+p,y=u+f;i[y*n+g]=m}}sampleAt(e,t,i,n,s,r){const{x:o,y:l}=Rv(t,e,i),c=(o-n.x)*xn,h=(l-n.y)*xn,d=Math.max(0,Math.min(r-1,Math.floor(c))),u=Math.max(0,Math.min(r-1,Math.floor(h))),f=Math.min(r-1,d+1),p=Math.min(r-1,u+1),v=c-d,m=h-u,g=s[u*r+d],y=s[u*r+f],M=s[p*r+d],b=s[p*r+f],x=g+(y-g)*v,E=M+(b-M)*v;return x+(E-x)*m}}const Oc=256,Oy=5;async function kv(a,e,t,i){const n=(a.south+a.north)/2,s=(a.west+a.east)/2,r=Math.abs(li(n,a.east,n,a.west).x),o=Math.abs(li(a.north,s,a.south,s).z),l=Math.max(r,o),{zoom:c,gridSize:h}=ky(n,l,Math.max(e.width,e.height)),{tiles:d,bounds:u}=Lv(s,n,c,h),f=h*Oc,p=document.createElement("canvas");p.width=f,p.height=f;const v=p.getContext("2d");if(!v)throw new Error("2D canvas context unavailable");const m=d[0];await Promise.all(d.map(async b=>{const x=t(b),E=await i(x);if(!E.ok)throw new Error(`Imagery tile fetch failed (${E.status}): ${x}`);const I=await createImageBitmap(await E.blob());v.drawImage(I,(b.x-m.x)*Oc,(b.y-m.y)*Oc)}));const g=Math.min(Math.max(e.width,e.height),f);if(g===f)return{source:p,width:f,height:f,bounds:u};const y=document.createElement("canvas");y.width=g,y.height=g;const M=y.getContext("2d");if(!M)throw new Error("2D canvas context unavailable");return M.drawImage(p,0,0,f,f,0,0,g,g),{source:y,width:g,height:g,bounds:u}}function ky(a,e,t){let i=Cy(a,e/Math.max(1,t)),n=M0(a,i,e);for(;n>Oy&&i>0;)i--,n=M0(a,i,e);return{zoom:i,gridSize:n,mPerPixel:Cv(a,i)/Oc}}function M0(a,e,t){const i=Math.ceil(t/2/Cv(a,e));return Math.max(3,2*i+1)}class Nv{attribution="Imagery © Esri, Maxar, Earthstar Geographics, and the GIS User Community";fetchImpl;tileUrlTemplate;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=e.tileUrlTemplate??"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"}async getImageryTexture(e,t){return kv(e,t,i=>this.tileUrlTemplate.replace("{z}",String(i.z)).replace("{y}",String(i.y)).replace("{x}",String(i.x)),this.fetchImpl)}}class On{attribution="Roads © OpenStreetMap contributors, as surveyed today";contemporary=!0;static DRIVABLE=["motorway","trunk","primary","secondary","tertiary","unclassified","residential","service","track","motorway_link","trunk_link","primary_link","secondary_link","tertiary_link"];static WIDTH_M={motorway:11,trunk:9,primary:8,secondary:7,tertiary:6.5,unclassified:5.5,residential:5.5,service:4,track:3.5};static DEFAULT_WIDTH_M=5;static ENDPOINTS=["https://overpass-api.de/api/interpreter","https://overpass.kumi.systems/api/interpreter","https://overpass.private.coffee/api/interpreter"];fetchImpl;endpoints;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.endpoints=e.endpoints??On.ENDPOINTS}static queue=Promise.resolve();static RETRY_MS=4e3;async getRoads(e){const t=`${e.south},${e.west},${e.north},${e.east}`,i=`[out:json][timeout:30];way["highway"~"^(${On.DRIVABLE.join("|")})$"](${t});out geom;`;return this.waysFrom(await this.queued(()=>this.ask(i)))}waysFrom(e){const t=[];for(const i of e.elements??[]){const n=i.geometry,s=i.tags;!s||!n||n.length<2||t.push({id:`osm-${i.id??t.length}`,name:s.name,surface:On.surfaceOf(s),widthM:On.widthOf(s),points:n.map(r=>({lat:r.lat,lng:r.lon}))})}return t}queued(e){const t=On.queue.then(e,e);return On.queue=t.catch(()=>{}),t}async ask(e){let t;for(const i of this.endpoints)for(let n=0;n<2;n++){try{const s=await this.fetchImpl(`${i}?data=${encodeURIComponent(e)}`);if(s.ok)return await s.json();if(t=new Error(`${new URL(i).host} refused (${s.status})`),s.status!==429&&s.status!==504)break}catch(s){t=new Error(`${new URL(i).host} unreachable (${String(s)})`);break}await new Promise(s=>setTimeout(s,On.RETRY_MS))}throw t??new Error("No Overpass instance answered")}static widthOf(e){const t=Number.parseFloat(e.width??e.est_width??"");if(Number.isFinite(t)&&t>0)return t;const i=Number.parseInt(e.lanes??"",10);return Number.isFinite(i)&&i>0?i*3.5:On.WIDTH_M[e.highway]??On.DEFAULT_WIDTH_M}static surfaceOf(e){const t=e.surface;return t==="dirt"||t==="earth"||t==="mud"?"dirt":t==="gravel"||t==="fine_gravel"||t==="compacted"||t==="ground"||t==="sand"||t==="unpaved"?"gravel":t?"paved":e.highway==="track"?"gravel":"paved"}}const Wh="https://ufoathome.org/roads/index.json";class Qf{attributionRead;contemporaryRead;fetchImpl;indexUrls;fallback;index;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.indexUrls=e.indexUrls??Qf.defaultIndexUrls(),this.fallback=e.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Roads © OpenStreetMap contributors"}get contemporary(){return this.contemporaryRead??this.fallback?.contemporary??!0}async getRoads(e){const t=await this.held(e);if(t)return t;if(!this.fallback)return[];const i=await this.fallback.getRoads(e);return this.attributionRead=this.fallback.attribution,this.contemporaryRead=this.fallback.contemporary,i}async held(e){let t;try{t=await this.load()}catch{return}const i=t.find(({entry:n})=>n.north>=e.north&&n.south<=e.south&&n.east>=e.east&&n.west<=e.west);if(i)try{const n=await this.fetchImpl(new URL(i.entry.file,i.indexUrl).href);if(!n.ok)return;const s=await n.json();return Array.isArray(s?.ways)?(this.attributionRead=s.attribution,this.contemporaryRead=s.contemporary,s.ways):void 0}catch{return}}load(){return this.index??=this.fetchFirstAvailable(),this.index}async fetchFirstAvailable(){for(const e of this.indexUrls)try{const t=await this.fetchImpl(e);if(!t.ok)continue;const i=await t.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:e}))}catch{}return[]}static defaultIndexUrls(){const e=`?v=${encodeURIComponent("0.70.0")}`,t=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(t&&t!==Wh?[t,Wh]:[Wh]).map(i=>i+e)}}function Ny(){return{elevation:new Ov,imagery:Fv(),roads:Fy()}}function Fv(){return new Nv}function Fy(){return new Qf({fallback:new On})}const Uy=new Set,Zr="show-observer-map",$a="hide-milestones";class Li extends HTMLElement{static get observedAttributes(){return["src",Zr,$a]}shadow;stageElement;canvas;canvasRenderer;tooltip;toolbar;playPauseButton;static OBSERVER_MAP_MIN_SPAN_M=400;static OBSERVER_MAP_MARGIN=.6;static OBSERVER_MAP_IMAGERY_PX=768;fullscreenButton;observerMapButton;referencesButton;referenceOpacityInput;referencesShownState=!0;referenceOpacityTouched=!1;milestonesButton;observerMapPanel;observerMapCanvas;observerMapRenderer;mapZoomInButton;mapZoomOutButton;mapFitButton;observerMapView=new xi;observerMapDrag;suppressObserverMapClick=!1;observerMapImageryTimer;observerPlacing=!1;seekInput;playbackFlash;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;observerPath;observerMapBounds;observerMapImagery;observerMapImageryBounds;observerMapImageryCredit;observerMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=xh.create();sightingAudio=new gy;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;steadyObserver=!1;selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=_v;realDurationMs;realStartMs;showClockTime=!0;handleFullscreenChange=()=>{this.updateFullscreenButton(),this.resizeObserverMap()};observerMapResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.resizeObserverMap());resizeObserverMap(){this.observerMapPanel.hidden||(this.sizeObserverMapCanvas(),this.paintObserverMap(this.currentTime))}simulatedFullscreen=!1;styleBeforeSimulatedFullscreen;bodyOverflowBeforeSimulatedFullscreen;handleSimulatedFullscreenKey=e=>{e.key==="Escape"&&this.exitSimulatedFullscreen()};handlePointerMove=e=>{const t=this.canvasPointFromEvent(e),i=t&&this.shapeAt(t.x,t.y),n=this.said.read(i?.shape.title);if(!n){this.tooltip.hidden=!0;return}this.tooltip.textContent=n,this.tooltip.hidden=!1;const s=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${e.clientX-s.left+12}px`,this.tooltip.style.top=`${e.clientY-s.top+12}px`};handleObserverMapPointerMove=e=>{if(this.dragObserverMap(e))return;const t=this.observerMapTargetFrom(e);if(!t){if(!this.observerPlacing){this.tooltip.hidden=!0,this.observerMapCanvas.style.cursor="grab";return}this.observerMapCanvas.style.cursor="crosshair",this.showObserverMapTooltip(e,this.messages.placeObserverHere);return}this.observerMapCanvas.style.cursor="pointer",this.showObserverMapTooltip(e,t.label)};showObserverMapTooltip(e,t){this.tooltip.textContent=t,this.tooltip.hidden=!1;const i=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${e.clientX-i.left+12}px`,this.tooltip.style.top=`${e.clientY-i.top+12}px`}handleObserverMapClick=e=>{if(this.suppressObserverMapClick){this.suppressObserverMapClick=!1;return}const t=this.observerMapTargetFrom(e);if(!t){this.observerPlacing&&this.placeObserverFrom(e);return}if(t.kind==="milestone"&&t.t!==void 0){this.player.seek(t.t);return}this.dispatchEvent(new CustomEvent("lookat",{detail:{lat:t.lat,lng:t.lng,kind:t.kind},bubbles:!0,composed:!0}))};observerMapTargetFrom(e){const t=this.observerMapCanvas.getBoundingClientRect();if(!(t.width===0||t.height===0))return this.observerMapRenderer.hitTest((e.clientX-t.left)/t.width*this.observerMapCanvas.width,(e.clientY-t.top)/t.height*this.observerMapCanvas.height)}handlePointerLeave=()=>{this.tooltip.hidden=!0};handleObserverMapPointerDown=e=>{e.button===0&&(this.suppressObserverMapClick=!1,this.observerMapDrag={pointerId:e.pointerId,startX:e.clientX,startY:e.clientY,lastX:e.clientX,lastY:e.clientY,moved:!1})};handleObserverMapPointerUp=e=>{const t=this.observerMapDrag;!t||t.pointerId!==e.pointerId||(this.observerMapDrag=void 0,this.observerMapCanvas.classList.remove("dragging"),t.moved&&(this.suppressObserverMapClick=!0,this.observerMapCanvas.hasPointerCapture?.(e.pointerId)&&this.observerMapCanvas.releasePointerCapture(e.pointerId)))};dragObserverMap(e){const t=this.observerMapDrag;if(!t||t.pointerId!==e.pointerId)return!1;if(!t.moved){if(Math.hypot(e.clientX-t.startX,e.clientY-t.startY)<Li.OBSERVER_MAP_DRAG_PX)return!1;t.moved=!0,this.tooltip.hidden=!0,this.observerMapCanvas.classList.add("dragging"),this.observerMapCanvas.setPointerCapture?.(e.pointerId)}const i=this.observerMapCanvas.getBoundingClientRect();return i.width>0&&i.height>0&&(this.observerMapView.panBy((e.clientX-t.lastX)/i.width,(e.clientY-t.lastY)/i.height),this.observerMapViewChanged()),t.lastX=e.clientX,t.lastY=e.clientY,!0}static OBSERVER_MAP_DRAG_PX=4;handleObserverMapWheel=e=>{e.preventDefault();const t=this.observerMapCanvas.getBoundingClientRect();if(t.width===0||t.height===0)return;const i=e.deltaMode===0?e.deltaY:e.deltaY*40;this.zoomObserverMap((e.clientX-t.left)/t.width,(e.clientY-t.top)/t.height,Math.exp(-i*.002))};zoomObserverMap(e,t,i){this.observerMapView.zoomAt(e,t,i),this.observerMapViewChanged()}observerMapViewChanged(){this.mapFitButton.hidden=!this.observerMapView.changed,this.mapZoomInButton.disabled=this.observerMapView.zoomFactor>=xi.MAX_ZOOM,this.mapZoomOutButton.disabled=this.observerMapView.zoomFactor<=xi.MIN_ZOOM,this.paintObserverMap(this.currentTime),clearTimeout(this.observerMapImageryTimer),this.observerMapImageryTimer=setTimeout(()=>void this.loadObserverMapImagery(),Li.OBSERVER_MAP_IMAGERY_DELAY_MS)}static OBSERVER_MAP_IMAGERY_DELAY_MS=300;get observerMapViewBounds(){return this.observerMapBounds&&this.observerMapView.boundsWithin(this.observerMapBounds)}placeObserverFrom(e){const t=this.observerMapViewBounds,i=this.observerMapCanvas.getBoundingClientRect();if(!t||i.width===0||i.height===0)return;const n=xi.pointAt(t,(e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height);this.dispatchEvent(new CustomEvent("observerplace",{detail:n,bubbles:!0,composed:!0}))}constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${uy}</style>${dy}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new ul(this.canvas.getContext("2d")),this.tooltip=this.shadow.getElementById("tooltip"),this.toolbar=this.shadow.getElementById("toolbar"),this.playPauseButton=this.shadow.getElementById("play-pause"),this.fullscreenButton=this.shadow.getElementById("fullscreen"),this.observerMapButton=this.shadow.getElementById("observer-map"),this.referencesButton=this.shadow.getElementById("references"),this.referenceOpacityInput=this.shadow.getElementById("reference-opacity"),this.milestonesButton=this.shadow.getElementById("milestones"),this.observerMapPanel=this.shadow.getElementById("observer-map-panel"),this.observerMapCanvas=this.shadow.getElementById("observer-map-canvas"),this.observerMapRenderer=new Fr(this.observerMapCanvas.getContext("2d")),this.mapZoomInButton=this.shadow.getElementById("map-zoom-in"),this.mapZoomOutButton=this.shadow.getElementById("map-zoom-out"),this.mapFitButton=this.shadow.getElementById("map-fit"),this.seekInput=this.shadow.getElementById("seek"),this.playbackFlash=this.shadow.getElementById("playback-flash"),this.milestoneMarks=this.shadow.getElementById("milestone-marks"),this.milestoneCaption=this.shadow.getElementById("milestone-caption"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end");for(const t of[this.timeStartLabel,this.timeEndLabel])t.addEventListener("click",()=>this.toggleTimeDisplay()),t.addEventListener("keydown",i=>{i.key!=="Enter"&&i.key!==" "||(i.preventDefault(),this.toggleTimeDisplay())});this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.observerMapButton.addEventListener("click",()=>this.toggleObserverMap()),this.referencesButton.addEventListener("click",()=>this.toggleReferences()),this.referenceOpacityInput.addEventListener("input",()=>{this.referenceOpacityTouched=!0,this.dispatchReferenceView()}),this.milestonesButton.addEventListener("click",()=>this.toggleMilestones()),this.observerMapCanvas.addEventListener("pointermove",this.handleObserverMapPointerMove),this.observerMapCanvas.addEventListener("pointerleave",this.handlePointerLeave),this.observerMapCanvas.addEventListener("click",this.handleObserverMapClick),this.observerMapCanvas.addEventListener("pointerdown",this.handleObserverMapPointerDown),this.observerMapCanvas.addEventListener("pointerup",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("pointercancel",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("wheel",this.handleObserverMapWheel,{passive:!1}),this.mapZoomInButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,2)),this.mapZoomOutButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,.5)),this.mapFitButton.addEventListener("click",()=>{this.observerMapView.reset(),this.observerMapViewChanged()}),this.seekInput.addEventListener("input",()=>this.player.seek(this.snapSeekToMark(Number(this.seekInput.value)))),this.seekInput.addEventListener("pointerdown",t=>{this.seekSnapArmed=!0,this.nameMarkUnder(t)}),this.seekInput.addEventListener("pointerup",()=>{this.seekSnapArmed=!1}),this.seekInput.addEventListener("pointermove",t=>this.nameMarkUnder(t)),this.seekInput.addEventListener("pointerleave",()=>this.seekInput.removeAttribute("title")),this.seekInput.addEventListener("keydown",this.handleSeekKey),this.canvas.addEventListener("click",t=>{this.enableClickToPlay&&(t.detail<=1&&(this.playbackBeforeClick={state:this.playbackState,time:this.currentTime}),this.togglePlayPause())}),this.canvas.addEventListener("dblclick",t=>{this.enableClickToPlay&&(t.preventDefault(),this.restorePlayback(),this.toggleFullscreen())}),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerleave",this.handlePointerLeave),document.addEventListener("fullscreenchange",this.handleFullscreenChange),this.observerMapResizeObserver?.observe(this.observerMapPanel),this.hostControls(void 0),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateMilestonesButton(),this.refresh(),this.loadLocaleMessages()}connectedCallback(){this.saidTexts=void 0;const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.observerMapResizeObserver?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(e,t,i){e==="src"&&i&&i!==t&&this.isConnected&&this.loadFromSrc(i),e===Zr&&this.applyObserverMapDefault(),e===$a&&this.setMilestonesShown(!this.hasAttribute($a))}async loadFromSrc(e){this.sightingData=await Zf.json(e)}get sightingData(){return vy(this.currentSighting)}set sightingData(e){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=by(e),this.observerMapView.reset(),this.mapFitButton.hidden=!0,this.observerMapAsked=!1,this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyObserverMapDefault()}get sighting(){return this.currentSighting}previewSound(e){this.soundPreview=e,this.sightingAudio.resume(),this.sightingAudio.setSound(e)}stopSoundPreview(){this.soundPreview=void 0,this.sightingAudio.silence()}get canvasElement(){return this.canvas}get renderer(){return this.canvasRenderer}get currentTime(){return this.player.time}set currentTime(e){this.player.seek(e)}get seekableDuration(){return this.player.seekableDuration}get autoReplayEnabled(){return this.loopEnabled}set autoReplayEnabled(e){e!==this.loopEnabled&&this.toggleLoop()}play(){this.player.seekableDuration<=0||this.playbackState==="playing"||this.togglePlayPause()}pause(){this.playbackState==="playing"&&this.togglePlayPause()}get positionLabel(){return this.timeStartLabel.textContent??""}get durationLabel(){return this.timeEndLabel.textContent??""}get showingClockTime(){return this.canShowClockTime}get canSwitchTimeDisplay(){return this.realStartMs!==void 0}toggleTimeDisplay(){this.canSwitchTimeDisplay&&(this.showClockTime=!this.showClockTime,this.updateTimeLabels(),this.updateTimeLabelTitles(),this.dispatchEvent(new CustomEvent("timedisplaychange",{bubbles:!0,composed:!0})))}get canShowClockTime(){return this.realStartMs!==void 0&&this.showClockTime}set showToolbar(e){this.toolbar.classList.toggle("hidden",!e)}get playbackState(){return this.player.playbackState}get selectedSourceIds(){return this.highlightedSourceIds}get durationSeconds(){return this.currentSighting.event.durationSeconds}set durationSeconds(e){this.currentSighting.event.durationSeconds=e,this.updateTimeLabels(),this.refresh(),this.updatePlayPauseButton()}set selectedSourceIds(e){const t=new Set(e);t.size===this.highlightedSourceIds.size&&[...t].every(n=>this.highlightedSourceIds.has(n))||(this.highlightedSourceIds=t,this.refresh())}hasVisibleShapeAt(e,t){return this.shapeAt(e,t)!==void 0}refresh(){this.applyFrameFormat(),this.updateTimeLabels(),this.seekInput.max=String(this.player.seekableDuration),this.refreshMilestoneMarks(),this.updateMilestonesButton(),this.updateObserverMap(),this.updateReferences(),this.player.seek(this.player.time)}hostControls(e){const t=[this.milestonesButton,this.referenceOpacityInput,this.referencesButton,this.observerMapButton];if(e)for(const i of t)e.appendChild(i);else for(const i of t)this.toolbar.appendChild(i)}get referencesShown(){return this.referencesShownState}get referenceOpacity(){return Number(this.referenceOpacityInput.value)}toggleReferences(){this.referencesShownState=!this.referencesShownState,this.updateReferencesButton(),this.dispatchReferenceView()}updateReferences(){const e=this.currentSighting.references;!this.referenceOpacityTouched&&e.length>0&&(this.referenceOpacityInput.value=String(e[0].opacity)),this.updateReferencesButton()}updateReferencesButton(){const e=this.currentSighting.references.length>0;this.referencesButton.hidden=!e,this.referenceOpacityInput.hidden=!e||!this.referencesShownState,this.referencesButton.setAttribute("aria-pressed",String(this.referencesShownState));const t=this.referencesShownState?this.messages.hideReferences:this.messages.showReferences;this.referencesButton.title=t,this.referencesButton.setAttribute("aria-label",t),this.referenceOpacityInput.title=this.messages.referenceOpacity,this.referenceOpacityInput.setAttribute("aria-label",this.messages.referenceOpacity)}dispatchReferenceView(){this.dispatchEvent(new CustomEvent("referenceview",{detail:{shown:this.referencesShown,opacity:this.referenceOpacity}}))}refreshMilestoneMarks(){const e=this.player.seekableDuration,t=e>0?ao(this.sighting.milestones):[];this.milestoneMarks.replaceChildren(...t.map(i=>{const n=document.createElement("button");n.type="button",n.className="milestone-mark",n.style.left=`${Math.min(Math.max(i.t/e,0),1)*100}%`;const s=this.said.read(i.label)??"",r=this.said.read(i.note),o=r?`${s} — ${r}`:s;return n.title=o,n.setAttribute("aria-label",o),n.dataset.t=String(i.t),n.addEventListener("click",()=>this.player.seek(i.t)),n}))}seekSnapArmed=!1;static MARK_SNAP_PX=6;markNear(e){const t=this.player.seekableDuration,i=this.seekInput.getBoundingClientRect().width;if(t<=0||i<=0)return;const n=Li.MARK_SNAP_PX/i*t;let s;for(const r of this.milestoneMarks.children){const o=Number(r.dataset.t);Math.abs(o-e)>n||(!s||Math.abs(o-e)<Math.abs(s.t-e))&&(s={t:o,name:r.title})}return s}snapSeekToMark(e){return this.seekSnapArmed?(this.seekSnapArmed=!1,this.markNear(e)?.t??e):e}nameMarkUnder(e){const t=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(t.width<=0||i<=0)return;const n=(e.clientX-t.left)/t.width*i,s=this.markNear(n);s?this.seekInput.title=s.name:this.seekInput.removeAttribute("title")}showMilestoneAt(e){const t=this.milestonesShown&&this.sighting.milestones.length>0?v0(this.sighting.milestones,e):void 0;if(this.milestoneCaption.hidden=t===void 0,!t)return;const i=document.createElement("b");i.textContent=this.said.read(t.label)??"";const n=this.said.read(t.note),s=n?` — ${n}`:"";this.milestoneCaption.replaceChildren(i,document.createTextNode(s))}exposureInstants(e){const t=this.exposureTimes(e),i=1/t.length;return t.map(n=>({shapes:this.shapesAt(n),share:i}))}exposureTimes(e=this.currentTime){const t=Un.windowEndingAt(e,this.currentSighting.exposure??0);if(t.ms<Li.SHORTEST_VISIBLE_EXPOSURE_MS)return[e];const i=Math.min(Li.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(t.ms/Li.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(t.fromMs,t.ms)/Li.EXPOSURE_STEP_PX),s=Math.min(Li.MAX_TRAVEL_STEPS,Math.max(i,n)),r=[];for(let o=0;o<s;o++)r.push(t.fromMs+t.ms*o/(s-1));return r}travelPxOver(e,t){const i=this.shapesAt(e),n=this.shapesAt(e+t);let s=0;for(const[r,o]of i){const l=n.get(r);if(!l)continue;const c=l.bounds.x+l.bounds.width/2-(o.bounds.x+o.bounds.width/2),h=l.bounds.y+l.bounds.height/2-(o.bounds.y+o.bounds.height/2);s=Math.max(s,Math.hypot(c,h))}return s}shapeAt(e,t,i){for(const n of this.exposureTimes()){const s=this.currentSighting.timeline.hitTest(n,e,t,i);if(s)return s}}shapesAt(e){const t=new Map;for(const i of this.currentSighting.timeline.sourceIds){const n=this.currentSighting.timeline.getInterpolatedShapeAt(e,i);n&&t.set(i,n)}return t}static SHORTEST_VISIBLE_EXPOSURE_MS=20;static MAX_EXPOSURE_STEPS=48;static EXPOSURE_STEP_PX=2;static MAX_TRAVEL_STEPS=320;applyFrameFormat(){const e=Mt.frameWidthPx(this.currentSighting.instrument,this.canvas.height);if(this.canvas.width===e)return;this.canvas.width=e,this.canvas.parentElement?.style.setProperty("--frame-aspect",`${e} / ${this.canvas.height}`)}canvasPointFromEvent(e){const t=this.canvas.getBoundingClientRect();if(!(t.width===0||t.height===0))return{x:(e.clientX-t.left)/t.width*this.canvas.width,y:(e.clientY-t.top)/t.height*this.canvas.height}}onFrame(e,t){this.canvasRenderer.clear(this.canvas.width,this.canvas.height);const i=this.playbackState!=="playing"?this.highlightedSourceIds:Uy;this.canvasRenderer.setStarPoints(Mt.starPointsOf(this.sighting.instrument));const n=(nt(this.sighting,e)?.rollDeg??0)+this.gaitAt(e).rollDeg;this.canvasRenderer.setRoll(n*Math.PI/180);const s=this.exposureInstants(e),r=this.frameShift;if(this.paintsShapes)for(const o of s)for(const[,l]of o.shapes){const c=o.share,h=c===1?l:{...l,transparency:1-(1-l.transparency)*c};this.canvasRenderer.paintShape(this.shifted(h,r))}for(const[o,l]of s[0].shapes)!this.selectionShown||!i.has(o)||(this.paintsShapes?i.size===1?this.canvasRenderer.paintShape({...l,selected:!0}):this.canvasRenderer.paintMemberOutline(l):this.canvasRenderer.paintSelectionOnly(this.shifted(l,r)));if(this.selectionShown&&i.size>1){const o=gt.groupBoundsFor([...t].filter(([l])=>i.has(l)).map(([,l])=>l.bounds));this.canvasRenderer.paintGroupHandles(o)}this.overlayPainter?.(this.canvasRenderer),this.mapShapeBounds=s.flatMap(o=>[...o.shapes.values()].filter(l=>l.transparency<1).map(l=>this.shifted(l,r).bounds)),this.keepObserverMapClear(),this.seekInput.value=String(e),this.timeStartLabel.textContent=this.formatPosition(e),this.showMilestoneAt(e),this.paintObserverMap(e),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(Kf(this.currentSighting,e))):this.soundPreview?this.sightingAudio.setSound(this.soundPreview):this.sightingAudio.silence(),this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("timeupdate",{detail:{time:e}}))}shifted(e,t){return t.x===0&&t.y===0?e:{...e,bounds:{...e.bounds,x:e.bounds.x+t.x,y:e.bounds.y+t.y}}}createPlayer(){const e=new fy(this.currentSighting.timeline,(t,i)=>this.onFrame(t,i));return e.loop=this.loopEnabled,e.onEnded=()=>{this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("ended",{bubbles:!0,composed:!0}))},e}static SEEK_KEY_STEP_MS=5e3;handleSeekKey=e=>{if(e.altKey||e.ctrlKey||e.metaKey)return;const t=e.key==="ArrowLeft"?-1:e.key==="ArrowRight"?1:0;if(t){e.preventDefault();const i=this.player.seekableDuration;this.player.seek(Math.min(i,Math.max(0,this.player.time+t*Li.SEEK_KEY_STEP_MS)))}else e.key===" "&&(e.preventDefault(),this.togglePlayPause())};togglePlayPause(){this.player.seekableDuration<=0||(this.player.playbackState==="playing"?(this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh()):(this.sightingAudio.resume(),this.player.play()),this.updatePlayPauseButton(),this.flashPlayback())}flashPlayback(){const e=this.playbackFlash;e.textContent=this.player.playbackState==="playing"?"▶":"⏸",e.classList.remove("flashing"),e.offsetWidth,e.classList.add("flashing")}updatePlayPauseButton(){const e=this.player.playbackState==="playing";this.playPauseButton.textContent=e?"⏸":"▶";const t=this.player.seekableDuration>0;this.playPauseButton.disabled=!t;const i=t?e?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=i,this.playPauseButton.setAttribute("aria-label",i)}toggleLoop(){this.loopEnabled=!this.loopEnabled,this.player.loop=this.loopEnabled}restorePlayback(){const e=this.playbackBeforeClick;e&&(this.currentTime=e.time,e.state==="playing"?this.play():this.pause())}get canUseNativeFullscreen(){return typeof this.fullscreenTarget.requestFullscreen=="function"&&document.fullscreenEnabled}toggleFullscreen(){if(!this.canUseNativeFullscreen){this.simulatedFullscreen?this.exitSimulatedFullscreen():this.enterSimulatedFullscreen();return}document.fullscreenElement?document.exitFullscreen():this.fullscreenTarget.requestFullscreen().catch(e=>{console.error("<rr0-ufo>: requestFullscreen() failed —",e)})}enterSimulatedFullscreen(){const e=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen=e.getAttribute("style")??"",this.bodyOverflowBeforeSimulatedFullscreen=document.body.style.overflow;const t=e.style;t.setProperty("position","fixed"),t.setProperty("inset","0"),t.setProperty("margin","0"),t.setProperty("max-width","none"),t.setProperty("max-height","none"),t.setProperty("aspect-ratio","auto"),t.setProperty("z-index","2147483647"),t.setProperty("background","#000"),t.setProperty("width","100vw"),t.setProperty("width","100dvw"),t.setProperty("height","100vh"),t.setProperty("height","100dvh"),document.body.style.overflow="hidden",this.simulatedFullscreen=!0,document.addEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}exitSimulatedFullscreen(){if(!this.simulatedFullscreen)return;const e=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen?e.setAttribute("style",this.styleBeforeSimulatedFullscreen):e.removeAttribute("style"),document.body.style.overflow=this.bodyOverflowBeforeSimulatedFullscreen??"",this.simulatedFullscreen=!1,document.removeEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}toggleObserverMap(){const e=this.observerMapPanel.hidden;this.observerMapAsked=e,this.setObserverMapOpen(e),this.keepObserverMapClear()}observerMapAsked=!1;applyObserverMapDefault(){const e=this.getAttribute(Zr),t=e===null?this.observerPath?.travels===!0:e!=="false";this.setObserverMapOpen(t&&this.observerPath!==void 0)}setObserverMapOpen(e){this.observerMapPanel.hidden=!e,this.observerMapPanel.removeAttribute("title"),this.observerMapButton.setAttribute("aria-pressed",String(e)),this.updateObserverMapButton(),e&&(this.sizeObserverMapCanvas(),this.loadObserverMapImagery(),this.paintObserverMap(this.currentTime))}updateObserverMapButton(){const t=!this.observerMapPanel.hidden?this.messages.hideObserverMap:this.messages.showObserverMap;this.observerMapButton.title=t,this.observerMapButton.setAttribute("aria-label",t);const i=[[this.mapZoomInButton,this.messages.zoomMapIn],[this.mapZoomOutButton,this.messages.zoomMapOut],[this.mapFitButton,this.messages.fitMap]];for(const[n,s]of i)n.title=s,n.setAttribute("aria-label",s)}updateObserverMap(){const e=this.observerPath!==void 0;if(this.observerPath=qa.of(this.currentSighting),this.observerMapButton.hidden=this.observerPath===void 0,!e&&this.observerPath&&this.applyObserverMapDefault(),!this.observerPath){this.setObserverMapOpen(!1),this.observerMapBounds=void 0;return}const t=this.observerPath.boundsAround(Li.OBSERVER_MAP_MIN_SPAN_M,Li.OBSERVER_MAP_MARGIN);(!this.observerMapBounds||!this.sameGround(this.observerMapBounds,t))&&(this.observerMapBounds&&this.observerMapView.refit(this.observerMapBounds,t),this.observerMapBounds=t,this.observerMapImagery=void 0,this.observerMapImageryCredit=void 0,this.observerMapImageryFailed=!1,this.observerMapImageryBounds=void 0,this.observerMapPanel.hidden||this.loadObserverMapImagery())}sameGround(e,t){const i=Math.abs(e.east-e.west)/20;return Math.abs(e.north-t.north)<i&&Math.abs(e.south-t.south)<i&&Math.abs(e.west-t.west)<i&&Math.abs(e.east-t.east)<i}async loadObserverMapImagery(){const e=this.observerMapViewBounds;if(!e||this.observerMapPanel.hidden||!this.observerMapImageryNeededFor(e))return;this.observerMapImageryBounds=e;const t=Fv();try{const i=await t.getImageryTexture(e,{width:Li.OBSERVER_MAP_IMAGERY_PX,height:Li.OBSERVER_MAP_IMAGERY_PX});if(this.observerMapImageryBounds!==e)return;this.observerMapImagery=i,this.observerMapImageryCredit=t.attribution,this.observerMapImageryFailed=!1}catch{if(this.observerMapImageryBounds!==e)return;this.observerMapImageryFailed=this.observerMapImagery===void 0}this.paintObserverMap(this.currentTime)}observerMapImageryNeededFor(e){const t=this.observerMapImageryBounds;if(!t)return!0;const i=this.observerMapImagery?.bounds??t,n=e.west>=i.west&&e.east<=i.east&&e.south>=i.south&&e.north<=i.north,s=e.east-e.west>(t.east-t.west)/2;return!n||!s}get observerMapCredit(){return this.observerMapImageryCredit}get observerMapFooterLine(){return this.observerMapImageryFailed?this.messages.mapImageryUnavailable:this.creditShownExternally?void 0:this.observerMapImageryCredit}mapShapeBounds=[];mapSceneBounds=[];setMapSubjectBounds(e){this.mapSceneBounds=e.map(t=>({x:t.x*this.canvas.width,y:t.y*this.canvas.height,width:t.width*this.canvas.width,height:t.height*this.canvas.height})),this.keepObserverMapClear()}keepObserverMapClear(){if(this.observerMapPanel.hidden)return;const e=this.observerMapBoxPx;if(!e)return;const t=[...this.mapShapeBounds,...this.mapSceneBounds],i=(c,h,d)=>{for(const u of t)if(!(u.x+u.width<c-d||u.x>h+d)&&!(u.y>e.bottom+d||u.y+u.height<e.top-d))return!0;return!1},n=[this.canvas.width-e.width,this.canvas.width],s=[0,e.width],r=Li.OBSERVER_MAP_CLEARANCE_PX,o=i(...n,0),l=i(...s,0);if(this.observerMapPanel.classList.toggle("subject-overlap",o&&l&&!this.observerMapAsked),this.observerMapPanel.classList.contains("on-the-left")){!o&&(l||!i(n[0],n[1],r))&&this.observerMapPanel.classList.remove("on-the-left");return}i(n[0],n[1],0)&&!i(s[0],s[1],0)&&this.observerMapPanel.classList.add("on-the-left")}observerMapBoxPx;static OBSERVER_MAP_CLEARANCE_PX=24;sizeObserverMapCanvas(){const e=this.observerMapPanel.clientWidth;if(e===0)return;const t=Math.round(e*(globalThis.devicePixelRatio??1));this.measureObserverMapBox(),this.observerMapCanvas.width!==t&&(this.observerMapCanvas.width=t,this.observerMapCanvas.height=t)}measureObserverMapBox(){const e=this.observerMapPanel.getBoundingClientRect(),t=this.canvas.getBoundingClientRect();if(t.width===0||t.height===0)return;const i=this.canvas.width/t.width,n=this.canvas.height/t.height;this.observerMapBoxPx={width:e.width*i,top:(e.top-t.top)*n,bottom:(e.bottom-t.top)*n}}paintObserverMap(e){if(this.observerMapPanel.hidden||!this.observerPath||!this.observerMapBounds)return;const t=nt(this.currentSighting,e),i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?v0(this.currentSighting.milestones,e):void 0;for(const r of this.milestonesShown?ao(this.currentSighting.milestones):[]){const o=nt(this.currentSighting,r.t);o?.lat===void 0||o.lng===void 0||n.push({label:this.said.read(r.label)??"",note:this.said.read(r.note),t:r.t,lat:o.lat,lng:o.lng,current:r===s})}this.observerMapRenderer.paint({bounds:this.observerMapViewBounds,imagery:this.observerMapImagery,path:this.observerPath,position:t?.lat!==void 0&&t.lng!==void 0?{lat:t.lat,lng:t.lng}:void 0,headingDeg:t?.headingDeg===void 0?void 0:t.headingDeg+this.lookYawDeg,coneHalfAngleDeg:t?Gn.of(i,this.canvas.height,t.fovDeg).halfWidthAngleDeg(Mt.aspectOf(i)):void 0,markers:n,decor:this.observerMapDecorAt(e),observerLabel:this.said.read(this.currentSighting.observer?.title)??this.messages.observerHere,nightFraction:this.observerMapNightFraction,attribution:this.observerMapFooterLine})}toggleMilestones(){this.setMilestonesShown(!this.milestonesShown)}setMilestonesShown(e){this.milestonesShown=e,this.milestoneMarks.hidden=!e,this.milestonesButton.setAttribute("aria-pressed",String(e)),this.updateMilestonesButton(),this.showMilestoneAt(this.currentTime),this.paintObserverMap(this.currentTime)}updateMilestonesButton(){this.milestonesButton.hidden=this.currentSighting.milestones.length===0;const e=this.milestonesShown?this.messages.hideMilestones:this.messages.showMilestones;this.milestonesButton.title=e,this.milestonesButton.setAttribute("aria-label",e)}observerMapDecorAt(e){const t=nt(this.currentSighting,0);return t?.lat===void 0||t.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=vr(i,e),{lat:s,lng:r}=Os(n.eastM,-n.northM,t.lat,t.lng);return{lat:s,lng:r,headingDeg:n.headingDeg,label:this.said.read(i.title)??this.messages.decorHere}})}observerMapNightFraction;setSunAltitude(e){const t=e===void 0?void 0:Math.max(0,Math.min(1,-e/12));t!==this.observerMapNightFraction&&(this.observerMapNightFraction=t,this.paintObserverMap(this.currentTime))}setLookOffset(e,t){e===this.lookYawDeg&&t===this.lookPitchDeg||(this.lookYawDeg=e,this.lookPitchDeg=t,this.refresh())}get frameShiftPx(){return this.frameShift}get frameShift(){const e=this.gaitAt(this.currentTime),t=this.lookYawDeg+e.yawDeg,i=this.lookPitchDeg+e.pitchDeg;if(t===0&&i===0)return{x:0,y:0};const n=nt(this.currentSighting,this.currentTime),s=Gn.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(t),y:s.angleDegToRadiusPx(i)}}gaitAt(e){return Et.bodyAt(this.currentSighting,e,this.steadyObserver)}updateFullscreenButton(){const e=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;this.fullscreenButton.title=e?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}get said(){return this.saidTexts??=new us(pr.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const e=oo(pr.preferencesFor(this),Mu);e!=="en"&&this.applyMessages(await wy(e))}updateTimeLabelTitles(){const e=this.showClockTime?this.messages.switchToElapsed:this.messages.switchToClockTime,t=this.canSwitchTimeDisplay?` — ${e}`:"";this.timeStartLabel.title=this.messages.currentPosition+t,this.timeEndLabel.title=this.messages.duration+t;for(const i of[this.timeStartLabel,this.timeEndLabel])i.classList.toggle("switchable",this.canSwitchTimeDisplay),this.canSwitchTimeDisplay?(i.setAttribute("role","button"),i.setAttribute("tabindex","0")):(i.removeAttribute("role"),i.removeAttribute("tabindex"))}applyMessages(e){this.messages=e,this.updateTimeLabelTitles(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateMilestonesButton()}updateTimeLabels(){const e=this.currentSighting.event,t=ro(e);this.realDurationMs=t!==void 0&&t>0?t:void 0,this.realStartMs=e.time?uu(e.time):void 0;const i=this.currentSighting.timeline.duration;this.player.playbackRate=this.realDurationMs!==void 0&&i>0?i/this.realDurationMs:1,this.player.durationOverrideMs=i>0?0:this.realDurationMs??0,this.timeEndLabel.textContent=this.formatEndOfTimeline(),this.timeStartLabel.textContent=this.formatPosition(this.player.time),this.updateTimeLabelTitles()}formatPosition(e){if(this.realDurationMs===void 0)return Ol(e);const t=this.currentSighting.timeline.duration,i=t>0&&e<=t?e/t*this.realDurationMs:e;return this.canShowClockTime?x0(w0(this.realStartMs+i)):Ol(i)}formatEndOfTimeline(){return this.realDurationMs===void 0?Ol(this.currentSighting.timeline.duration):this.canShowClockTime?x0(w0(this.realStartMs+this.realDurationMs)):Ol(this.realDurationMs)}}function w0(a){const e=new Date(a);return{hour:e.getUTCHours(),minute:e.getUTCMinutes(),second:e.getUTCSeconds()}}function x0(a){if(a.hour===void 0)return"0:00";const e=t=>String(t).padStart(2,"0");return a.second?`${e(a.hour)}:${e(a.minute??0)}:${e(a.second)}`:`${e(a.hour)}:${e(a.minute??0)}`}function Ol(a){const e=Math.round(a/1e3),t=Math.floor(e/60),i=e%60;return`${t}:${String(i).padStart(2,"0")}`}const wu="rr0-ufo";function Sh(){customElements.get(wu)||customElements.define(wu,Li)}class Qo{constructor(e,t){this.seekInput=e,this.layer=t,e.addEventListener("pointerdown",i=>{this.snapArmed=!0,this.nameMarkUnder(i)}),e.addEventListener("pointerup",()=>this.snapArmed=!1),e.addEventListener("pointermove",i=>this.nameMarkUnder(i)),e.addEventListener("pointerleave",()=>e.removeAttribute("title"))}static SNAP_PX=6;marks=[];duration=0;drawn="";snapArmed=!1;show(e,t){const i=t>0?[...e].sort((s,r)=>s.t-r.t):[],n=`${t}|${i.map(s=>`${s.kind}:${s.t}:${s.label}`).join("|")}`;n!==this.drawn&&(this.drawn=n,this.marks=i,this.duration=t,this.layer.replaceChildren(...i.map(s=>{const r=document.createElement("span");return r.className=`timeline-mark ${s.kind}`,r.style.left=`${Math.min(Math.max(s.t/t,0),1)*100}%`,r})))}snap(e){return this.snapArmed?(this.snapArmed=!1,this.markNear(e)?.t??e):e}next(e){return this.marks.find(t=>t.t>e+Qo.SAME_INSTANT)?.t}previous(e){return[...this.marks].reverse().find(t=>t.t<e-Qo.SAME_INSTANT)?.t}static SAME_INSTANT=.5;markNear(e){const t=this.seekInput.getBoundingClientRect().width;if(this.duration<=0||t<=0)return;const i=Qo.SNAP_PX/t*this.duration;let n;for(const s of this.marks)Math.abs(s.t-e)>i||(!n||Math.abs(s.t-e)<Math.abs(n.t-e)||s.t===n.t&&s.kind==="milestone")&&(n=s);return n}nameMarkUnder(e){const t=this.seekInput.getBoundingClientRect();if(t.width<=0||this.duration<=0)return;const i=this.marksNear((e.clientX-t.left)/t.width*this.duration);i?this.seekInput.title=i:this.seekInput.removeAttribute("title")}marksNear(e){const t=this.markNear(e);if(t)return[...new Set(this.marks.filter(i=>i.t===t.t).map(i=>i.label))].join(" · ")}}const By=.08,S0=.15,E0=2,zy=2e3;class Hy{context;noiseBuffer;voices=new Map;paused=!0;requested=[];resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(e){console.warn("VehicleAudio: Web Audio unavailable, vehicles stay silent:",e);return}}this.context.state==="suspended"&&this.context.resume(),this.apply()}setPaused(e){e!==this.paused&&(this.paused=e,this.apply())}setVoices(e){this.requested=e,this.apply()}dispose(){for(const e of[...this.voices.keys()])this.release(e);this.context?.close(),this.context=void 0}apply(){const e=this.context;if(!e)return;const t=this.paused?[]:this.requested.filter(n=>n.inside||n.distanceM<zy),i=new Set(t.map(n=>n.id));for(const n of[...this.voices.keys()])i.has(n)||this.release(n);for(const n of t){const s=this.voices.get(n.id)??this.build(e,n.id);this.retarget(e,s,n)}}build(e,t){const i=e.createGain();i.gain.value=0;const n=e.createBiquadFilter();n.type="lowpass",n.connect(i).connect(e.destination);const s=e.createOscillator();s.type="sawtooth";const r=e.createOscillator();r.type="sine";const o=e.createGain(),l=e.createBiquadFilter();l.type="lowpass",l.frequency.value=900,s.connect(l),r.connect(l),l.connect(o).connect(n);const c=()=>{const x=e.createBufferSource();return x.buffer=this.noise(e),x.loop=!0,x.loopStart=Math.random()*E0*.5,x},h=c(),d=e.createBiquadFilter();d.type="bandpass",d.Q.value=4;const u=e.createGain();h.connect(d).connect(u).connect(n);const f=c(),p=e.createBiquadFilter();p.type="lowpass",p.frequency.value=600;const v=e.createGain();f.connect(p).connect(v).connect(n);const m=c(),g=e.createBiquadFilter();g.type="bandpass",g.frequency.value=1400,g.Q.value=.7;const y=e.createGain();m.connect(g).connect(y).connect(n);const M=[s,r,h,f,m];for(const x of M)x.start();const b={nodes:[i,n,o,l,d,u,p,v,g,y,...M],sources:M,firing:s,crank:r,knock:d,engineGain:o,knockGain:u,roadGain:v,windGain:y,cabin:n,output:i};return this.voices.set(t,b),b}retarget(e,t,{profile:i,state:n,noise:s,inside:r,windowsOpen:o,distanceM:l}){const c=e.currentTime,h=(y,M)=>y.setTargetAtTime(M,c,By),d=n.rpm/60,u=d*i.cylinders/2,f=Math.min(1,n.rpm/i.shiftUpRpm),p=Math.min(1.5,n.speedMps/30);h(t.firing.frequency,u),h(t.crank.frequency,d),h(t.knock.frequency,u*3),h(t.engineGain.gain,i.engineGain*(.25+.75*n.load)*(.5+.5*f)*.3),h(t.knockGain.gain,i.roughness*(.2+.8*n.load)*.4),h(t.roadGain.gain,i.roadGain*p**1.5*.8);const v=!r||o;h(t.windGain.gain,p**2*(v?.5:.06));const m=r?o?3500:700:8e3/(1+l/60);h(t.cabin.frequency,m);const g=r?.5:Math.min(1,8/Math.max(l,1));h(t.output.gain,g*s)}release(e){const t=this.voices.get(e);if(!t)return;this.voices.delete(e);const i=this.context;i&&(t.output.gain.setTargetAtTime(0,i.currentTime,S0/3),setTimeout(()=>{for(const n of t.sources)try{n.stop()}catch{}for(const n of t.nodes)n.disconnect()},S0*1e3*3))}noise(e){if(this.noiseBuffer)return this.noiseBuffer;const t=e.createBuffer(1,e.sampleRate*E0,e.sampleRate),i=t.getChannelData(0);for(let n=0;n<i.length;n++)i[n]=Math.random()*2-1;return this.noiseBuffer=t,t}}class fl{static BY_KIND={car:{cylinders:4,idleRpm:800,kmhPer1000Rpm:[8,14,21,29,37,45],shiftUpRpm:3e3,shiftDownRpm:1300,engineGain:.6,roadGain:.5,roughness:.15},generic:{cylinders:4,idleRpm:800,kmhPer1000Rpm:[8,14,21,29,37,45],shiftUpRpm:3e3,shiftDownRpm:1300,engineGain:.6,roadGain:.5,roughness:.15},van:{cylinders:4,idleRpm:750,kmhPer1000Rpm:[7,12,19,27,35,42],shiftUpRpm:2600,shiftDownRpm:1200,engineGain:.8,roadGain:.7,roughness:.45},truck:{cylinders:6,idleRpm:600,kmhPer1000Rpm:[5,8,12,17,23,30,38,48],shiftUpRpm:1900,shiftDownRpm:1e3,engineGain:1,roadGain:.9,roughness:.55},motorcycle:{cylinders:2,idleRpm:1100,kmhPer1000Rpm:[12,18,24,30,35,40],shiftUpRpm:6e3,shiftDownRpm:2500,engineGain:.9,roadGain:.3,roughness:.3}};static of(e){return fl.BY_KIND[e??"generic"]??fl.BY_KIND.generic}}class Vr{constructor(e,t){this.samples=e,this.startMs=t}static SAMPLE_MS=100;static STANDING_MPS=.3;static of(e,t,i,n){const s=Vr.SAMPLE_MS,r=[];for(let c=i;c<=n+s/2;c+=s){const h=t(c-s/2),d=t(c+s/2);if(!h||!d)return;r.push(Math.hypot(d.eastM-h.eastM,d.northM-h.northM)/(s/1e3))}const o=[];let l=1;for(let c=0;c<r.length;c++){const h=r[c],d=(r[Math.min(c+1,r.length-1)]-r[Math.max(c-1,0)])/(2*s/1e3);if(h<Vr.STANDING_MPS){l=1,o.push({speedMps:h,rpm:e.idleRpm,load:.1,gear:0});continue}const u=h*3.6,f=g=>u/e.kmhPer1000Rpm[g-1]*1e3;for(;l<e.kmhPer1000Rpm.length&&f(l)>e.shiftUpRpm;)l++;for(;l>1&&f(l)<e.shiftDownRpm;)l--;const p=Math.max(f(l),e.idleRpm*(1+.3*Math.min(1,h/3))),v=.15+.5*Math.min(1,(h/35)**2),m=d>.15?Math.min(1,v+d/2.5):d<-.3?.05:v;o.push({speedMps:h,rpm:p,load:m,gear:l})}return new Vr(o,i)}at(e){const t=(e-this.startMs)/Vr.SAMPLE_MS,i=Math.min(Math.max(Math.floor(t),0),this.samples.length-1),n=this.samples[i],s=this.samples[Math.min(i+1,this.samples.length-1)],r=Math.min(Math.max(t-i,0),1);return{speedMps:n.speedMps+(s.speedMps-n.speedMps)*r,rpm:n.rpm+(s.rpm-n.rpm)*r,load:n.load+(s.load-n.load)*r,gear:r<.5?n.gear:s.gear}}}class jc{drives=new Map;at(e,t){const i=[],n=e.event.place?.[0],s=c=>{const h=e.observerTrack.getInterpolatedPoseAt(c),d=h?.lat??n?.lat,u=h?.lng??n?.lng;if(d===void 0||u===void 0||!n)return;const f=li(d,u,n.lat,n.lng);return{eastM:f.x,northM:-f.z}},r=Math.max(e.observerTrack.duration,(e.event.durationSeconds??0)*1e3),o=e.vehicle;if(o){const c=fl.of(o.kind),h=this.drive(`observer:${o.kind}`,jc.trackKey(e),()=>Vr.of(c,s,0,r));h&&i.push({id:"observer",profile:c,state:h.at(t),noise:o.noise??1,inside:!0,windowsOpen:o.windowsOpen===!0,distanceM:0})}const l=s(t);for(const c of e.decor){if(!c.engine||!l)continue;const h=fl.of(c.engine.kind),d=v=>{const m=vr(c,v);return{eastM:m.eastM,northM:m.northM}},u=this.drive(`decor:${c.id}`,jc.decorKey(c,r),()=>Vr.of(h,d,0,r));if(!u)continue;const f=vr(c,t),p=Math.hypot(f.eastM-l.eastM,f.northM-l.northM,f.altitudeM);i.push({id:`decor:${c.id}`,profile:h,state:u.at(t),noise:c.engine.noise??1,inside:!1,windowsOpen:!0,distanceM:p})}return i}drive(e,t,i){const n=this.drives.get(e);if(n&&n.key===t)return n.drive;const s=i();return this.drives.set(e,{key:t,drive:s}),s}static trackKey(e){return e.observerTrack.allKeyframes.map(i=>`${i.t}:${i.pose.lat}:${i.pose.lng}`).join(";")}static decorKey(e,t){return`${t}|${e.eastM},${e.northM}|`+(e.track??[]).map(i=>`${i.t}:${i.eastM}:${i.northM}`).join(";")}}const Gy=`
2147
2147
  <div class="stage" id="stage">
2148
2148
  <div class="frame" id="frame">
2149
2149
  <canvas id="scene-canvas"></canvas>
@@ -8192,7 +8192,7 @@ void main()
8192
8192
  if (ice <= 0.0) discard;
8193
8193
  gl_FragColor = vec4(iceHaloLight(dir, ice), 1.0);
8194
8194
  }
8195
- `,transparent:!0,blending:Vi,depthWrite:!1,side:qt,fog:!1}),this.object=new Ie(new hi(ki.RADIUS,64,32),this.material),this.object.renderOrder=-1,this.object.frustumCulled=!1,this.object.visible=!1;const i=this.material.uniforms;this.deckUniforms={uSource:i.uSource,uUp:i.uUp,uStrength:i.uStrength,uTint:i.uTint,uMap:i.uMap,uGain:i.uGain,uHaloShown:{value:0}}}deckUniforms;shown=!1;hostedByDeck=!1;set hosted(e){this.hostedByDeck=e,this.show(this.shown)}show(e){this.shown=e,this.object.visible=e&&!this.hostedByDeck,this.deckUniforms.uHaloShown.value=e?1:0}get awaitingFirstDisplay(){return this.tracing&&!this.everDisplayed}setUrgent(e){this.urgent=e}set onReady(e){this.onRepaint=e}update(e,t,i,n,s,r){const o=this.material.uniforms;if(i<=0){o.uStrength.value=0,this.show(!1),this.stopWork();return}o.uSource.value.set(e.x,e.y,e.z).normalize(),o.uStrength.value=i,o.uTint.value.set(n[0],n[1],n[2]),o.uIceCover.value=s.cover,o.uIceHeight.value=s.layerHeight,this.show(this.everDisplayed),this.requestMap(t,r)}requestMap(e,t){if(!(!(Math.abs(e-this.mappedAltitudeDeg)<ki.ALTITUDE_STEP_DEG)||!(Math.abs(t-this.mappedAlignment)<ki.ALIGNMENT_STEP))){this.next=void 0;return}if(this.tracing){if(this.tracingFor(e,t)){this.next=void 0;return}if(!(!(Math.abs(e-this.pendingAltitudeDeg)<ki.LEAP_ALTITUDE_DEG)||!(Math.abs(t-this.pendingAlignment)<ki.LEAP_ALIGNMENT))){this.next={sourceAltitudeDeg:e,alignment:t};return}}this.next=void 0,this.pendingAltitudeDeg=e,this.pendingAlignment=t,this.sky.begin(e,t),this.tracing=!0,this.scheduleWork()}pendingAltitudeDeg=Number.NaN;pendingAlignment=Number.NaN;next;tracingFor(e,t){return this.tracing&&Math.abs(e-this.pendingAltitudeDeg)<ki.ALTITUDE_STEP_DEG&&Math.abs(t-this.pendingAlignment)<ki.ALIGNMENT_STEP}scheduleWork(){if(this.workHandle!==void 0)return;const e=()=>{if(this.workHandle=void 0,!this.tracing)return;const t=performance.now(),i=this.urgent?ki.URGENT_BUDGET_MS:ki.BUDGET_MS;do this.sky.trace(ki.RAYS_PER_BATCH);while(this.sky.tracedRays<ki.RAYS&&performance.now()-t<i);if(this.sky.tracedRays>=ki.RAYS){this.publish(),this.tracing=!1,this.mappedAltitudeDeg=this.pendingAltitudeDeg,this.mappedAlignment=this.pendingAlignment;const s=this.next;s&&this.requestMap(s.sourceAltitudeDeg,s.alignment);return}this.workHandle=requestAnimationFrame(e)};this.workHandle=requestAnimationFrame(e)}stopWork(){this.workHandle!==void 0&&cancelAnimationFrame(this.workHandle),this.workHandle=void 0,this.tracing=!1,this.next=void 0}publish(){const t=this.sky.harvest().data;for(let i=0,n=0;n<t.length;i+=4,n+=3)this.texels[i]=Wn.toHalfFloat(t[n]),this.texels[i+1]=Wn.toHalfFloat(t[n+1]),this.texels[i+2]=Wn.toHalfFloat(t[n+2]),this.texels[i+3]=1;this.texture.needsUpdate=!0,this.everDisplayed=!0,this.show(this.material.uniforms.uStrength.value>0),this.onRepaint?.()}dispose(){this.stopWork(),this.texture.dispose(),this.object.geometry.dispose(),this.material.dispose()}}class wi{static MAX_CONCURRENT=24;static POINTS=8;static SEGMENTS=wi.POINTS-1;static ACROSS=3;static VERTICES_PER_SEGMENT=(wi.ACROSS-1)*6;static RADIUS=840;static MIN_HALF_WIDTH_DEG=.05;static BRIGHT_HALF_WIDTH_DEG=.22;object;positions;colors;meteors=[];radiantAltitudeDeg=0;radiantAzimuthDeg=0;constructor(){const e=wi.MAX_CONCURRENT*wi.SEGMENTS*wi.VERTICES_PER_SEGMENT;this.positions=new Float32Array(e*3),this.colors=new Float32Array(e*3);const t=new ht;t.setAttribute("position",new tt(this.positions,3)),t.setAttribute("color",new tt(this.colors,3)),t.setDrawRange(0,0),this.object=new Ie(t,new Dn({vertexColors:!0,transparent:!0,blending:Vi,depthWrite:!1,fog:!1,side:on})),this.object.frustumCulled=!1}get schedule(){return this.meteors}setShower(e,t,i){this.meteors=e,this.radiantAltitudeDeg=t,this.radiantAzimuthDeg=i}update(e){const t=this.object.geometry;if(this.meteors.length===0){t.setDrawRange(0,0);return}const i=jr.aliveAt(this.meteors,e).slice(0,wi.MAX_CONCURRENT);let n=0;for(const{meteor:s,progress:r}of i){const o=this.radiantOf(s);if(!o)continue;const l=fi(o.altitudeDeg,o.azimuthDeg,1),[c,h]=this.basisAround(l),d=s.fromRadiantDeg+r*s.lengthDeg,u=Math.max(s.fromRadiantDeg,d-s.lengthDeg*.6),f=Math.min(1,(1-r)*2.5),p=this.turn(c,h,s.bearingDeg),v=(.15+.85*s.brightness)*f,m=M=>v*M**1.6,g=M=>this.onSphere(l,p,u+(d-u)*M),y=M=>wi.RADIUS*((wi.MIN_HALF_WIDTH_DEG+wi.BRIGHT_HALF_WIDTH_DEG*s.brightness*M)*Math.PI/180);for(let M=1;M<wi.POINTS;M++){const b=(M-1)/wi.SEGMENTS,x=M/wi.SEGMENTS;n=this.pushRibbon(n,g(b),g(x),y(b),y(x),m(b),m(x))}}t.setDrawRange(0,n),t.getAttribute("position").needsUpdate=!0,t.getAttribute("color").needsUpdate=!0}midpointOf(e){const t=this.radiantOf(e);if(!t)return;const i=fi(t.altitudeDeg,t.azimuthDeg,1),[n,s]=this.basisAround(i),r=this.turn(n,s,e.bearingDeg),o=this.onSphere(i,r,e.fromRadiantDeg+e.lengthDeg/2),l=Math.hypot(o.x,o.y,o.z)||1;return{altitudeDeg:Math.asin(o.y/l)*180/Math.PI,azimuthDeg:(Math.atan2(o.x,-o.z)*180/Math.PI+360)%360}}radiantOf(e){return e.radiant?e.radiant:this.radiantAltitudeDeg>0?{altitudeDeg:this.radiantAltitudeDeg,azimuthDeg:this.radiantAzimuthDeg}:void 0}pushRibbon(e,t,i,n,s,r,o){const l=this.normalise(this.cross(this.normalise(t),this.normalise(this.subtract(i,t))));for(let c=0;c<wi.ACROSS-1;c++){const h=c-1,d=c,u=this.across(t,l,n,h),f=this.across(i,l,s,h),p=this.across(t,l,n,d),v=this.across(i,l,s,d),m=(g,y)=>g===0?y:0;e=this.push(e,u,m(h,r)),e=this.push(e,f,m(h,o)),e=this.push(e,p,m(d,r)),e=this.push(e,f,m(h,o)),e=this.push(e,v,m(d,o)),e=this.push(e,p,m(d,r))}return e}across(e,t,i,n){return{x:e.x+t.x*i*n,y:e.y+t.y*i*n,z:e.z+t.z*i*n}}push(e,t,i){const n=e*3;this.positions[n]=t.x,this.positions[n+1]=t.y,this.positions[n+2]=t.z;const s=_e.relativeOfResponse(Math.max(0,Math.min(1,i)));return this.colors[n]=s*.9,this.colors[n+1]=s*.95,this.colors[n+2]=s,e+1}turn(e,t,i){const n=i*Math.PI/180,s=Math.cos(n),r=Math.sin(n);return{x:e.x*s+t.x*r,y:e.y*s+t.y*r,z:e.z*s+t.z*r}}onSphere(e,t,i){const n=i*Math.PI/180,s=Math.cos(n),r=Math.sin(n);return{x:(e.x*s+t.x*r)*wi.RADIUS,y:(e.y*s+t.y*r)*wi.RADIUS,z:(e.z*s+t.z*r)*wi.RADIUS}}basisAround(e){const t=Math.abs(e.y)<.9?{x:0,y:1,z:0}:{x:1,y:0,z:0},i=this.normalise(this.cross(e,t));return[i,this.normalise(this.cross(e,i))]}subtract(e,t){return{x:e.x-t.x,y:e.y-t.y,z:e.z-t.z}}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}}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}}dispose(){this.object.geometry.dispose(),this.object.material.dispose()}}class Nt{constructor(e,t={}){this.size=e,this.span=Math.min(e.lengthM,Math.max(0,t.spanM??e.lengthM)),this.bank=(e.lengthM-this.span)/2,this.deck=Math.min(e.heightM,t.deckThicknessM??Nt.DEFAULT_DECK_THICKNESS_M),this.railHeight=t.railing?.heightM??Nt.DEFAULT_RAILING_HEIGHT_M,this.postSpacing=Math.max(.3,t.railing?.postSpacingM??Nt.DEFAULT_POST_SPACING_M),this.rails=Math.max(0,Math.round(t.railing?.rails??Nt.DEFAULT_RAILS))}static DEFAULT_DECK_THICKNESS_M=1.2;static DEFAULT_RAILING_HEIGHT_M=1.05;static DEFAULT_POST_SPACING_M=1.5;static DEFAULT_RAILS=2;static BANK_SLOPE=1.5;static ABUTMENT_THICKNESS_M=1;static POST_SIDE_M=.08;static RAIL_HEIGHT_M=.08;static RAIL_DEPTH_M=.06;static BANK_STATIONS=12;static NATURAL_SIZE=Object.freeze({widthM:9,lengthM:40,heightM:6.5});span;bank;deck;railHeight;postSpacing;rails;roadAt(e){const t=Math.abs(e)-this.span/2;return t<=0?this.size.heightM:this.bank<=0?0:Math.max(0,this.size.heightM*(1-t/this.bank))}build(){const{widthM:e,heightM:t}=this.size,i=this.span/2,n=[];if(this.span>0){n.push(Nt.box(e,this.deck,this.span,0,t-this.deck/2,0));for(const l of[-1,1]){const c=t-this.deck;c>0&&this.bank>0&&n.push(Nt.box(e+1,c,Nt.ABUTMENT_THICKNESS_M,0,c/2,l*(i-Nt.ABUTMENT_THICKNESS_M/2)))}}const s=[];this.span>0&&s.push(Nt.box(e,.04,this.span,0,t+.02,0));const r=[];for(const l of[-1,1])this.bank<=0||(r.push(this.embankment(l)),s.push(this.bankRoad(l)));const o=[];for(const l of[-1,1])o.push(...this.railing(l*(e/2-Nt.POST_SIDE_M)));return{concrete:Nt.merge(n),road:Nt.merge(s),earth:Nt.merge(r),railing:Nt.merge(o)}}embankment(e){const t=this.size.widthM/2,i=this.stations(e),n=[],s=(c,h,d,u)=>{n.push(c.x,c.y,c.z,h.x,h.y,h.z,d.x,d.y,d.z,c.x,c.y,c.z,d.x,d.y,d.z,u.x,u.y,u.z)},r=c=>{const h=this.roadAt(c),d=t+Nt.BANK_SLOPE*h;return{leftFoot:new C(-d,0,c),leftTop:new C(-t,h,c),rightTop:new C(t,h,c),rightFoot:new C(d,0,c)}};for(let c=1;c<i.length;c++){const h=r(i[c-1]),d=r(i[c]),u=e>0,f=(p,v,m,g)=>u?s(p,v,m,g):s(g,m,v,p);f(h.leftFoot,h.leftTop,d.leftTop,d.leftFoot),f(h.leftTop,h.rightTop,d.rightTop,d.leftTop),f(h.rightTop,h.rightFoot,d.rightFoot,d.rightTop)}const o=r(i[0]);e>0?s(o.leftFoot,o.rightFoot,o.rightTop,o.leftTop):s(o.leftTop,o.rightTop,o.rightFoot,o.leftFoot);const l=new ht;return l.setAttribute("position",new mt(n,3)),l.computeVertexNormals(),l}bankRoad(e){const t=this.size.widthM/2,i=this.stations(e),n=[];for(let r=1;r<i.length;r++){const o=i[r-1],l=i[r],c=this.roadAt(o)+.02,h=this.roadAt(l)+.02,d=e>0?[[-t,c,o],[t,c,o],[t,h,l],[-t,h,l]]:[[-t,h,l],[t,h,l],[t,c,o],[-t,c,o]];for(const u of[0,2,1,0,3,2])n.push(...d[u])}const s=new ht;return s.setAttribute("position",new mt(n,3)),s.computeVertexNormals(),s}stations(e){const t=[];for(let i=0;i<=Nt.BANK_STATIONS;i++)t.push(e*(this.span/2+this.bank*i/Nt.BANK_STATIONS));return t}railing(e){const t=this.size.lengthM/2,i=Math.max(1,Math.round(this.size.lengthM/this.postSpacing)),n=[];for(let o=0;o<=i;o++)n.push(-t+this.size.lengthM*o/i);const s=[],r=Nt.POST_SIDE_M;for(const o of n)s.push(Nt.box(r,this.railHeight,r,e,this.roadAt(o)+this.railHeight/2,o));for(let o=1;o<=this.rails;o++){const l=this.railHeight*o/this.rails-Nt.RAIL_HEIGHT_M/2;for(let c=1;c<n.length;c++){const h=new C(e,this.roadAt(n[c-1])+l,n[c-1]),d=new C(e,this.roadAt(n[c])+l,n[c]);s.push(Nt.beam(h,d))}}return s}static box(e,t,i,n,s,r){return new ji(e,t,i).translate(n,s,r)}static beam(e,t){const i=new C().subVectors(t,e),n=new ji(Nt.RAIL_DEPTH_M,Nt.RAIL_HEIGHT_M,i.length()),s=new Gi().setFromUnitVectors(new C(0,0,1),i.clone().normalize()),r=new C().addVectors(e,t).multiplyScalar(.5);return n.applyMatrix4(new $e().compose(r,s,new C(1,1,1)))}static merge(e){const t=e.map(l=>l.getIndex()?l.toNonIndexed():l),i=t.reduce((l,c)=>l+c.getAttribute("position").count,0),n=new Float32Array(i*3),s=new Float32Array(i*3);let r=0;for(const l of t){const c=l.getAttribute("position"),h=l.getAttribute("normal");n.set(c.array,r*3),h&&s.set(h.array,r*3),r+=c.count}const o=new ht;o.setAttribute("position",new mt(n,3)),o.setAttribute("normal",new mt(s,3));for(const l of e)l.dispose();for(const l of t)l.dispose();return o}}const kd=Math.PI/180;function Ut(a,e,t,i,n=!1){const s=n?new Dn({color:new se(...t)}):new go({color:new se(...t)}),r=new Ie(e,s);return r.position.y=i,r.userData={emissive:n},r.castShadow=!n,r.receiveShadow=!n,a.add(r),r}const Nd=.25,G5=.002,V5=100,W5=1500,X5=.25,Y5=1e3,q5=.15;function $5(a){const e=/^#([0-9a-f]{6})$/i.exec(a);if(!e)return[1,1,1];const t=parseInt(e[1],16);return[(t>>16&255)/255,(t>>8&255)/255,(t&255)/255]}const K5=[.32,.32,.3],j1=[1,.85,.5],Z5=[.25,.25,.25],J1=[1,.97,.85],j5=[.55,.68,.72],os=.03,ls=.05,Q1={front:0,behind:Math.PI,left:Math.PI/2,right:-Math.PI/2,"front-left":Math.PI/2,"behind-left":Math.PI/2,"front-right":-Math.PI/2,"behind-right":-Math.PI/2};function qi(a,e){return a?.[e]}function cs(a,e,t,i,n,s,r,o){if(o===void 0)return;const l=new go({color:new se(...j5),transparent:!0,opacity:o/100}),c=new Ie(new ji(e,t,i),l);c.position.set(n,s,r),a.add(c)}const An=.05,Fd=[.6,.58,.53],og=[.5,.5,.48];function Va(a,e,t,i,n,s,r,o){const l=new go({color:new se(...o),side:qt}),c=new Ie(new ji(e,t,i),l);c.position.set(n,s,r),a.add(c)}function J5(a,e,t,i,n,s,r,o,l){const c=(i-s)/2,h=(p,v,m,g)=>{p<=0||(e?Va(a,p,v,An,m,o+g,r,l):Va(a,An,v,p,r,o+g,m,l))};h(t,c,0,i/2-c/2),h(t,c,0,-(i/2-c/2));const d=[...n].sort((p,v)=>p.center-v.center);let u=-t/2;for(const p of d){const m=p.center-p.main/2-u;h(m,s,u+m/2,0),u=p.center+p.main/2}const f=t/2-u;h(f,s,u+f/2,0)}function eb(a,e,t,i,n,s,r,o,l,c){const h=(i+n)/2,d=n-i,u=(f,p,v,m)=>{f.length===0?p?Va(a,v,d,An,0,h,m,Fd):Va(a,An,d,v,m,h,0,Fd):J5(a,p,v,d,f,s,m,h,Fd)};u(r,!0,e*2,-t+An),u(o,!0,e*2,t-An),u(l,!1,t*2,-e+An),u(c,!1,t*2,e-An),Va(a,e*2,An,t*2,0,i+An,0,og),Va(a,e*2,An,t*2,0,n-An,0,og)}function zf(a,e,t,i){switch(a){case"front":return{x:0,z:-(t-i)};case"behind":return{x:0,z:t-i};case"left":return{x:-(e-i),z:0};case"right":return{x:e-i,z:0};case"front-left":return{x:-(e-i),z:-hs};case"front-right":return{x:e-i,z:-hs};case"behind-left":return{x:-(e-i),z:hs};case"behind-right":return{x:e-i,z:hs}}}function tb(a,e,t,i,n,s,r){const o=Vf();o.scale.setScalar(i),o.rotation.y=Q1[e];const{x:l,z:c}=zf(e,n,s,r);o.position.set(l,t,c),a.add(o)}const Hf=6,Gf=6,or=3,No=1.4,Fo=or*.5,ib=1.2,nb=.35,Q5=.75,eA=1.6;function lg(a,e,t,i){const n=new Lt,s=Math.max(1,a+1),r=s*or;Ut(n,new ji(Hf,r,Gf),[.55,.54,.5],r/2);const o=Hf/2,l=Gf/2;for(let c=0;c<s;c++){const h=c*or+or/2;cs(n,No,Fo,ls,0,h,-l-os,qi(e,"front")),cs(n,No,Fo,ls,0,h,l+os,qi(e,"behind")),cs(n,ls,Fo,No,-o-os,h,0,qi(e,"left")),cs(n,ls,Fo,No,o+os,h,0,qi(e,"right"))}if(t){const c=Math.min(Math.max(i??0,0),s-1);tb(n,t,c*or,.72,o,l,ib);const h=d=>qi(e,d)!==void 0?[{main:No,center:0}]:[];eb(n,o,l,c*or,(c+1)*or,Fo,h("front"),h("behind"),h("left"),h("right"))}return n}function cg(){const a=new Lt,e=[[0,0,.55,.5],[.4,.1,.35,.4],[-.35,-.2,.4,.38],[.1,-.4,.35,.36],[-.15,.4,.3,.34]];for(const[t,i,n,s]of e){const r=new hi(n,10,7);r.scale(1,.85,1),r.translate(t,0,i),Ut(a,r,[.26,.28,.17],s)}return a}function tA(a){const e=new Lt,t=new Nt(oi.sizeOf(a),a.bridge).build();Ut(e,t.concrete,[.6,.6,.58],0);const i=Ut(e,t.road,[.2,.2,.21],0),n=Ut(e,t.earth,[.3,.36,.22],0);for(const s of[i,n])s.material.side=on;return Ut(e,t.railing,[.5,.52,.55],0),e}function hg(){const a=new Lt;return Ut(a,new ws(.15,.22,2,8),[.32,.22,.14],1),Ut(a,new mo(1.4,3,8),[.16,.32,.14],3.5),a}const dg=.275,iA=.35,nA=.9,sA=34,rA=8,aA=1.4;function ug(){const a=new Lt,e=new hi(dg,7,3,0,Math.PI*2,0,Math.PI/2);e.scale(1,iA/dg,1);const t=oi.repeatOnGrid(e,sA,nA,rA,aA),i=Ut(a,t,[.26,.28,.22],0);return i.castShadow=!0,i.userData.cropBasePositions=t.getAttribute("position").array.slice(),i.userData.cropVerticesPerClump=e.getAttribute("position").count,e.dispose(),a}function fg(){const a=new Lt,e=new hi(1,7,3,0,Math.PI*2,0,Math.PI/2);return Ut(a,e,[.38,.36,.32],0),a}function pg(a){const e=new Lt;return Ut(e,new ws(.05,.08,5,8),[.28,.28,.3],2.5),Ut(e,new hi(.25,12,8),a?j1:K5,5.1,!0),e}const oA=[.08,.08,.08],nr=.8,ka=1,es=1.7,Ud=.6,Cr=.4,yc=1.2,Da=.7,hs=.5,lA=es;function mg(a,e,t){const i=new Lt;Ut(i,new ji(1.8,1.4,4.2),[.45,.14,.14],.7),Ut(i,new ji(nr*2,Ud,ka*2),[.4,.12,.12],es);for(const s of[-1.4,1.4])for(const r of[-.95,.95]){const o=Ut(i,new ws(.4,.4,.3,12),oA,.4);o.rotation.z=Math.PI/2,o.position.x=r,o.position.z=s}const n=a?J1:Z5;for(const s of[-.7,.7])Ut(i,new hi(.15,8,6),n,.7,!0).position.set(s,.7,-2.1);if(cs(i,yc,Cr,ls,0,es,-ka-os,qi(e,"front")),cs(i,yc,Cr,ls,0,es,ka+os,qi(e,"behind")),cs(i,ls,Cr,Da,-nr-os,es,-hs,qi(e,"front-left")),cs(i,ls,Cr,Da,-nr-os,es,hs,qi(e,"behind-left")),cs(i,ls,Cr,Da,nr+os,es,-hs,qi(e,"front-right")),cs(i,ls,Cr,Da,nr+os,es,hs,qi(e,"behind-right")),t){tb(i,t,Q5,.5,nr,ka,nb);const s=(l,c)=>{const h=[];return qi(e,l)!==void 0&&h.push({main:Da,center:-hs}),qi(e,c)!==void 0&&h.push({main:Da,center:hs}),h},r=qi(e,"front")!==void 0?[{main:yc,center:0}]:[],o=qi(e,"behind")!==void 0?[{main:yc,center:0}]:[];eb(i,nr,ka,es-Ud/2,es+Ud/2,Cr,r,o,s("front-left","behind-left"),s("front-right","behind-right"))}return i}const gg=new Map;function vg(a,e){if(!a)return;const t=[[a.lengthM,e.lengthM],[a.heightM,e.heightM],[a.widthM,e.widthM]];for(const[i,n]of t)if(i!==void 0&&n>1e-6)return i/n}function Bd(a,e){return e>1e-6?a/e:1}const sb=[.95,.9,.82],bg=[.72,.74,.78];function yg(){const a=new Lt;Ut(a,new ws(.25,.3,1.5,10),bg,.75),Ut(a,new hi(.26,10,8),bg,1.74);const e=Ut(a,new mo(.07,.16,8),sb,1.74);return e.rotation.x=-Math.PI/2,e.position.z=-.22,a}function Vf(){const a=new Lt;Ut(a,new ws(.25,.3,1.5,10),[.3,.3,.35],.75),Ut(a,new hi(.22,10,8),[.62,.52,.46],1.72);const e=Ut(a,new mo(.07,.16,8),sb,1.72);return e.rotation.x=-Math.PI/2,e.position.z=-.2,a}const cA=17,Mg=18.5,zd=[.16,.16,.18];function wg(){const a=new Lt,e=Ut(a,new ws(1.8,1.8,Mg*2,10),zd,0);e.rotation.x=Math.PI/2,Ut(a,new ji(cA*2,.5,4.5),zd,0);const t=Ut(a,new ji(.4,5.5,4),zd,3);return t.position.z=-Mg+2,a}class oi{static GROWS_FROM_GROUND=new Set(["tree","shrub","crop","mound"]);static groundUnderFootprint(e,t,i,n,s,r=0){const o=oi.sizeOf(e);if(r>o.heightM)return s(t,i);const l=(n??0)*Math.PI/180,c=Math.min(21,Math.max(2,Math.ceil(o.lengthM/.75)+1)),h=Math.min(21,Math.max(2,Math.ceil(o.widthM/.75)+1)),d=oi.GROWS_FROM_GROUND.has(e.kind);let u=d?1/0:-1/0;for(let f=0;f<c;f++){const p=(f/(c-1)-.5)*o.lengthM;for(let v=0;v<h;v++){const m=(v/(h-1)-.5)*o.widthM,g=t+Math.sin(l)*p+Math.cos(l)*m,y=i-Math.cos(l)*p+Math.sin(l)*m;u=d?Math.min(u,s(g,y)):Math.max(u,s(g,y))}}return Number.isFinite(u)?u:s(t,i)}static occupantView(e){const t=e.observerSide;if(!t)throw new Error("occupantView requires object.observerSide to be set");const{x:i,z:n}=e.kind==="vehicle"?zf(t,nr,ka,nb):zf(t,Hf/2,Gf/2,ib),s=e.kind==="vehicle"?lA:(e.occupiedFloor??0)*or+eA,r=(e.headingDeg??0)-Q1[t]/kd,o=this.scaleFor(e);return{x:i*o.x,z:n*o.z,eyeY:s*o.y,headingDeg:r}}static BODY_NAME="decor-body";static bodyOf(e){return e.getObjectByName(oi.BODY_NAME)??e}static repeatOnGrid(e,t,i,n,s){const r=e.getAttribute("position"),o=e.getAttribute("normal"),l=e.getIndex();if(!l)throw new Error("repeatOnGrid needs an indexed geometry");const c=r.count,h=t*n,d=new Float32Array(c*h*3),u=new Float32Array(c*h*3),f=new Uint32Array(l.count*h),p=-((t-1)*i)/2,v=-((n-1)*s)/2;let m=0;for(let y=0;y<n;y++)for(let M=0;M<t;M++,m++){const b=v+y*s,x=p+M*i;for(let E=0;E<c;E++){const I=(m*c+E)*3;d[I]=r.getX(E)+b,d[I+1]=r.getY(E),d[I+2]=r.getZ(E)+x,u[I]=o.getX(E),u[I+1]=o.getY(E),u[I+2]=o.getZ(E)}for(let E=0;E<l.count;E++)f[m*l.count+E]=l.getX(E)+m*c}const g=new ht;return g.setAttribute("position",new mt(d,3)),g.setAttribute("normal",new mt(u,3)),g.setIndex(new mp(f,1)),g}static fitCropToGround(e,t){e.updateMatrixWorld(!0);const i=new C;e.traverse(n=>{const s=n,r=s.userData.cropBasePositions,o=s.userData.cropVerticesPerClump;if(!s.isMesh||!r||!o)return;const l=s.geometry.getAttribute("position"),c=new $e().copy(s.matrixWorld).invert();for(let h=0;h<l.count;h+=o){i.set(r[h*3],0,r[h*3+2]).applyMatrix4(s.matrixWorld),i.y=t(i.x,i.z),i.applyMatrix4(c);for(let d=h;d<h+o;d++)l.setY(d,r[d*3+1]+i.y)}l.needsUpdate=!0,s.geometry.computeBoundingBox(),s.geometry.computeBoundingSphere()})}static paint(e,t){e.traverse(i=>{const n=i,s=n.userData;if(!n.isMesh||s?.emissive)return;const r=n.material;r?.color&&r.color.set(t)})}static build(e,t){const i=e.kind==="building"?lg(e.floors??Ya,e.windows,e.observerSide,e.occupiedFloor):e.kind==="tree"?hg():e.kind==="shrub"?cg():e.kind==="bridge"?tA(e):e.kind==="crop"?ug():e.kind==="mound"?fg():e.kind==="streetlight"?pg(t):e.kind==="vehicle"?mg(t,e.windows,e.observerSide):e.kind==="aircraft"?wg():e.kind==="entity"?yg():Vf();e.color&&this.paint(i,e.color);const n=this.scaleFor(e),s=new Lt;return i.name=oi.BODY_NAME,i.scale.copy(n),s.add(i),e.headingDeg!==void 0&&(s.rotation.y=-e.headingDeg*kd),this.addLights(s,e.lights),s}static scaleFor(e){const t=e.sizeM;if(!t||e.kind==="bridge")return new C(1,1,1);const i=this.naturalSize(e.kind,e.floors);return new C(t.widthM===void 0?1:Bd(t.widthM,i.widthM),t.heightM===void 0?1:Bd(t.heightM,i.heightM),t.lengthM===void 0?1:Bd(t.lengthM,i.lengthM))}static naturalSize(e,t){const i=e==="building"?Math.max(1,(t??Ya)+1):0;if(e==="bridge")return Nt.NATURAL_SIZE;const n=`${e}:${i}`,s=gg.get(n);if(s)return s;const r=e==="building"?lg(i-1,void 0,void 0,void 0):e==="tree"?hg():e==="shrub"?cg():e==="crop"?ug():e==="mound"?fg():e==="streetlight"?pg(!1):e==="vehicle"?mg(!1,void 0,void 0):e==="aircraft"?wg():e==="entity"?yg():Vf(),o=new Zi().setFromObject(r),l={widthM:o.max.x-o.min.x,heightM:o.max.y-o.min.y,lengthM:o.max.z-o.min.z};return this.dispose(r),gg.set(n,l),l}static usesModel(e){return e.model!==void 0&&!(e.observerSide!==void 0&&Ua(e.kind))}static applyModel(e,t,i,n={}){const s=this.bodyOf(e),r=new Lt;r.name=oi.BODY_NAME,i.rotation.y=-(n.headingOffsetDeg??0)*kd,i.updateMatrixWorld(!0);const o=new Zi().setFromObject(i),l={lengthM:o.max.z-o.min.z,heightM:o.max.y-o.min.y,widthM:o.max.x-o.min.x},c=vg(t.sizeM,l)??vg(n.depictedSizeM,l)??1;i.scale.multiplyScalar(c);const h=o.getCenter(new C).multiplyScalar(c);i.position.x-=h.x,i.position.z-=h.z,i.position.y-=t.kind==="aircraft"?h.y:o.min.y*c,i.traverse(d=>{d instanceof Ie&&(d.castShadow=!0,d.receiveShadow=!0)}),r.add(i),s.parent?(s.parent.add(r),s.removeFromParent()):e.add(r),this.dispose(s)}static sizeOf(e){const t=this.naturalSize(e.kind,e.floors);return{widthM:e.sizeM?.widthM??t.widthM,lengthM:e.sizeM?.lengthM??t.lengthM,heightM:e.sizeM?.heightM??t.heightM}}static addLights(e,t){for(const i of t??[]){const n=$5(i.color),s=Ut(e,new hi(Nd,8,6),n,i.offsetM.y,!0);s.position.set(i.offsetM.x,i.offsetM.y,i.offsetM.z),s.userData={emissive:!0,lightId:i.id,lightColor:n},s.visible=!1}}static setLights(e,t,i,n,s=0,r=1,o=G5){if(!t||t.length===0)return;const l=new Map(t.map(u=>[u.id,u])),c=Math.max(1,n*o/Nd),h=Nd*c,d=r/(Math.PI*h*h);for(const u of e.children){if(!(u instanceof Ie))continue;const f=u.userData.lightId;if(!f)continue;const p=l.get(f);if(!p)continue;const v=s>0?Ev(p,i,i+s):sy(p,i)?1:0;u.visible=v>0;const m=u.material,g=u.userData.lightColor;if(g){const y=v*V5*(p.intensity??1)*d;m.color.setRGB(g[0]*y,g[1]*y,g[2]*y)}u.scale.setScalar(c)}}static setLit(e,t,i,n=1){const[s,r,o]=t==="streetlight"?[W5,X5,j1]:[Y5,q5,J1],l=i?s*n/(Math.PI*r*r):0,c=[o[0]*l,o[1]*l,o[2]*l];e.traverse(h=>{const d=h.userData;!(h instanceof Ie)||!d.emissive||d.lightId||h.material.color.setRGB(...c)})}static dispose(e){e.traverse(t=>{if(!(t instanceof Ie))return;t.geometry.dispose();const i=t.material;for(const n of Array.isArray(i)?i:[i])n.dispose()})}}const Hd="https://ufoathome.org/models/index.json";class hA{attribution="3D models re-hosted by UFO@home, each under its own author's licence";fetchImpl;indexUrls;loading;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.indexUrls=e.indexUrls??dA()}async entries(e){const t=await this.load();return e?t.filter(i=>i.kind===e):t}async entry(e){return(await this.load()).find(t=>t.id===e)}load(){return this.loading??=this.fetchFirstAvailable(),this.loading}async fetchFirstAvailable(){for(const e of this.indexUrls){const t=await this.fetchIndex(e);if(t)return t}return[]}async fetchIndex(e){try{const t=await this.fetchImpl(e);if(!t.ok)return;const i=await t.json();return Array.isArray(i?.models)?i.models.map(({file:n,...s})=>({...s,url:new URL(n,e).href})):void 0}catch{return}}}function dA(){const a=`?v=${encodeURIComponent("0.69.2")}`,e=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(e&&e!==Hd?[e,Hd]:[Hd]).map(t=>t+a)}const Vc=[{id:"ufoathome",name:"UFO@home",credit:"3D models re-hosted by UFO@home, each under its own author's licence",creditUrl:"https://ufoathome.org/models/",create:()=>new hA}];async function xg(a){const{GLTFLoader:e}=await Mn(async()=>{const{GLTFLoader:i}=await import("./GLTFLoader-C33uvPO8.js");return{GLTFLoader:i}},[],import.meta.url),t=new e;return new Promise((i,n)=>{t.load(a,s=>i(Object.assign(s.scene,{animations:s.animations})),void 0,s=>n(new Error(`Could not load 3D model ${a}: ${s instanceof Error?s.message:String(s)}`)))})}const rb=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class vn{static MIN_ANGLE_RAD=.002;static FILL=(1-Math.exp(-4))/4;static MAX_SHARE=.3;mesh;constructor(e,t){this.mesh=new Ie(new Ji(2,2),new dt({uniforms:{uColor:{value:new se(0,0,0)},uRadius:{value:1}},vertexShader:vn.VERTEX,fragmentShader:vn.FRAGMENT,transparent:!0,depthWrite:!1,blending:Vi,toneMapped:!1})),this.mesh.name=e,this.mesh.frustumCulled=!1,this.mesh.renderOrder=t,this.mesh.visible=!1}shine(e,t,i){this.mesh.visible=!0,this.mesh.position.set(e.x,e.y,e.z),this.mesh.material.uniforms.uRadius.value=t,this.mesh.material.uniforms.uColor.value.setRGB(i[0],i[1],i[2])}hide(){this.mesh.visible=!1}dispose(){this.mesh.geometry.dispose(),this.mesh.material.dispose()}static spread(e,t,i,n){const s=Math.max(e,n*vn.MIN_ANGLE_RAD),r=vn.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(vn.MAX_SHARE,t/r)}}static conserving(e){return Math.sqrt(e/(vn.MAX_SHARE*vn.FILL*Math.PI))}static VERTEX=`
8195
+ `,transparent:!0,blending:Vi,depthWrite:!1,side:qt,fog:!1}),this.object=new Ie(new hi(ki.RADIUS,64,32),this.material),this.object.renderOrder=-1,this.object.frustumCulled=!1,this.object.visible=!1;const i=this.material.uniforms;this.deckUniforms={uSource:i.uSource,uUp:i.uUp,uStrength:i.uStrength,uTint:i.uTint,uMap:i.uMap,uGain:i.uGain,uHaloShown:{value:0}}}deckUniforms;shown=!1;hostedByDeck=!1;set hosted(e){this.hostedByDeck=e,this.show(this.shown)}show(e){this.shown=e,this.object.visible=e&&!this.hostedByDeck,this.deckUniforms.uHaloShown.value=e?1:0}get awaitingFirstDisplay(){return this.tracing&&!this.everDisplayed}setUrgent(e){this.urgent=e}set onReady(e){this.onRepaint=e}update(e,t,i,n,s,r){const o=this.material.uniforms;if(i<=0){o.uStrength.value=0,this.show(!1),this.stopWork();return}o.uSource.value.set(e.x,e.y,e.z).normalize(),o.uStrength.value=i,o.uTint.value.set(n[0],n[1],n[2]),o.uIceCover.value=s.cover,o.uIceHeight.value=s.layerHeight,this.show(this.everDisplayed),this.requestMap(t,r)}requestMap(e,t){if(!(!(Math.abs(e-this.mappedAltitudeDeg)<ki.ALTITUDE_STEP_DEG)||!(Math.abs(t-this.mappedAlignment)<ki.ALIGNMENT_STEP))){this.next=void 0;return}if(this.tracing){if(this.tracingFor(e,t)){this.next=void 0;return}if(!(!(Math.abs(e-this.pendingAltitudeDeg)<ki.LEAP_ALTITUDE_DEG)||!(Math.abs(t-this.pendingAlignment)<ki.LEAP_ALIGNMENT))){this.next={sourceAltitudeDeg:e,alignment:t};return}}this.next=void 0,this.pendingAltitudeDeg=e,this.pendingAlignment=t,this.sky.begin(e,t),this.tracing=!0,this.scheduleWork()}pendingAltitudeDeg=Number.NaN;pendingAlignment=Number.NaN;next;tracingFor(e,t){return this.tracing&&Math.abs(e-this.pendingAltitudeDeg)<ki.ALTITUDE_STEP_DEG&&Math.abs(t-this.pendingAlignment)<ki.ALIGNMENT_STEP}scheduleWork(){if(this.workHandle!==void 0)return;const e=()=>{if(this.workHandle=void 0,!this.tracing)return;const t=performance.now(),i=this.urgent?ki.URGENT_BUDGET_MS:ki.BUDGET_MS;do this.sky.trace(ki.RAYS_PER_BATCH);while(this.sky.tracedRays<ki.RAYS&&performance.now()-t<i);if(this.sky.tracedRays>=ki.RAYS){this.publish(),this.tracing=!1,this.mappedAltitudeDeg=this.pendingAltitudeDeg,this.mappedAlignment=this.pendingAlignment;const s=this.next;s&&this.requestMap(s.sourceAltitudeDeg,s.alignment);return}this.workHandle=requestAnimationFrame(e)};this.workHandle=requestAnimationFrame(e)}stopWork(){this.workHandle!==void 0&&cancelAnimationFrame(this.workHandle),this.workHandle=void 0,this.tracing=!1,this.next=void 0}publish(){const t=this.sky.harvest().data;for(let i=0,n=0;n<t.length;i+=4,n+=3)this.texels[i]=Wn.toHalfFloat(t[n]),this.texels[i+1]=Wn.toHalfFloat(t[n+1]),this.texels[i+2]=Wn.toHalfFloat(t[n+2]),this.texels[i+3]=1;this.texture.needsUpdate=!0,this.everDisplayed=!0,this.show(this.material.uniforms.uStrength.value>0),this.onRepaint?.()}dispose(){this.stopWork(),this.texture.dispose(),this.object.geometry.dispose(),this.material.dispose()}}class wi{static MAX_CONCURRENT=24;static POINTS=8;static SEGMENTS=wi.POINTS-1;static ACROSS=3;static VERTICES_PER_SEGMENT=(wi.ACROSS-1)*6;static RADIUS=840;static MIN_HALF_WIDTH_DEG=.05;static BRIGHT_HALF_WIDTH_DEG=.22;object;positions;colors;meteors=[];radiantAltitudeDeg=0;radiantAzimuthDeg=0;constructor(){const e=wi.MAX_CONCURRENT*wi.SEGMENTS*wi.VERTICES_PER_SEGMENT;this.positions=new Float32Array(e*3),this.colors=new Float32Array(e*3);const t=new ht;t.setAttribute("position",new tt(this.positions,3)),t.setAttribute("color",new tt(this.colors,3)),t.setDrawRange(0,0),this.object=new Ie(t,new Dn({vertexColors:!0,transparent:!0,blending:Vi,depthWrite:!1,fog:!1,side:on})),this.object.frustumCulled=!1}get schedule(){return this.meteors}setShower(e,t,i){this.meteors=e,this.radiantAltitudeDeg=t,this.radiantAzimuthDeg=i}update(e){const t=this.object.geometry;if(this.meteors.length===0){t.setDrawRange(0,0);return}const i=jr.aliveAt(this.meteors,e).slice(0,wi.MAX_CONCURRENT);let n=0;for(const{meteor:s,progress:r}of i){const o=this.radiantOf(s);if(!o)continue;const l=fi(o.altitudeDeg,o.azimuthDeg,1),[c,h]=this.basisAround(l),d=s.fromRadiantDeg+r*s.lengthDeg,u=Math.max(s.fromRadiantDeg,d-s.lengthDeg*.6),f=Math.min(1,(1-r)*2.5),p=this.turn(c,h,s.bearingDeg),v=(.15+.85*s.brightness)*f,m=M=>v*M**1.6,g=M=>this.onSphere(l,p,u+(d-u)*M),y=M=>wi.RADIUS*((wi.MIN_HALF_WIDTH_DEG+wi.BRIGHT_HALF_WIDTH_DEG*s.brightness*M)*Math.PI/180);for(let M=1;M<wi.POINTS;M++){const b=(M-1)/wi.SEGMENTS,x=M/wi.SEGMENTS;n=this.pushRibbon(n,g(b),g(x),y(b),y(x),m(b),m(x))}}t.setDrawRange(0,n),t.getAttribute("position").needsUpdate=!0,t.getAttribute("color").needsUpdate=!0}midpointOf(e){const t=this.radiantOf(e);if(!t)return;const i=fi(t.altitudeDeg,t.azimuthDeg,1),[n,s]=this.basisAround(i),r=this.turn(n,s,e.bearingDeg),o=this.onSphere(i,r,e.fromRadiantDeg+e.lengthDeg/2),l=Math.hypot(o.x,o.y,o.z)||1;return{altitudeDeg:Math.asin(o.y/l)*180/Math.PI,azimuthDeg:(Math.atan2(o.x,-o.z)*180/Math.PI+360)%360}}radiantOf(e){return e.radiant?e.radiant:this.radiantAltitudeDeg>0?{altitudeDeg:this.radiantAltitudeDeg,azimuthDeg:this.radiantAzimuthDeg}:void 0}pushRibbon(e,t,i,n,s,r,o){const l=this.normalise(this.cross(this.normalise(t),this.normalise(this.subtract(i,t))));for(let c=0;c<wi.ACROSS-1;c++){const h=c-1,d=c,u=this.across(t,l,n,h),f=this.across(i,l,s,h),p=this.across(t,l,n,d),v=this.across(i,l,s,d),m=(g,y)=>g===0?y:0;e=this.push(e,u,m(h,r)),e=this.push(e,f,m(h,o)),e=this.push(e,p,m(d,r)),e=this.push(e,f,m(h,o)),e=this.push(e,v,m(d,o)),e=this.push(e,p,m(d,r))}return e}across(e,t,i,n){return{x:e.x+t.x*i*n,y:e.y+t.y*i*n,z:e.z+t.z*i*n}}push(e,t,i){const n=e*3;this.positions[n]=t.x,this.positions[n+1]=t.y,this.positions[n+2]=t.z;const s=_e.relativeOfResponse(Math.max(0,Math.min(1,i)));return this.colors[n]=s*.9,this.colors[n+1]=s*.95,this.colors[n+2]=s,e+1}turn(e,t,i){const n=i*Math.PI/180,s=Math.cos(n),r=Math.sin(n);return{x:e.x*s+t.x*r,y:e.y*s+t.y*r,z:e.z*s+t.z*r}}onSphere(e,t,i){const n=i*Math.PI/180,s=Math.cos(n),r=Math.sin(n);return{x:(e.x*s+t.x*r)*wi.RADIUS,y:(e.y*s+t.y*r)*wi.RADIUS,z:(e.z*s+t.z*r)*wi.RADIUS}}basisAround(e){const t=Math.abs(e.y)<.9?{x:0,y:1,z:0}:{x:1,y:0,z:0},i=this.normalise(this.cross(e,t));return[i,this.normalise(this.cross(e,i))]}subtract(e,t){return{x:e.x-t.x,y:e.y-t.y,z:e.z-t.z}}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}}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}}dispose(){this.object.geometry.dispose(),this.object.material.dispose()}}class Nt{constructor(e,t={}){this.size=e,this.span=Math.min(e.lengthM,Math.max(0,t.spanM??e.lengthM)),this.bank=(e.lengthM-this.span)/2,this.deck=Math.min(e.heightM,t.deckThicknessM??Nt.DEFAULT_DECK_THICKNESS_M),this.railHeight=t.railing?.heightM??Nt.DEFAULT_RAILING_HEIGHT_M,this.postSpacing=Math.max(.3,t.railing?.postSpacingM??Nt.DEFAULT_POST_SPACING_M),this.rails=Math.max(0,Math.round(t.railing?.rails??Nt.DEFAULT_RAILS))}static DEFAULT_DECK_THICKNESS_M=1.2;static DEFAULT_RAILING_HEIGHT_M=1.05;static DEFAULT_POST_SPACING_M=1.5;static DEFAULT_RAILS=2;static BANK_SLOPE=1.5;static ABUTMENT_THICKNESS_M=1;static POST_SIDE_M=.08;static RAIL_HEIGHT_M=.08;static RAIL_DEPTH_M=.06;static BANK_STATIONS=12;static NATURAL_SIZE=Object.freeze({widthM:9,lengthM:40,heightM:6.5});span;bank;deck;railHeight;postSpacing;rails;roadAt(e){const t=Math.abs(e)-this.span/2;return t<=0?this.size.heightM:this.bank<=0?0:Math.max(0,this.size.heightM*(1-t/this.bank))}build(){const{widthM:e,heightM:t}=this.size,i=this.span/2,n=[];if(this.span>0){n.push(Nt.box(e,this.deck,this.span,0,t-this.deck/2,0));for(const l of[-1,1]){const c=t-this.deck;c>0&&this.bank>0&&n.push(Nt.box(e+1,c,Nt.ABUTMENT_THICKNESS_M,0,c/2,l*(i-Nt.ABUTMENT_THICKNESS_M/2)))}}const s=[];this.span>0&&s.push(Nt.box(e,.04,this.span,0,t+.02,0));const r=[];for(const l of[-1,1])this.bank<=0||(r.push(this.embankment(l)),s.push(this.bankRoad(l)));const o=[];for(const l of[-1,1])o.push(...this.railing(l*(e/2-Nt.POST_SIDE_M)));return{concrete:Nt.merge(n),road:Nt.merge(s),earth:Nt.merge(r),railing:Nt.merge(o)}}embankment(e){const t=this.size.widthM/2,i=this.stations(e),n=[],s=(c,h,d,u)=>{n.push(c.x,c.y,c.z,h.x,h.y,h.z,d.x,d.y,d.z,c.x,c.y,c.z,d.x,d.y,d.z,u.x,u.y,u.z)},r=c=>{const h=this.roadAt(c),d=t+Nt.BANK_SLOPE*h;return{leftFoot:new C(-d,0,c),leftTop:new C(-t,h,c),rightTop:new C(t,h,c),rightFoot:new C(d,0,c)}};for(let c=1;c<i.length;c++){const h=r(i[c-1]),d=r(i[c]),u=e>0,f=(p,v,m,g)=>u?s(p,v,m,g):s(g,m,v,p);f(h.leftFoot,h.leftTop,d.leftTop,d.leftFoot),f(h.leftTop,h.rightTop,d.rightTop,d.leftTop),f(h.rightTop,h.rightFoot,d.rightFoot,d.rightTop)}const o=r(i[0]);e>0?s(o.leftFoot,o.rightFoot,o.rightTop,o.leftTop):s(o.leftTop,o.rightTop,o.rightFoot,o.leftFoot);const l=new ht;return l.setAttribute("position",new mt(n,3)),l.computeVertexNormals(),l}bankRoad(e){const t=this.size.widthM/2,i=this.stations(e),n=[];for(let r=1;r<i.length;r++){const o=i[r-1],l=i[r],c=this.roadAt(o)+.02,h=this.roadAt(l)+.02,d=e>0?[[-t,c,o],[t,c,o],[t,h,l],[-t,h,l]]:[[-t,h,l],[t,h,l],[t,c,o],[-t,c,o]];for(const u of[0,2,1,0,3,2])n.push(...d[u])}const s=new ht;return s.setAttribute("position",new mt(n,3)),s.computeVertexNormals(),s}stations(e){const t=[];for(let i=0;i<=Nt.BANK_STATIONS;i++)t.push(e*(this.span/2+this.bank*i/Nt.BANK_STATIONS));return t}railing(e){const t=this.size.lengthM/2,i=Math.max(1,Math.round(this.size.lengthM/this.postSpacing)),n=[];for(let o=0;o<=i;o++)n.push(-t+this.size.lengthM*o/i);const s=[],r=Nt.POST_SIDE_M;for(const o of n)s.push(Nt.box(r,this.railHeight,r,e,this.roadAt(o)+this.railHeight/2,o));for(let o=1;o<=this.rails;o++){const l=this.railHeight*o/this.rails-Nt.RAIL_HEIGHT_M/2;for(let c=1;c<n.length;c++){const h=new C(e,this.roadAt(n[c-1])+l,n[c-1]),d=new C(e,this.roadAt(n[c])+l,n[c]);s.push(Nt.beam(h,d))}}return s}static box(e,t,i,n,s,r){return new ji(e,t,i).translate(n,s,r)}static beam(e,t){const i=new C().subVectors(t,e),n=new ji(Nt.RAIL_DEPTH_M,Nt.RAIL_HEIGHT_M,i.length()),s=new Gi().setFromUnitVectors(new C(0,0,1),i.clone().normalize()),r=new C().addVectors(e,t).multiplyScalar(.5);return n.applyMatrix4(new $e().compose(r,s,new C(1,1,1)))}static merge(e){const t=e.map(l=>l.getIndex()?l.toNonIndexed():l),i=t.reduce((l,c)=>l+c.getAttribute("position").count,0),n=new Float32Array(i*3),s=new Float32Array(i*3);let r=0;for(const l of t){const c=l.getAttribute("position"),h=l.getAttribute("normal");n.set(c.array,r*3),h&&s.set(h.array,r*3),r+=c.count}const o=new ht;o.setAttribute("position",new mt(n,3)),o.setAttribute("normal",new mt(s,3));for(const l of e)l.dispose();for(const l of t)l.dispose();return o}}const kd=Math.PI/180;function Ut(a,e,t,i,n=!1){const s=n?new Dn({color:new se(...t)}):new go({color:new se(...t)}),r=new Ie(e,s);return r.position.y=i,r.userData={emissive:n},r.castShadow=!n,r.receiveShadow=!n,a.add(r),r}const Nd=.25,G5=.002,V5=100,W5=1500,X5=.25,Y5=1e3,q5=.15;function $5(a){const e=/^#([0-9a-f]{6})$/i.exec(a);if(!e)return[1,1,1];const t=parseInt(e[1],16);return[(t>>16&255)/255,(t>>8&255)/255,(t&255)/255]}const K5=[.32,.32,.3],j1=[1,.85,.5],Z5=[.25,.25,.25],J1=[1,.97,.85],j5=[.55,.68,.72],os=.03,ls=.05,Q1={front:0,behind:Math.PI,left:Math.PI/2,right:-Math.PI/2,"front-left":Math.PI/2,"behind-left":Math.PI/2,"front-right":-Math.PI/2,"behind-right":-Math.PI/2};function qi(a,e){return a?.[e]}function cs(a,e,t,i,n,s,r,o){if(o===void 0)return;const l=new go({color:new se(...j5),transparent:!0,opacity:o/100}),c=new Ie(new ji(e,t,i),l);c.position.set(n,s,r),a.add(c)}const An=.05,Fd=[.6,.58,.53],og=[.5,.5,.48];function Va(a,e,t,i,n,s,r,o){const l=new go({color:new se(...o),side:qt}),c=new Ie(new ji(e,t,i),l);c.position.set(n,s,r),a.add(c)}function J5(a,e,t,i,n,s,r,o,l){const c=(i-s)/2,h=(p,v,m,g)=>{p<=0||(e?Va(a,p,v,An,m,o+g,r,l):Va(a,An,v,p,r,o+g,m,l))};h(t,c,0,i/2-c/2),h(t,c,0,-(i/2-c/2));const d=[...n].sort((p,v)=>p.center-v.center);let u=-t/2;for(const p of d){const m=p.center-p.main/2-u;h(m,s,u+m/2,0),u=p.center+p.main/2}const f=t/2-u;h(f,s,u+f/2,0)}function eb(a,e,t,i,n,s,r,o,l,c){const h=(i+n)/2,d=n-i,u=(f,p,v,m)=>{f.length===0?p?Va(a,v,d,An,0,h,m,Fd):Va(a,An,d,v,m,h,0,Fd):J5(a,p,v,d,f,s,m,h,Fd)};u(r,!0,e*2,-t+An),u(o,!0,e*2,t-An),u(l,!1,t*2,-e+An),u(c,!1,t*2,e-An),Va(a,e*2,An,t*2,0,i+An,0,og),Va(a,e*2,An,t*2,0,n-An,0,og)}function zf(a,e,t,i){switch(a){case"front":return{x:0,z:-(t-i)};case"behind":return{x:0,z:t-i};case"left":return{x:-(e-i),z:0};case"right":return{x:e-i,z:0};case"front-left":return{x:-(e-i),z:-hs};case"front-right":return{x:e-i,z:-hs};case"behind-left":return{x:-(e-i),z:hs};case"behind-right":return{x:e-i,z:hs}}}function tb(a,e,t,i,n,s,r){const o=Vf();o.scale.setScalar(i),o.rotation.y=Q1[e];const{x:l,z:c}=zf(e,n,s,r);o.position.set(l,t,c),a.add(o)}const Hf=6,Gf=6,or=3,No=1.4,Fo=or*.5,ib=1.2,nb=.35,Q5=.75,eA=1.6;function lg(a,e,t,i){const n=new Lt,s=Math.max(1,a+1),r=s*or;Ut(n,new ji(Hf,r,Gf),[.55,.54,.5],r/2);const o=Hf/2,l=Gf/2;for(let c=0;c<s;c++){const h=c*or+or/2;cs(n,No,Fo,ls,0,h,-l-os,qi(e,"front")),cs(n,No,Fo,ls,0,h,l+os,qi(e,"behind")),cs(n,ls,Fo,No,-o-os,h,0,qi(e,"left")),cs(n,ls,Fo,No,o+os,h,0,qi(e,"right"))}if(t){const c=Math.min(Math.max(i??0,0),s-1);tb(n,t,c*or,.72,o,l,ib);const h=d=>qi(e,d)!==void 0?[{main:No,center:0}]:[];eb(n,o,l,c*or,(c+1)*or,Fo,h("front"),h("behind"),h("left"),h("right"))}return n}function cg(){const a=new Lt,e=[[0,0,.55,.5],[.4,.1,.35,.4],[-.35,-.2,.4,.38],[.1,-.4,.35,.36],[-.15,.4,.3,.34]];for(const[t,i,n,s]of e){const r=new hi(n,10,7);r.scale(1,.85,1),r.translate(t,0,i),Ut(a,r,[.26,.28,.17],s)}return a}function tA(a){const e=new Lt,t=new Nt(oi.sizeOf(a),a.bridge).build();Ut(e,t.concrete,[.6,.6,.58],0);const i=Ut(e,t.road,[.2,.2,.21],0),n=Ut(e,t.earth,[.3,.36,.22],0);for(const s of[i,n])s.material.side=on;return Ut(e,t.railing,[.5,.52,.55],0),e}function hg(){const a=new Lt;return Ut(a,new ws(.15,.22,2,8),[.32,.22,.14],1),Ut(a,new mo(1.4,3,8),[.16,.32,.14],3.5),a}const dg=.275,iA=.35,nA=.9,sA=34,rA=8,aA=1.4;function ug(){const a=new Lt,e=new hi(dg,7,3,0,Math.PI*2,0,Math.PI/2);e.scale(1,iA/dg,1);const t=oi.repeatOnGrid(e,sA,nA,rA,aA),i=Ut(a,t,[.26,.28,.22],0);return i.castShadow=!0,i.userData.cropBasePositions=t.getAttribute("position").array.slice(),i.userData.cropVerticesPerClump=e.getAttribute("position").count,e.dispose(),a}function fg(){const a=new Lt,e=new hi(1,7,3,0,Math.PI*2,0,Math.PI/2);return Ut(a,e,[.38,.36,.32],0),a}function pg(a){const e=new Lt;return Ut(e,new ws(.05,.08,5,8),[.28,.28,.3],2.5),Ut(e,new hi(.25,12,8),a?j1:K5,5.1,!0),e}const oA=[.08,.08,.08],nr=.8,ka=1,es=1.7,Ud=.6,Cr=.4,yc=1.2,Da=.7,hs=.5,lA=es;function mg(a,e,t){const i=new Lt;Ut(i,new ji(1.8,1.4,4.2),[.45,.14,.14],.7),Ut(i,new ji(nr*2,Ud,ka*2),[.4,.12,.12],es);for(const s of[-1.4,1.4])for(const r of[-.95,.95]){const o=Ut(i,new ws(.4,.4,.3,12),oA,.4);o.rotation.z=Math.PI/2,o.position.x=r,o.position.z=s}const n=a?J1:Z5;for(const s of[-.7,.7])Ut(i,new hi(.15,8,6),n,.7,!0).position.set(s,.7,-2.1);if(cs(i,yc,Cr,ls,0,es,-ka-os,qi(e,"front")),cs(i,yc,Cr,ls,0,es,ka+os,qi(e,"behind")),cs(i,ls,Cr,Da,-nr-os,es,-hs,qi(e,"front-left")),cs(i,ls,Cr,Da,-nr-os,es,hs,qi(e,"behind-left")),cs(i,ls,Cr,Da,nr+os,es,-hs,qi(e,"front-right")),cs(i,ls,Cr,Da,nr+os,es,hs,qi(e,"behind-right")),t){tb(i,t,Q5,.5,nr,ka,nb);const s=(l,c)=>{const h=[];return qi(e,l)!==void 0&&h.push({main:Da,center:-hs}),qi(e,c)!==void 0&&h.push({main:Da,center:hs}),h},r=qi(e,"front")!==void 0?[{main:yc,center:0}]:[],o=qi(e,"behind")!==void 0?[{main:yc,center:0}]:[];eb(i,nr,ka,es-Ud/2,es+Ud/2,Cr,r,o,s("front-left","behind-left"),s("front-right","behind-right"))}return i}const gg=new Map;function vg(a,e){if(!a)return;const t=[[a.lengthM,e.lengthM],[a.heightM,e.heightM],[a.widthM,e.widthM]];for(const[i,n]of t)if(i!==void 0&&n>1e-6)return i/n}function Bd(a,e){return e>1e-6?a/e:1}const sb=[.95,.9,.82],bg=[.72,.74,.78];function yg(){const a=new Lt;Ut(a,new ws(.25,.3,1.5,10),bg,.75),Ut(a,new hi(.26,10,8),bg,1.74);const e=Ut(a,new mo(.07,.16,8),sb,1.74);return e.rotation.x=-Math.PI/2,e.position.z=-.22,a}function Vf(){const a=new Lt;Ut(a,new ws(.25,.3,1.5,10),[.3,.3,.35],.75),Ut(a,new hi(.22,10,8),[.62,.52,.46],1.72);const e=Ut(a,new mo(.07,.16,8),sb,1.72);return e.rotation.x=-Math.PI/2,e.position.z=-.2,a}const cA=17,Mg=18.5,zd=[.16,.16,.18];function wg(){const a=new Lt,e=Ut(a,new ws(1.8,1.8,Mg*2,10),zd,0);e.rotation.x=Math.PI/2,Ut(a,new ji(cA*2,.5,4.5),zd,0);const t=Ut(a,new ji(.4,5.5,4),zd,3);return t.position.z=-Mg+2,a}class oi{static GROWS_FROM_GROUND=new Set(["tree","shrub","crop","mound"]);static groundUnderFootprint(e,t,i,n,s,r=0){const o=oi.sizeOf(e);if(r>o.heightM)return s(t,i);const l=(n??0)*Math.PI/180,c=Math.min(21,Math.max(2,Math.ceil(o.lengthM/.75)+1)),h=Math.min(21,Math.max(2,Math.ceil(o.widthM/.75)+1)),d=oi.GROWS_FROM_GROUND.has(e.kind);let u=d?1/0:-1/0;for(let f=0;f<c;f++){const p=(f/(c-1)-.5)*o.lengthM;for(let v=0;v<h;v++){const m=(v/(h-1)-.5)*o.widthM,g=t+Math.sin(l)*p+Math.cos(l)*m,y=i-Math.cos(l)*p+Math.sin(l)*m;u=d?Math.min(u,s(g,y)):Math.max(u,s(g,y))}}return Number.isFinite(u)?u:s(t,i)}static occupantView(e){const t=e.observerSide;if(!t)throw new Error("occupantView requires object.observerSide to be set");const{x:i,z:n}=e.kind==="vehicle"?zf(t,nr,ka,nb):zf(t,Hf/2,Gf/2,ib),s=e.kind==="vehicle"?lA:(e.occupiedFloor??0)*or+eA,r=(e.headingDeg??0)-Q1[t]/kd,o=this.scaleFor(e);return{x:i*o.x,z:n*o.z,eyeY:s*o.y,headingDeg:r}}static BODY_NAME="decor-body";static bodyOf(e){return e.getObjectByName(oi.BODY_NAME)??e}static repeatOnGrid(e,t,i,n,s){const r=e.getAttribute("position"),o=e.getAttribute("normal"),l=e.getIndex();if(!l)throw new Error("repeatOnGrid needs an indexed geometry");const c=r.count,h=t*n,d=new Float32Array(c*h*3),u=new Float32Array(c*h*3),f=new Uint32Array(l.count*h),p=-((t-1)*i)/2,v=-((n-1)*s)/2;let m=0;for(let y=0;y<n;y++)for(let M=0;M<t;M++,m++){const b=v+y*s,x=p+M*i;for(let E=0;E<c;E++){const I=(m*c+E)*3;d[I]=r.getX(E)+b,d[I+1]=r.getY(E),d[I+2]=r.getZ(E)+x,u[I]=o.getX(E),u[I+1]=o.getY(E),u[I+2]=o.getZ(E)}for(let E=0;E<l.count;E++)f[m*l.count+E]=l.getX(E)+m*c}const g=new ht;return g.setAttribute("position",new mt(d,3)),g.setAttribute("normal",new mt(u,3)),g.setIndex(new mp(f,1)),g}static fitCropToGround(e,t){e.updateMatrixWorld(!0);const i=new C;e.traverse(n=>{const s=n,r=s.userData.cropBasePositions,o=s.userData.cropVerticesPerClump;if(!s.isMesh||!r||!o)return;const l=s.geometry.getAttribute("position"),c=new $e().copy(s.matrixWorld).invert();for(let h=0;h<l.count;h+=o){i.set(r[h*3],0,r[h*3+2]).applyMatrix4(s.matrixWorld),i.y=t(i.x,i.z),i.applyMatrix4(c);for(let d=h;d<h+o;d++)l.setY(d,r[d*3+1]+i.y)}l.needsUpdate=!0,s.geometry.computeBoundingBox(),s.geometry.computeBoundingSphere()})}static paint(e,t){e.traverse(i=>{const n=i,s=n.userData;if(!n.isMesh||s?.emissive)return;const r=n.material;r?.color&&r.color.set(t)})}static build(e,t){const i=e.kind==="building"?lg(e.floors??Ya,e.windows,e.observerSide,e.occupiedFloor):e.kind==="tree"?hg():e.kind==="shrub"?cg():e.kind==="bridge"?tA(e):e.kind==="crop"?ug():e.kind==="mound"?fg():e.kind==="streetlight"?pg(t):e.kind==="vehicle"?mg(t,e.windows,e.observerSide):e.kind==="aircraft"?wg():e.kind==="entity"?yg():Vf();e.color&&this.paint(i,e.color);const n=this.scaleFor(e),s=new Lt;return i.name=oi.BODY_NAME,i.scale.copy(n),s.add(i),e.headingDeg!==void 0&&(s.rotation.y=-e.headingDeg*kd),this.addLights(s,e.lights),s}static scaleFor(e){const t=e.sizeM;if(!t||e.kind==="bridge")return new C(1,1,1);const i=this.naturalSize(e.kind,e.floors);return new C(t.widthM===void 0?1:Bd(t.widthM,i.widthM),t.heightM===void 0?1:Bd(t.heightM,i.heightM),t.lengthM===void 0?1:Bd(t.lengthM,i.lengthM))}static naturalSize(e,t){const i=e==="building"?Math.max(1,(t??Ya)+1):0;if(e==="bridge")return Nt.NATURAL_SIZE;const n=`${e}:${i}`,s=gg.get(n);if(s)return s;const r=e==="building"?lg(i-1,void 0,void 0,void 0):e==="tree"?hg():e==="shrub"?cg():e==="crop"?ug():e==="mound"?fg():e==="streetlight"?pg(!1):e==="vehicle"?mg(!1,void 0,void 0):e==="aircraft"?wg():e==="entity"?yg():Vf(),o=new Zi().setFromObject(r),l={widthM:o.max.x-o.min.x,heightM:o.max.y-o.min.y,lengthM:o.max.z-o.min.z};return this.dispose(r),gg.set(n,l),l}static usesModel(e){return e.model!==void 0&&!(e.observerSide!==void 0&&Ua(e.kind))}static applyModel(e,t,i,n={}){const s=this.bodyOf(e),r=new Lt;r.name=oi.BODY_NAME,i.rotation.y=-(n.headingOffsetDeg??0)*kd,i.updateMatrixWorld(!0);const o=new Zi().setFromObject(i),l={lengthM:o.max.z-o.min.z,heightM:o.max.y-o.min.y,widthM:o.max.x-o.min.x},c=vg(t.sizeM,l)??vg(n.depictedSizeM,l)??1;i.scale.multiplyScalar(c);const h=o.getCenter(new C).multiplyScalar(c);i.position.x-=h.x,i.position.z-=h.z,i.position.y-=t.kind==="aircraft"?h.y:o.min.y*c,i.traverse(d=>{d instanceof Ie&&(d.castShadow=!0,d.receiveShadow=!0)}),r.add(i),s.parent?(s.parent.add(r),s.removeFromParent()):e.add(r),this.dispose(s)}static sizeOf(e){const t=this.naturalSize(e.kind,e.floors);return{widthM:e.sizeM?.widthM??t.widthM,lengthM:e.sizeM?.lengthM??t.lengthM,heightM:e.sizeM?.heightM??t.heightM}}static addLights(e,t){for(const i of t??[]){const n=$5(i.color),s=Ut(e,new hi(Nd,8,6),n,i.offsetM.y,!0);s.position.set(i.offsetM.x,i.offsetM.y,i.offsetM.z),s.userData={emissive:!0,lightId:i.id,lightColor:n},s.visible=!1}}static setLights(e,t,i,n,s=0,r=1,o=G5){if(!t||t.length===0)return;const l=new Map(t.map(u=>[u.id,u])),c=Math.max(1,n*o/Nd),h=Nd*c,d=r/(Math.PI*h*h);for(const u of e.children){if(!(u instanceof Ie))continue;const f=u.userData.lightId;if(!f)continue;const p=l.get(f);if(!p)continue;const v=s>0?Ev(p,i,i+s):sy(p,i)?1:0;u.visible=v>0;const m=u.material,g=u.userData.lightColor;if(g){const y=v*V5*(p.intensity??1)*d;m.color.setRGB(g[0]*y,g[1]*y,g[2]*y)}u.scale.setScalar(c)}}static setLit(e,t,i,n=1){const[s,r,o]=t==="streetlight"?[W5,X5,j1]:[Y5,q5,J1],l=i?s*n/(Math.PI*r*r):0,c=[o[0]*l,o[1]*l,o[2]*l];e.traverse(h=>{const d=h.userData;!(h instanceof Ie)||!d.emissive||d.lightId||h.material.color.setRGB(...c)})}static dispose(e){e.traverse(t=>{if(!(t instanceof Ie))return;t.geometry.dispose();const i=t.material;for(const n of Array.isArray(i)?i:[i])n.dispose()})}}const Hd="https://ufoathome.org/models/index.json";class hA{attribution="3D models re-hosted by UFO@home, each under its own author's licence";fetchImpl;indexUrls;loading;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.indexUrls=e.indexUrls??dA()}async entries(e){const t=await this.load();return e?t.filter(i=>i.kind===e):t}async entry(e){return(await this.load()).find(t=>t.id===e)}load(){return this.loading??=this.fetchFirstAvailable(),this.loading}async fetchFirstAvailable(){for(const e of this.indexUrls){const t=await this.fetchIndex(e);if(t)return t}return[]}async fetchIndex(e){try{const t=await this.fetchImpl(e);if(!t.ok)return;const i=await t.json();return Array.isArray(i?.models)?i.models.map(({file:n,...s})=>({...s,url:new URL(n,e).href})):void 0}catch{return}}}function dA(){const a=`?v=${encodeURIComponent("0.70.0")}`,e=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(e&&e!==Hd?[e,Hd]:[Hd]).map(t=>t+a)}const Vc=[{id:"ufoathome",name:"UFO@home",credit:"3D models re-hosted by UFO@home, each under its own author's licence",creditUrl:"https://ufoathome.org/models/",create:()=>new hA}];async function xg(a){const{GLTFLoader:e}=await Mn(async()=>{const{GLTFLoader:i}=await import("./GLTFLoader-C33uvPO8.js");return{GLTFLoader:i}},[],import.meta.url),t=new e;return new Promise((i,n)=>{t.load(a,s=>i(Object.assign(s.scene,{animations:s.animations})),void 0,s=>n(new Error(`Could not load 3D model ${a}: ${s instanceof Error?s.message:String(s)}`)))})}const rb=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class vn{static MIN_ANGLE_RAD=.002;static FILL=(1-Math.exp(-4))/4;static MAX_SHARE=.3;mesh;constructor(e,t){this.mesh=new Ie(new Ji(2,2),new dt({uniforms:{uColor:{value:new se(0,0,0)},uRadius:{value:1}},vertexShader:vn.VERTEX,fragmentShader:vn.FRAGMENT,transparent:!0,depthWrite:!1,blending:Vi,toneMapped:!1})),this.mesh.name=e,this.mesh.frustumCulled=!1,this.mesh.renderOrder=t,this.mesh.visible=!1}shine(e,t,i){this.mesh.visible=!0,this.mesh.position.set(e.x,e.y,e.z),this.mesh.material.uniforms.uRadius.value=t,this.mesh.material.uniforms.uColor.value.setRGB(i[0],i[1],i[2])}hide(){this.mesh.visible=!1}dispose(){this.mesh.geometry.dispose(),this.mesh.material.dispose()}static spread(e,t,i,n){const s=Math.max(e,n*vn.MIN_ANGLE_RAD),r=vn.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(vn.MAX_SHARE,t/r)}}static conserving(e){return Math.sqrt(e/(vn.MAX_SHARE*vn.FILL*Math.PI))}static VERTEX=`
8196
8196
  uniform float uRadius;
8197
8197
  varying vec2 vOffset;
8198
8198
  void main() {
@@ -8751,7 +8751,7 @@ cloudPoint = (modelMatrix * vec4(transformed, 1.0)).xyz - cameraPosition;`);let
8751
8751
  vec3 light = texture2D(uMap, vec2((along * (uSteps - 1.0) + 0.5) / uSteps, 0.5)).rgb;
8752
8752
  gl_FragColor = vec4(light, 1.0);
8753
8753
  }
8754
- `,transparent:!0,blending:Vi,depthWrite:!1,side:qt,fog:!1});this.object=new Ie(new hi(Bp.RADIUS,128,32,0,Math.PI*2,0,vt.MAX_ANGLE_RAD),t),this.object.renderOrder=-1,this.object.frustumCulled=!1,this.object.visible=!1}show(e,t){if(!e||!t){this.object.visible=!1;return}this.towards.set(e.x,e.y,e.z).normalize(),this.object.quaternion.setFromUnitVectors(this.up,this.towards),this.object.material.uniforms.uSource.value.copy(this.towards);for(let i=0;i<vt.STEPS;i++){for(let n=0;n<3;n++)this.texels[i*4+n]=Wn.toHalfFloat(Math.min(t[i*3+n],6e4));this.texels[i*4+3]=Wn.toHalfFloat(1)}this.texture.needsUpdate=!0,this.object.visible=!0}dispose(){this.object.geometry.dispose(),this.object.material.dispose(),this.texture.dispose()}}class yh{constructor(e){this.generator=e}static SIZE=128;target=new wl(yh.SIZE,{type:Zt,generateMipmaps:!1,minFilter:ct,magFilter:ct});camera=new xp(.1,2e5,this.target);filteredTarget;capturedAtMs=-1/0;capturedVersion;get sharp(){return this.target.texture}get filtered(){return this.filteredTarget?.texture}capture(e,t,i,n=[]){const s=e.shadowMap.autoUpdate;e.shadowMap.autoUpdate=!1;const r=n.map(o=>o.visible);for(const o of n)o.visible=!1;this.camera.position.copy(i),this.camera.update(e,t),n.forEach((o,l)=>{o.visible=r[l]}),e.shadowMap.autoUpdate=s,this.filteredTarget=this.generator.fromCubemap(this.target.texture,this.filteredTarget),this.capturedAtMs=performance.now()}dispose(){this.target.dispose(),this.filteredTarget?.dispose()}}class pn{static REFRESH_MS=250;generator;eye;probes=new Map;constructor(e){pn.install(),this.generator=new uf(e),this.eye=new yh(this.generator)}static decor;refresh(e,t,i,n,s,r,o,l=[],c){for(const v of[...this.probes.keys()])n.some(m=>m.id===v&&m.shiny)||(this.probes.get(v).dispose(),this.probes.delete(v));const h=[{probe:this.eye}];for(const v of n){if(!v.shiny)continue;let m=this.probes.get(v.id);m||(m=new yh(this.generator),this.probes.set(v.id,m)),h.push({probe:m,reflector:v})}const d=performance.now(),u=()=>h.filter(({probe:v})=>v.capturedVersion!==o),f=u().filter(({probe:v})=>d-v.capturedAtMs>=pn.REFRESH_MS);if(f.length>0){const v=f.reduce((m,g)=>g.probe.capturedAtMs<m.probe.capturedAtMs?g:m);if(v.reflector){const m=v.reflector.holder.getWorldPosition(this.scratch);v.probe.capture(e,t,m,[v.reflector.holder,...s]),pn.reflectOn(v.reflector.holder,v.probe)}else{v.probe.capture(e,t,i,[...s,...l]),c?.(v.probe.sharp),pn.decor=v.probe.filtered;for(const m of r)pn.reflectOn(m,v.probe);for(const m of n)m.shiny||pn.reflectOn(m.holder,v.probe)}v.probe.capturedVersion=o}const p=u();if(p.length!==0)return Math.max(16,Math.min(...p.map(({probe:v})=>pn.REFRESH_MS-(d-v.capturedAtMs))))}scratch=new C;static reflectOn(e,t={filtered:pn.decor}){e.traverse(i=>{const n=i.material;for(const s of Array.isArray(n)?n:n?[n]:[])s instanceof Sl?t.sharp&&s.setSurroundings(t.sharp):s instanceof Br&&t.filtered&&s.envMap!==t.filtered&&(s.envMap=t.filtered,s.needsUpdate=!0)})}dispose(){this.eye.dispose();for(const e of this.probes.values())e.dispose();this.generator.dispose()}static installed=!1;static install(){if(pn.installed)return;pn.installed=!0;const e="iblIrradiance += getIBLIrradiance( geometryNormal );";if(!Ye.lights_fragment_maps.includes(e)){console.warn("Reflections: three's lights_fragment_maps changed; the environment will light diffusely too");return}Ye.lights_fragment_maps=Ye.lights_fragment_maps.replace(e,"// The sky's diffuse light is the hemisphere light's (see Reflections).")}}function pA(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.relativeHumidity===e.relativeHumidity&&a.precipitationType===e.precipitationType&&a.precipitationIntensity===e.precipitationIntensity&&a.precipitationAmount===e.precipitationAmount&&a.windDirectionDeg===e.windDirectionDeg&&a.windSpeed===e.windSpeed&&a.storm===e.storm}const xc=900,Gd=1,Sg=4,Eg=5,_g=.5,Jo=900,mA=6371e3,gA=3e4;function Ag(a){const e=Math.sqrt(2*mA*Math.max(a,0));return Math.max(Jo,Math.min(e,gA))}const Vd=.5,Wd=850,Tg=.03,dn=850,Bo=300,tr=120,vA=700,bA=.04,zo=4,Xd=1.5,Ig=-1,yA=6,Wf=-4,MA=2,wA=20,Sc=2600,xA=.97,SA=.38,Ec=Wf,Dg=1500,EA=400,_A=[0,45,90,135,180,225,270,315],AA={en:["N","NE","E","SE","S","SW","W","NW"],fr:["N","NE","E","SE","S","SO","O","NO"]},TA=["en","fr"],IA=2,DA=16,Cg=2500,Rg=880,_c=40,Pg=60,CA=10,RA=1,PA=150,LA=55,OA=.5,kA=17,Lg=.265,Og=[[0,0],...Array.from({length:8},(a,e)=>{const t=e*Math.PI/4;return[Math.cos(t)*Lg,Math.sin(t)*Lg]})],Yd=700,qd=250/1e3,NA=12,kg=5,$d=6,Rr=[.92,.92,.95],Kd=[.15,.15,.19],Zd={snow:{fallSpeedMPerS:2,size:.3,color:new se(1,1,1),driftSensitivity:1,radiusM:25,topYM:20,opacity:.75,poolSize:2400},hail:{fallSpeedMPerS:14,size:.5,color:new se(.95,.98,1),driftSensitivity:.25,radiusM:25,topYM:10,opacity:.95,poolSize:1200}},Na=0,jd=0,FA=150,Jd=3e3,Ho=20,UA=15,Ng=Na,BA=40,Fg=1,zA=9;function Qd(a){return Fg+(zA-Fg)*a}const Ug=new se(.75,.82,.92),HA=10,GA=.5;function Bg(a){return Wa(a/HA,GA,1)}const Pr=200,zg=.18,Hg=.32,VA=.35,Gg=new se(.85,.9,.98),Vg=5,Wg=.85,Xg=.01;function WA(a,e,t=1){return Math.round(a*(Xg+(1-Xg)*e)*t)}function XA(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}const Yg=230,qg=.7,$g=.05,YA=.6,qA=.7,$A=.15,Kg=.35,KA=3,ZA=1/12,jA=.5,Qn=new se(.82,.86,1),JA=2500,QA=1.6,eu=15,eT={Venus:new se(1,.96,.85),Mars:new se(1,.55,.4),Jupiter:new se(.95,.87,.72),Saturn:new se(.92,.86,.68)};class Gt{renderer;scene=new Bs;phenomena=new Nn(this.scene);references=new kn(this.scene,()=>this.render());camera;celestialGroup=new Lt;skyMesh;skyGradientMaterial;scatteredSky;lastAstronomy;skyColoursStale=!1;scatteredSkyFrameId=null;skyHoldUntilMs=void 0;onFirstFrameHold;firstFrameReady(){return(!this.scatteredSky||this.scatteredSky.ambient!==void 0)&&!this.iceHalos?.awaitingFirstDisplay}groundMesh;terrainMesh;terrainProviders;terrainOrigin;terrainBuildToken=0;terrainAttribution;roadSystem=new _n;roadAttribution;roadWays;statedRoads=[];decorModelProvider=Vc[0].create();decorModelToken=0;decorModelCredits=new Map;bodySystem=new ft(e=>this.loadBodyModel(e),()=>this.render(),()=>this.relativeScale);bodyOrigin={x:0,z:0};starTiers=[];bodyMeshes=new Map;hitAreas=new Map;glareSprites=new Map;decorObjects=[];decorGroups=new Map;decorReferencePose;decorCurrentPose;decorTime=0;celestialLight=new vm(16777215,0);celestialLightTarget=new Bt;skyLight=new zM(16777215,0,0);streetlightLights=new Map;compassSprites=[];showCompass=!1;compassHovered=!1;compassForced=!1;animationFrameId=null;resolution;cssSize={width:1,height:1};frameDirty=!1;flushFrameId=null;framesDriven=!1;lastFrameTimeMs;raycaster=new zc;weather=qf;observerElevationM=0;siteElevationM=0;air=new Tn;groundRadius=Jo;terrainRadius=Jo;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 be;lightningArmed=!1;lightningFlashes=[];lightningLevel=0;lightningBolt;lightningLight=new vm(16777215,0);baseFogColor=[0,0,0];lastSunPosition;lensFlare;sunUnhiddenFraction=1;lensFlareArtifactIntensity=0;sunWorldPosition=new C;sunVisible=!1;lensFlareScratch=new C;sunOcclusionRaycaster=new zc;sunOcclusionDirectionScratch=new C;sunOcclusionRightScratch=new C;sunOcclusionUpScratch=new C;ufoOcclusionRaycaster=new zc;projectionKind="rectilinear";starPoints=0;namedStars=[];equidistantPass;depthOfFieldPass;finishPass;exposureAccumulation;exposureInstants=1;get developingExposure(){return this.exposureInstants>1&&this.exposureInstantAt!==void 0}static EXPOSURE_BUDGET_MS=12;static exposureInstantsPerFrame(e){return Math.max(3,Math.round(6e6/Math.max(1,e)))}exposureFrameId=null;exposureInstantsDone=0;exposureInstantAt;restatingExposure=!1;lensOptics;instrumentMagnitudeGain=0;meteorSystem;cometTail;satelliteField;iceHalos;lunarDiffraction;lunarDiffractionKey="";rainbow;skyGlow;cometKey;novaKeys=new Set;constructor(e,t=Ny()){this.renderer=new Q3({canvas:e,antialias:!0}),this.resolution=new yt(Math.min(window.devicePixelRatio||1,2),this.renderer.getContext()),this.renderer.setPixelRatio(this.resolution.pixelRatio),this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=el,this.camera=new an(60,e.width/Math.max(e.height,1),.1,xc*1.2),this.camera.position.set(0,1.6,0),this.terrainProviders=t,this.celestialLight.shadow.mapSize.set(1024,1024),this.celestialLight.shadow.camera.left=-tr,this.celestialLight.shadow.camera.right=tr,this.celestialLight.shadow.camera.top=tr,this.celestialLight.shadow.camera.bottom=-tr,this.celestialLight.shadow.camera.near=dn-Bo,this.celestialLight.shadow.camera.far=dn+Bo,this.celestialLight.shadow.bias=-.03/(2*Bo),this.celestialLight.shadow.normalBias=bA,this.celestialLight.target=this.celestialLightTarget,this.lightningLight.color.copy(Qn),this.scene.add(this.celestialLight,this.celestialLightTarget,this.skyLight,this.lightningLight),this.scene.add(this.celestialGroup),this.scene.add(this.bodySystem.group),this.scene.add(this.roadSystem.group);const i=new $t(this.renderer,()=>{this.skyColoursStale=!0,this.render()});i.supported?this.scatteredSky=i:i.dispose()}get currentTerrainAttribution(){return this.terrainAttribution}get currentRoadAttribution(){return this.roadAttribution}resize(e,t){this.cssSize.width=e,this.cssSize.height=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.cloudTransmissionMemo.clear(),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*qd,0,e.z*qd);for(const i of[this.cloudUniforms,this.cirrusUniforms])i?.fieldOffset.value.copy(this.cloudFieldOffset);this.iceHalos?.setCloudOffset(this.layeredClouds?.cirrusMask?.offset??this.cloudFieldOffset)}setObserverPose(e){const t=((e.rollDeg??0)+this.gaitOffset.rollDeg)*en,i=(e.pitchDeg+this.lookPitchDeg+this.gaitOffset.pitchDeg)*en;if(e.headingDeg!==void 0?this.camera.rotation.set(i,-(e.headingDeg+this.lookYawDeg+this.gaitOffset.yawDeg)*en,t,"YXZ"):this.camera.rotation.set(i,this.camera.rotation.y,t,"YXZ"),e.elevationM!==this.observerElevationM&&(this.observerElevationM=e.elevationM,this.syncCloudLayer(),Math.abs(Ag(e.elevationM)-this.groundRadius)>1&&(this.buildGround(),this.celestialGroup.scale.setScalar(this.groundRadius/Jo),this.camera.far=Math.max(xc*1.2,this.groundRadius*2.5),this.camera.updateProjectionMatrix())),this.terrainMesh&&this.terrainOrigin&&e.lat!==void 0&&e.lng!==void 0){const n=li(this.terrainOrigin.lat,this.terrainOrigin.lng,e.lat,e.lng);this.terrainMesh.position.x=n.x,this.terrainMesh.position.z=n.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.stopTerrainFade(),this.terrainProviders=e,this.disposeMesh(this.terrainMesh),this.terrainMesh=void 0,this.terrainOrigin=void 0,this.terrainAttribution=void 0,this.roadSystem.clear(),this.roadAttribution=void 0,this.roadWays=void 0,this.applyGroundDepthWrite(),this.terrainBuildToken++}setTerrainOrigin(e,t,i){if(e===void 0||t===void 0)return;const n=this.groundRadius;if(this.terrainOrigin&&Math.abs(this.terrainRadius-n)<n*.1){const{x:l,z:c}=li(e,t,this.terrainOrigin.lat,this.terrainOrigin.lng);if(Math.sqrt(l*l+c*c)<PA*(n/Jo))return}const s=this.terrainOrigin,r=this.terrainRadius;(!s||s.lat!==e||s.lng!==t)&&(this.roadSystem.clear(),this.roadAttribution=void 0),this.terrainOrigin={lat:e,lng:t},this.terrainRadius=n;const o=++this.terrainBuildToken;E5(e,t,this.terrainProviders,n).then(({mesh:l,attribution:c,originElevationM:h})=>{if(o!==this.terrainBuildToken)return;this.setSiteElevation(h??0);const d=this.terrainMesh,u=s?li(e,t,s.lat,s.lng):void 0;d&&u&&Math.hypot(u.x,u.z)<=r&&(l.position.y=d.position.y+this.groundYOfPatch(d,u.x,u.z)),d&&u&&Math.hypot(u.x,u.z)<=r?this.crossfadeTerrain(l,d):this.disposeMesh(this.terrainMesh),l.renderOrder=RA,this.terrainMesh=l,this.compileNextFrameOffThread(),this.terrainAttribution=c,this.scene.add(l),this.applyGroundDepthWrite(),this.decorCurrentPose&&(this.setObserverPose(this.decorCurrentPose),this.updateDecorAnchoring(this.decorReferencePose,this.decorCurrentPose,this.decorTime)),this.buildRoads(e,t,n),this.drapeStatedRoads(),this.render(),i?.()}).catch(l=>{console.warn("Terrain build failed, keeping the flat ground fallback:",l),i?.()})}static TERRAIN_CROSSFADE_MS=1200;fadingTerrain;crossfadeTerrain(e,t){this.stopTerrainFade();const i=e.material;i.opacity=0,i.polygonOffset=!0,i.polygonOffsetFactor=-1,i.polygonOffsetUnits=-4;const n=performance.now(),s=()=>{const r=Math.min(1,(performance.now()-n)/Gt.TERRAIN_CROSSFADE_MS);if(i.opacity=r*r*(3-2*r),this.render(),r<1&&this.fadingTerrain){this.fadingTerrain.frameId=requestAnimationFrame(s);return}i.polygonOffset=!1,i.opacity=1,this.fadingTerrain&&this.disposeMesh(this.fadingTerrain.mesh),this.fadingTerrain=void 0,this.render()};this.fadingTerrain={mesh:t,frameId:requestAnimationFrame(s)}}stopTerrainFade(){if(!this.fadingTerrain)return;cancelAnimationFrame(this.fadingTerrain.frameId),this.disposeMesh(this.fadingTerrain.mesh),this.fadingTerrain=void 0;const e=this.terrainMesh?.material;e&&(e.opacity=1,e.polygonOffset=!1)}static ROADS_MAX_RADIUS_M=5e3;buildRoads(e,t,i){const n=this.terrainProviders.roads;if(!n||i>Gt.ROADS_MAX_RADIUS_M){this.roadSystem.clear(),this.roadAttribution=void 0;return}const s=this.roadWays;if(s&&s.lat===e&&s.lng===t&&s.radiusM===i){this.drapeRoads(s.ways,e,t,n.contemporary);return}n.getRoads(Z1(e,t,i)).then(r=>{this.terrainOrigin?.lat!==e||this.terrainOrigin?.lng!==t||(this.roadWays={lat:e,lng:t,radiusM:i,ways:r},this.drapeRoads(r,e,t,n.contemporary))}).catch(r=>{console.warn("Roads unavailable, drawing none:",r)})}setStatedRoads(e){e!==this.statedRoads&&(this.statedRoads=e,this.drapeStatedRoads(),this.render())}drapeStatedRoads(){const e=this.terrainMesh;e&&(this.roadSystem.group.position.copy(e.position),this.roadSystem.setStated(this.statedRoads,(t,i)=>this.groundYOfPatch(e,t,i)))}drapeRoads(e,t,i,n){const s=this.terrainMesh;s&&(this.roadSystem.group.position.copy(s.position),this.roadSystem.set(e,t,i,(r,o)=>this.groundYOfPatch(s,r,o),n),this.roadAttribution=e.length>0?this.terrainProviders.roads?.attribution:void 0,this.compileNextFrameOffThread(),this.render())}setShowCompass(e){this.showCompass!==e&&(this.showCompass=e,this.disposeCompassLabels(),e&&this.buildCompassLabels(),this.render())}applyLensFlareTint(e){if(!this.lensFlare)return;const t=LA*(this.sunArriving[1]/kA);this.lensFlare.uniforms.uColorGain.value.setRGB(t*e[0],t*e[1],t*e[2]),this.applyDazzleStrength()}applyDazzleStrength(){if(!this.lensFlare)return;const[e,t,i]=this.sunArriving,n=Math.max(t,1e-30);this.lensFlare.uniforms.uDazzleColour.value.setRGB(e/n,1,i/n),this.lensFlare.uniforms.uVeilStrength.value=Bi.K*t*this.sunUnhiddenFraction}sunArriving=[0,0,0];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;if(this.compassSprites.some(t=>t.visible!==e)){for(const t of this.compassSprites)t.visible=e;this.developingExposure?this.exposureInstantsDone>0&&this.presentExposure():this.render()}}setWeather(e){if(pA(this.weather,e))return;this.cloudTransmissionMemo.clear();const t=this.weather;this.weather=e;const i=!XA(t,e),n=t.precipitationType!==e.precipitationType,s=t.precipitationIntensity!==e.precipitationIntensity||t.precipitationAmount!==e.precipitationAmount;(t.relativeHumidity!==e.relativeHumidity||n||s)&&(this.air=Tn.of(e),this.applyAir(),this.scatteredSky?.setConditions({aerosolOpticalDepth:e.relativeHumidity===void 0?void 0:Ns.steppedOpticalDepth(e.relativeHumidity)}),this.pumpScatteredSky()),i&&(this.buildClouds(),this.buildCirrus()),n?this.buildPrecipitation():s&&this.updatePrecipitationDensity(),this.lastAstronomy&&(i&&(this.buildIceHalos(this.lastAstronomy.sun,this.lastAstronomy.moon),this.buildLunarDiffraction(this.lastAstronomy.moon)),(i||n||s)&&this.buildRainbow(this.lastAstronomy.sun,this.lastAstronomy.moon)),this.lightningArmed=e.storm&&e.cloudDarkness>=jA,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(),oi.dispose(t);this.decorGroups.clear(),this.streetlightLights.clear();for(const t of e){const i=oi.build(t,t.lit??!1);this.scene.add(i),this.decorGroups.set(t.id,i),t.kind==="streetlight"&&this.addStreetlightLight(t.id,i),this.loadDecorModel(t,this.decorModelToken)}this.celestialLight.castShadow=this.decorGroups.size>0||this.bodySystem.any}}setDecorModelProvider(e){this.decorModelProvider=e;const t=this.decorObjects;this.decorObjects=[],this.setDecor(t)}get currentDecorModelCredits(){return[...this.decorModelCredits.values(),...this.bodySystem.modelCredits]}get bodyGround(){const{x:e,z:t}=this.bodyOrigin,i=this.groundYUnder(e,t);return{heightAt:(n,s)=>this.groundYUnder(e+n,t-s)-i}}setBodies(e,t=0,i=e.map(r=>r.id),n=[],s){const{x:r,z:o}=this.bodyOrigin,l=this.scatteredSky;this.bodySystem.set(e,{originX:r,originZ:o,originGroundY:this.groundYUnder(r,o),eye:this.camera.position,groundYAt:(h,d)=>this.groundYUnder(h,d),wind:s,light:this.plumeLight(),occluders:[...this.decorGroups.values()],transmittance:(h,d,u)=>this.transmittanceTo(h,d,u)},t,l?(h,d)=>l.relativeOfLuminance(h,d):void 0,i),this.bodySystem.setSmoke(n,t),this.bodySystem.any&&(this.celestialLight.castShadow=!0),this.fitShadowToBodies();const c=this.bodySystem.furthestFrom(this.camera.position)*1.2;c>this.camera.far&&(this.camera.far=c,this.camera.updateProjectionMatrix())}plumeLight(){const e=this.celestialLight.color,t=this.celestialLight.intensity*.5,i=this.skyLight.color,n=this.skyLight.groundColor,s=this.skyLight.intensity,r=(o,l,c)=>(o*t+(l+c)/2*s)/Math.PI;return[r(e.r,i.r,n.r),r(e.g,i.g,n.g),r(e.b,i.b,n.b)]}bodyOutline(e,t){return this.bodySystem.outlineOf(e,t)}documentUrl;modelUrl(e){return e.url?this.documentRelative(e.url):void 0}documentRelative(e){if(e.startsWith("data:"))return e;const t=this.documentUrl??(typeof location>"u"?void 0:location.href);return t?new URL(e,t).href:e}async loadBodyModel(e){const t=e.url?void 0:e.id?await this.decorModelProvider.entry(e.id):void 0,i=this.modelUrl(e)??t?.url,n=e.credit??t?.credit;if(!(!i||!n))return{scene:await xg(i),credit:n,headingOffsetDeg:e.headingOffsetDeg??t?.headingOffsetDeg}}async loadDecorModel(e,t){const i=e.model;if(!(!i||!oi.usesModel(e)))try{const n=i.url?void 0:i.id?await this.decorModelProvider.entry(i.id):void 0,s=this.modelUrl(i)??n?.url,r=i.credit??n?.credit;if(!s||!r)return;const o=await xg(s);if(t!==this.decorModelToken)return;const l=this.decorGroups.get(e.id);if(!l)return;pn.reflectOn(o),oi.applyModel(l,e,o,{headingOffsetDeg:i.headingOffsetDeg??n?.headingOffsetDeg,depictedSizeM:n?.sizeM}),this.decorModelCredits.set(e.id,r),this.render()}catch(n){console.warn(`Keeping the built-in shape for decor "${e.id}":`,n)}}updateDecorAnchoring(e,t,i=0){this.decorReferencePose=e,this.decorCurrentPose=t,this.decorTime=i;const n=e?.lat!==void 0&&e.lng!==void 0&&t?.lat!==void 0&&t?.lng!==void 0?li(e.lat,e.lng,t.lat,t.lng):{x:0,z:0},s=this.decorObjects.find(c=>c.observerSide!==void 0&&Ua(c.kind));if(this.terrainMesh&&this.terrainOrigin&&t?.lat!==void 0&&t.lng!==void 0){const c=li(this.terrainOrigin.lat,this.terrainOrigin.lng,t.lat,t.lng);this.terrainMesh.position.x=c.x-(s?0:this.gaitOffset.eastM),this.terrainMesh.position.z=c.z+(s?0:this.gaitOffset.northM),this.roadSystem.group.position.copy(this.terrainMesh.position)}s||(n.x-=this.gaitOffset.eastM,n.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=oi.occupantView(s),h=-(s.headingDeg??0)*en,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+n.x,p=-s.northM+n.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*en,-(c.headingDeg+this.indoorLookYawDeg)*en,0,"YXZ")}this.bodyOrigin={x:n.x+r.x,z:n.z+r.z},this.placeShadowFrustum();for(const c of this.decorObjects){const h=this.decorGroups.get(c.id);if(!h)continue;const d=vr(c,i),u=d.eastM+n.x+r.x,f=-d.northM+n.z+r.z,p=this.terrainMesh,v=`${p?.geometry.uuid}:${(u-(p?.position.x??0)).toFixed(3)}:${(f-(p?.position.z??0)).toFixed(3)}:${(p?.position.y??0).toFixed(3)}:${d.headingDeg}:${d.altitudeM}`;if(h.userData.footprintKey!==v&&(h.userData.footprintGroundY=this.groundUnderFootprint(c,u,f,d.headingDeg,d.altitudeM),h.userData.footprintKey=v),h.position.set(u,h.userData.footprintGroundY+d.altitudeM,f),c.kind==="crop"){const m=Math.hypot(u,f);h.visible=m<=FA}if(d.headingDeg!==void 0&&(h.rotation.y=-d.headingDeg*en),c.kind==="crop"&&h.visible){const m=this.terrainMesh,g=[m?.geometry.uuid,u-(m?.position.x??0),f-(m?.position.z??0),h.position.y-(m?.position.y??0),d.headingDeg,d.altitudeM].map(y=>typeof y=="number"?y.toFixed(4):y).join(":");h.userData.cropGroundKey!==g&&(oi.fitCropToGround(h,(y,M)=>this.groundYUnder(y,M)+d.altitudeM),h.userData.cropGroundKey=g)}o=Math.max(o,h.position.distanceTo(this.camera.position))}const l=Math.max(xc*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 i=this.terrainMesh;return i?i.position.y+this.groundYOfPatch(i,e-i.position.x,t-i.position.z):jd}groundYOfPatch(e,t,i){const n=e.geometry.getAttribute("position"),s=Math.round(Math.sqrt(n.count));if(s<2||s*s!==n.count)return jd;const r=n.getX(0),o=n.getX(s-1),l=n.getZ(0),c=n.getZ((s-1)*s),h=Wa((t-r)/(o-r)*(s-1),0,s-1),d=Wa((i-l)/(c-l)*(s-1),0,s-1);if(!Number.isFinite(h)||!Number.isFinite(d))return jd;const u=Math.min(Math.floor(h),s-2),f=Math.min(Math.floor(d),s-2),p=h-u,v=d-f,m=(x,E)=>n.getY(x*s+E),g=m(f,u),y=m(f,u+1),M=m(f+1,u),b=m(f+1,u+1);return p+v<=1?g+(y-g)*p+(M-g)*v:b+(M-b)*(1-p)+(y-b)*(1-v)}groundUnderFootprint(e,t,i,n,s=0){return oi.groundUnderFootprint(e,t,i,n,(r,o)=>this.groundYUnder(r,o),s)}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}medium;setMedium(e,t,i,n){const s=e&&t!==void 0&&t>0&&i!==void 0&&i>0?{kind:e.kind,iso:n??e.iso,autoExposure:e.autoExposure===!0,exposureSeconds:t,fNumber:i}:void 0;JSON.stringify(s)!==JSON.stringify(this.medium)&&(this.medium=s,this.render())}applyMedium(){const e=this.medium,t=Math.max(this.relativeScale,1e-30);if(!e){$i.uMedium.value=0;return}$i.uMedium.value=e.kind==="negative"?1:e.kind==="slide"?2:3;const i=e.autoExposure?this.scatteredSky?.sceneAdaptation:void 0;$i.uMediumExposure.value=i!==void 0&&i>0?1/(t*i):.065*e.exposureSeconds*e.iso/(e.fNumber*e.fNumber*t)}grain;lampBloomRadiusRad(){if(!this.grain)return;const e=this.camera.fov*Math.PI/180,t=this.grain.frameHeightMm/(2*Math.tan(e/2)),i=Math.max(1,this.renderer.getDrawingBufferSize(this.bloomSize).y);return Math.max(this.grain.detailUm*.001/t,e/i)}bloomSize=new be;updateDecorLitState(e,t=0){const i=this.lampBloomRadiusRad();for(const n of this.decorObjects){const s=this.decorGroups.get(n.id);if(s&&n.lights?.length&&oi.setLights(s,n.lights,e,s.position.distanceTo(this.camera.position),t,this.relativeScale,i),n.kind!=="streetlight"&&n.kind!=="vehicle")continue;const r=this.decorGroups.get(n.id);if(!r)continue;const o=Kc(n,e);oi.setLit(r,n.kind,o,this.relativeScale);const l=this.streetlightLights.get(n.id);l&&(l.visible=o)}}addStreetlightLight(e,t){const i=oi.bodyOf(t),n=i.children.find(r=>r.userData.emissive);if(!n)return;const s=new g1(16764006,Dg*this.relativeScale,EA);s.position.copy(n.position).multiply(i.scale),s.castShadow=!0,s.shadow.mapSize.set(512,512),s.shadow.bias=-.002,t.add(s),this.streetlightLights.set(e,s)}setAstronomy(e){(!this.lastAstronomy||Math.abs(this.lastAstronomy.sun.altitudeDeg-e.sun.altitudeDeg)>2)&&(this.surroundings=void 0,this.scatteredSky?.resetSurroundings()),this.lastAstronomy=e,this.scatteredSky?.update(this.scatteredSkyState(e)),this.skyHoldUntilMs===void 0&&(this.skyHoldUntilMs=performance.now()+Cg,this.onFirstFrameHold?.(!0),setTimeout(()=>this.render(),Cg+20)),this.pumpScatteredSky(),this.lastSunPosition=e.sun,this.buildSky(e.sun),this.buildGround();const t=ur(e.sun.altitudeDeg,this.instrumentMagnitudeGain);this.buildStars(e.stars,t),this.placeBodies(e,t),this.buildIceHalos(e.sun,e.moon),this.buildRainbow(e.sun,e.moon),this.applySkyColours(e),this.syncAnimationLoop(),this.render()}static relativeSkyOf(e,t){const i=r=>{const o=Hn.luminanceOf(r);if(!(o>0))return[0,0,0];const l=_e.relativeOfResponse(o)/o;return[r[0]*l,r[1]*l,r[2]*l]},n=i(e.zenith),s=i(e.horizon);return{zenith:n,horizon:s,airlight:s,skyIrradiance:[n[0]*Math.PI,n[1]*Math.PI,n[2]*Math.PI],scale:t}}placeBodies(e,t){this.bodiesScale=this.relativeScale,this.setBodyMesh("sun",e.sun,zo,new se(1,.96,.88),e.sun.magnitude),this.setMoonMesh(e.moon,t),this.buildPlanets(e.planets,t),this.buildComet(e.comet,t),this.buildNovae(e.novae??[],t)}bodiesScale=0;applySkyColours(e){this.skyColoursStale=!1,this.bodiesScale!==this.relativeScale&&(this.placeBodies(e,ur(e.sun.altitudeDeg,this.instrumentMagnitudeGain)),this.applyDazzleStrength(),this.buildIceHalos(e.sun,e.moon),this.buildRainbow(e.sun,e.moon));const t=this.scatteredSky?.ambient??Gt.relativeSkyOf(wf(e.sun.altitudeDeg),this.relativeScale),i=t,n=this.lightUnderClouds(e),s=r=>n?[0,1,2].map(o=>r[o]*n.through+n.radiance[o]*(1-n.through)):[r[0],r[1],r[2]];this.baseFogColor=[i.horizon[0],i.horizon[1],i.horizon[2]],this.airlight=s(i.airlight),this.skyMesh&&this.skyGradientMaterial&&(this.skyMesh.material=this.scatteredSky?.ready?this.scatteredSky.material:this.skyGradientMaterial),this.updateCelestialLight(e,t),this.updateCloudLighting(e.sun,this.baseFogColor),rt.setEye(this.scatteredSky?.rodShare??0,this.relativeScale),this.updateTwinkle(this.twinkleSeconds);for(const r of this.streetlightLights.values())r.intensity=Dg*this.relativeScale;this.buildSkyGlow(e,i.zenith),this.applyAir(),this.buildLunarDiffraction(e.moon)}reflections;sceneVersion=0;reflectionTimer;buildLunarDiffraction(e){const t=this.scatteredSky?.ready?this.scatteredSky:void 0;if(e.altitudeDeg<-.5||!t){this.lunarDiffraction?.show(void 0),this.lunarDiffractionKey="";return}const i=this.weather.relativeHumidity,n=(i===void 0?ke.DEFAULT_AEROSOL_OPTICAL_DEPTH:Ns.opticalDepth(i))*ke.aerosolDensity(this.siteElevationM+this.observerElevationM),s=this.cloudTransmission(e),r=-Math.log(Math.max(this.cloudTransmission(e,!0),1e-4)),o=vt.aureoleScale(n,vt.airMass(e.altitudeDeg))*s,l=vt.coronaScale(r),c=vt.illuminanceOf(e.magnitude),h=[e.altitudeDeg.toFixed(1),e.azimuthDeg.toFixed(1),e.magnitude.toFixed(2),o.toExponential(2),l.toExponential(2),Math.log10(Math.max(t.adaptation,1e-12)).toFixed(2)].join(":");if(h===this.lunarDiffractionKey)return;this.lunarDiffractionKey=h,this.lunarDiffraction||(this.lunarDiffraction=new Bp,this.celestialGroup.add(this.lunarDiffraction.object));const d=vt.profile(vt.HAZE_COARSE_MODE),u=vt.profile(vt.CLOUD_DROPLETS),f=qm(e.altitudeDeg),p=new Float32Array(vt.STEPS*3);let v=0;for(let M=0;M<vt.STEPS;M++){const b=M*3,x=[0,1,2].map(I=>c*f[I]*(o*d[b+I]+l*u[b+I])),E=Hn.shown(x,Hn.luminanceOf(x),(I,w)=>t.relativeOfLuminance(I,w));p.set(E,b),v=Math.max(v,Hn.response(E))}const{x:m,y:g,z:y}=fi(e.altitudeDeg,e.azimuthDeg,1);this.lunarDiffraction.show(v>1/200?{x:m,y:g,z:y}:void 0,p)}applyAir(){this.scene.fog instanceof Jr||(this.scene.fog=new Jr),this.scene.fog.setAir(this.air,this.siteElevationM,this.airlight)}airlight=[0,0,0];transmittanceTo(e,t,i){const n=this.camera.position;return this.air.transmittance(this.siteElevationM+n.y,this.siteElevationM+t,Math.hypot(e-n.x,t-n.y,i-n.z))}setSiteElevation(e){Math.abs(e-this.siteElevationM)<1||(this.siteElevationM=e,this.applyAir(),this.lastAstronomy&&this.scatteredSky?.update(this.scatteredSkyState(this.lastAstronomy)))}scatteredSkyState(e){return{altitudeM:this.siteElevationM+this.observerElevationM+1.6,sun:{altitudeDeg:e.sun.altitudeDeg,azimuthDeg:e.sun.azimuthDeg,magnitude:e.sun.magnitude},moon:{altitudeDeg:e.moon.altitudeDeg,azimuthDeg:e.moon.azimuthDeg,magnitude:e.moon.magnitude,phaseAngleDeg:We.phaseAngleOf(e.moon.phase.illuminatedFraction)}}}pumpScatteredSky(){const e=this.scatteredSky;!e||e.tables.ready||this.scatteredSkyFrameId!==null||this.contextReleased||(this.scatteredSkyFrameId=requestAnimationFrame(()=>{this.scatteredSkyFrameId=null,!this.contextReleased&&(e.advance(this.skyHoldUntilMs?DA:IA),this.pumpScatteredSky())}))}cancelScatteredSkyPump(){this.scatteredSkyFrameId!==null&&(cancelAnimationFrame(this.scatteredSkyFrameId),this.scatteredSkyFrameId=null)}setSatellites(e){if(e.length===0&&!this.satelliteField?.count)return;this.satelliteField||(this.satelliteField=new H5(Wd),this.celestialGroup.add(this.satelliteField.object));const t=ur(this.lastSunPosition?.altitudeDeg??-90,this.instrumentMagnitudeGain);this.satelliteField.set(e,t,i=>this.cloudTransmission(i),(i,n)=>this.arrivingIlluminance(i,n,1)),this.render()}pickSatelliteAt(e,t){if(!this.satelliteField?.count)return;this.aimAtScreenPoint(this.raycaster,e,t);const i=Math.cos(Tg*this.camera.fov*Math.PI/180),n=this.satelliteField.nearest(this.raycaster.ray.direction,i);return n&&this.groundHides(e,t)?void 0:n}updateCelestialLight(e,t){const i=this.relativeScale,n=e.sun.altitudeDeg>=Ec,s=!n&&e.moon.altitudeDeg>=Ec,r=n?e.sun:e.moon,o=[0,0,0],l=Math.max(0,Math.sin(Math.max(r.altitudeDeg,0)*en)),c=n||s?this.cloudTransmission(r):1,h=-Math.log(Math.max(c,1e-6)),d=Math.max(0,1/(1+.1125*h)-c),u=[0,0,0];if(n||s){const y=vt.illuminanceOf(r.magnitude)*i,M=this.air.transmittanceFromSpace(this.siteElevationM+this.observerElevationM,r.altitudeDeg);for(let I=0;I<3;I++)o[I]=y*M[I]*c,u[I]=y*M[I]*d*l,this.cloudBeam[I]=y*M[I];const{x:b,y:x,z:E}=fi(r.altitudeDeg,r.azimuthDeg,1);this.cloudBeamDirection.set(b,x,E)}else this.cloudBeam.fill(0);const f=this.surroundings;if(f)this.skyLight.color.setRGB(f.up[0]*i,f.up[1]*i,f.up[2]*i),this.skyLight.groundColor.setRGB(f.down[0]*i,f.down[1]*i,f.down[2]*i);else{const y=this.skyCloudTransmission(),M=t.skyIrradiance,b=[0,1,2].map(E=>M[E]*y+u[E]);this.skyLight.color.setRGB(b[0],b[1],b[2]);const x=Ve.GROUND_ALBEDO;this.skyLight.groundColor.setRGB(x*(b[0]+o[0]*l),x*(b[1]+o[1]*l),x*(b[2]+o[2]*l))}if(this.skyLight.intensity=1,!n&&!s){this.celestialLight.intensity=0;return}const{x:p,y:v,z:m}=fi(r.altitudeDeg,r.azimuthDeg,1);this.lightDirection.set(p,v,m),this.placeShadowFrustum();const g=Math.max(o[0],o[1],o[2],1e-30);this.celestialLight.color.setRGB(o[0]/g,o[1]/g,o[2]/g),this.celestialLight.intensity=g,this.celestialLight.castShadow=this.decorGroups.size>0||this.bodySystem.any}lightDirection=new C(0,1,0);placeShadowFrustum(){const e=this.lightDirection,t=this.celestialLight.shadow.camera,i=(t.right-t.left)/this.celestialLight.shadow.mapSize.x,n=this.shadowAxisX.crossVectors(this.shadowUp,e);n.lengthSq()<1e-8&&n.set(1,0,0),n.normalize();const s=this.shadowAxisY.crossVectors(e,n).normalize(),r=this.shadowWorld.set(this.bodyOrigin.x,0,this.bodyOrigin.z),o=c=>{const h=r.dot(c)/i;return(h-Math.round(h))*i},l=this.celestialLightTarget.position.set(0,0,0).addScaledVector(n,o(n)).addScaledVector(s,o(s));this.celestialLightTarget.updateMatrixWorld(),this.celestialLight.position.copy(l).addScaledVector(e,this.shadowLightDistanceM)}fitShadowToBodies(){const e=this.bodySystem.reachFrom(this.camera.position),t=Math.min(vA,Math.max(tr,Math.ceil(e*1.25/20)*20));if(t===this.shadowHalfExtentM)return;this.shadowHalfExtentM=t;const i=this.celestialLight.shadow,n=i.camera;n.left=-t,n.right=t,n.top=t,n.bottom=-t;const s=Math.max(Bo,t*(Bo/tr));this.shadowLightDistanceM=Math.max(dn,s+10),n.near=this.shadowLightDistanceM-s,n.far=this.shadowLightDistanceM+s,n.updateProjectionMatrix(),i.bias=-.03/(2*s);const r=t>2*tr?2048:1024;i.mapSize.x!==r&&(i.mapSize.set(r,r),i.map?.dispose(),i.map=null),this.placeShadowFrustum()}shadowHalfExtentM=tr;shadowLightDistanceM=dn;shadowUp=new C(0,1,0);shadowAxisX=new C;shadowAxisY=new C;shadowWorld=new C;skyCloudTransmission(){let e=this.cloudTransmission({altitudeDeg:90,azimuthDeg:0}),t=1;for(const i of[20,45,70]){const n=i*en,s=Math.sin(n)*Math.cos(n)*2;for(let r=0;r<360;r+=60)e+=s*this.cloudTransmission({altitudeDeg:i,azimuthDeg:r}),t+=s}return e/t}cloudBeam=[0,0,0];cloudBeamDirection=new C(0,1,0);get relativeScale(){return this.scatteredSky?.relativeScale??1/_e.semiSaturation(_e.DAYLIGHT_ANCHOR_CD_M2)}setMeteorShower(e,t,i){this.meteorSystem||(this.meteorSystem=new wi,this.celestialGroup.add(this.meteorSystem.object)),this.meteorSystem.setShower(e,t,i)}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,this.grain=e.detailUm!==void 0&&e.frame?{detailUm:e.detailUm,frameHeightMm:e.frame.heightMm}:void 0;const t=Mt.starPointsOf(e),i=Mt.flareArtifactsOf(e);t===this.starPoints&&i===this.lensFlareArtifactIntensity||(this.starPoints=t,this.lensFlareArtifactIntensity=i,this.lensFlare&&(this.lensFlare.uniforms.uStarPoints.value=t,this.lensFlare.uniforms.uFlareIntensity.value=i),this.render())}setInstrumentGain(e,t=!1){this.instrumentMagnitudeGain=Number.isFinite(e)?e:0,this.scatteredSky?.setInstrument(t,this.instrumentMagnitudeGain)}render(){this.restatingExposure||(this.sceneVersion++,this.frameDirty=!0,this.resolution.noteChange(performance.now()),!(this.animationFrameId!==null||this.framesDriven||this.flushFrameId!==null)&&(this.flushFrameId=requestAnimationFrame(()=>{this.flushFrameId=null,this.drawIfDirty()})))}drawIfDirty(){if(!(!this.frameDirty||this.contextReleased)){if(this.skyHoldUntilMs){if(!this.firstFrameReady()&&performance.now()<this.skyHoldUntilMs)return;this.skyHoldUntilMs=null,this.iceHalos?.setUrgent(!1),this.onFirstFrameHold?.(!1)}if(this.skyColoursStale&&this.lastAstronomy&&this.applySkyColours(this.lastAstronomy),this.compileBeforeNextDraw){this.compileBeforeNextDraw=!1;const e=this.compileOffThread().then(()=>{this.compiling===e&&(this.compiling=void 0,this.render())});this.compiling=e;return}if(!this.compiling){this.frameDirty=!1,this.refreshReflections(),this.resolution.beginDrawing();try{this.renderOnce()}finally{this.resolution.endDrawing()}this.developingExposure&&this.startExposure()}}}compileBeforeNextDraw=!1;compiling;static COMPILE_WAIT_MS=1500;compileOffThread(){const e=this.renderer.compile(this.scene,this.camera);if(!this.renderer.extensions.get("KHR_parallel_shader_compile"))return Promise.resolve();const t=this.renderer.properties,i=performance.now()+Gt.COMPILE_WAIT_MS;return new Promise(n=>{const s=()=>{if(this.contextReleased)return n();for(const r of e){const o=t.get(r)?.currentProgram;(!o||o.isReady())&&e.delete(r)}e.size===0||performance.now()>i?n():setTimeout(s,10)};s()})}compileNextFrameOffThread(){this.compileBeforeNextDraw=!0}contextReleased=!1;releaseContext(){this.contextReleased||(this.contextReleased=!0,this.stopTwinkle(),this.cancelFlush(),this.cancelExposure(),this.compiling=void 0,this.cancelScatteredSkyPump(),this.renderer.forceContextLoss())}restoreContext(){this.contextReleased&&(this.contextReleased=!1,this.renderer.forceContextRestore(),this.scatteredSky?.invalidate(),this.pumpScatteredSky(),this.compileNextFrameOffThread(),this.syncAnimationLoop(),this.render())}cancelFlush(){this.flushFrameId!==null&&(cancelAnimationFrame(this.flushFrameId),this.flushFrameId=null)}frame(e){if(this.animationsRunning){const t=this.lastFrameTimeMs===void 0?0:e-this.lastFrameTimeMs;this.lastFrameTimeMs=e,this.hasAnimations()&&this.animate(e,t);const i=this.resolution.ratioFor(e,t);i!==this.renderer.getPixelRatio()&&this.applyPixelRatio(i)}this.drawIfDirty()}refreshReflections(){this.reflections??=new pn(this.renderer);const e=[...this.compassSprites,...this.lensFlare?[this.lensFlare.mesh]:[],...[...this.glareSprites.values()].map(s=>s.mesh)],t=[...this.starTiers.map(s=>s.points),...[...this.bodyMeshes.values()].filter(s=>s instanceof Ps),...[this.rainSystem?.points,this.precipitationPoints,this.rainSplashSystem?.points].filter(s=>s!==void 0)],i=this.relativeScale,n=this.reflections.refresh(this.renderer,this.scene,this.camera.position,this.bodySystem.reflectors,e,[...this.decorGroups.values()],this.sceneVersion,t,s=>this.measureSurroundings(s,i));n===void 0||this.reflectionTimer||(this.reflectionTimer=setTimeout(()=>{this.reflectionTimer=void 0,this.frameDirty=!0,!(this.animationFrameId!==null||this.framesDriven||this.flushFrameId!==null)&&(this.flushFrameId=requestAnimationFrame(()=>{this.flushFrameId=null,this.drawIfDirty()}))},n))}measureSurroundings(e,t){const i=this.lastAstronomy;if(!i)return;this.probeIrradiance??=new rl;const n=[i.sun,i.moon].filter(s=>s.altitudeDeg>-2).map(s=>fi(s.altitudeDeg,s.azimuthDeg,1));this.probeIrradiance.measure(this.renderer,e,n,s=>{const r=u=>u.map(f=>f/t),o=this.surroundings,l={up:r(s.up),down:r(s.down)},c=(u,f)=>u.some((p,v)=>Math.abs(p-f[v])>.03*Math.max(Math.abs(p),Math.abs(f[v]),1e-12)),h=!o||c(o.up,l.up)||c(o.down,l.down);h&&(this.surroundings=l);const d=this.scatteredSky?.adaptToSurroundings(Math.exp(s.logAverage)/t)??!1;!h&&!d||(this.skyColoursStale=!0,this.render())})}lightUnderClouds(e){const t=this.surroundings;if(!t)return;const i=e.sun.altitudeDeg>=Ec?e.sun:e.moon.altitudeDeg>=Ec?e.moon:void 0;if(!i)return;const n=this.relativeScale/Math.PI;return{through:this.cloudTransmission(i),radiance:[t.up[0]*n,t.up[1]*n,t.up[2]*n]}}probeIrradiance;surroundings;animate(e,t){const i=Math.min(t/1e3,ZA);this.twinkleSeconds=e/1e3,this.updateTwinkle(this.twinkleSeconds),this.updatePrecipitation(e/1e3,i),this.updateRain(i),this.lensFlare&&(this.lensFlare.uniforms.uTime.value=e/1e3),this.developingExposure||(this.frameDirty=!0)}setMaxPixelRatio(e){this.resolution.maximum=e,this.renderer.getPixelRatio()>this.resolution.maximum&&this.applyPixelRatio(this.resolution.maximum)}applyPixelRatio(e){this.renderer.setPixelRatio(e),this.renderer.setSize(this.cssSize.width,this.cssSize.height,!1),this.frameDirty=!0}setExposure(e,t){const i=t?Math.max(1,Math.round(e)):1;if(i===this.exposureInstants&&(i===1||t===this.exposureInstantAt)){this.exposureInstantAt=t;return}this.exposureInstants=i,this.exposureInstantAt=t,i===1&&(this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0),this.render()}renderOnce(e){if(this.onMapSubjectBounds){const r=this.mapSubjectBounds();e?this.exposureSubjectBounds.push(...r):this.onMapSubjectBounds(r)}const t=this.usableEquidistantPass();this.phenomena.setCloudLayers(this.layeredClouds?.volumes??[]),this.phenomena.place(this.camera,(r,o,l)=>this.directionAtScreenPoint(r,o,l),r=>this.screenPointOf(r)),this.references.place(this.camera);const i=Math.max(this.phenomena.furthestM,this.references.furthestM)*1.2;i>this.camera.far&&(this.camera.far=i,this.camera.updateProjectionMatrix()),$i.uRodShare.value=this.scatteredSky?.rodShare??0,$i.uRelativeScale.value=this.relativeScale,this.applyMedium();const n=this.references.any||this.phenomena.any||this.compassSprites.some(r=>r.visible);$i.uHasOverlay.value=n?1:0;const s=n?r=>this.renderOverlayPasses(r):void 0;if(this.skyGlow?.setDestinationEncoded(!1),!t){this.updateLensFlarePosition();const r=this.usableDepthOfFieldPass();r?r.render(this.renderer,this.scene,this.camera,s,e):this.usableFinishPass().render(this.renderer,this.scene,this.camera,s,void 0,e);return}t.render(this.renderer,this.scene,this.camera,this.camera.fov,()=>this.updateLensFlarePosition(),s,r=>{this.lensFlare&&(this.lensFlare.mesh.visible=r?!1:this.sunVisible)},()=>this.renderDazzleOnResample(),e)}renderOverlayPasses(e=this.camera){this.renderReferencesPass(e),this.renderPhenomenaPass(e),this.renderHudPass(e)}renderHudPass(e){if(!this.compassSprites.some(n=>n.visible))return;const t=this.renderer.autoClear,i=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,e.layers.set(Eg),this.renderer.render(this.scene,e),e.layers.set(0),this.renderer.autoClear=t,this.renderer.shadowMap.autoUpdate=i}renderReferencesPass(e){if(!this.references.any)return;const t=this.renderer.autoClear,i=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,e.layers.set(ob),this.renderer.render(this.scene,e),e.layers.set(0),this.renderer.autoClear=t,this.renderer.shadowMap.autoUpdate=i}setReferences(e,t){this.references.set(e.map(i=>{const n=this.documentRelative(i.src);return n===i.src?i:{...i,src:n}}),void 0,t)}referenceAspect(e){return this.references.aspectOf(e)}directionAt(e,t){return this.directionAtScreenPoint(e,t,new C)}referenceFailedToLoad(e){return this.references.failedToLoad(this.documentRelative(e))}setReferencesShown(e){this.references.setShown(e),this.render()}setReferenceView(e,t){this.references.setView(e,t),this.render()}renderPhenomenaPass(e){if(!this.phenomena.any)return;const t=this.renderer.autoClear,i=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,this.renderer.clearDepth();for(const n of this.decorObjects){const s=this.decorGroups.get(n.id);s&&Gt.markDecorDepth(s,n.kind!=="crop")}e.layers.set(Gd),this.scene.overrideMaterial=this.decorDepthMaterial,this.renderer.render(this.scene,e),this.scene.overrideMaterial=null,e.layers.set(ab),this.renderer.render(this.scene,e),e.layers.set(0),this.renderer.autoClear=t,this.renderer.shadowMap.autoUpdate=i}decorDepthMaterial=new Dn({colorWrite:!1});static markDecorDepth(e,t){e.traverse(i=>{if(!(i instanceof Ie))return;const n=Array.isArray(i.material)?i.material[0]:i.material;t&&n.depthWrite!==!1&&n.blending!==Vi?i.layers.enable(Gd):i.layers.disable(Gd)})}startExposure(){this.cancelExposure(),this.exposureSubjectBounds=[];const e=this.renderer.getDrawingBufferSize(new be),t=Math.max(1,Math.round(e.x)),i=Math.max(1,Math.round(e.y));this.exposureAccumulation||(this.exposureAccumulation=new o_(t,i)),this.exposureAccumulation.resize(t,i),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 i=1/this.exposureInstants;this.resolution.beginDrawing();const n=performance.now()+Gt.EXPOSURE_BUDGET_MS,s=Gt.exposureInstantsPerFrame(t.instantTarget.scene.width*t.instantTarget.scene.height);let r=0;do{this.restateAt(e,this.exposureInstantsDone);const o=this.compassSprites.map(l=>l.visible);for(const l of this.compassSprites)l.visible=!1;try{this.renderOnce(t.instantTarget)}finally{this.compassSprites.forEach((l,c)=>{l.visible=o[c]})}t.add(this.renderer,i),this.exposureInstantsDone++,r++}while(this.exposureInstantsDone<this.exposureInstants&&performance.now()<n&&r<s);this.restateAt(e,0),this.presentExposure(),this.resolution.endDrawing(),this.exposureInstantsDone<this.exposureInstants&&(this.exposureFrameId=requestAnimationFrame(()=>this.developExposure()))}presentExposure(){if($i.uRodShare.value=this.scatteredSky?.rodShare??0,$i.uHasOverlay.value=1,$i.uRelativeScale.value=this.relativeScale,this.applyMedium(),this.exposureAccumulation?.develop(this.renderer,this.exposureInstants/this.exposureInstantsDone),this.onMapSubjectBounds?.(this.exposureSubjectBounds),!this.compassSprites.some(s=>s.visible))return;const e=new Bs,t=new Xn(-1,1,1,-1,0,2),i=_c/(Rg*Math.tan(Pg*en/2));for(const s of this.compassSprites){if(!s.visible)continue;const r=s.getWorldPosition(new C).sub(this.camera.position).normalize(),o=this.screenPointOf(r);if(!o)continue;const l=new To(s.material);l.position.set(o.ndcX,o.ndcY,-1),l.scale.set(i/this.camera.aspect,i,1),e.add(l)}const n=this.renderer.autoClear;this.renderer.autoClear=!1;try{this.renderer.render(e,t)}finally{this.renderer.autoClear=n}}onMapSubjectBounds;exposureSubjectBounds=[];static MAP_SUBJECT_NEAREST_M=8;mapSubjectBounds(){const e=[],t=new Zi,i=new C,n=this.decorObjects.filter(r=>r.track?.length||r.kind==="aircraft"||r.kind==="vehicle").map(r=>this.decorGroups.get(r.id)),s=this.bodySystem.reflectors.map(r=>r.holder);for(const r of[...n,...s]){if(!r?.visible||(t.setFromObject(r),t.isEmpty())||t.distanceToPoint(this.camera.position)<Gt.MAP_SUBJECT_NEAREST_M)continue;let o=1/0,l=-1/0,c=1/0,h=-1/0;for(const d of[t.min.x,t.max.x])for(const u of[t.min.y,t.max.y])for(const f of[t.min.z,t.max.z]){i.set(d,u,f).sub(this.camera.position).normalize();const p=this.screenPointOf(i);if(!p)continue;const v=(p.ndcX+1)/2,m=(1-p.ndcY)/2;o=Math.min(o,v),l=Math.max(l,v),c=Math.min(c,m),h=Math.max(h,m)}Number.isFinite(o)&&e.push({x:o,y:c,width:l-o,height:h-c})}return e}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 be),i=Math.max(1,Math.round(t.x)),n=Math.max(1,Math.round(t.y));return this.depthOfFieldPass||(this.depthOfFieldPass=new al(i,n)),this.depthOfFieldPass.resize(i,n),this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.depthOfFieldPass}usableFinishPass(){const e=this.renderer.getDrawingBufferSize(new be);return this.finishPass?this.finishPass.resize(e.x,e.y):this.finishPass=new Up(e.x,e.y),this.finishPass}usableEquidistantPass(){if(this.projectionKind!=="equidistant")return;const e=this.renderer.getDrawingBufferSize(new be);return this.equidistantPass?this.equidistantPass.resize(e.x,e.y):this.equidistantPass=new Si(e.x,e.y),this.equidistantPass}aimAtScreenPoint(e,t,i){const n=this.projectionKind==="equidistant"?this.equidistantPass:void 0;if(!n){e.setFromCamera(new be(t,i),this.camera);return}const s=n.directionFor(t,i,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 C)}directionAtScreenPoint(e,t,i){return this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),i.copy(this.ufoOcclusionRaycaster.ray.direction)}screenPointOf(e){this.camera.updateMatrixWorld();const t=this.screenPointScratch.copy(e).applyQuaternion(this.screenPointQuaternion.copy(this.camera.quaternion).invert()),i=this.renderer.getDrawingBufferSize(this.screenPointSize),n=i.x/Math.max(i.y,1);if(this.projectionKind==="equidistant"&&this.equidistantPass)return Si.ndcFor(t,this.camera.fov,n);if(t.z>=0)return;const s=Math.tan(this.camera.fov/2*en);return{ndcX:t.x/-t.z/(n*s),ndcY:t.y/-t.z/s}}screenPointScratch=new C;screenPointQuaternion=new Gi;screenPointSize=new be;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 i=this.lensFlareScratch.copy(this.sunWorldPosition).project(this.camera);e.uniforms.uLensPosition.value.set(i.x,i.y);const n=this.renderer.domElement.width,s=this.renderer.domElement.height;e.uniforms.uResolution.value.set(n,s),e.uniforms.uTanHalfFov.value=Math.tan(this.camera.fov*Math.PI/360)}renderDazzleOnResample(){const e=this.lensFlare;if(!e||!this.sunVisible)return;const t=this.sunVisibleFraction();if(t<=0)return;this.sunUnhiddenFraction=t,this.applyDazzleStrength();const i=this.screenPointOf(this.lensFlareScratch.copy(this.sunWorldPosition).sub(this.camera.position).normalize());if(!i)return;const n=this.renderer.getDrawingBufferSize(this.screenPointSize);e.uniforms.uLensPosition.value.set(i.ndcX,i.ndcY),e.uniforms.uResolution.value.set(n.x,n.y),e.uniforms.uEquidistant.value=1,e.uniforms.uHalfFovRad.value=this.camera.fov*Math.PI/360;const s=this.renderer.autoClear;this.renderer.autoClear=!1,e.mesh.visible=!0,e.mesh.layers.enable(Sg),this.camera.layers.set(Sg),this.renderer.render(this.scene,this.camera),this.camera.layers.set(0),e.mesh.visible=!1,e.uniforms.uEquidistant.value=0,this.renderer.autoClear=s}sunVisibleFraction(){this.raycastableDecor().length>0&&this.scene.updateMatrixWorld();let e=0;for(const t of Og)this.isSunOccluded(t[0],t[1])||e++;return e/Og.length}raycastableDecor(){const e=[];for(const t of this.decorObjects){if(t.kind==="crop")continue;const i=this.decorGroups.get(t.id);i&&e.push(i)}return e}isSunOccluded(e=0,t=0){const i=this.raycastableDecor();if(!this.groundMesh&&!this.terrainMesh&&i.length===0)return!1;const n=this.sunOcclusionDirectionScratch.copy(this.sunWorldPosition).sub(this.camera.position),s=n.length();if(n.normalize(),e!==0||t!==0){const o=Math.PI/180,l=this.sunOcclusionRightScratch.set(n.z,0,-n.x);l.lengthSq()<1e-9&&l.set(1,0,0),l.normalize();const c=this.sunOcclusionUpScratch.crossVectors(l,n).normalize();n.addScaledVector(l,e*o).addScaledVector(c,t*o).normalize()}if(this.groundBlocks(this.camera.position,n,s))return!0;if(i.length===0)return!1;this.sunOcclusionRaycaster.set(this.camera.position,n);const r=this.sunOcclusionRaycaster.intersectObjects(i,!0)[0];return r!==void 0&&r.distance<s}groundBlocks(e,t,i,n=0){const s=this.groundMesh;if(s&&t.y<0){const m=(s.position.y-e.y)/t.y;if(m>n&&m<i){const g=e.x+t.x*m-s.position.x,y=e.z+t.z*m-s.position.z;if(Math.hypot(g,y)<=this.groundRadius)return!0}}const r=this.terrainMesh;if(!r)return!1;const o=r.geometry.getAttribute("position"),l=Math.round(Math.sqrt(o.count));if(l<2||l*l!==o.count)return!1;const c=[r.position.x+o.getX(0),r.position.x+o.getX(l-1)],h=[r.position.z+o.getZ(0),r.position.z+o.getZ((l-1)*l)],d=Math.min(Math.abs(c[1]-c[0]),Math.abs(h[1]-h[0]))/(l-1);if(!(d>0))return!1;let u=n,f=i;for(const[m,g,y]of[[e.x,t.x,c],[e.z,t.z,h]]){const M=Math.min(y[0],y[1]),b=Math.max(y[0],y[1]);if(Math.abs(g)<1e-12){if(m<M||m>b)return!1;continue}const x=(M-m)/g,E=(b-m)/g;u=Math.max(u,Math.min(x,E)),f=Math.min(f,Math.max(x,E))}if(!(f>u))return!1;const p=Math.hypot(t.x,t.z),v=Math.min(4096,Math.max(8,Math.ceil((f-u)*p/(d/2))));for(let m=0;m<=v;m++){const g=u+(f-u)*m/v,y=e.x+t.x*g,M=e.y+t.y*g,b=e.z+t.z*g;if(M<=this.groundYUnder(y,b))return!0}return!1}setPhenomena(e,t){this.phenomena.set(e,t)}decorDistancesAt(e,t,i){this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=_g;let n,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(i)?n=n===void 0?l.distance:Math.max(n,l.distance):s=s===void 0?l.distance:Math.min(s,l.distance))}return{behindM:n,inFrontM:s}}pickBodyAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const i=[...this.hitAreas.entries()],n=this.raycaster.intersectObjects(i.map(([,s])=>s))[0];if(n&&!this.groundHides(e,t))return i.find(([,s])=>s===n.object)?.[0]}pickStarAt(e,t){if(this.namedStars.length===0)return;this.aimAtScreenPoint(this.raycaster,e,t);const i=this.raycaster.ray.direction,n=Math.cos(Tg*this.camera.fov*Math.PI/180);let s,r=n;for(const o of this.namedStars){const l=o.direction.dot(i);l>r&&(r=l,s={star:o.star,altitudeDeg:o.altitudeDeg})}return s&&this.groundHides(e,t)?void 0:s}groundHides(e,t){if(!this.terrainMesh&&!this.groundMesh)return!1;this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t);const i=this.ufoOcclusionRaycaster.ray;return this.groundBlocks(i.origin,i.direction,1/0,_g)}bodyScreenBox(e){const t=this.bodySystem.boxOf(e,this.bodyBoxScratch);if(!t)return;let i=1/0,n=1/0,s=-1/0,r=-1/0;for(let o=0;o<8;o++){const l=this.bodyCornerScratch.set(o&1?t.max.x:t.min.x,o&2?t.max.y:t.min.y,o&4?t.max.z:t.min.z),c=this.screenPointOf(l.sub(this.camera.position).normalize());if(!c)return;i=Math.min(i,c.ndcX),s=Math.max(s,c.ndcX),n=Math.min(n,c.ndcY),r=Math.max(r,c.ndcY)}return{minX:i,minY:n,maxX:s,maxY:r}}bodyBoxScratch=new Zi;bodyCornerScratch=new C;pickPlacedBodyAt(e,t){return this.aimAtScreenPoint(this.raycaster,e,t),this.bodySystem.pick(this.raycaster)}pickDecorAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const i=[...this.decorGroups.entries()],n=this.raycaster.intersectObjects(i.map(([,r])=>r),!0)[0];if(!n)return;let s=n.object;for(;s&&!i.some(([,r])=>r===s);)s=s.parent;return i.find(([,r])=>r===s)?.[0]}dispose(){this.stopTerrainFade(),this.stopTwinkle(),this.cancelFlush(),this.phenomena.clear(),this.references.disposeAll(),this.terrainBuildToken++,this.cancelScatteredSkyPump(),this.skyMesh&&this.skyGradientMaterial&&(this.skyMesh.material=this.skyGradientMaterial),this.scatteredSky?.dispose(),this.scatteredSky=void 0,this.disposeMesh(this.skyMesh),this.disposeMesh(this.groundMesh),this.disposeMesh(this.terrainMesh),this.roadSystem.dispose(),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.finishPass?.dispose(),this.depthOfFieldPass=void 0,this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0,this.cometTail?.dispose(),this.cometTail=void 0,this.satelliteField?.dispose(),this.satelliteField=void 0,this.lightningBolt?.dispose(),this.lightningBolt=void 0;for(const e of this.bodyMeshes.values())this.disposeMesh(e);this.bodyMeshes.clear(),this.novaKeys.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())oi.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;this.cancelFlush();const e=t=>{this.frame(t),this.animationFrameId=requestAnimationFrame(e)};this.animationFrameId=requestAnimationFrame(e)}setAnimationsRunning(e,t=!1){const i=e&&t;if(e===this.animationsRunning&&i===this.framesDriven)return;const n=this.animationsRunning;this.animationsRunning=e,this.framesDriven=i,e&&!n&&(this.lastFrameTimeMs=void 0,this.resolution.reset()),!e&&this.renderer.getPixelRatio()!==this.resolution.maximum&&this.applyPixelRatio(this.resolution.maximum),this.syncAnimationLoop(),(!e||this.frameDirty)&&this.render()}stopTwinkle(){this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}needsAnimationLoop(){return this.animationsRunning&&!this.framesDriven&&this.hasAnimations()}hasAnimations(){return this.starTiers.length>0||this.precipitationPoints!==void 0||this.rainSystem!==void 0||this.lensFlare!==void 0&&this.sunVisible}syncAnimationLoop(){this.needsAnimationLoop()?this.startTwinkle():this.stopTwinkle()}buildSky(e){const t=this.skyMesh?.geometry??new hi(xc,32,16),i=t.attributes.position,n=t.getAttribute("color")??new mt(new Float32Array(i.count*3),3);for(let r=0;r<i.count;r++){const{altitudeDeg:o,azimuthDeg:l}=h_(i.getX(r),i.getY(r),i.getZ(r)),c=b_(o,l,e.azimuthDeg,e.altitudeDeg);n.setXYZ(r,c[0],c[1],c[2])}if(n.needsUpdate=!0,this.skyMesh)return;t.setAttribute("color",n);const s=new Dn({vertexColors:!0,side:qt,fog:!1,depthWrite:!1});this.skyGradientMaterial=s,this.skyMesh=new Ie(t,s),this.skyMesh.renderOrder=-1,this.celestialGroup.add(this.skyMesh)}buildGround(){const e=Ag(this.observerElevationM);if(this.groundMesh&&e===this.groundRadius)return;this.disposeMesh(this.groundMesh),this.groundRadius=e;const t=new vp(this.groundRadius,48),i=new go({color:new se(Vd,Vd,Vd),fog:!0});Jr.fadeRim(i,this.groundRadius*.75,this.groundRadius),this.groundMesh=new Ie(t,i),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,t=!1){const i=`${e.altitudeDeg.toFixed(1)}:${e.azimuthDeg.toFixed(1)}:${Math.round(this.cloudOffsetM.x/10)}:${Math.round(this.cloudOffsetM.z/10)}:${Math.round(this.observerElevationM)}:`+Object.entries(this.cloudLayerOffsetsM).map(([r,o])=>`${r}=${Math.round(o.x/10)},${Math.round(o.z/10)}`).join(";")+(t?":water":""),n=this.cloudTransmissionMemo.get(i);if(n!==void 0)return n;this.cloudTransmissionMemo.size>256&&this.cloudTransmissionMemo.clear();const s=this.computeCloudTransmission(e,t);return this.cloudTransmissionMemo.set(i,s),s}cloudTransmissionMemo=new Map;computeCloudTransmission(e,t=!1){const i=fi(e.altitudeDeg,e.azimuthDeg,1);if(this.layeredClouds)return this.layeredClouds.transmissionAt(i,t);let n=1;const s=this.lowerCloudCover();s>0&&(n*=1-bt.alphaAt(i,Math.abs(this.cloudLayerOffset()),s,this.cloudFieldOffset)*xA);const r=t?0:this.weather.highCloudCover??0;return r>0&&(n*=1-bt.iceAlphaAt(i,Sc,r,this.cloudFieldOffset)*SA),Math.max(0,Math.min(1,n))}setBodyMesh(e,t,i,n,s){if(t.altitudeDeg<Wf){this.disposeMesh(this.bodyMeshes.get(e)),this.bodyMeshes.delete(e),this.disposeHitArea(e),this.disposeGlare(e),e==="sun"&&(this.sunVisible=!1);return}const{x:r,y:o,z:l}=fi(t.altitudeDeg,t.azimuthDeg,dn),c=qm(t.altitudeDeg),h=this.cloudTransmission(t),d=this.arrivingIlluminance(t,s,h),u=Gt.unitLuminance(n);let f=this.bodyMeshes.get(e);if(e==="sun"){const p=Math.PI*(i/dn)**2,v=[0,1,2].map(m=>Math.min(Gt.BRIGHTEST_RELATIVE,u[m]*d[m]/p));f instanceof Ie||(this.disposeMesh(f),f=new Ie(new hi(1,16,16),new Dn({fog:!1})),this.celestialGroup.add(f),this.bodyMeshes.set(e,f)),f.material.color.setRGB(v[0],v[1],v[2]),f.scale.setScalar(i)}else{if(!(f instanceof Ps)){this.disposeMesh(f);const m=new ht;m.setAttribute("position",new tt(new Float32Array(3),3)),m.setAttribute("color",new tt(new Float32Array(3),3)),f=new Ps(m,rt.material(sl[sl.length-1].size,!1)),rt.track(f),this.celestialGroup.add(f),this.bodyMeshes.set(e,f)}const p=f.geometry.getAttribute("color"),v=e.startsWith("comet:")?this.pointToPixel():1;p.setXYZ(0,u[0]*d[0]*v,u[1]*d[1]*v,u[2]*d[2]*v),p.needsUpdate=!0}if(f.position.set(r,o,l),this.setHitArea(e,r,o,l,i),e==="sun"&&(this.sunArriving=d),e.startsWith("comet:")?this.disposeGlare(e):e!=="sun"&&this.setGlare(e,r,o,l,d,i/dn*(180/Math.PI),Gt.POINT_VEIL_HOLD_DEG),e==="sun"){this.sunVisible=!0;const p=this.celestialGroup.scale.x;this.sunWorldPosition.set(r*p,o*p+this.celestialGroup.position.y,l*p),this.lensFlare||(this.lensFlare=z5(),this.lensFlare.uniforms.uOpacity.value=OA,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 i="moon";if(e.magnitude>t||e.altitudeDeg<Wf){this.disposeMesh(this.bodyMeshes.get(i)),this.bodyMeshes.delete(i),this.disposeHitArea(i),this.disposeGlare(i);return}const{x:n,y:s,z:r}=fi(e.altitudeDeg,e.azimuthDeg,dn),o=this.cloudTransmission(e),l=this.arrivingIlluminance(e,e.magnitude,o),c=Math.max(Wa(e.phase.illuminatedFraction,0,1),.01)*Math.PI*(zo/dn)**2,h=new se(...l.map(f=>Math.min(Gt.BRIGHTEST_RELATIVE,f/c))),d=`${e.phase.phaseFraction<.5}:${Math.round(Wa(e.phase.illuminatedFraction,0,1)*500)}`;let u=this.bodyMeshes.get(i);if(u instanceof To)u.userData.phaseKey!==d&&(u.material.map?.dispose(),u.material.map=jg(e.phase),u.userData.phaseKey=d),u.material.color.copy(h);else{this.disposeMesh(u),u=new To(new Bc({map:jg(e.phase),color:h,fog:!1})),u.userData.phaseKey=d;const f=zo*2;u.scale.set(f,f,1),this.celestialGroup.add(u),this.bodyMeshes.set(i,u)}u.position.set(n,s,r),this.setHitArea(i,n,s,r,zo),this.setGlare(i,n,s,r,l,zo/dn*(180/Math.PI))}bentLight(e,t,i=MA){const[n,s,r]=this.arrivingIlluminance(e,t,1),o=Math.max(s,1e-30);return{scale:s/i,tint:[n/o,1,r/o]}}static litBySky(e,t){return Gt.litScratch.setRGB(e.r*t[0],e.g*t[1],e.b*t[2])}static litScratch=new se;pointToPixel(){const e=Math.max(1,this.renderer.getDrawingBufferSize(this.pointScratch).y),t=(this.camera.fov*Math.PI/180/e)**2;return Math.min(1,rt.CONE_SOLID_ANGLE/t)}pointScratch=new be;static POINT_VEIL_HOLD_DEG=.25;static BRIGHTEST_RELATIVE=6e4;arrivingIlluminance(e,t,i){const n=this.air.transmittanceFromSpace(this.siteElevationM+this.observerElevationM,e.altitudeDeg),s=vt.illuminanceOf(t)*i*this.relativeScale;return[n[0]*s,n[1]*s,n[2]*s]}static unitLuminance(e){const t=Hn.luminanceOf([e.r,e.g,e.b]);return t>0?[e.r/t,e.g/t,e.b/t]:[1,1,1]}setHitArea(e,t,i,n,s){let r=this.hitAreas.get(e);if(!r){const l=new Bc({transparent:!0,opacity:0,depthTest:!1,depthWrite:!1,fog:!1});r=new To(l),this.celestialGroup.add(r),this.hitAreas.set(e,r)}r.position.set(t,i,n);const o=s*yA;r.scale.set(o,o,1)}disposeHitArea(e){const t=this.hitAreas.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.hitAreas.delete(e))}setGlare(e,t,i,n,s,r,o=0){if(Bi.radiusDeg(Bi.K*Math.max(...s))<=Math.max(r,o)){this.disposeGlare(e);return}let l=this.glareSprites.get(e);l||(l=new Bi(`veil:${e}`),this.celestialGroup.add(l.mesh),this.glareSprites.set(e,l)),l.shine({x:t,y:i,z:n},s,r,o)}disposeGlare(e){const t=this.glareSprites.get(e);t&&(t.mesh.removeFromParent(),t.dispose(),this.glareSprites.delete(e))}buildComet(e,t){const i=e&&`comet:${e.id}`;if(!e||!i||e.magnitude>t){this.disposeComet();return}this.cometKey&&this.cometKey!==i&&this.disposeComet();const n=Ko(e.magnitude,t),s=Rd(n);this.cometKey=i,this.setBodyMesh(i,e.position,Xd*(.5+.5*n),new se(s,s,s),e.magnitude),this.cometTail||(this.cometTail=new fn(dn),this.celestialGroup.add(this.cometTail.object)),this.cometTail.set(e.position,e.tailEnd,n)}buildIceHalos(e,t){this.iceHalos||(this.iceHalos=new ki,this.iceHalos.setCloudOffset(this.cloudFieldOffset),this.iceHalos.onReady=()=>this.render(),this.celestialGroup.add(this.iceHalos.object)),this.iceHalos.setUrgent(!!this.skyHoldUntilMs);const i=this.highCloudCover(),n=this.layeredClouds?.cirrusMask;if(this.iceHalos.setCloudOffset(n?.offset??this.cloudFieldOffset),this.layeredClouds?.hostHalo(this.iceHalos),i===void 0){this.iceHalos.update({x:0,y:1,z:0},-1,0,[1,1,1],{cover:0,layerHeight:Sc},0);return}const s=this.lowerCloudCover(),r=ot.deckLitUntilDeg(ot.DECK_HEIGHT_M),o=e.altitudeDeg>-r?e:t,l=this.bentLight(o,o===e?$t.SUN_MAGNITUDE:t.magnitude),c=ot.strength(i,s,o.altitudeDeg,r)*l.scale,{x:h,y:d,z:u}=fi(o.altitudeDeg,o.azimuthDeg,1);this.iceHalos.update({x:h,y:d,z:u},o.altitudeDeg,c,l.tint,{cover:n?.cover??i,layerHeight:n?.layerHeight??Sc},n?.iceCrystalAlignment??this.weather.iceCrystalAlignment??.65)}buildRainbow(e,t){this.rainbow||(this.rainbow=new Yr,this.celestialGroup.add(this.rainbow.object));const i=this.weather.precipitationType==="rain"?this.weather.precipitationIntensity*(this.weather.precipitationAmount??1):0,n=e.altitudeDeg>0,s=n?e:t,r=this.lowerCloudCover(),o=this.bentLight(s,n?$t.SUN_MAGNITUDE:t.magnitude,wA),l=Ui.strength(i,r,s.altitudeDeg)*o.scale;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}=fi(s.altitudeDeg,s.azimuthDeg,1);this.rainbow.update({x:c,y:h,z:d},l,o.tint,n)}buildSkyGlow(e,t){if(!e.frame){this.skyGlow?.hide();return}this.skyGlow||(this.skyGlow=new rr,this.skyGlow.onReady=()=>this.render(),this.celestialGroup.add(this.skyGlow.object));const{date:i,observer:n}=e.frame,s=gn.galactic(i,n),r=Gt.directionOf(s.centre),o=Gt.directionOf(s.rotation),l=Gt.directionOf(s.pole),c=new Xe().set(r.x,r.y,r.z,o.x,o.y,o.z,l.x,l.y,l.z),h=Gt.directionOf(gn.eclipticPole(i,n)),d=Gt.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:Gt.directionOf(e.moon),altitudeDeg:e.moon.altitudeDeg,phaseAngleDeg:We.phaseAngleOf(e.moon.phase.illuminatedFraction)},skyColor:new C(t[0],t[1],t[2])})}static directionOf(e){const{x:t,y:i,z:n}=fi(e.altitudeDeg,e.azimuthDeg,1);return new C(t,i,n).normalize()}buildNovae(e,t){const i=new Set;for(const n of e){if(n.magnitude>t)continue;const s=`nova:${n.id}`;i.add(s);const r=Ko(n.magnitude,t),o=Rd(r);this.setBodyMesh(s,n.position,Xd*(.5+.5*r),new se(o,o,o),n.magnitude)}for(const n of this.novaKeys)i.has(n)||(this.disposeMesh(this.bodyMeshes.get(n)),this.bodyMeshes.delete(n),this.disposeHitArea(n),this.disposeGlare(n));this.novaKeys=i}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 i=new Set(["sun","moon",...this.cometKey?[this.cometKey]:[],...this.novaKeys]);for(const n of e){if(n.magnitude>t)continue;i.add(n.body);const s=Ko(n.magnitude,t),r=Rd(s),o=eT[n.body]??new se(1,1,1),l=new se(o.r*r,o.g*r,o.b*r),c=Xd*(.5+.5*s);this.setBodyMesh(n.body,n.position,c,l,n.magnitude)}for(const n of[...this.bodyMeshes.keys()])i.has(n)||(this.disposeMesh(this.bodyMeshes.get(n)),this.bodyMeshes.delete(n),this.disposeHitArea(n),this.disposeGlare(n))}buildStars(e,t){if(this.namedStars=[],!e||e.catalog.count===0){this.disposeStarTiers(),this.syncAnimationLoop();return}const{catalog:i,date:n,observer:s}=e,r=new Bn(n,s),o=tu(1337),l=[],c=this.siteElevationM+this.observerElevationM;for(let h=0;h<i.count;h++){const d=i.mag[h];if(d>t)break;const{altitudeDeg:u,azimuthDeg:f}=r.position(i.ra[h],i.dec[h]);if(u<Ig)continue;const{x:p,y:v,z:m}=fi(u,f,Wd);l.push({x:p,y:v,z:m,brightness:Ko(d,t),illuminance:this.air.transmittanceFromSpace(c,u).map(g=>g*vt.illuminanceOf(d)),phase:o()*Math.PI*2,speedFactor:.7+o()*.6})}for(const h of y5){if(h.mag>t)continue;const{altitudeDeg:d,azimuthDeg:u}=r.position(h.raHours,h.decDeg);if(d<Ig)continue;const{x:f,y:p,z:v}=fi(d,u,Wd);this.namedStars.push({star:h,direction:new C(f,p,v).normalize(),altitudeDeg:d})}this.starTiers=sl.map((h,d)=>{const u=l.filter(x=>C1(x.brightness)===d),f=new Float32Array(u.length*3),p=new Float32Array(u.length),v=new Float32Array(u.length*3),m=new Float32Array(u.length),g=new Float32Array(u.length);u.forEach((x,E)=>{f[E*3]=x.x,f[E*3+1]=x.y,f[E*3+2]=x.z,p[E]=x.brightness,v.set(x.illuminance,E*3),m[E]=x.phase,g[E]=x.speedFactor});const y=new ht;y.setAttribute("position",new tt(f,3)),y.setAttribute("seed",new tt(m.map(x=>x/(2*Math.PI)),1));const M=new tt(new Float32Array(u.length*3),3);y.setAttribute("color",M);let b=this.starTiers[d]?.points;return b?(b.geometry.dispose(),b.geometry=y):(b=new Ps(y,rt.material(h.size)),rt.track(b),this.celestialGroup.add(b)),{points:b,colorAttribute:M,brightness:p,illuminance:v,phase:m,speedFactor:g}}),this.starColoursRelative=Number.NaN,this.updateTwinkle(this.twinkleSeconds),this.startTwinkle()}twinkleSeconds=0;starColoursRelative=Number.NaN;updateTwinkle(e){rt.setTime(e);const t=this.relativeScale;if(t!==this.starColoursRelative){this.starColoursRelative=t;for(const i of this.starTiers){const n=i.colorAttribute.array;for(let s=0;s<i.brightness.length;s++)n[s*3]=i.illuminance[s*3]*t,n[s*3+1]=i.illuminance[s*3+1]*t,n[s*3+2]=i.illuminance[s*3+2]*t;i.colorAttribute.needsUpdate=!0}}}buildClouds(){if(this.cloudRendering==="volume"||this.weather.cloudLayers!==void 0){this.layeredClouds||(this.disposeCloudSystem(),this.layeredClouds=new Ja(this.celestialGroup,Yd,this.cloudRendering)),this.disposeCirrus(),this.layeredClouds.hostHalo(this.iceHalos),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}const e=this.lowerCloudCover();if(e<=0){this.disposeCloudSystem();return}const t=this.weather.cloudDarkness,i=new se(Rr[0]+(Kd[0]-Rr[0])*t,Rr[1]+(Kd[1]-Rr[1])*t,Rr[2]+(Kd[2]-Rr[2])*t);if(this.cloudMesh&&this.cloudUniforms){this.cloudUniforms.coverage.value=e,this.cloudUniforms.baseColor.value.copy(i),this.syncCloudLayer(),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}this.disposeCloudSystem();const{material:n,uniforms:s}=gf(i,e,Math.abs(this.cloudLayerOffset()));this.cloudMaterial=n,this.cloudUniforms=s,s.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);const r=vf(Yd);this.cloudMesh=new Ie(r,n),this.faceCloudDeck(this.cloudMesh,this.cloudLayerOffset()),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(){const e=this.weather.highCloudCover??0;if(this.layeredClouds||e<=0){this.disposeCirrus();return}if(this.cirrusMesh&&this.cirrusUniforms){this.cirrusUniforms.coverage.value=e,this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}const{material:t,uniforms:i}=gf(new se(...Rr),e,Sc,1);this.cirrusMaterial=t,this.cirrusUniforms=i,i.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.cirrusMesh=new Ie(vf(Yd*1.04),t),this.cirrusMesh.renderOrder=kg-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.faceCloudDeck(this.cloudMesh,e)}faceCloudDeck(e,t){const i=t<0;e.scale.y=i?-1:1,e.renderOrder=i?Ja.deckOrder(!0,0,1):kg}cloudLayerOffset(){const t=((this.weather.cloudBaseM??1e3)-this.observerElevationM)*qd;return Math.sign(t||1)*Math.max(Math.abs(t),NA)}updateCloudLighting(e,t){const i=[this.cloudUniforms,this.cirrusUniforms].filter(d=>d!==void 0);if(i.length===0&&!this.layeredClouds)return;const n=this.cloudBeamDirection,[s,r,o]=this.cloudBeam.map(d=>d/Math.PI),l=this.lightningLevel*eu*this.relativeScale/Math.PI,c=new se(t[0]+Qn.r*l,t[1]+Qn.g*l,t[2]+Qn.b*l);this.layeredClouds?.setLighting(n.clone(),new se(s,r,o),c,c);const h=Math.max(0,n.y);for(const d of i)d.sunDir.value.copy(n),d.sunColor.value.setRGB(s*h,r*h,o*h),d.ambientColor.value.copy(c)}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}precipitationCount(e){return WA(e,this.weather.precipitationIntensity,this.weather.precipitationAmount??1)}updatePrecipitationDensity(){const e=[[this.rainSystem?.points,Jd],[this.rainSplashSystem?.points,Pr],[this.precipitationPoints,this.weather.precipitationType==="none"||this.weather.precipitationType==="rain"?void 0:Zd[this.weather.precipitationType].poolSize]];for(const[t,i]of e)t&&i!==void 0&&t.geometry.setDrawRange(0,this.precipitationCount(i));this.rainSystem&&(this.rainSystem.uniforms.uSpeedStreak.value=Bg(Qd(this.weather.precipitationIntensity)))}buildPrecipitation(){this.disposePrecipitationPoints(),this.disposeRain();const e=this.weather.precipitationType;if(e==="none")return;if(e==="rain"){this.buildRain();return}const t=Zd[e],i=t.poolSize,n=tu(9001),s=new Float32Array(i*3),r=new Float32Array(i),o=new Float32Array(i),l=new Float32Array(i),c=new Float32Array(i),h=new Float32Array(i),d=new Float32Array(i),u=new Float32Array(i),f=new Float32Array(i),p=new Float32Array(i);for(let M=0;M<i;M++){const b=n()*Math.PI*2,x=n()*t.radiusM;s[M*3]=Math.cos(b)*x,s[M*3+1]=Na+n()*(t.topYM-Na),s[M*3+2]=Math.sin(b)*x,r[M]=n()*Math.PI*2,o[M]=.7+n()*.6,l[M]=.6+n()*.8,c[M]=.4+n()*1.2}const v=new ht;v.setAttribute("position",new tt(s,3)),v.setDrawRange(0,this.precipitationCount(i));const m={uSize:{value:t.size},uScale:{value:.5*this.renderer.domElement.height},uOpacity:{value:t.opacity},uColor:{value:t.color.clone()},uHazeColor:{value:new se(...this.baseFogColor)},uTexture:{value:tT(e)},uNearFocusDistance:{value:Vg},uHazeDistance:{value:t.radiusM*Wg}},g=new dt({uniforms:m,vertexShader:oT,fragmentShader:lT,transparent:!0,depthWrite:!1});this.precipitationUniforms=m;const y=new Ps(v,g);y.renderOrder=$d,this.scene.add(y),this.precipitationPoints=y,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)return;this.precipitationUniforms?.uHazeColor.value.setRGB(...this.baseFogColor);const i=this.weather.precipitationType;if(i==="none"||i==="rain")return;const n=Zd[i];if(this.precipitationUniforms?.uColor.value.copy(Gt.litBySky(n.color,this.baseFogColor)),t<=0)return;const s=this.weather.windDirectionDeg*en,r=Math.sin(s)*this.weather.windSpeed*n.driftSensitivity,o=-Math.cos(s)*this.weather.windSpeed*n.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,y=i==="snow"&&d&&u,M=i==="hail"&&f&&p&&v&&m&&g;for(let b=0,x=0;b<l.length;b+=3,x++){if(M&&f[x]>0){if(f[x]-=t,f[x]<=0){const w=Math.random()*Math.PI*2,T=Math.sqrt(Math.random())*n.radiusM;l[b]=Math.cos(w)*T,l[b+1]=n.topYM,l[b+2]=Math.sin(w)*T,f[x]=0}else{const w=1-f[x]/v[x];l[b+1]=Na+Math.sin(Math.PI*w)*p[x],l[b]=Ac(l[b]+(r+m[x])*t,n.radiusM),l[b+2]=Ac(l[b+2]+(o+g[x])*t,n.radiusM)}continue}let E=0,I=0;if(y){const w=YA*d[x],T=qA*u[x];E=Math.sin(e*w*Math.PI*2+c[x])*T,I=Math.sin(e*w*Math.PI*2+c[x]+Math.PI/2)*T}if(l[b]+=(r+E)*t,l[b+1]-=n.fallSpeedMPerS*h[x]*t,l[b+2]+=(o+I)*t,l[b]=Ac(l[b],n.radiusM),l[b+2]=Ac(l[b+2],n.radiusM),l[b+1]<Na){if(M){p[x]=Kg*(.2+Math.random()*1.6),v[x]=$A*(.5+Math.random()),f[x]=v[x];const A=Math.random()*Math.PI*2,D=KA*(p[x]/Kg);m[x]=Math.cos(A)*D,g[x]=Math.sin(A)*D,l[b+1]=Na;continue}const w=Math.random()*Math.PI*2,T=Math.sqrt(Math.random())*n.radiusM;l[b]=Math.cos(w)*T,l[b+1]=n.topYM,l[b+2]=Math.sin(w)*T}}this.precipitationPoints.geometry.attributes.position.needsUpdate=!0}buildRain(){const e=Qd(this.weather.precipitationIntensity);this.rainSystem=N5({count:Jd,radiusM:Ho,heightM:UA,bottomYM:Ng,overallSpeed:BA,color:Ug.clone(),opacity:.85,visibleCount:this.precipitationCount(Jd),speedStreak:Bg(e),pixelSize:Yg,seed:9001,nearFocusDistanceM:Vg,hazeDistanceM:Ho*Wg,hazeColor:new se(...this.baseFogColor)}),this.rainLastVerticalFacing=-1,this.syncRainSlant(),this.rainSystem.points.renderOrder=$d,this.scene.add(this.rainSystem.points),this.buildRainSplashes()}buildRainSplashes(){const e=tu(4242),t=new Float32Array(Pr*3),i=new Float32Array(Pr),n=new Float32Array(Pr),s=new Float32Array(Pr);for(let h=0;h<Pr;h++){const d=e()*Math.PI*2,u=Math.sqrt(e())*Ho;t[h*3]=Math.cos(d)*u,t[h*3+1]=Ng,t[h*3+2]=Math.sin(d)*u,n[h]=Zg(zg,Hg),i[h]=e()*n[h],s[h]=i[h]/n[h]}const r=new ht;r.setAttribute("position",new tt(t,3));const o=new tt(s,1);r.setAttribute("aLife",o),r.setDrawRange(0,this.precipitationCount(Pr));const l=new dt({uniforms:{uMaxSize:{value:VA},uScale:{value:.5*this.renderer.domElement.height},uColor:{value:Gg.clone()},uTexture:{value:sT()}},vertexShader:rT,fragmentShader:aT,transparent:!0,depthWrite:!1}),c=new Ps(r,l);c.renderOrder=$d,this.scene.add(c),this.rainSplashSystem={points:c,positions:t,life:i,duration:n,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*en;e.uniforms.uDropVelocity.value.set(Math.sin(t)*this.weather.windSpeed,-Qd(this.weather.precipitationIntensity),-Math.cos(t)*this.weather.windSpeed);const i=this.renderer.getSize(this.rainViewportSize);e.uniforms.uAspect.value=i.x/Math.max(i.y,1)}updateRain(e){const t=this.rainSystem;if(!t)return;t.uniforms.uTime.value+=e,t.uniforms.uHazeColor.value.setRGB(...this.baseFogColor),t.uniforms.uColor.value.copy(Gt.litBySky(Ug,this.baseFogColor));const i=this.rainSplashSystem?.points.material?.uniforms?.uColor;i&&i.value.copy(Gt.litBySky(Gg,this.baseFogColor));const n=this.weather.windDirectionDeg*en,s=Math.sin(n)*this.weather.windSpeed,r=-Math.cos(n)*this.weather.windSpeed,o=Ho,l=h=>(h%(o*2)+o*3)%(o*2)-o;t.uniforms.uWindOffset.value.set(l(t.uniforms.uWindOffset.value.x+s*e),l(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 h=qg+(1-qg)*(1-c),d=$g+(1-$g)*(1-c);t.uniforms.uUvSquash.value=d,t.uniforms.uPixelSize.value=Yg*h*(.5+.5*d)}this.updateRainSplashes(e)}updateRainSplashes(e){const t=this.rainSplashSystem;if(!t||e<=0)return;const{positions:i,life:n,duration:s,lifeAttribute:r}=t,o=r.array;for(let l=0,c=0;l<i.length;l+=3,c++){if(n[c]+=e,n[c]>=s[c]){const h=Math.random()*Math.PI*2,d=Math.sqrt(Math.random())*Ho;i[l]=Math.cos(h)*d,i[l+2]=Math.sin(h)*d,s[c]=Zg(zg,Hg),n[c]=0}o[c]=n[c]/s[c]}t.points.geometry.attributes.position.needsUpdate=!0,r.needsUpdate=!0}setLightning(e){this.lightningFlashes=e}updateLightning(e){let t,i=0;if(this.lightningArmed)for(const l of this.lightningFlashes){if(l.t>e)break;const c=pi.brightnessAt(l,e);c>i&&(t=l,i=c)}const n=t?Math.min(1,Math.max(.1,(JA/t.distanceM)**2)):0,s=i*n*(t?.cloudToGround?1:.6);if(s===this.lightningLevel&&!t?.cloudToGround)return;if(this.lightningLevel=s,this.scene.fog){const l=this.scene.fog,c=s*eu*this.relativeScale/Math.PI;l.color.setRGB(this.airlight[0]+Qn.r*c,this.airlight[1]+Qn.g*c,this.airlight[2]+Qn.b*c)}const r=this.skyMesh?.material?.color;if(r){const l=s*QA;r.setRGB(1+l*Qn.r,1+l*Qn.g,1+l*Qn.b)}if(this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.lightningLight.intensity=s*eu*this.relativeScale,t){const{x:l,y:c,z:h}=fi(25,t.azimuthDeg,dn);this.lightningLight.position.set(l,c,h)}this.lightningBolt||(this.lightningBolt=new ar(dn*.95),this.celestialGroup.add(this.lightningBolt.object));const o=this.weather.cloudBaseM??1500;this.lightningBolt.set(t,i,o),this.render()}buildCompassLabels(){const e=oo(navigator.languages,TA),t=AA[e];this.compassSprites=_A.map((i,n)=>{const s=t[n],r=new Bc({map:cT(s),depthTest:!1,fog:!1}),o=new To(r),{x:l,y:c,z:h}=fi(0,i,Rg);return o.position.set(l,c,h),o.scale.set(_c,_c,1),o.renderOrder=CA,o.layers.set(Eg),o.visible=this.compassHovered||this.compassForced,this.celestialGroup.add(o),o}),this.updateCompassScale()}updateCompassScale(){const e=this.camera.fov*Math.PI/360,t=Pg*Math.PI/360,i=_c*Math.tan(e)/Math.tan(t);for(const n of this.compassSprites)n.scale.set(i,i,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 i of Array.isArray(t)?t:[t]){const n=i.map;n&&n.dispose(),i.dispose()}}}const en=Math.PI/180;function Wa(a,e,t){return Math.max(e,Math.min(t,a))}function Zg(a,e){return a+Math.random()*(e-a)}function Ac(a,e){return(a%(e*2)+e*3)%(e*2)-e}let Tc,Ic;function tT(a){switch(a){case"snow":return iT();case"hail":return nT()}}function iT(){if(Tc)return Tc;const a=64,e=document.createElement("canvas");e.width=a,e.height=a;const t=e.getContext("2d"),i=t.createRadialGradient(a/2,a/2,0,a/2,a/2,a/2);return i.addColorStop(0,"rgba(255,255,255,0.95)"),i.addColorStop(.5,"rgba(255,255,255,0.55)"),i.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=i,t.fillRect(0,0,a,a),Tc=new Vs(e),Tc}function nT(){if(Ic)return Ic;const a=64,e=document.createElement("canvas");e.width=a,e.height=a;const t=e.getContext("2d"),i=t.createRadialGradient(a/2,a/2,0,a/2,a/2,a/2);return i.addColorStop(0,"rgba(255,255,255,1)"),i.addColorStop(.55,"rgba(255,255,255,0.95)"),i.addColorStop(.8,"rgba(255,255,255,0.4)"),i.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=i,t.fillRect(0,0,a,a),Ic=new Vs(e),Ic}let Dc;function sT(){if(Dc)return Dc;const a=64,e=document.createElement("canvas");e.width=a,e.height=a;const t=e.getContext("2d"),i=t.createRadialGradient(a/2,a/2,0,a/2,a/2,a/2);return i.addColorStop(0,"rgba(255,255,255,0)"),i.addColorStop(.4,"rgba(255,255,255,0)"),i.addColorStop(.6,"rgba(255,255,255,0.9)"),i.addColorStop(.8,"rgba(255,255,255,0.25)"),i.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=i,t.fillRect(0,0,a,a),Dc=new Vs(e),Dc}const rT=`
8754
+ `,transparent:!0,blending:Vi,depthWrite:!1,side:qt,fog:!1});this.object=new Ie(new hi(Bp.RADIUS,128,32,0,Math.PI*2,0,vt.MAX_ANGLE_RAD),t),this.object.renderOrder=-1,this.object.frustumCulled=!1,this.object.visible=!1}show(e,t){if(!e||!t){this.object.visible=!1;return}this.towards.set(e.x,e.y,e.z).normalize(),this.object.quaternion.setFromUnitVectors(this.up,this.towards),this.object.material.uniforms.uSource.value.copy(this.towards);for(let i=0;i<vt.STEPS;i++){for(let n=0;n<3;n++)this.texels[i*4+n]=Wn.toHalfFloat(Math.min(t[i*3+n],6e4));this.texels[i*4+3]=Wn.toHalfFloat(1)}this.texture.needsUpdate=!0,this.object.visible=!0}dispose(){this.object.geometry.dispose(),this.object.material.dispose(),this.texture.dispose()}}class yh{constructor(e){this.generator=e}static SIZE=128;target=new wl(yh.SIZE,{type:Zt,generateMipmaps:!1,minFilter:ct,magFilter:ct});camera=new xp(.1,2e5,this.target);filteredTarget;capturedAtMs=-1/0;capturedVersion;get sharp(){return this.target.texture}get filtered(){return this.filteredTarget?.texture}capture(e,t,i,n=[]){const s=e.shadowMap.autoUpdate;e.shadowMap.autoUpdate=!1;const r=n.map(o=>o.visible);for(const o of n)o.visible=!1;this.camera.position.copy(i),this.camera.update(e,t),n.forEach((o,l)=>{o.visible=r[l]}),e.shadowMap.autoUpdate=s,this.filteredTarget=this.generator.fromCubemap(this.target.texture,this.filteredTarget),this.capturedAtMs=performance.now()}dispose(){this.target.dispose(),this.filteredTarget?.dispose()}}class pn{static REFRESH_MS=250;generator;eye;probes=new Map;constructor(e){pn.install(),this.generator=new uf(e),this.eye=new yh(this.generator)}static decor;refresh(e,t,i,n,s,r,o,l=[],c){for(const v of[...this.probes.keys()])n.some(m=>m.id===v&&m.shiny)||(this.probes.get(v).dispose(),this.probes.delete(v));const h=[{probe:this.eye}];for(const v of n){if(!v.shiny)continue;let m=this.probes.get(v.id);m||(m=new yh(this.generator),this.probes.set(v.id,m)),h.push({probe:m,reflector:v})}const d=performance.now(),u=()=>h.filter(({probe:v})=>v.capturedVersion!==o),f=u().filter(({probe:v})=>d-v.capturedAtMs>=pn.REFRESH_MS);if(f.length>0){const v=f.reduce((m,g)=>g.probe.capturedAtMs<m.probe.capturedAtMs?g:m);if(v.reflector){const m=v.reflector.holder.getWorldPosition(this.scratch);v.probe.capture(e,t,m,[v.reflector.holder,...s]),pn.reflectOn(v.reflector.holder,v.probe)}else{v.probe.capture(e,t,i,[...s,...l]),c?.(v.probe.sharp),pn.decor=v.probe.filtered;for(const m of r)pn.reflectOn(m,v.probe);for(const m of n)m.shiny||pn.reflectOn(m.holder,v.probe)}v.probe.capturedVersion=o}const p=u();if(p.length!==0)return Math.max(16,Math.min(...p.map(({probe:v})=>pn.REFRESH_MS-(d-v.capturedAtMs))))}scratch=new C;static reflectOn(e,t={filtered:pn.decor}){e.traverse(i=>{const n=i.material;for(const s of Array.isArray(n)?n:n?[n]:[])s instanceof Sl?t.sharp&&s.setSurroundings(t.sharp):s instanceof Br&&t.filtered&&s.envMap!==t.filtered&&(s.envMap=t.filtered,s.needsUpdate=!0)})}dispose(){this.eye.dispose();for(const e of this.probes.values())e.dispose();this.generator.dispose()}static installed=!1;static install(){if(pn.installed)return;pn.installed=!0;const e="iblIrradiance += getIBLIrradiance( geometryNormal );";if(!Ye.lights_fragment_maps.includes(e)){console.warn("Reflections: three's lights_fragment_maps changed; the environment will light diffusely too");return}Ye.lights_fragment_maps=Ye.lights_fragment_maps.replace(e,"// The sky's diffuse light is the hemisphere light's (see Reflections).")}}function pA(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.relativeHumidity===e.relativeHumidity&&a.precipitationType===e.precipitationType&&a.precipitationIntensity===e.precipitationIntensity&&a.precipitationAmount===e.precipitationAmount&&a.windDirectionDeg===e.windDirectionDeg&&a.windSpeed===e.windSpeed&&a.storm===e.storm}const xc=900,Gd=1,Sg=4,Eg=5,_g=.5,Jo=900,mA=6371e3,gA=3e4;function Ag(a){const e=Math.sqrt(2*mA*Math.max(a,0));return Math.max(Jo,Math.min(e,gA))}const Vd=.5,Wd=850,Tg=.03,dn=850,Bo=300,tr=120,vA=700,bA=.04,zo=4,Xd=1.5,Ig=-1,yA=6,Wf=-4,MA=2,wA=20,Sc=2600,xA=.97,SA=.38,Ec=Wf,Dg=1500,EA=400,_A=[0,45,90,135,180,225,270,315],AA={en:["N","NE","E","SE","S","SW","W","NW"],fr:["N","NE","E","SE","S","SO","O","NO"]},TA=["en","fr"],IA=2,DA=16,Cg=2500,Rg=880,_c=40,Pg=60,CA=10,RA=1,PA=150,LA=55,OA=.5,kA=17,Lg=.265,Og=[[0,0],...Array.from({length:8},(a,e)=>{const t=e*Math.PI/4;return[Math.cos(t)*Lg,Math.sin(t)*Lg]})],Yd=700,qd=250/1e3,NA=12,kg=5,$d=6,Rr=[.92,.92,.95],Kd=[.15,.15,.19],Zd={snow:{fallSpeedMPerS:2,size:.3,color:new se(1,1,1),driftSensitivity:1,radiusM:25,topYM:20,opacity:.75,poolSize:2400},hail:{fallSpeedMPerS:14,size:.5,color:new se(.95,.98,1),driftSensitivity:.25,radiusM:25,topYM:10,opacity:.95,poolSize:1200}},Na=0,jd=0,FA=150,Jd=3e3,Ho=20,UA=15,Ng=Na,BA=40,Fg=1,zA=9;function Qd(a){return Fg+(zA-Fg)*a}const Ug=new se(.75,.82,.92),HA=10,GA=.5;function Bg(a){return Wa(a/HA,GA,1)}const Pr=200,zg=.18,Hg=.32,VA=.35,Gg=new se(.85,.9,.98),Vg=5,Wg=.85,Xg=.01;function WA(a,e,t=1){return Math.round(a*(Xg+(1-Xg)*e)*t)}function XA(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}const Yg=230,qg=.7,$g=.05,YA=.6,qA=.7,$A=.15,Kg=.35,KA=3,ZA=1/12,jA=.5,Qn=new se(.82,.86,1),JA=2500,QA=1.6,eu=15,eT={Venus:new se(1,.96,.85),Mars:new se(1,.55,.4),Jupiter:new se(.95,.87,.72),Saturn:new se(.92,.86,.68)};class Gt{renderer;scene=new Bs;phenomena=new Nn(this.scene);references=new kn(this.scene,()=>this.render());camera;celestialGroup=new Lt;skyMesh;skyGradientMaterial;scatteredSky;lastAstronomy;skyColoursStale=!1;scatteredSkyFrameId=null;skyHoldUntilMs=void 0;onFirstFrameHold;firstFrameReady(){return(!this.scatteredSky||this.scatteredSky.ambient!==void 0)&&!this.iceHalos?.awaitingFirstDisplay}groundMesh;terrainMesh;terrainProviders;terrainOrigin;terrainBuildToken=0;terrainAttribution;roadSystem=new _n;roadAttribution;roadWays;statedRoads=[];decorModelProvider=Vc[0].create();decorModelToken=0;decorModelCredits=new Map;bodySystem=new ft(e=>this.loadBodyModel(e),()=>this.render(),()=>this.relativeScale);bodyOrigin={x:0,z:0};starTiers=[];bodyMeshes=new Map;hitAreas=new Map;glareSprites=new Map;decorObjects=[];decorGroups=new Map;decorReferencePose;decorCurrentPose;decorTime=0;celestialLight=new vm(16777215,0);celestialLightTarget=new Bt;skyLight=new zM(16777215,0,0);streetlightLights=new Map;compassSprites=[];showCompass=!1;compassHovered=!1;compassForced=!1;animationFrameId=null;resolution;cssSize={width:1,height:1};frameDirty=!1;flushFrameId=null;framesDriven=!1;lastFrameTimeMs;raycaster=new zc;weather=qf;observerElevationM=0;siteElevationM=0;air=new Tn;groundRadius=Jo;terrainRadius=Jo;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 be;lightningArmed=!1;lightningFlashes=[];lightningLevel=0;lightningBolt;lightningLight=new vm(16777215,0);baseFogColor=[0,0,0];lastSunPosition;lensFlare;sunUnhiddenFraction=1;lensFlareArtifactIntensity=0;sunWorldPosition=new C;sunVisible=!1;lensFlareScratch=new C;sunOcclusionRaycaster=new zc;sunOcclusionDirectionScratch=new C;sunOcclusionRightScratch=new C;sunOcclusionUpScratch=new C;ufoOcclusionRaycaster=new zc;projectionKind="rectilinear";starPoints=0;namedStars=[];equidistantPass;depthOfFieldPass;finishPass;exposureAccumulation;exposureInstants=1;get developingExposure(){return this.exposureInstants>1&&this.exposureInstantAt!==void 0}static EXPOSURE_BUDGET_MS=12;static exposureInstantsPerFrame(e){return Math.max(3,Math.round(6e6/Math.max(1,e)))}exposureFrameId=null;exposureInstantsDone=0;exposureInstantAt;restatingExposure=!1;lensOptics;instrumentMagnitudeGain=0;meteorSystem;cometTail;satelliteField;iceHalos;lunarDiffraction;lunarDiffractionKey="";rainbow;skyGlow;cometKey;novaKeys=new Set;constructor(e,t=Ny()){this.renderer=new Q3({canvas:e,antialias:!0}),this.resolution=new yt(Math.min(window.devicePixelRatio||1,2),this.renderer.getContext()),this.renderer.setPixelRatio(this.resolution.pixelRatio),this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=el,this.camera=new an(60,e.width/Math.max(e.height,1),.1,xc*1.2),this.camera.position.set(0,1.6,0),this.terrainProviders=t,this.celestialLight.shadow.mapSize.set(1024,1024),this.celestialLight.shadow.camera.left=-tr,this.celestialLight.shadow.camera.right=tr,this.celestialLight.shadow.camera.top=tr,this.celestialLight.shadow.camera.bottom=-tr,this.celestialLight.shadow.camera.near=dn-Bo,this.celestialLight.shadow.camera.far=dn+Bo,this.celestialLight.shadow.bias=-.03/(2*Bo),this.celestialLight.shadow.normalBias=bA,this.celestialLight.target=this.celestialLightTarget,this.lightningLight.color.copy(Qn),this.scene.add(this.celestialLight,this.celestialLightTarget,this.skyLight,this.lightningLight),this.scene.add(this.celestialGroup),this.scene.add(this.bodySystem.group),this.scene.add(this.roadSystem.group);const i=new $t(this.renderer,()=>{this.skyColoursStale=!0,this.render()});i.supported?this.scatteredSky=i:i.dispose()}get currentTerrainAttribution(){return this.terrainAttribution}get currentRoadAttribution(){return this.roadAttribution}resize(e,t){this.cssSize.width=e,this.cssSize.height=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.cloudTransmissionMemo.clear(),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*qd,0,e.z*qd);for(const i of[this.cloudUniforms,this.cirrusUniforms])i?.fieldOffset.value.copy(this.cloudFieldOffset);this.iceHalos?.setCloudOffset(this.layeredClouds?.cirrusMask?.offset??this.cloudFieldOffset)}setObserverPose(e){const t=((e.rollDeg??0)+this.gaitOffset.rollDeg)*en,i=(e.pitchDeg+this.lookPitchDeg+this.gaitOffset.pitchDeg)*en;if(e.headingDeg!==void 0?this.camera.rotation.set(i,-(e.headingDeg+this.lookYawDeg+this.gaitOffset.yawDeg)*en,t,"YXZ"):this.camera.rotation.set(i,this.camera.rotation.y,t,"YXZ"),e.elevationM!==this.observerElevationM&&(this.observerElevationM=e.elevationM,this.syncCloudLayer(),Math.abs(Ag(e.elevationM)-this.groundRadius)>1&&(this.buildGround(),this.celestialGroup.scale.setScalar(this.groundRadius/Jo),this.camera.far=Math.max(xc*1.2,this.groundRadius*2.5),this.camera.updateProjectionMatrix())),this.terrainMesh&&this.terrainOrigin&&e.lat!==void 0&&e.lng!==void 0){const n=li(this.terrainOrigin.lat,this.terrainOrigin.lng,e.lat,e.lng);this.terrainMesh.position.x=n.x,this.terrainMesh.position.z=n.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.stopTerrainFade(),this.terrainProviders=e,this.disposeMesh(this.terrainMesh),this.terrainMesh=void 0,this.terrainOrigin=void 0,this.terrainAttribution=void 0,this.roadSystem.clear(),this.roadAttribution=void 0,this.roadWays=void 0,this.applyGroundDepthWrite(),this.terrainBuildToken++}setTerrainOrigin(e,t,i){if(e===void 0||t===void 0)return;const n=this.groundRadius;if(this.terrainOrigin&&Math.abs(this.terrainRadius-n)<n*.1){const{x:l,z:c}=li(e,t,this.terrainOrigin.lat,this.terrainOrigin.lng);if(Math.sqrt(l*l+c*c)<PA*(n/Jo))return}const s=this.terrainOrigin,r=this.terrainRadius;(!s||s.lat!==e||s.lng!==t)&&(this.roadSystem.clear(),this.roadAttribution=void 0),this.terrainOrigin={lat:e,lng:t},this.terrainRadius=n;const o=++this.terrainBuildToken;E5(e,t,this.terrainProviders,n).then(({mesh:l,attribution:c,originElevationM:h})=>{if(o!==this.terrainBuildToken)return;this.setSiteElevation(h??0);const d=this.terrainMesh,u=s?li(e,t,s.lat,s.lng):void 0;d&&u&&Math.hypot(u.x,u.z)<=r&&(l.position.y=d.position.y+this.groundYOfPatch(d,u.x,u.z)),d&&u&&Math.hypot(u.x,u.z)<=r?this.crossfadeTerrain(l,d):this.disposeMesh(this.terrainMesh),l.renderOrder=RA,this.terrainMesh=l,this.compileNextFrameOffThread(),this.terrainAttribution=c,this.scene.add(l),this.applyGroundDepthWrite(),this.decorCurrentPose&&(this.setObserverPose(this.decorCurrentPose),this.updateDecorAnchoring(this.decorReferencePose,this.decorCurrentPose,this.decorTime)),this.buildRoads(e,t,n),this.drapeStatedRoads(),this.render(),i?.()}).catch(l=>{console.warn("Terrain build failed, keeping the flat ground fallback:",l),i?.()})}static TERRAIN_CROSSFADE_MS=1200;fadingTerrain;crossfadeTerrain(e,t){this.stopTerrainFade();const i=e.material;i.opacity=0,i.polygonOffset=!0,i.polygonOffsetFactor=-1,i.polygonOffsetUnits=-4;const n=performance.now(),s=()=>{const r=Math.min(1,(performance.now()-n)/Gt.TERRAIN_CROSSFADE_MS);if(i.opacity=r*r*(3-2*r),this.render(),r<1&&this.fadingTerrain){this.fadingTerrain.frameId=requestAnimationFrame(s);return}i.polygonOffset=!1,i.opacity=1,this.fadingTerrain&&this.disposeMesh(this.fadingTerrain.mesh),this.fadingTerrain=void 0,this.render()};this.fadingTerrain={mesh:t,frameId:requestAnimationFrame(s)}}stopTerrainFade(){if(!this.fadingTerrain)return;cancelAnimationFrame(this.fadingTerrain.frameId),this.disposeMesh(this.fadingTerrain.mesh),this.fadingTerrain=void 0;const e=this.terrainMesh?.material;e&&(e.opacity=1,e.polygonOffset=!1)}static ROADS_MAX_RADIUS_M=5e3;buildRoads(e,t,i){const n=this.terrainProviders.roads;if(!n||i>Gt.ROADS_MAX_RADIUS_M){this.roadSystem.clear(),this.roadAttribution=void 0;return}const s=this.roadWays;if(s&&s.lat===e&&s.lng===t&&s.radiusM===i){this.drapeRoads(s.ways,e,t,n.contemporary);return}n.getRoads(Z1(e,t,i)).then(r=>{this.terrainOrigin?.lat!==e||this.terrainOrigin?.lng!==t||(this.roadWays={lat:e,lng:t,radiusM:i,ways:r},this.drapeRoads(r,e,t,n.contemporary))}).catch(r=>{console.warn("Roads unavailable, drawing none:",r)})}setStatedRoads(e){e!==this.statedRoads&&(this.statedRoads=e,this.drapeStatedRoads(),this.render())}drapeStatedRoads(){const e=this.terrainMesh;e&&(this.roadSystem.group.position.copy(e.position),this.roadSystem.setStated(this.statedRoads,(t,i)=>this.groundYOfPatch(e,t,i)))}drapeRoads(e,t,i,n){const s=this.terrainMesh;s&&(this.roadSystem.group.position.copy(s.position),this.roadSystem.set(e,t,i,(r,o)=>this.groundYOfPatch(s,r,o),n),this.roadAttribution=e.length>0?this.terrainProviders.roads?.attribution:void 0,this.compileNextFrameOffThread(),this.render())}setShowCompass(e){this.showCompass!==e&&(this.showCompass=e,this.disposeCompassLabels(),e&&this.buildCompassLabels(),this.render())}applyLensFlareTint(e){if(!this.lensFlare)return;const t=LA*(this.sunArriving[1]/kA);this.lensFlare.uniforms.uColorGain.value.setRGB(t*e[0],t*e[1],t*e[2]),this.applyDazzleStrength()}applyDazzleStrength(){if(!this.lensFlare)return;const[e,t,i]=this.sunArriving,n=Math.max(t,1e-30);this.lensFlare.uniforms.uDazzleColour.value.setRGB(e/n,1,i/n),this.lensFlare.uniforms.uVeilStrength.value=Bi.K*t*this.sunUnhiddenFraction}sunArriving=[0,0,0];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;if(this.compassSprites.some(t=>t.visible!==e)){for(const t of this.compassSprites)t.visible=e;this.developingExposure?this.exposureInstantsDone>0&&this.presentExposure():this.render()}}setWeather(e){if(pA(this.weather,e))return;this.cloudTransmissionMemo.clear();const t=this.weather;this.weather=e;const i=!XA(t,e),n=t.precipitationType!==e.precipitationType,s=t.precipitationIntensity!==e.precipitationIntensity||t.precipitationAmount!==e.precipitationAmount;(t.relativeHumidity!==e.relativeHumidity||n||s)&&(this.air=Tn.of(e),this.applyAir(),this.scatteredSky?.setConditions({aerosolOpticalDepth:e.relativeHumidity===void 0?void 0:Ns.steppedOpticalDepth(e.relativeHumidity)}),this.pumpScatteredSky()),i&&(this.buildClouds(),this.buildCirrus()),n?this.buildPrecipitation():s&&this.updatePrecipitationDensity(),this.lastAstronomy&&(i&&(this.buildIceHalos(this.lastAstronomy.sun,this.lastAstronomy.moon),this.buildLunarDiffraction(this.lastAstronomy.moon)),(i||n||s)&&this.buildRainbow(this.lastAstronomy.sun,this.lastAstronomy.moon)),this.lightningArmed=e.storm&&e.cloudDarkness>=jA,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(),oi.dispose(t);this.decorGroups.clear(),this.streetlightLights.clear();for(const t of e){const i=oi.build(t,t.lit??!1);this.scene.add(i),this.decorGroups.set(t.id,i),t.kind==="streetlight"&&this.addStreetlightLight(t.id,i),this.loadDecorModel(t,this.decorModelToken)}this.celestialLight.castShadow=this.decorGroups.size>0||this.bodySystem.any}}setDecorModelProvider(e){this.decorModelProvider=e;const t=this.decorObjects;this.decorObjects=[],this.setDecor(t)}get currentDecorModelCredits(){return[...this.decorModelCredits.values(),...this.bodySystem.modelCredits]}get bodyGround(){const{x:e,z:t}=this.bodyOrigin,i=this.groundYUnder(e,t);return{heightAt:(n,s)=>this.groundYUnder(e+n,t-s)-i}}setBodies(e,t=0,i=e.map(r=>r.id),n=[],s){const{x:r,z:o}=this.bodyOrigin,l=this.scatteredSky;this.bodySystem.set(e,{originX:r,originZ:o,originGroundY:this.groundYUnder(r,o),eye:this.camera.position,groundYAt:(h,d)=>this.groundYUnder(h,d),wind:s,light:this.plumeLight(),occluders:[...this.decorGroups.values()],transmittance:(h,d,u)=>this.transmittanceTo(h,d,u)},t,l?(h,d)=>l.relativeOfLuminance(h,d):void 0,i),this.bodySystem.setSmoke(n,t),this.bodySystem.any&&(this.celestialLight.castShadow=!0),this.fitShadowToBodies();const c=this.bodySystem.furthestFrom(this.camera.position)*1.2;c>this.camera.far&&(this.camera.far=c,this.camera.updateProjectionMatrix())}plumeLight(){const e=this.celestialLight.color,t=this.celestialLight.intensity*.5,i=this.skyLight.color,n=this.skyLight.groundColor,s=this.skyLight.intensity,r=(o,l,c)=>(o*t+(l+c)/2*s)/Math.PI;return[r(e.r,i.r,n.r),r(e.g,i.g,n.g),r(e.b,i.b,n.b)]}bodyOutline(e,t){return this.bodySystem.outlineOf(e,t)}documentUrl;modelUrl(e){return e.url?this.documentRelative(e.url):void 0}documentRelative(e){if(e.startsWith("data:"))return e;const t=this.documentUrl??(typeof location>"u"?void 0:location.href);return t?new URL(e,t).href:e}async loadBodyModel(e){const t=e.url?void 0:e.id?await this.decorModelProvider.entry(e.id):void 0,i=this.modelUrl(e)??t?.url,n=e.credit??t?.credit;if(!(!i||!n))return{scene:await xg(i),credit:n,headingOffsetDeg:e.headingOffsetDeg??t?.headingOffsetDeg}}async loadDecorModel(e,t){const i=e.model;if(!(!i||!oi.usesModel(e)))try{const n=i.url?void 0:i.id?await this.decorModelProvider.entry(i.id):void 0,s=this.modelUrl(i)??n?.url,r=i.credit??n?.credit;if(!s||!r)return;const o=await xg(s);if(t!==this.decorModelToken)return;const l=this.decorGroups.get(e.id);if(!l)return;pn.reflectOn(o),oi.applyModel(l,e,o,{headingOffsetDeg:i.headingOffsetDeg??n?.headingOffsetDeg,depictedSizeM:n?.sizeM}),this.decorModelCredits.set(e.id,r),this.render()}catch(n){console.warn(`Keeping the built-in shape for decor "${e.id}":`,n)}}updateDecorAnchoring(e,t,i=0){this.decorReferencePose=e,this.decorCurrentPose=t,this.decorTime=i;const n=e?.lat!==void 0&&e.lng!==void 0&&t?.lat!==void 0&&t?.lng!==void 0?li(e.lat,e.lng,t.lat,t.lng):{x:0,z:0},s=this.decorObjects.find(c=>c.observerSide!==void 0&&Ua(c.kind));if(this.terrainMesh&&this.terrainOrigin&&t?.lat!==void 0&&t.lng!==void 0){const c=li(this.terrainOrigin.lat,this.terrainOrigin.lng,t.lat,t.lng);this.terrainMesh.position.x=c.x-(s?0:this.gaitOffset.eastM),this.terrainMesh.position.z=c.z+(s?0:this.gaitOffset.northM),this.roadSystem.group.position.copy(this.terrainMesh.position)}s||(n.x-=this.gaitOffset.eastM,n.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=oi.occupantView(s),h=-(s.headingDeg??0)*en,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+n.x,p=-s.northM+n.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*en,-(c.headingDeg+this.indoorLookYawDeg)*en,0,"YXZ")}this.bodyOrigin={x:n.x+r.x,z:n.z+r.z},this.placeShadowFrustum();for(const c of this.decorObjects){const h=this.decorGroups.get(c.id);if(!h)continue;const d=vr(c,i),u=d.eastM+n.x+r.x,f=-d.northM+n.z+r.z,p=this.terrainMesh,v=`${p?.geometry.uuid}:${(u-(p?.position.x??0)).toFixed(3)}:${(f-(p?.position.z??0)).toFixed(3)}:${(p?.position.y??0).toFixed(3)}:${d.headingDeg}:${d.altitudeM}`;if(h.userData.footprintKey!==v&&(h.userData.footprintGroundY=this.groundUnderFootprint(c,u,f,d.headingDeg,d.altitudeM),h.userData.footprintKey=v),h.position.set(u,h.userData.footprintGroundY+d.altitudeM,f),c.kind==="crop"){const m=Math.hypot(u,f);h.visible=m<=FA}if(d.headingDeg!==void 0&&(h.rotation.y=-d.headingDeg*en),c.kind==="crop"&&h.visible){const m=this.terrainMesh,g=[m?.geometry.uuid,u-(m?.position.x??0),f-(m?.position.z??0),h.position.y-(m?.position.y??0),d.headingDeg,d.altitudeM].map(y=>typeof y=="number"?y.toFixed(4):y).join(":");h.userData.cropGroundKey!==g&&(oi.fitCropToGround(h,(y,M)=>this.groundYUnder(y,M)+d.altitudeM),h.userData.cropGroundKey=g)}o=Math.max(o,h.position.distanceTo(this.camera.position))}const l=Math.max(xc*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 i=this.terrainMesh;return i?i.position.y+this.groundYOfPatch(i,e-i.position.x,t-i.position.z):jd}groundYOfPatch(e,t,i){const n=e.geometry.getAttribute("position"),s=Math.round(Math.sqrt(n.count));if(s<2||s*s!==n.count)return jd;const r=n.getX(0),o=n.getX(s-1),l=n.getZ(0),c=n.getZ((s-1)*s),h=Wa((t-r)/(o-r)*(s-1),0,s-1),d=Wa((i-l)/(c-l)*(s-1),0,s-1);if(!Number.isFinite(h)||!Number.isFinite(d))return jd;const u=Math.min(Math.floor(h),s-2),f=Math.min(Math.floor(d),s-2),p=h-u,v=d-f,m=(x,E)=>n.getY(x*s+E),g=m(f,u),y=m(f,u+1),M=m(f+1,u),b=m(f+1,u+1);return p+v<=1?g+(y-g)*p+(M-g)*v:b+(M-b)*(1-p)+(y-b)*(1-v)}groundUnderFootprint(e,t,i,n,s=0){return oi.groundUnderFootprint(e,t,i,n,(r,o)=>this.groundYUnder(r,o),s)}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}medium;setMedium(e,t,i,n){const s=e&&t!==void 0&&t>0&&i!==void 0&&i>0?{kind:e.kind,iso:n??e.iso,autoExposure:e.autoExposure===!0,exposureSeconds:t,fNumber:i}:void 0;JSON.stringify(s)!==JSON.stringify(this.medium)&&(this.medium=s,this.render())}applyMedium(){const e=this.medium,t=Math.max(this.relativeScale,1e-30);if(!e){$i.uMedium.value=0;return}$i.uMedium.value=e.kind==="negative"?1:e.kind==="slide"?2:3;const i=e.autoExposure?this.scatteredSky?.sceneAdaptation:void 0;$i.uMediumExposure.value=i!==void 0&&i>0?1/(t*i):.065*e.exposureSeconds*e.iso/(e.fNumber*e.fNumber*t)}grain;lampBloomRadiusRad(){if(!this.grain)return;const e=this.camera.fov*Math.PI/180,t=this.grain.frameHeightMm/(2*Math.tan(e/2)),i=Math.max(1,this.renderer.getDrawingBufferSize(this.bloomSize).y);return Math.max(this.grain.detailUm*.001/t,e/i)}bloomSize=new be;updateDecorLitState(e,t=0){const i=this.lampBloomRadiusRad();for(const n of this.decorObjects){const s=this.decorGroups.get(n.id);if(s&&n.lights?.length&&oi.setLights(s,n.lights,e,s.position.distanceTo(this.camera.position),t,this.relativeScale,i),n.kind!=="streetlight"&&n.kind!=="vehicle")continue;const r=this.decorGroups.get(n.id);if(!r)continue;const o=Kc(n,e);oi.setLit(r,n.kind,o,this.relativeScale);const l=this.streetlightLights.get(n.id);l&&(l.visible=o)}}addStreetlightLight(e,t){const i=oi.bodyOf(t),n=i.children.find(r=>r.userData.emissive);if(!n)return;const s=new g1(16764006,Dg*this.relativeScale,EA);s.position.copy(n.position).multiply(i.scale),s.castShadow=!0,s.shadow.mapSize.set(512,512),s.shadow.bias=-.002,t.add(s),this.streetlightLights.set(e,s)}setAstronomy(e){(!this.lastAstronomy||Math.abs(this.lastAstronomy.sun.altitudeDeg-e.sun.altitudeDeg)>2)&&(this.surroundings=void 0,this.scatteredSky?.resetSurroundings()),this.lastAstronomy=e,this.scatteredSky?.update(this.scatteredSkyState(e)),this.skyHoldUntilMs===void 0&&(this.skyHoldUntilMs=performance.now()+Cg,this.onFirstFrameHold?.(!0),setTimeout(()=>this.render(),Cg+20)),this.pumpScatteredSky(),this.lastSunPosition=e.sun,this.buildSky(e.sun),this.buildGround();const t=ur(e.sun.altitudeDeg,this.instrumentMagnitudeGain);this.buildStars(e.stars,t),this.placeBodies(e,t),this.buildIceHalos(e.sun,e.moon),this.buildRainbow(e.sun,e.moon),this.applySkyColours(e),this.syncAnimationLoop(),this.render()}static relativeSkyOf(e,t){const i=r=>{const o=Hn.luminanceOf(r);if(!(o>0))return[0,0,0];const l=_e.relativeOfResponse(o)/o;return[r[0]*l,r[1]*l,r[2]*l]},n=i(e.zenith),s=i(e.horizon);return{zenith:n,horizon:s,airlight:s,skyIrradiance:[n[0]*Math.PI,n[1]*Math.PI,n[2]*Math.PI],scale:t}}placeBodies(e,t){this.bodiesScale=this.relativeScale,this.setBodyMesh("sun",e.sun,zo,new se(1,.96,.88),e.sun.magnitude),this.setMoonMesh(e.moon,t),this.buildPlanets(e.planets,t),this.buildComet(e.comet,t),this.buildNovae(e.novae??[],t)}bodiesScale=0;applySkyColours(e){this.skyColoursStale=!1,this.bodiesScale!==this.relativeScale&&(this.placeBodies(e,ur(e.sun.altitudeDeg,this.instrumentMagnitudeGain)),this.applyDazzleStrength(),this.buildIceHalos(e.sun,e.moon),this.buildRainbow(e.sun,e.moon));const t=this.scatteredSky?.ambient??Gt.relativeSkyOf(wf(e.sun.altitudeDeg),this.relativeScale),i=t,n=this.lightUnderClouds(e),s=r=>n?[0,1,2].map(o=>r[o]*n.through+n.radiance[o]*(1-n.through)):[r[0],r[1],r[2]];this.baseFogColor=[i.horizon[0],i.horizon[1],i.horizon[2]],this.airlight=s(i.airlight),this.skyMesh&&this.skyGradientMaterial&&(this.skyMesh.material=this.scatteredSky?.ready?this.scatteredSky.material:this.skyGradientMaterial),this.updateCelestialLight(e,t),this.updateCloudLighting(e.sun,this.baseFogColor),rt.setEye(this.scatteredSky?.rodShare??0,this.relativeScale),this.updateTwinkle(this.twinkleSeconds);for(const r of this.streetlightLights.values())r.intensity=Dg*this.relativeScale;this.buildSkyGlow(e,i.zenith),this.applyAir(),this.buildLunarDiffraction(e.moon)}reflections;sceneVersion=0;reflectionTimer;buildLunarDiffraction(e){const t=this.scatteredSky?.ready?this.scatteredSky:void 0;if(e.altitudeDeg<-.5||!t){this.lunarDiffraction?.show(void 0),this.lunarDiffractionKey="";return}const i=this.weather.relativeHumidity,n=(i===void 0?ke.DEFAULT_AEROSOL_OPTICAL_DEPTH:Ns.opticalDepth(i))*ke.aerosolDensity(this.siteElevationM+this.observerElevationM),s=this.cloudTransmission(e),r=-Math.log(Math.max(this.cloudTransmission(e,!0),1e-4)),o=vt.aureoleScale(n,vt.airMass(e.altitudeDeg))*s,l=vt.coronaScale(r),c=vt.illuminanceOf(e.magnitude),h=[e.altitudeDeg.toFixed(1),e.azimuthDeg.toFixed(1),e.magnitude.toFixed(2),o.toExponential(2),l.toExponential(2),Math.log10(Math.max(t.adaptation,1e-12)).toFixed(2)].join(":");if(h===this.lunarDiffractionKey)return;this.lunarDiffractionKey=h,this.lunarDiffraction||(this.lunarDiffraction=new Bp,this.celestialGroup.add(this.lunarDiffraction.object));const d=vt.profile(vt.HAZE_COARSE_MODE),u=vt.profile(vt.CLOUD_DROPLETS),f=qm(e.altitudeDeg),p=new Float32Array(vt.STEPS*3);let v=0;for(let M=0;M<vt.STEPS;M++){const b=M*3,x=[0,1,2].map(I=>c*f[I]*(o*d[b+I]+l*u[b+I])),E=Hn.shown(x,Hn.luminanceOf(x),(I,w)=>t.relativeOfLuminance(I,w));p.set(E,b),v=Math.max(v,Hn.response(E))}const{x:m,y:g,z:y}=fi(e.altitudeDeg,e.azimuthDeg,1);this.lunarDiffraction.show(v>1/200?{x:m,y:g,z:y}:void 0,p)}applyAir(){this.scene.fog instanceof Jr||(this.scene.fog=new Jr),this.scene.fog.setAir(this.air,this.siteElevationM,this.airlight)}airlight=[0,0,0];transmittanceTo(e,t,i){const n=this.camera.position;return this.air.transmittance(this.siteElevationM+n.y,this.siteElevationM+t,Math.hypot(e-n.x,t-n.y,i-n.z))}setSiteElevation(e){Math.abs(e-this.siteElevationM)<1||(this.siteElevationM=e,this.applyAir(),this.lastAstronomy&&this.scatteredSky?.update(this.scatteredSkyState(this.lastAstronomy)))}scatteredSkyState(e){return{altitudeM:this.siteElevationM+this.observerElevationM+1.6,sun:{altitudeDeg:e.sun.altitudeDeg,azimuthDeg:e.sun.azimuthDeg,magnitude:e.sun.magnitude},moon:{altitudeDeg:e.moon.altitudeDeg,azimuthDeg:e.moon.azimuthDeg,magnitude:e.moon.magnitude,phaseAngleDeg:We.phaseAngleOf(e.moon.phase.illuminatedFraction)}}}pumpScatteredSky(){const e=this.scatteredSky;!e||e.tables.ready||this.scatteredSkyFrameId!==null||this.contextReleased||(this.scatteredSkyFrameId=requestAnimationFrame(()=>{this.scatteredSkyFrameId=null,!this.contextReleased&&(e.advance(this.skyHoldUntilMs?DA:IA),this.pumpScatteredSky())}))}cancelScatteredSkyPump(){this.scatteredSkyFrameId!==null&&(cancelAnimationFrame(this.scatteredSkyFrameId),this.scatteredSkyFrameId=null)}setSatellites(e){if(e.length===0&&!this.satelliteField?.count)return;this.satelliteField||(this.satelliteField=new H5(Wd),this.celestialGroup.add(this.satelliteField.object));const t=ur(this.lastSunPosition?.altitudeDeg??-90,this.instrumentMagnitudeGain);this.satelliteField.set(e,t,i=>this.cloudTransmission(i),(i,n)=>this.arrivingIlluminance(i,n,1)),this.render()}pickSatelliteAt(e,t){if(!this.satelliteField?.count)return;this.aimAtScreenPoint(this.raycaster,e,t);const i=Math.cos(Tg*this.camera.fov*Math.PI/180),n=this.satelliteField.nearest(this.raycaster.ray.direction,i);return n&&this.groundHides(e,t)?void 0:n}updateCelestialLight(e,t){const i=this.relativeScale,n=e.sun.altitudeDeg>=Ec,s=!n&&e.moon.altitudeDeg>=Ec,r=n?e.sun:e.moon,o=[0,0,0],l=Math.max(0,Math.sin(Math.max(r.altitudeDeg,0)*en)),c=n||s?this.cloudTransmission(r):1,h=-Math.log(Math.max(c,1e-6)),d=Math.max(0,1/(1+.1125*h)-c),u=[0,0,0];if(n||s){const y=vt.illuminanceOf(r.magnitude)*i,M=this.air.transmittanceFromSpace(this.siteElevationM+this.observerElevationM,r.altitudeDeg);for(let I=0;I<3;I++)o[I]=y*M[I]*c,u[I]=y*M[I]*d*l,this.cloudBeam[I]=y*M[I];const{x:b,y:x,z:E}=fi(r.altitudeDeg,r.azimuthDeg,1);this.cloudBeamDirection.set(b,x,E)}else this.cloudBeam.fill(0);const f=this.surroundings;if(f)this.skyLight.color.setRGB(f.up[0]*i,f.up[1]*i,f.up[2]*i),this.skyLight.groundColor.setRGB(f.down[0]*i,f.down[1]*i,f.down[2]*i);else{const y=this.skyCloudTransmission(),M=t.skyIrradiance,b=[0,1,2].map(E=>M[E]*y+u[E]);this.skyLight.color.setRGB(b[0],b[1],b[2]);const x=Ve.GROUND_ALBEDO;this.skyLight.groundColor.setRGB(x*(b[0]+o[0]*l),x*(b[1]+o[1]*l),x*(b[2]+o[2]*l))}if(this.skyLight.intensity=1,!n&&!s){this.celestialLight.intensity=0;return}const{x:p,y:v,z:m}=fi(r.altitudeDeg,r.azimuthDeg,1);this.lightDirection.set(p,v,m),this.placeShadowFrustum();const g=Math.max(o[0],o[1],o[2],1e-30);this.celestialLight.color.setRGB(o[0]/g,o[1]/g,o[2]/g),this.celestialLight.intensity=g,this.celestialLight.castShadow=this.decorGroups.size>0||this.bodySystem.any}lightDirection=new C(0,1,0);placeShadowFrustum(){const e=this.lightDirection,t=this.celestialLight.shadow.camera,i=(t.right-t.left)/this.celestialLight.shadow.mapSize.x,n=this.shadowAxisX.crossVectors(this.shadowUp,e);n.lengthSq()<1e-8&&n.set(1,0,0),n.normalize();const s=this.shadowAxisY.crossVectors(e,n).normalize(),r=this.shadowWorld.set(this.bodyOrigin.x,0,this.bodyOrigin.z),o=c=>{const h=r.dot(c)/i;return(h-Math.round(h))*i},l=this.celestialLightTarget.position.set(0,0,0).addScaledVector(n,o(n)).addScaledVector(s,o(s));this.celestialLightTarget.updateMatrixWorld(),this.celestialLight.position.copy(l).addScaledVector(e,this.shadowLightDistanceM)}fitShadowToBodies(){const e=this.bodySystem.reachFrom(this.camera.position),t=Math.min(vA,Math.max(tr,Math.ceil(e*1.25/20)*20));if(t===this.shadowHalfExtentM)return;this.shadowHalfExtentM=t;const i=this.celestialLight.shadow,n=i.camera;n.left=-t,n.right=t,n.top=t,n.bottom=-t;const s=Math.max(Bo,t*(Bo/tr));this.shadowLightDistanceM=Math.max(dn,s+10),n.near=this.shadowLightDistanceM-s,n.far=this.shadowLightDistanceM+s,n.updateProjectionMatrix(),i.bias=-.03/(2*s);const r=t>2*tr?2048:1024;i.mapSize.x!==r&&(i.mapSize.set(r,r),i.map?.dispose(),i.map=null),this.placeShadowFrustum()}shadowHalfExtentM=tr;shadowLightDistanceM=dn;shadowUp=new C(0,1,0);shadowAxisX=new C;shadowAxisY=new C;shadowWorld=new C;skyCloudTransmission(){let e=this.cloudTransmission({altitudeDeg:90,azimuthDeg:0}),t=1;for(const i of[20,45,70]){const n=i*en,s=Math.sin(n)*Math.cos(n)*2;for(let r=0;r<360;r+=60)e+=s*this.cloudTransmission({altitudeDeg:i,azimuthDeg:r}),t+=s}return e/t}cloudBeam=[0,0,0];cloudBeamDirection=new C(0,1,0);get relativeScale(){return this.scatteredSky?.relativeScale??1/_e.semiSaturation(_e.DAYLIGHT_ANCHOR_CD_M2)}setMeteorShower(e,t,i){this.meteorSystem||(this.meteorSystem=new wi,this.celestialGroup.add(this.meteorSystem.object)),this.meteorSystem.setShower(e,t,i)}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,this.grain=e.detailUm!==void 0&&e.frame?{detailUm:e.detailUm,frameHeightMm:e.frame.heightMm}:void 0;const t=Mt.starPointsOf(e),i=Mt.flareArtifactsOf(e);t===this.starPoints&&i===this.lensFlareArtifactIntensity||(this.starPoints=t,this.lensFlareArtifactIntensity=i,this.lensFlare&&(this.lensFlare.uniforms.uStarPoints.value=t,this.lensFlare.uniforms.uFlareIntensity.value=i),this.render())}setInstrumentGain(e,t=!1){this.instrumentMagnitudeGain=Number.isFinite(e)?e:0,this.scatteredSky?.setInstrument(t,this.instrumentMagnitudeGain)}render(){this.restatingExposure||(this.sceneVersion++,this.frameDirty=!0,this.resolution.noteChange(performance.now()),!(this.animationFrameId!==null||this.framesDriven||this.flushFrameId!==null)&&(this.flushFrameId=requestAnimationFrame(()=>{this.flushFrameId=null,this.drawIfDirty()})))}drawIfDirty(){if(!(!this.frameDirty||this.contextReleased)){if(this.skyHoldUntilMs){if(!this.firstFrameReady()&&performance.now()<this.skyHoldUntilMs)return;this.skyHoldUntilMs=null,this.iceHalos?.setUrgent(!1),this.onFirstFrameHold?.(!1)}if(this.skyColoursStale&&this.lastAstronomy&&this.applySkyColours(this.lastAstronomy),this.compileBeforeNextDraw){this.compileBeforeNextDraw=!1;const e=this.compileOffThread().then(()=>{this.compiling===e&&(this.compiling=void 0,this.render())});this.compiling=e;return}if(!this.compiling){this.frameDirty=!1,this.refreshReflections(),this.resolution.beginDrawing();try{this.renderOnce()}finally{this.resolution.endDrawing()}this.developingExposure&&this.startExposure()}}}compileBeforeNextDraw=!1;compiling;static COMPILE_WAIT_MS=1500;compileOffThread(){const e=this.renderer.compile(this.scene,this.camera);if(!this.renderer.extensions.get("KHR_parallel_shader_compile"))return Promise.resolve();const t=this.renderer.properties,i=performance.now()+Gt.COMPILE_WAIT_MS;return new Promise(n=>{const s=()=>{if(this.contextReleased)return n();for(const r of e){const o=t.get(r)?.currentProgram;(!o||o.isReady())&&e.delete(r)}e.size===0||performance.now()>i?n():setTimeout(s,10)};s()})}compileNextFrameOffThread(){this.compileBeforeNextDraw=!0}contextReleased=!1;releaseContext(){this.contextReleased||(this.contextReleased=!0,this.stopTwinkle(),this.cancelFlush(),this.cancelExposure(),this.compiling=void 0,this.cancelScatteredSkyPump(),this.renderer.forceContextLoss())}restoreContext(){this.contextReleased&&(this.contextReleased=!1,this.renderer.forceContextRestore(),this.scatteredSky?.invalidate(),this.pumpScatteredSky(),this.compileNextFrameOffThread(),this.syncAnimationLoop(),this.render())}cancelFlush(){this.flushFrameId!==null&&(cancelAnimationFrame(this.flushFrameId),this.flushFrameId=null)}frame(e){if(this.animationsRunning){const t=this.lastFrameTimeMs===void 0?0:e-this.lastFrameTimeMs;this.lastFrameTimeMs=e,this.hasAnimations()&&this.animate(e,t);const i=this.resolution.ratioFor(e,t);i!==this.renderer.getPixelRatio()&&this.applyPixelRatio(i)}this.drawIfDirty()}refreshReflections(){this.reflections??=new pn(this.renderer);const e=[...this.compassSprites,...this.lensFlare?[this.lensFlare.mesh]:[],...[...this.glareSprites.values()].map(s=>s.mesh)],t=[...this.starTiers.map(s=>s.points),...[...this.bodyMeshes.values()].filter(s=>s instanceof Ps),...[this.rainSystem?.points,this.precipitationPoints,this.rainSplashSystem?.points].filter(s=>s!==void 0)],i=this.relativeScale,n=this.reflections.refresh(this.renderer,this.scene,this.camera.position,this.bodySystem.reflectors,e,[...this.decorGroups.values()],this.sceneVersion,t,s=>this.measureSurroundings(s,i));n===void 0||this.reflectionTimer||(this.reflectionTimer=setTimeout(()=>{this.reflectionTimer=void 0,this.frameDirty=!0,!(this.animationFrameId!==null||this.framesDriven||this.flushFrameId!==null)&&(this.flushFrameId=requestAnimationFrame(()=>{this.flushFrameId=null,this.drawIfDirty()}))},n))}measureSurroundings(e,t){const i=this.lastAstronomy;if(!i)return;this.probeIrradiance??=new rl;const n=[i.sun,i.moon].filter(s=>s.altitudeDeg>-2).map(s=>fi(s.altitudeDeg,s.azimuthDeg,1));this.probeIrradiance.measure(this.renderer,e,n,s=>{const r=u=>u.map(f=>f/t),o=this.surroundings,l={up:r(s.up),down:r(s.down)},c=(u,f)=>u.some((p,v)=>Math.abs(p-f[v])>.03*Math.max(Math.abs(p),Math.abs(f[v]),1e-12)),h=!o||c(o.up,l.up)||c(o.down,l.down);h&&(this.surroundings=l);const d=this.scatteredSky?.adaptToSurroundings(Math.exp(s.logAverage)/t)??!1;!h&&!d||(this.skyColoursStale=!0,this.render())})}lightUnderClouds(e){const t=this.surroundings;if(!t)return;const i=e.sun.altitudeDeg>=Ec?e.sun:e.moon.altitudeDeg>=Ec?e.moon:void 0;if(!i)return;const n=this.relativeScale/Math.PI;return{through:this.cloudTransmission(i),radiance:[t.up[0]*n,t.up[1]*n,t.up[2]*n]}}probeIrradiance;surroundings;animate(e,t){const i=Math.min(t/1e3,ZA);this.twinkleSeconds=e/1e3,this.updateTwinkle(this.twinkleSeconds),this.updatePrecipitation(e/1e3,i),this.updateRain(i),this.lensFlare&&(this.lensFlare.uniforms.uTime.value=e/1e3),this.developingExposure||(this.frameDirty=!0)}setMaxPixelRatio(e){this.resolution.maximum=e,this.renderer.getPixelRatio()>this.resolution.maximum&&this.applyPixelRatio(this.resolution.maximum)}applyPixelRatio(e){this.renderer.setPixelRatio(e),this.renderer.setSize(this.cssSize.width,this.cssSize.height,!1),this.frameDirty=!0}setExposure(e,t){const i=t?Math.max(1,Math.round(e)):1;if(i===this.exposureInstants&&(i===1||t===this.exposureInstantAt)){this.exposureInstantAt=t;return}this.exposureInstants=i,this.exposureInstantAt=t,i===1&&(this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0),this.render()}renderOnce(e){if(this.onMapSubjectBounds){const r=this.mapSubjectBounds();e?this.exposureSubjectBounds.push(...r):this.onMapSubjectBounds(r)}const t=this.usableEquidistantPass();this.phenomena.setCloudLayers(this.layeredClouds?.volumes??[]),this.phenomena.place(this.camera,(r,o,l)=>this.directionAtScreenPoint(r,o,l),r=>this.screenPointOf(r)),this.references.place(this.camera);const i=Math.max(this.phenomena.furthestM,this.references.furthestM)*1.2;i>this.camera.far&&(this.camera.far=i,this.camera.updateProjectionMatrix()),$i.uRodShare.value=this.scatteredSky?.rodShare??0,$i.uRelativeScale.value=this.relativeScale,this.applyMedium();const n=this.references.any||this.phenomena.any||this.compassSprites.some(r=>r.visible);$i.uHasOverlay.value=n?1:0;const s=n?r=>this.renderOverlayPasses(r):void 0;if(this.skyGlow?.setDestinationEncoded(!1),!t){this.updateLensFlarePosition();const r=this.usableDepthOfFieldPass();r?r.render(this.renderer,this.scene,this.camera,s,e):this.usableFinishPass().render(this.renderer,this.scene,this.camera,s,void 0,e);return}t.render(this.renderer,this.scene,this.camera,this.camera.fov,()=>this.updateLensFlarePosition(),s,r=>{this.lensFlare&&(this.lensFlare.mesh.visible=r?!1:this.sunVisible)},()=>this.renderDazzleOnResample(),e)}renderOverlayPasses(e=this.camera){this.renderReferencesPass(e),this.renderPhenomenaPass(e),this.renderHudPass(e)}renderHudPass(e){if(!this.compassSprites.some(n=>n.visible))return;const t=this.renderer.autoClear,i=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,e.layers.set(Eg),this.renderer.render(this.scene,e),e.layers.set(0),this.renderer.autoClear=t,this.renderer.shadowMap.autoUpdate=i}renderReferencesPass(e){if(!this.references.any)return;const t=this.renderer.autoClear,i=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,e.layers.set(ob),this.renderer.render(this.scene,e),e.layers.set(0),this.renderer.autoClear=t,this.renderer.shadowMap.autoUpdate=i}setReferences(e,t){this.references.set(e.map(i=>{const n=this.documentRelative(i.src);return n===i.src?i:{...i,src:n}}),void 0,t)}referenceAspect(e){return this.references.aspectOf(e)}directionAt(e,t){return this.directionAtScreenPoint(e,t,new C)}referenceFailedToLoad(e){return this.references.failedToLoad(this.documentRelative(e))}setReferencesShown(e){this.references.setShown(e),this.render()}setReferenceView(e,t){this.references.setView(e,t),this.render()}renderPhenomenaPass(e){if(!this.phenomena.any)return;const t=this.renderer.autoClear,i=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,this.renderer.clearDepth();for(const n of this.decorObjects){const s=this.decorGroups.get(n.id);s&&Gt.markDecorDepth(s,n.kind!=="crop")}e.layers.set(Gd),this.scene.overrideMaterial=this.decorDepthMaterial,this.renderer.render(this.scene,e),this.scene.overrideMaterial=null,e.layers.set(ab),this.renderer.render(this.scene,e),e.layers.set(0),this.renderer.autoClear=t,this.renderer.shadowMap.autoUpdate=i}decorDepthMaterial=new Dn({colorWrite:!1});static markDecorDepth(e,t){e.traverse(i=>{if(!(i instanceof Ie))return;const n=Array.isArray(i.material)?i.material[0]:i.material;t&&n.depthWrite!==!1&&n.blending!==Vi?i.layers.enable(Gd):i.layers.disable(Gd)})}startExposure(){this.cancelExposure(),this.exposureSubjectBounds=[];const e=this.renderer.getDrawingBufferSize(new be),t=Math.max(1,Math.round(e.x)),i=Math.max(1,Math.round(e.y));this.exposureAccumulation||(this.exposureAccumulation=new o_(t,i)),this.exposureAccumulation.resize(t,i),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 i=1/this.exposureInstants;this.resolution.beginDrawing();const n=performance.now()+Gt.EXPOSURE_BUDGET_MS,s=Gt.exposureInstantsPerFrame(t.instantTarget.scene.width*t.instantTarget.scene.height);let r=0;do{this.restateAt(e,this.exposureInstantsDone);const o=this.compassSprites.map(l=>l.visible);for(const l of this.compassSprites)l.visible=!1;try{this.renderOnce(t.instantTarget)}finally{this.compassSprites.forEach((l,c)=>{l.visible=o[c]})}t.add(this.renderer,i),this.exposureInstantsDone++,r++}while(this.exposureInstantsDone<this.exposureInstants&&performance.now()<n&&r<s);this.restateAt(e,0),this.presentExposure(),this.resolution.endDrawing(),this.exposureInstantsDone<this.exposureInstants&&(this.exposureFrameId=requestAnimationFrame(()=>this.developExposure()))}presentExposure(){if($i.uRodShare.value=this.scatteredSky?.rodShare??0,$i.uHasOverlay.value=1,$i.uRelativeScale.value=this.relativeScale,this.applyMedium(),this.exposureAccumulation?.develop(this.renderer,this.exposureInstants/this.exposureInstantsDone),this.onMapSubjectBounds?.(this.exposureSubjectBounds),!this.compassSprites.some(s=>s.visible))return;const e=new Bs,t=new Xn(-1,1,1,-1,0,2),i=_c/(Rg*Math.tan(Pg*en/2));for(const s of this.compassSprites){if(!s.visible)continue;const r=s.getWorldPosition(new C).sub(this.camera.position).normalize(),o=this.screenPointOf(r);if(!o)continue;const l=new To(s.material);l.position.set(o.ndcX,o.ndcY,-1),l.scale.set(i/this.camera.aspect,i,1),e.add(l)}const n=this.renderer.autoClear;this.renderer.autoClear=!1;try{this.renderer.render(e,t)}finally{this.renderer.autoClear=n}}onMapSubjectBounds;exposureSubjectBounds=[];static MAP_SUBJECT_NEAREST_M=8;mapSubjectBounds(){const e=[],t=new Zi,i=new C,n=this.camera.getWorldDirection(new C),s=this.decorObjects.filter(o=>o.track?.length||o.kind==="aircraft"||o.kind==="vehicle").map(o=>this.decorGroups.get(o.id)),r=this.bodySystem.reflectors.map(o=>o.holder);for(const o of[...s,...r]){if(!o?.visible||(t.setFromObject(o),t.isEmpty())||t.distanceToPoint(this.camera.position)<Gt.MAP_SUBJECT_NEAREST_M)continue;let l=1/0,c=-1/0,h=1/0,d=-1/0;for(const u of[t.min.x,t.max.x])for(const f of[t.min.y,t.max.y])for(const p of[t.min.z,t.max.z]){if(i.set(u,f,p).sub(this.camera.position).normalize(),i.dot(n)<=0)continue;const v=this.screenPointOf(i);if(!v)continue;const m=(v.ndcX+1)/2,g=(1-v.ndcY)/2;l=Math.min(l,m),c=Math.max(c,m),h=Math.min(h,g),d=Math.max(d,g)}l=Math.max(l,0),c=Math.min(c,1),h=Math.max(h,0),d=Math.min(d,1),c>=l&&d>=h&&e.push({x:l,y:h,width:c-l,height:d-h})}return e}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 be),i=Math.max(1,Math.round(t.x)),n=Math.max(1,Math.round(t.y));return this.depthOfFieldPass||(this.depthOfFieldPass=new al(i,n)),this.depthOfFieldPass.resize(i,n),this.depthOfFieldPass.setLens(e.focalLengthMm,e.fNumber,e.focusDistance,e.frameHeightMm),this.depthOfFieldPass}usableFinishPass(){const e=this.renderer.getDrawingBufferSize(new be);return this.finishPass?this.finishPass.resize(e.x,e.y):this.finishPass=new Up(e.x,e.y),this.finishPass}usableEquidistantPass(){if(this.projectionKind!=="equidistant")return;const e=this.renderer.getDrawingBufferSize(new be);return this.equidistantPass?this.equidistantPass.resize(e.x,e.y):this.equidistantPass=new Si(e.x,e.y),this.equidistantPass}aimAtScreenPoint(e,t,i){const n=this.projectionKind==="equidistant"?this.equidistantPass:void 0;if(!n){e.setFromCamera(new be(t,i),this.camera);return}const s=n.directionFor(t,i,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 C)}directionAtScreenPoint(e,t,i){return this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),i.copy(this.ufoOcclusionRaycaster.ray.direction)}screenPointOf(e){this.camera.updateMatrixWorld();const t=this.screenPointScratch.copy(e).applyQuaternion(this.screenPointQuaternion.copy(this.camera.quaternion).invert()),i=this.renderer.getDrawingBufferSize(this.screenPointSize),n=i.x/Math.max(i.y,1);if(this.projectionKind==="equidistant"&&this.equidistantPass)return Si.ndcFor(t,this.camera.fov,n);if(t.z>=0)return;const s=Math.tan(this.camera.fov/2*en);return{ndcX:t.x/-t.z/(n*s),ndcY:t.y/-t.z/s}}screenPointScratch=new C;screenPointQuaternion=new Gi;screenPointSize=new be;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 i=this.lensFlareScratch.copy(this.sunWorldPosition).project(this.camera);e.uniforms.uLensPosition.value.set(i.x,i.y);const n=this.renderer.domElement.width,s=this.renderer.domElement.height;e.uniforms.uResolution.value.set(n,s),e.uniforms.uTanHalfFov.value=Math.tan(this.camera.fov*Math.PI/360)}renderDazzleOnResample(){const e=this.lensFlare;if(!e||!this.sunVisible)return;const t=this.sunVisibleFraction();if(t<=0)return;this.sunUnhiddenFraction=t,this.applyDazzleStrength();const i=this.screenPointOf(this.lensFlareScratch.copy(this.sunWorldPosition).sub(this.camera.position).normalize());if(!i)return;const n=this.renderer.getDrawingBufferSize(this.screenPointSize);e.uniforms.uLensPosition.value.set(i.ndcX,i.ndcY),e.uniforms.uResolution.value.set(n.x,n.y),e.uniforms.uEquidistant.value=1,e.uniforms.uHalfFovRad.value=this.camera.fov*Math.PI/360;const s=this.renderer.autoClear;this.renderer.autoClear=!1,e.mesh.visible=!0,e.mesh.layers.enable(Sg),this.camera.layers.set(Sg),this.renderer.render(this.scene,this.camera),this.camera.layers.set(0),e.mesh.visible=!1,e.uniforms.uEquidistant.value=0,this.renderer.autoClear=s}sunVisibleFraction(){this.raycastableDecor().length>0&&this.scene.updateMatrixWorld();let e=0;for(const t of Og)this.isSunOccluded(t[0],t[1])||e++;return e/Og.length}raycastableDecor(){const e=[];for(const t of this.decorObjects){if(t.kind==="crop")continue;const i=this.decorGroups.get(t.id);i&&e.push(i)}return e}isSunOccluded(e=0,t=0){const i=this.raycastableDecor();if(!this.groundMesh&&!this.terrainMesh&&i.length===0)return!1;const n=this.sunOcclusionDirectionScratch.copy(this.sunWorldPosition).sub(this.camera.position),s=n.length();if(n.normalize(),e!==0||t!==0){const o=Math.PI/180,l=this.sunOcclusionRightScratch.set(n.z,0,-n.x);l.lengthSq()<1e-9&&l.set(1,0,0),l.normalize();const c=this.sunOcclusionUpScratch.crossVectors(l,n).normalize();n.addScaledVector(l,e*o).addScaledVector(c,t*o).normalize()}if(this.groundBlocks(this.camera.position,n,s))return!0;if(i.length===0)return!1;this.sunOcclusionRaycaster.set(this.camera.position,n);const r=this.sunOcclusionRaycaster.intersectObjects(i,!0)[0];return r!==void 0&&r.distance<s}groundBlocks(e,t,i,n=0){const s=this.groundMesh;if(s&&t.y<0){const m=(s.position.y-e.y)/t.y;if(m>n&&m<i){const g=e.x+t.x*m-s.position.x,y=e.z+t.z*m-s.position.z;if(Math.hypot(g,y)<=this.groundRadius)return!0}}const r=this.terrainMesh;if(!r)return!1;const o=r.geometry.getAttribute("position"),l=Math.round(Math.sqrt(o.count));if(l<2||l*l!==o.count)return!1;const c=[r.position.x+o.getX(0),r.position.x+o.getX(l-1)],h=[r.position.z+o.getZ(0),r.position.z+o.getZ((l-1)*l)],d=Math.min(Math.abs(c[1]-c[0]),Math.abs(h[1]-h[0]))/(l-1);if(!(d>0))return!1;let u=n,f=i;for(const[m,g,y]of[[e.x,t.x,c],[e.z,t.z,h]]){const M=Math.min(y[0],y[1]),b=Math.max(y[0],y[1]);if(Math.abs(g)<1e-12){if(m<M||m>b)return!1;continue}const x=(M-m)/g,E=(b-m)/g;u=Math.max(u,Math.min(x,E)),f=Math.min(f,Math.max(x,E))}if(!(f>u))return!1;const p=Math.hypot(t.x,t.z),v=Math.min(4096,Math.max(8,Math.ceil((f-u)*p/(d/2))));for(let m=0;m<=v;m++){const g=u+(f-u)*m/v,y=e.x+t.x*g,M=e.y+t.y*g,b=e.z+t.z*g;if(M<=this.groundYUnder(y,b))return!0}return!1}setPhenomena(e,t){this.phenomena.set(e,t)}decorDistancesAt(e,t,i){this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t),this.ufoOcclusionRaycaster.near=_g;let n,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(i)?n=n===void 0?l.distance:Math.max(n,l.distance):s=s===void 0?l.distance:Math.min(s,l.distance))}return{behindM:n,inFrontM:s}}pickBodyAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const i=[...this.hitAreas.entries()],n=this.raycaster.intersectObjects(i.map(([,s])=>s))[0];if(n&&!this.groundHides(e,t))return i.find(([,s])=>s===n.object)?.[0]}pickStarAt(e,t){if(this.namedStars.length===0)return;this.aimAtScreenPoint(this.raycaster,e,t);const i=this.raycaster.ray.direction,n=Math.cos(Tg*this.camera.fov*Math.PI/180);let s,r=n;for(const o of this.namedStars){const l=o.direction.dot(i);l>r&&(r=l,s={star:o.star,altitudeDeg:o.altitudeDeg})}return s&&this.groundHides(e,t)?void 0:s}groundHides(e,t){if(!this.terrainMesh&&!this.groundMesh)return!1;this.aimAtScreenPoint(this.ufoOcclusionRaycaster,e,t);const i=this.ufoOcclusionRaycaster.ray;return this.groundBlocks(i.origin,i.direction,1/0,_g)}bodyScreenBox(e){const t=this.bodySystem.boxOf(e,this.bodyBoxScratch);if(!t)return;let i=1/0,n=1/0,s=-1/0,r=-1/0;for(let o=0;o<8;o++){const l=this.bodyCornerScratch.set(o&1?t.max.x:t.min.x,o&2?t.max.y:t.min.y,o&4?t.max.z:t.min.z),c=this.screenPointOf(l.sub(this.camera.position).normalize());if(!c)return;i=Math.min(i,c.ndcX),s=Math.max(s,c.ndcX),n=Math.min(n,c.ndcY),r=Math.max(r,c.ndcY)}return{minX:i,minY:n,maxX:s,maxY:r}}bodyBoxScratch=new Zi;bodyCornerScratch=new C;pickPlacedBodyAt(e,t){return this.aimAtScreenPoint(this.raycaster,e,t),this.bodySystem.pick(this.raycaster)}pickDecorAt(e,t){this.aimAtScreenPoint(this.raycaster,e,t);const i=[...this.decorGroups.entries()],n=this.raycaster.intersectObjects(i.map(([,r])=>r),!0)[0];if(!n)return;let s=n.object;for(;s&&!i.some(([,r])=>r===s);)s=s.parent;return i.find(([,r])=>r===s)?.[0]}dispose(){this.stopTerrainFade(),this.stopTwinkle(),this.cancelFlush(),this.phenomena.clear(),this.references.disposeAll(),this.terrainBuildToken++,this.cancelScatteredSkyPump(),this.skyMesh&&this.skyGradientMaterial&&(this.skyMesh.material=this.skyGradientMaterial),this.scatteredSky?.dispose(),this.scatteredSky=void 0,this.disposeMesh(this.skyMesh),this.disposeMesh(this.groundMesh),this.disposeMesh(this.terrainMesh),this.roadSystem.dispose(),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.finishPass?.dispose(),this.depthOfFieldPass=void 0,this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0,this.cometTail?.dispose(),this.cometTail=void 0,this.satelliteField?.dispose(),this.satelliteField=void 0,this.lightningBolt?.dispose(),this.lightningBolt=void 0;for(const e of this.bodyMeshes.values())this.disposeMesh(e);this.bodyMeshes.clear(),this.novaKeys.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())oi.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;this.cancelFlush();const e=t=>{this.frame(t),this.animationFrameId=requestAnimationFrame(e)};this.animationFrameId=requestAnimationFrame(e)}setAnimationsRunning(e,t=!1){const i=e&&t;if(e===this.animationsRunning&&i===this.framesDriven)return;const n=this.animationsRunning;this.animationsRunning=e,this.framesDriven=i,e&&!n&&(this.lastFrameTimeMs=void 0,this.resolution.reset()),!e&&this.renderer.getPixelRatio()!==this.resolution.maximum&&this.applyPixelRatio(this.resolution.maximum),this.syncAnimationLoop(),(!e||this.frameDirty)&&this.render()}stopTwinkle(){this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}needsAnimationLoop(){return this.animationsRunning&&!this.framesDriven&&this.hasAnimations()}hasAnimations(){return this.starTiers.length>0||this.precipitationPoints!==void 0||this.rainSystem!==void 0||this.lensFlare!==void 0&&this.sunVisible}syncAnimationLoop(){this.needsAnimationLoop()?this.startTwinkle():this.stopTwinkle()}buildSky(e){const t=this.skyMesh?.geometry??new hi(xc,32,16),i=t.attributes.position,n=t.getAttribute("color")??new mt(new Float32Array(i.count*3),3);for(let r=0;r<i.count;r++){const{altitudeDeg:o,azimuthDeg:l}=h_(i.getX(r),i.getY(r),i.getZ(r)),c=b_(o,l,e.azimuthDeg,e.altitudeDeg);n.setXYZ(r,c[0],c[1],c[2])}if(n.needsUpdate=!0,this.skyMesh)return;t.setAttribute("color",n);const s=new Dn({vertexColors:!0,side:qt,fog:!1,depthWrite:!1});this.skyGradientMaterial=s,this.skyMesh=new Ie(t,s),this.skyMesh.renderOrder=-1,this.celestialGroup.add(this.skyMesh)}buildGround(){const e=Ag(this.observerElevationM);if(this.groundMesh&&e===this.groundRadius)return;this.disposeMesh(this.groundMesh),this.groundRadius=e;const t=new vp(this.groundRadius,48),i=new go({color:new se(Vd,Vd,Vd),fog:!0});Jr.fadeRim(i,this.groundRadius*.75,this.groundRadius),this.groundMesh=new Ie(t,i),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,t=!1){const i=`${e.altitudeDeg.toFixed(1)}:${e.azimuthDeg.toFixed(1)}:${Math.round(this.cloudOffsetM.x/10)}:${Math.round(this.cloudOffsetM.z/10)}:${Math.round(this.observerElevationM)}:`+Object.entries(this.cloudLayerOffsetsM).map(([r,o])=>`${r}=${Math.round(o.x/10)},${Math.round(o.z/10)}`).join(";")+(t?":water":""),n=this.cloudTransmissionMemo.get(i);if(n!==void 0)return n;this.cloudTransmissionMemo.size>256&&this.cloudTransmissionMemo.clear();const s=this.computeCloudTransmission(e,t);return this.cloudTransmissionMemo.set(i,s),s}cloudTransmissionMemo=new Map;computeCloudTransmission(e,t=!1){const i=fi(e.altitudeDeg,e.azimuthDeg,1);if(this.layeredClouds)return this.layeredClouds.transmissionAt(i,t);let n=1;const s=this.lowerCloudCover();s>0&&(n*=1-bt.alphaAt(i,Math.abs(this.cloudLayerOffset()),s,this.cloudFieldOffset)*xA);const r=t?0:this.weather.highCloudCover??0;return r>0&&(n*=1-bt.iceAlphaAt(i,Sc,r,this.cloudFieldOffset)*SA),Math.max(0,Math.min(1,n))}setBodyMesh(e,t,i,n,s){if(t.altitudeDeg<Wf){this.disposeMesh(this.bodyMeshes.get(e)),this.bodyMeshes.delete(e),this.disposeHitArea(e),this.disposeGlare(e),e==="sun"&&(this.sunVisible=!1);return}const{x:r,y:o,z:l}=fi(t.altitudeDeg,t.azimuthDeg,dn),c=qm(t.altitudeDeg),h=this.cloudTransmission(t),d=this.arrivingIlluminance(t,s,h),u=Gt.unitLuminance(n);let f=this.bodyMeshes.get(e);if(e==="sun"){const p=Math.PI*(i/dn)**2,v=[0,1,2].map(m=>Math.min(Gt.BRIGHTEST_RELATIVE,u[m]*d[m]/p));f instanceof Ie||(this.disposeMesh(f),f=new Ie(new hi(1,16,16),new Dn({fog:!1})),this.celestialGroup.add(f),this.bodyMeshes.set(e,f)),f.material.color.setRGB(v[0],v[1],v[2]),f.scale.setScalar(i)}else{if(!(f instanceof Ps)){this.disposeMesh(f);const m=new ht;m.setAttribute("position",new tt(new Float32Array(3),3)),m.setAttribute("color",new tt(new Float32Array(3),3)),f=new Ps(m,rt.material(sl[sl.length-1].size,!1)),rt.track(f),this.celestialGroup.add(f),this.bodyMeshes.set(e,f)}const p=f.geometry.getAttribute("color"),v=e.startsWith("comet:")?this.pointToPixel():1;p.setXYZ(0,u[0]*d[0]*v,u[1]*d[1]*v,u[2]*d[2]*v),p.needsUpdate=!0}if(f.position.set(r,o,l),this.setHitArea(e,r,o,l,i),e==="sun"&&(this.sunArriving=d),e.startsWith("comet:")?this.disposeGlare(e):e!=="sun"&&this.setGlare(e,r,o,l,d,i/dn*(180/Math.PI),Gt.POINT_VEIL_HOLD_DEG),e==="sun"){this.sunVisible=!0;const p=this.celestialGroup.scale.x;this.sunWorldPosition.set(r*p,o*p+this.celestialGroup.position.y,l*p),this.lensFlare||(this.lensFlare=z5(),this.lensFlare.uniforms.uOpacity.value=OA,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 i="moon";if(e.magnitude>t||e.altitudeDeg<Wf){this.disposeMesh(this.bodyMeshes.get(i)),this.bodyMeshes.delete(i),this.disposeHitArea(i),this.disposeGlare(i);return}const{x:n,y:s,z:r}=fi(e.altitudeDeg,e.azimuthDeg,dn),o=this.cloudTransmission(e),l=this.arrivingIlluminance(e,e.magnitude,o),c=Math.max(Wa(e.phase.illuminatedFraction,0,1),.01)*Math.PI*(zo/dn)**2,h=new se(...l.map(f=>Math.min(Gt.BRIGHTEST_RELATIVE,f/c))),d=`${e.phase.phaseFraction<.5}:${Math.round(Wa(e.phase.illuminatedFraction,0,1)*500)}`;let u=this.bodyMeshes.get(i);if(u instanceof To)u.userData.phaseKey!==d&&(u.material.map?.dispose(),u.material.map=jg(e.phase),u.userData.phaseKey=d),u.material.color.copy(h);else{this.disposeMesh(u),u=new To(new Bc({map:jg(e.phase),color:h,fog:!1})),u.userData.phaseKey=d;const f=zo*2;u.scale.set(f,f,1),this.celestialGroup.add(u),this.bodyMeshes.set(i,u)}u.position.set(n,s,r),this.setHitArea(i,n,s,r,zo),this.setGlare(i,n,s,r,l,zo/dn*(180/Math.PI))}bentLight(e,t,i=MA){const[n,s,r]=this.arrivingIlluminance(e,t,1),o=Math.max(s,1e-30);return{scale:s/i,tint:[n/o,1,r/o]}}static litBySky(e,t){return Gt.litScratch.setRGB(e.r*t[0],e.g*t[1],e.b*t[2])}static litScratch=new se;pointToPixel(){const e=Math.max(1,this.renderer.getDrawingBufferSize(this.pointScratch).y),t=(this.camera.fov*Math.PI/180/e)**2;return Math.min(1,rt.CONE_SOLID_ANGLE/t)}pointScratch=new be;static POINT_VEIL_HOLD_DEG=.25;static BRIGHTEST_RELATIVE=6e4;arrivingIlluminance(e,t,i){const n=this.air.transmittanceFromSpace(this.siteElevationM+this.observerElevationM,e.altitudeDeg),s=vt.illuminanceOf(t)*i*this.relativeScale;return[n[0]*s,n[1]*s,n[2]*s]}static unitLuminance(e){const t=Hn.luminanceOf([e.r,e.g,e.b]);return t>0?[e.r/t,e.g/t,e.b/t]:[1,1,1]}setHitArea(e,t,i,n,s){let r=this.hitAreas.get(e);if(!r){const l=new Bc({transparent:!0,opacity:0,depthTest:!1,depthWrite:!1,fog:!1});r=new To(l),this.celestialGroup.add(r),this.hitAreas.set(e,r)}r.position.set(t,i,n);const o=s*yA;r.scale.set(o,o,1)}disposeHitArea(e){const t=this.hitAreas.get(e);t&&(t.removeFromParent(),t.material.dispose(),this.hitAreas.delete(e))}setGlare(e,t,i,n,s,r,o=0){if(Bi.radiusDeg(Bi.K*Math.max(...s))<=Math.max(r,o)){this.disposeGlare(e);return}let l=this.glareSprites.get(e);l||(l=new Bi(`veil:${e}`),this.celestialGroup.add(l.mesh),this.glareSprites.set(e,l)),l.shine({x:t,y:i,z:n},s,r,o)}disposeGlare(e){const t=this.glareSprites.get(e);t&&(t.mesh.removeFromParent(),t.dispose(),this.glareSprites.delete(e))}buildComet(e,t){const i=e&&`comet:${e.id}`;if(!e||!i||e.magnitude>t){this.disposeComet();return}this.cometKey&&this.cometKey!==i&&this.disposeComet();const n=Ko(e.magnitude,t),s=Rd(n);this.cometKey=i,this.setBodyMesh(i,e.position,Xd*(.5+.5*n),new se(s,s,s),e.magnitude),this.cometTail||(this.cometTail=new fn(dn),this.celestialGroup.add(this.cometTail.object)),this.cometTail.set(e.position,e.tailEnd,n)}buildIceHalos(e,t){this.iceHalos||(this.iceHalos=new ki,this.iceHalos.setCloudOffset(this.cloudFieldOffset),this.iceHalos.onReady=()=>this.render(),this.celestialGroup.add(this.iceHalos.object)),this.iceHalos.setUrgent(!!this.skyHoldUntilMs);const i=this.highCloudCover(),n=this.layeredClouds?.cirrusMask;if(this.iceHalos.setCloudOffset(n?.offset??this.cloudFieldOffset),this.layeredClouds?.hostHalo(this.iceHalos),i===void 0){this.iceHalos.update({x:0,y:1,z:0},-1,0,[1,1,1],{cover:0,layerHeight:Sc},0);return}const s=this.lowerCloudCover(),r=ot.deckLitUntilDeg(ot.DECK_HEIGHT_M),o=e.altitudeDeg>-r?e:t,l=this.bentLight(o,o===e?$t.SUN_MAGNITUDE:t.magnitude),c=ot.strength(i,s,o.altitudeDeg,r)*l.scale,{x:h,y:d,z:u}=fi(o.altitudeDeg,o.azimuthDeg,1);this.iceHalos.update({x:h,y:d,z:u},o.altitudeDeg,c,l.tint,{cover:n?.cover??i,layerHeight:n?.layerHeight??Sc},n?.iceCrystalAlignment??this.weather.iceCrystalAlignment??.65)}buildRainbow(e,t){this.rainbow||(this.rainbow=new Yr,this.celestialGroup.add(this.rainbow.object));const i=this.weather.precipitationType==="rain"?this.weather.precipitationIntensity*(this.weather.precipitationAmount??1):0,n=e.altitudeDeg>0,s=n?e:t,r=this.lowerCloudCover(),o=this.bentLight(s,n?$t.SUN_MAGNITUDE:t.magnitude,wA),l=Ui.strength(i,r,s.altitudeDeg)*o.scale;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}=fi(s.altitudeDeg,s.azimuthDeg,1);this.rainbow.update({x:c,y:h,z:d},l,o.tint,n)}buildSkyGlow(e,t){if(!e.frame){this.skyGlow?.hide();return}this.skyGlow||(this.skyGlow=new rr,this.skyGlow.onReady=()=>this.render(),this.celestialGroup.add(this.skyGlow.object));const{date:i,observer:n}=e.frame,s=gn.galactic(i,n),r=Gt.directionOf(s.centre),o=Gt.directionOf(s.rotation),l=Gt.directionOf(s.pole),c=new Xe().set(r.x,r.y,r.z,o.x,o.y,o.z,l.x,l.y,l.z),h=Gt.directionOf(gn.eclipticPole(i,n)),d=Gt.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:Gt.directionOf(e.moon),altitudeDeg:e.moon.altitudeDeg,phaseAngleDeg:We.phaseAngleOf(e.moon.phase.illuminatedFraction)},skyColor:new C(t[0],t[1],t[2])})}static directionOf(e){const{x:t,y:i,z:n}=fi(e.altitudeDeg,e.azimuthDeg,1);return new C(t,i,n).normalize()}buildNovae(e,t){const i=new Set;for(const n of e){if(n.magnitude>t)continue;const s=`nova:${n.id}`;i.add(s);const r=Ko(n.magnitude,t),o=Rd(r);this.setBodyMesh(s,n.position,Xd*(.5+.5*r),new se(o,o,o),n.magnitude)}for(const n of this.novaKeys)i.has(n)||(this.disposeMesh(this.bodyMeshes.get(n)),this.bodyMeshes.delete(n),this.disposeHitArea(n),this.disposeGlare(n));this.novaKeys=i}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 i=new Set(["sun","moon",...this.cometKey?[this.cometKey]:[],...this.novaKeys]);for(const n of e){if(n.magnitude>t)continue;i.add(n.body);const s=Ko(n.magnitude,t),r=Rd(s),o=eT[n.body]??new se(1,1,1),l=new se(o.r*r,o.g*r,o.b*r),c=Xd*(.5+.5*s);this.setBodyMesh(n.body,n.position,c,l,n.magnitude)}for(const n of[...this.bodyMeshes.keys()])i.has(n)||(this.disposeMesh(this.bodyMeshes.get(n)),this.bodyMeshes.delete(n),this.disposeHitArea(n),this.disposeGlare(n))}buildStars(e,t){if(this.namedStars=[],!e||e.catalog.count===0){this.disposeStarTiers(),this.syncAnimationLoop();return}const{catalog:i,date:n,observer:s}=e,r=new Bn(n,s),o=tu(1337),l=[],c=this.siteElevationM+this.observerElevationM;for(let h=0;h<i.count;h++){const d=i.mag[h];if(d>t)break;const{altitudeDeg:u,azimuthDeg:f}=r.position(i.ra[h],i.dec[h]);if(u<Ig)continue;const{x:p,y:v,z:m}=fi(u,f,Wd);l.push({x:p,y:v,z:m,brightness:Ko(d,t),illuminance:this.air.transmittanceFromSpace(c,u).map(g=>g*vt.illuminanceOf(d)),phase:o()*Math.PI*2,speedFactor:.7+o()*.6})}for(const h of y5){if(h.mag>t)continue;const{altitudeDeg:d,azimuthDeg:u}=r.position(h.raHours,h.decDeg);if(d<Ig)continue;const{x:f,y:p,z:v}=fi(d,u,Wd);this.namedStars.push({star:h,direction:new C(f,p,v).normalize(),altitudeDeg:d})}this.starTiers=sl.map((h,d)=>{const u=l.filter(x=>C1(x.brightness)===d),f=new Float32Array(u.length*3),p=new Float32Array(u.length),v=new Float32Array(u.length*3),m=new Float32Array(u.length),g=new Float32Array(u.length);u.forEach((x,E)=>{f[E*3]=x.x,f[E*3+1]=x.y,f[E*3+2]=x.z,p[E]=x.brightness,v.set(x.illuminance,E*3),m[E]=x.phase,g[E]=x.speedFactor});const y=new ht;y.setAttribute("position",new tt(f,3)),y.setAttribute("seed",new tt(m.map(x=>x/(2*Math.PI)),1));const M=new tt(new Float32Array(u.length*3),3);y.setAttribute("color",M);let b=this.starTiers[d]?.points;return b?(b.geometry.dispose(),b.geometry=y):(b=new Ps(y,rt.material(h.size)),rt.track(b),this.celestialGroup.add(b)),{points:b,colorAttribute:M,brightness:p,illuminance:v,phase:m,speedFactor:g}}),this.starColoursRelative=Number.NaN,this.updateTwinkle(this.twinkleSeconds),this.startTwinkle()}twinkleSeconds=0;starColoursRelative=Number.NaN;updateTwinkle(e){rt.setTime(e);const t=this.relativeScale;if(t!==this.starColoursRelative){this.starColoursRelative=t;for(const i of this.starTiers){const n=i.colorAttribute.array;for(let s=0;s<i.brightness.length;s++)n[s*3]=i.illuminance[s*3]*t,n[s*3+1]=i.illuminance[s*3+1]*t,n[s*3+2]=i.illuminance[s*3+2]*t;i.colorAttribute.needsUpdate=!0}}}buildClouds(){if(this.cloudRendering==="volume"||this.weather.cloudLayers!==void 0){this.layeredClouds||(this.disposeCloudSystem(),this.layeredClouds=new Ja(this.celestialGroup,Yd,this.cloudRendering)),this.disposeCirrus(),this.layeredClouds.hostHalo(this.iceHalos),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}const e=this.lowerCloudCover();if(e<=0){this.disposeCloudSystem();return}const t=this.weather.cloudDarkness,i=new se(Rr[0]+(Kd[0]-Rr[0])*t,Rr[1]+(Kd[1]-Rr[1])*t,Rr[2]+(Kd[2]-Rr[2])*t);if(this.cloudMesh&&this.cloudUniforms){this.cloudUniforms.coverage.value=e,this.cloudUniforms.baseColor.value.copy(i),this.syncCloudLayer(),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}this.disposeCloudSystem();const{material:n,uniforms:s}=gf(i,e,Math.abs(this.cloudLayerOffset()));this.cloudMaterial=n,this.cloudUniforms=s,s.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);const r=vf(Yd);this.cloudMesh=new Ie(r,n),this.faceCloudDeck(this.cloudMesh,this.cloudLayerOffset()),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(){const e=this.weather.highCloudCover??0;if(this.layeredClouds||e<=0){this.disposeCirrus();return}if(this.cirrusMesh&&this.cirrusUniforms){this.cirrusUniforms.coverage.value=e,this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}const{material:t,uniforms:i}=gf(new se(...Rr),e,Sc,1);this.cirrusMaterial=t,this.cirrusUniforms=i,i.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.cirrusMesh=new Ie(vf(Yd*1.04),t),this.cirrusMesh.renderOrder=kg-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.faceCloudDeck(this.cloudMesh,e)}faceCloudDeck(e,t){const i=t<0;e.scale.y=i?-1:1,e.renderOrder=i?Ja.deckOrder(!0,0,1):kg}cloudLayerOffset(){const t=((this.weather.cloudBaseM??1e3)-this.observerElevationM)*qd;return Math.sign(t||1)*Math.max(Math.abs(t),NA)}updateCloudLighting(e,t){const i=[this.cloudUniforms,this.cirrusUniforms].filter(d=>d!==void 0);if(i.length===0&&!this.layeredClouds)return;const n=this.cloudBeamDirection,[s,r,o]=this.cloudBeam.map(d=>d/Math.PI),l=this.lightningLevel*eu*this.relativeScale/Math.PI,c=new se(t[0]+Qn.r*l,t[1]+Qn.g*l,t[2]+Qn.b*l);this.layeredClouds?.setLighting(n.clone(),new se(s,r,o),c,c);const h=Math.max(0,n.y);for(const d of i)d.sunDir.value.copy(n),d.sunColor.value.setRGB(s*h,r*h,o*h),d.ambientColor.value.copy(c)}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}precipitationCount(e){return WA(e,this.weather.precipitationIntensity,this.weather.precipitationAmount??1)}updatePrecipitationDensity(){const e=[[this.rainSystem?.points,Jd],[this.rainSplashSystem?.points,Pr],[this.precipitationPoints,this.weather.precipitationType==="none"||this.weather.precipitationType==="rain"?void 0:Zd[this.weather.precipitationType].poolSize]];for(const[t,i]of e)t&&i!==void 0&&t.geometry.setDrawRange(0,this.precipitationCount(i));this.rainSystem&&(this.rainSystem.uniforms.uSpeedStreak.value=Bg(Qd(this.weather.precipitationIntensity)))}buildPrecipitation(){this.disposePrecipitationPoints(),this.disposeRain();const e=this.weather.precipitationType;if(e==="none")return;if(e==="rain"){this.buildRain();return}const t=Zd[e],i=t.poolSize,n=tu(9001),s=new Float32Array(i*3),r=new Float32Array(i),o=new Float32Array(i),l=new Float32Array(i),c=new Float32Array(i),h=new Float32Array(i),d=new Float32Array(i),u=new Float32Array(i),f=new Float32Array(i),p=new Float32Array(i);for(let M=0;M<i;M++){const b=n()*Math.PI*2,x=n()*t.radiusM;s[M*3]=Math.cos(b)*x,s[M*3+1]=Na+n()*(t.topYM-Na),s[M*3+2]=Math.sin(b)*x,r[M]=n()*Math.PI*2,o[M]=.7+n()*.6,l[M]=.6+n()*.8,c[M]=.4+n()*1.2}const v=new ht;v.setAttribute("position",new tt(s,3)),v.setDrawRange(0,this.precipitationCount(i));const m={uSize:{value:t.size},uScale:{value:.5*this.renderer.domElement.height},uOpacity:{value:t.opacity},uColor:{value:t.color.clone()},uHazeColor:{value:new se(...this.baseFogColor)},uTexture:{value:tT(e)},uNearFocusDistance:{value:Vg},uHazeDistance:{value:t.radiusM*Wg}},g=new dt({uniforms:m,vertexShader:oT,fragmentShader:lT,transparent:!0,depthWrite:!1});this.precipitationUniforms=m;const y=new Ps(v,g);y.renderOrder=$d,this.scene.add(y),this.precipitationPoints=y,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)return;this.precipitationUniforms?.uHazeColor.value.setRGB(...this.baseFogColor);const i=this.weather.precipitationType;if(i==="none"||i==="rain")return;const n=Zd[i];if(this.precipitationUniforms?.uColor.value.copy(Gt.litBySky(n.color,this.baseFogColor)),t<=0)return;const s=this.weather.windDirectionDeg*en,r=Math.sin(s)*this.weather.windSpeed*n.driftSensitivity,o=-Math.cos(s)*this.weather.windSpeed*n.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,y=i==="snow"&&d&&u,M=i==="hail"&&f&&p&&v&&m&&g;for(let b=0,x=0;b<l.length;b+=3,x++){if(M&&f[x]>0){if(f[x]-=t,f[x]<=0){const w=Math.random()*Math.PI*2,T=Math.sqrt(Math.random())*n.radiusM;l[b]=Math.cos(w)*T,l[b+1]=n.topYM,l[b+2]=Math.sin(w)*T,f[x]=0}else{const w=1-f[x]/v[x];l[b+1]=Na+Math.sin(Math.PI*w)*p[x],l[b]=Ac(l[b]+(r+m[x])*t,n.radiusM),l[b+2]=Ac(l[b+2]+(o+g[x])*t,n.radiusM)}continue}let E=0,I=0;if(y){const w=YA*d[x],T=qA*u[x];E=Math.sin(e*w*Math.PI*2+c[x])*T,I=Math.sin(e*w*Math.PI*2+c[x]+Math.PI/2)*T}if(l[b]+=(r+E)*t,l[b+1]-=n.fallSpeedMPerS*h[x]*t,l[b+2]+=(o+I)*t,l[b]=Ac(l[b],n.radiusM),l[b+2]=Ac(l[b+2],n.radiusM),l[b+1]<Na){if(M){p[x]=Kg*(.2+Math.random()*1.6),v[x]=$A*(.5+Math.random()),f[x]=v[x];const A=Math.random()*Math.PI*2,D=KA*(p[x]/Kg);m[x]=Math.cos(A)*D,g[x]=Math.sin(A)*D,l[b+1]=Na;continue}const w=Math.random()*Math.PI*2,T=Math.sqrt(Math.random())*n.radiusM;l[b]=Math.cos(w)*T,l[b+1]=n.topYM,l[b+2]=Math.sin(w)*T}}this.precipitationPoints.geometry.attributes.position.needsUpdate=!0}buildRain(){const e=Qd(this.weather.precipitationIntensity);this.rainSystem=N5({count:Jd,radiusM:Ho,heightM:UA,bottomYM:Ng,overallSpeed:BA,color:Ug.clone(),opacity:.85,visibleCount:this.precipitationCount(Jd),speedStreak:Bg(e),pixelSize:Yg,seed:9001,nearFocusDistanceM:Vg,hazeDistanceM:Ho*Wg,hazeColor:new se(...this.baseFogColor)}),this.rainLastVerticalFacing=-1,this.syncRainSlant(),this.rainSystem.points.renderOrder=$d,this.scene.add(this.rainSystem.points),this.buildRainSplashes()}buildRainSplashes(){const e=tu(4242),t=new Float32Array(Pr*3),i=new Float32Array(Pr),n=new Float32Array(Pr),s=new Float32Array(Pr);for(let h=0;h<Pr;h++){const d=e()*Math.PI*2,u=Math.sqrt(e())*Ho;t[h*3]=Math.cos(d)*u,t[h*3+1]=Ng,t[h*3+2]=Math.sin(d)*u,n[h]=Zg(zg,Hg),i[h]=e()*n[h],s[h]=i[h]/n[h]}const r=new ht;r.setAttribute("position",new tt(t,3));const o=new tt(s,1);r.setAttribute("aLife",o),r.setDrawRange(0,this.precipitationCount(Pr));const l=new dt({uniforms:{uMaxSize:{value:VA},uScale:{value:.5*this.renderer.domElement.height},uColor:{value:Gg.clone()},uTexture:{value:sT()}},vertexShader:rT,fragmentShader:aT,transparent:!0,depthWrite:!1}),c=new Ps(r,l);c.renderOrder=$d,this.scene.add(c),this.rainSplashSystem={points:c,positions:t,life:i,duration:n,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*en;e.uniforms.uDropVelocity.value.set(Math.sin(t)*this.weather.windSpeed,-Qd(this.weather.precipitationIntensity),-Math.cos(t)*this.weather.windSpeed);const i=this.renderer.getSize(this.rainViewportSize);e.uniforms.uAspect.value=i.x/Math.max(i.y,1)}updateRain(e){const t=this.rainSystem;if(!t)return;t.uniforms.uTime.value+=e,t.uniforms.uHazeColor.value.setRGB(...this.baseFogColor),t.uniforms.uColor.value.copy(Gt.litBySky(Ug,this.baseFogColor));const i=this.rainSplashSystem?.points.material?.uniforms?.uColor;i&&i.value.copy(Gt.litBySky(Gg,this.baseFogColor));const n=this.weather.windDirectionDeg*en,s=Math.sin(n)*this.weather.windSpeed,r=-Math.cos(n)*this.weather.windSpeed,o=Ho,l=h=>(h%(o*2)+o*3)%(o*2)-o;t.uniforms.uWindOffset.value.set(l(t.uniforms.uWindOffset.value.x+s*e),l(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 h=qg+(1-qg)*(1-c),d=$g+(1-$g)*(1-c);t.uniforms.uUvSquash.value=d,t.uniforms.uPixelSize.value=Yg*h*(.5+.5*d)}this.updateRainSplashes(e)}updateRainSplashes(e){const t=this.rainSplashSystem;if(!t||e<=0)return;const{positions:i,life:n,duration:s,lifeAttribute:r}=t,o=r.array;for(let l=0,c=0;l<i.length;l+=3,c++){if(n[c]+=e,n[c]>=s[c]){const h=Math.random()*Math.PI*2,d=Math.sqrt(Math.random())*Ho;i[l]=Math.cos(h)*d,i[l+2]=Math.sin(h)*d,s[c]=Zg(zg,Hg),n[c]=0}o[c]=n[c]/s[c]}t.points.geometry.attributes.position.needsUpdate=!0,r.needsUpdate=!0}setLightning(e){this.lightningFlashes=e}updateLightning(e){let t,i=0;if(this.lightningArmed)for(const l of this.lightningFlashes){if(l.t>e)break;const c=pi.brightnessAt(l,e);c>i&&(t=l,i=c)}const n=t?Math.min(1,Math.max(.1,(JA/t.distanceM)**2)):0,s=i*n*(t?.cloudToGround?1:.6);if(s===this.lightningLevel&&!t?.cloudToGround)return;if(this.lightningLevel=s,this.scene.fog){const l=this.scene.fog,c=s*eu*this.relativeScale/Math.PI;l.color.setRGB(this.airlight[0]+Qn.r*c,this.airlight[1]+Qn.g*c,this.airlight[2]+Qn.b*c)}const r=this.skyMesh?.material?.color;if(r){const l=s*QA;r.setRGB(1+l*Qn.r,1+l*Qn.g,1+l*Qn.b)}if(this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.lightningLight.intensity=s*eu*this.relativeScale,t){const{x:l,y:c,z:h}=fi(25,t.azimuthDeg,dn);this.lightningLight.position.set(l,c,h)}this.lightningBolt||(this.lightningBolt=new ar(dn*.95),this.celestialGroup.add(this.lightningBolt.object));const o=this.weather.cloudBaseM??1500;this.lightningBolt.set(t,i,o),this.render()}buildCompassLabels(){const e=oo(navigator.languages,TA),t=AA[e];this.compassSprites=_A.map((i,n)=>{const s=t[n],r=new Bc({map:cT(s),depthTest:!1,fog:!1}),o=new To(r),{x:l,y:c,z:h}=fi(0,i,Rg);return o.position.set(l,c,h),o.scale.set(_c,_c,1),o.renderOrder=CA,o.layers.set(Eg),o.visible=this.compassHovered||this.compassForced,this.celestialGroup.add(o),o}),this.updateCompassScale()}updateCompassScale(){const e=this.camera.fov*Math.PI/360,t=Pg*Math.PI/360,i=_c*Math.tan(e)/Math.tan(t);for(const n of this.compassSprites)n.scale.set(i,i,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 i of Array.isArray(t)?t:[t]){const n=i.map;n&&n.dispose(),i.dispose()}}}const en=Math.PI/180;function Wa(a,e,t){return Math.max(e,Math.min(t,a))}function Zg(a,e){return a+Math.random()*(e-a)}function Ac(a,e){return(a%(e*2)+e*3)%(e*2)-e}let Tc,Ic;function tT(a){switch(a){case"snow":return iT();case"hail":return nT()}}function iT(){if(Tc)return Tc;const a=64,e=document.createElement("canvas");e.width=a,e.height=a;const t=e.getContext("2d"),i=t.createRadialGradient(a/2,a/2,0,a/2,a/2,a/2);return i.addColorStop(0,"rgba(255,255,255,0.95)"),i.addColorStop(.5,"rgba(255,255,255,0.55)"),i.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=i,t.fillRect(0,0,a,a),Tc=new Vs(e),Tc}function nT(){if(Ic)return Ic;const a=64,e=document.createElement("canvas");e.width=a,e.height=a;const t=e.getContext("2d"),i=t.createRadialGradient(a/2,a/2,0,a/2,a/2,a/2);return i.addColorStop(0,"rgba(255,255,255,1)"),i.addColorStop(.55,"rgba(255,255,255,0.95)"),i.addColorStop(.8,"rgba(255,255,255,0.4)"),i.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=i,t.fillRect(0,0,a,a),Ic=new Vs(e),Ic}let Dc;function sT(){if(Dc)return Dc;const a=64,e=document.createElement("canvas");e.width=a,e.height=a;const t=e.getContext("2d"),i=t.createRadialGradient(a/2,a/2,0,a/2,a/2,a/2);return i.addColorStop(0,"rgba(255,255,255,0)"),i.addColorStop(.4,"rgba(255,255,255,0)"),i.addColorStop(.6,"rgba(255,255,255,0.9)"),i.addColorStop(.8,"rgba(255,255,255,0.25)"),i.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=i,t.fillRect(0,0,a,a),Dc=new Vs(e),Dc}const rT=`
8755
8755
  uniform float uMaxSize;
8756
8756
  uniform float uScale;
8757
8757
  attribute float aLife;